Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize tests #1027

Merged
merged 12 commits into from
May 13, 2021
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ storybook-static
.vscode
.idea
.env
.DS_Store
.DS_Store

# test artifacts
packages/files-ui/cypress/screenshots
packages/files-ui/cypress/videos
packages/files-ui/cypress/fixtures/storage
24 changes: 0 additions & 24 deletions packages/files-ui/cypress/integration/login.ts

This file was deleted.

17 changes: 17 additions & 0 deletions packages/files-ui/cypress/integration/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe("Settings", () => {
it("can navigate to the settings profile page", () => {
cy.web3Login()
cy.get("[data-cy=settings-nav]").click()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there perhaps a way we could make these markers constant or avoid needing magic strings?

CC: @FSM1 @tanmoyAtb

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I misunderstood what you mean but those data-cy are based on Cypress best practices, to make sure tests fail as little as possible, even when changing the copy, or the classes https://docs.cypress.io/guides/references/best-practices#Selecting-Elements

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean we could have a bunch of string constants, but I dont know if there is much benefit to be had yet. If we do start feeling overwhelmed by this, its easy enough to Ctrl+f data-cy and fix it later

Copy link
Collaborator Author

@Tbaut Tbaut May 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah now I get it. This is not something that should ever change, so I don't think we would get any benefit from having a list of strings there indeed.

cy.get("[data-cy=settings-profile-header").should("be.visible")
cy.url().should("include", "/settings")
})

it("can navigate to the settings security page on a phone", () => {
cy.viewport("iphone-6")
cy.web3Login()
cy.get(".hamburger-menu").click()
cy.get("[data-cy=settings-nav]").click()
cy.get("[data-cy=settings-profile-header]").should("not.exist")
cy.url().should("include", "/settings")
})
})
17 changes: 13 additions & 4 deletions packages/files-ui/cypress/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,26 @@
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
import { existsSync, readFileSync } from "fs"

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export default (on, config) => {

export default (on: any) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config

on("task", {
readFileMaybe(filename: string) {
if (existsSync(filename)) {
return readFileSync(filename, "utf8")
}

return null
}
})
}
102 changes: 83 additions & 19 deletions packages/files-ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,101 @@ import { ethers, Wallet } from "ethers"
import { testPrivateKey, testAccountPassword, localHost } from "../fixtures/loginData"
import { CustomizedBridge } from "./utils/CustomBridge"

export type Storage = Record<string, string>[]

export interface Web3LoginOptions {
url?: string
saveBrowser?: boolean
useLocalAndSessionStorage?: boolean
}

Cypress.Commands.add("web3Login", ({ saveBrowser = false, url = localHost }: Web3LoginOptions = {}) => {
const SESSION_FILE = "cypress/fixtures/storage/sessionStorage.json"
const LOCAL_FILE = "cypress/fixtures/storage/localStorage.json"

Cypress.Commands.add("web3Login", ({ saveBrowser = false, url = localHost, useLocalAndSessionStorage = true }: Web3LoginOptions = {}) => {
let session: Storage = []
let local: Storage = []

cy.task<string | null>("readFileMaybe", SESSION_FILE)
.then((unparsedSession) => {
session = unparsedSession && JSON.parse(unparsedSession) || []
})

cy.task<string | null>("readFileMaybe", LOCAL_FILE)
.then((unparsedLocal) => {
local = unparsedLocal && JSON.parse(unparsedLocal) || []
})

cy.on("window:before:load", (win) => {
const provider = new ethers.providers.JsonRpcProvider("https://rinkeby.infura.io/v3/4bf032f2d38a4ed6bb975b80d6340847", 4)
const signer = new Wallet(testPrivateKey, provider)

// inject ethereum object in the global window
Object.defineProperty(win, "ethereum", {
get: () => new CustomizedBridge(signer as any, provider as any)
})

// clear session storage in any case, if previous session storage should be
// kept will be decided after.
// Note that Cypress keep the session storage between test but clears localStorage
win.sessionStorage.clear()
win.localStorage.clear()

if (useLocalAndSessionStorage){
session.forEach(({ key, value }) => {
win.sessionStorage.setItem(key, value)
})

local.forEach(({ key, value }) => {
win.localStorage.setItem(key, value)
})
}
})

cy.visit(url)
cy.get("[data-cy=web3]").click()
cy.get(".bn-onboard-modal-select-wallets > :nth-child(1) > .bn-onboard-custom").click()
cy.get("[data-cy=sign-in-with-web3-button]").click()
cy.get("[data-cy=login-password-button]", { timeout: 10000 }).click()
cy.get("[data-cy=login-password-input]").type(`${testAccountPassword}{enter}`)

if(saveBrowser){
cy.get("[data-cy=save-browser-button]").click()
} else {
cy.get("[data-cy=do-not-save-browser-button]").click()
}

cy.get("[data-cy=files-app-header", { timeout: 30000 }).should("be.visible")
// with nothing in localstorage (and in session storage)
// the whole login flow should kick in
cy.then(() => {
cy.log("Loging in", !!local.length && "there is something in session storage ---> direct login")
Tbaut marked this conversation as resolved.
Show resolved Hide resolved

if(local.length === 0){
cy.log("nothing in session storage, --> click on web3 button")
cy.get("[data-cy=web3]").click()
cy.get(".bn-onboard-modal-select-wallets > :nth-child(1) > .bn-onboard-custom").click()
cy.get("[data-cy=sign-in-with-web3-button]").click()
cy.get("[data-cy=login-password-button]", { timeout: 20000 }).click()
cy.get("[data-cy=login-password-input]").type(`${testAccountPassword}{enter}`)

if(saveBrowser){
// this is taking forever for test accounts
cy.get("[data-cy=save-browser-button]").click()
} else {
cy.get("[data-cy=do-not-save-browser-button]").click()
}
}
})

cy.get("[data-cy=files-app-header", { timeout: 20000 }).should("be.visible")

// save local and session storage in files
cy.window().then((win) => {
const newLocal: Array<Record<string, string>> = []
const newSession: Array<Record<string, string>> = []

Object.keys(win.localStorage).forEach((key) => {
newLocal.push({ key, value: localStorage.getItem(key) || "" })
})

Object.keys(win.sessionStorage).forEach((key) => {
newSession.push({ key, value: sessionStorage.getItem(key) || "" })
})

const newLocalString = JSON.stringify(newLocal)
const newSessionString = JSON.stringify(newSession)

cy.writeFile(SESSION_FILE, newSessionString)
cy.writeFile(LOCAL_FILE, newLocalString)
})
})

// Must be declared global to be detected by typescript (allows import/export)
Expand All @@ -68,11 +132,11 @@ declare global {
namespace Cypress {
interface Chainable {
/**
* Login using Metamask to an instance of files running on localhost:3000.
* @param {Object} options
* @param {string} options.saveBrowser - save the browser to localstorage (default: false).
* @param {string} options.url - what url to visit (default: "http://localhost:3000").
* @example cy.web3Login({saveBrowser: true})
* Login using Metamask to an instance of Files.
* @param {String} options.url - (default: "http://localhost:3000") - what url to visit.
* @param {Boolean} options.saveBrowser - (default: false) - save the browser to localstorage.
* @param {Boolean} options.useLocalAndSessionStorage - (default: true) - use what could have been stored before to speedup login
* @example cy.web3Login({saveBrowser: true, url: 'http://localhost:8080'})
*/
web3Login: (options?: Web3LoginOptions) => Chainable
}
Expand Down
2 changes: 1 addition & 1 deletion packages/files-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"extract": "lingui extract",
"compile": "lingui compile",
"lingui-version": "lingui --version",
"lint": "eslint './src/**/*.{js,jsx,ts,tsx}'"
"lint": "eslint './{src, cypress}/**/*.{js,jsx,ts,tsx}'"
},
"browserslist": {
"production": [
Expand Down
2 changes: 1 addition & 1 deletion packages/files-ui/src/Components/Layouts/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ const AppHeader = ({ navOpen, setNavOpen }: IAppHeader) => {
<HamburgerMenu
onClick={() => setNavOpen(!navOpen)}
variant={navOpen ? "active" : "default"}
className={classes.hamburgerMenu}
className={clsx(classes.hamburgerMenu, "hamburger-menu")}
/>
<Link
className={classes.logo}
Expand Down
1 change: 1 addition & 0 deletions packages/files-ui/src/Components/Layouts/AppNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ const AppNav: React.FC<IAppNav> = ({ navOpen, setNavOpen }: IAppNav) => {
>
<SettingSvg />
<Typography
data-cy="settings-nav"
variant="h5"
className={classes.navItemText}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ const ProfileView = () => {
<Typography
variant="body1"
className={classes.label}
data-cy="settings-profile-header"
>
<Trans>Wallet address</Trans>
</Typography>
Expand Down
4 changes: 2 additions & 2 deletions packages/files-ui/src/Contexts/ThresholdKeyContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -825,11 +825,11 @@ const ThresholdKeyProvider = ({ children, network = "mainnet", enableLogging = f
loggedinAs
}}
>
{!isNewDevice && pendingShareTransferRequests.length > 0 && (
{/* {!isNewDevice && pendingShareTransferRequests.length > 0 && (
Tbaut marked this conversation as resolved.
Show resolved Hide resolved
<ShareTransferRequestModal
requests={pendingShareTransferRequests}
/>
)}
)} */}
{children}
</ThresholdKeyContext.Provider>
)
Expand Down