Skip to content

Commit

Permalink
Files API Client in Tests (#1097)
Browse files Browse the repository at this point in the history
* use api client in tests

* fix detached from the Dom (#1096)

Co-authored-by: Thibaut Sardan <github@thib.top>

* make eslint :D

* update yarn lock

* update commands

Co-authored-by: Thibaut Sardan <github@thib.top>
Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 9, 2021
1 parent 0409978 commit ad6ccd7
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 200 deletions.
238 changes: 131 additions & 107 deletions packages/files-ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
import { ethers, Wallet } from "ethers"
import { testPrivateKey, testAccountPassword, localHost } from "../fixtures/loginData"
import { CustomizedBridge } from "./utils/CustomBridge"
import { FilesApiClient } from "@chainsafe/files-api-client"
import "cypress-file-upload"
import axios from "axios"

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

export interface Web3LoginOptions {
url?: string
Expand All @@ -45,28 +47,30 @@ const LOCAL_FILE = "cypress/fixtures/storage/localStorage.json"
const REFRESH_TOKEN_KEY = "csf.refreshToken"

Cypress.Commands.add("clearCsfBucket", (apiUrlBase: string) => {
const axiosInstance = axios.create({
// Disable the internal Axios JSON de serialization as this is handled by the client
transformResponse: []
})

const apiClient = new FilesApiClient({}, apiUrlBase, axiosInstance)

cy.window().then((win) => {
cy.request("POST", `${apiUrlBase}/user/refresh`, { "refresh": win.sessionStorage.getItem(REFRESH_TOKEN_KEY) })
.then((res) => res.body.access_token.token)
.then((accessToken) => {
cy.request({
method: "POST",
url: `${apiUrlBase}/files/ls`,
body: { "path": "/", "source": { "type": "csf" } },
auth: { "bearer": accessToken }
}).then((res) => {
const toDelete = res.body.map(({ name }: { name: string }) => `/${name}`)
cy.log(`clearCsfBucket - Deleting ${JSON.stringify(toDelete)}`)
cy.request({
method: "POST",
url: `${apiUrlBase}/files/rm`,
body: { "paths": toDelete, "source": { "type": "csf" } },
auth: { "bearer": accessToken }
}).then(res => {
if(!res.isOkStatusCode){
throw new Error(`unexpected answer when deleting files: ${JSON.stringify(res, null, 2)}`)
}
})
apiClient
.getRefreshToken({
refresh: win.sessionStorage.getItem(REFRESH_TOKEN_KEY) || ""
})
.then((tokens) => {
apiClient.setToken(tokens.access_token.token)
apiClient.listBuckets("csf").then((buckets) => {
apiClient
.getBucketObjectChildrenList(buckets[0].id, { path: "/" })
.then((items) => {
const toDelete = items.map(
({ name }: { name: string }) => `/${name}`
)
console.log(`clearCsfBucket - Deleting ${JSON.stringify(toDelete)}`)
apiClient.removeBucketObject(buckets[0].id, { paths: toDelete }).catch()
})
})
})
})
Expand Down Expand Up @@ -94,117 +98,137 @@ Cypress.Commands.add("saveLocalAndSession", () => {
})
})

Cypress.Commands.add("web3Login", ({
saveBrowser = false,
url = localHost,
apiUrlBase = "https://stage.imploy.site/api/v1",
useLocalAndSessionStorage = true,
clearCSFBucket = false
}: 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) || []
})
Cypress.Commands.add(
"web3Login",
({
saveBrowser = false,
url = localHost,
apiUrlBase = "https://stage.imploy.site/api/v1",
useLocalAndSessionStorage = true,
clearCSFBucket = false
}: Web3LoginOptions = {}) => {
let session: Storage = []
let local: Storage = []

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

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)
})
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()
// 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)
})
if (useLocalAndSessionStorage) {
session.forEach(({ key, value }) => {
win.sessionStorage.setItem(key, value)
})

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

cy.visit(url)

// with nothing in localstorage (and in session storage)
// the whole login flow should kick in
cy.then(() => {
cy.log("Logging in", local.length > 0 && "there is something in session storage ---> direct login")

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.visit(url)

// with nothing in localstorage (and in session storage)
// the whole login flow should kick in
cy.then(() => {
cy.log(
"Logging in",
local.length > 0 &&
"there is something in session storage ---> direct login"
)

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")
cy.get("[data-cy=files-app-header]", { timeout: 20000 }).should(
"be.visible"
)

cy.saveLocalAndSession()
cy.saveLocalAndSession()

if (clearCSFBucket) {
cy.clearCsfBucket(apiUrlBase)
cy.reload()
cy.get("[data-cy=files-app-header]", { timeout: 20000 }).should("be.visible")
if (clearCSFBucket) {
cy.clearCsfBucket(apiUrlBase)
cy.reload()
cy.get("[data-cy=files-app-header]", { timeout: 20000 }).should(
"be.visible"
)
}
}
})
)

// Must be declared global to be detected by typescript (allows import/export)
// eslint-disable @typescript/interface-name
declare global {
namespace Cypress {
interface Chainable {
/**
* Login using Metamask to an instance of Files.
* @param {String} options.url - (default: "http://localhost:3000") - what url to visit.
* @param {String} apiUrlBase - (default: "https://stage.imploy.site/api/v1") - what url to call for the api.
* @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
* @param {Boolean} options.clearCSFBucket - (default: false) - whether any file in the csf bucket should be deleted.
* @example cy.web3Login({saveBrowser: true, url: 'http://localhost:8080'})
*/
* Login using Metamask to an instance of Files.
* @param {String} options.url - (default: "http://localhost:3000") - what url to visit.
* @param {String} apiUrlBase - (default: "https://stage.imploy.site/api/v1") - what url to call for the api.
* @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
* @param {Boolean} options.clearCSFBucket - (default: false) - whether any file in the csf bucket should be deleted.
* @example cy.web3Login({saveBrowser: true, url: 'http://localhost:8080'})
*/
web3Login: (options?: Web3LoginOptions) => Chainable

/**
* Removed any file or folder at the root
* @param {String} apiUrlBase - what url to call for the api.
* @example cy.clearCsfBucket("https://stage.imploy.site/api/v1")
*/
* Removed any file or folder at the root
* @param {String} apiUrlBase - what url to call for the api.
* @example cy.clearCsfBucket("https://stage.imploy.site/api/v1")
*/
clearCsfBucket: (apiUrlBase: string) => Chainable

/**
* Save local and session storage to local files
* @example cy.saveLocalAndSession()
*/
* Save local and session storage to local files
* @example cy.saveLocalAndSession()
*/
saveLocalAndSession: () => Chainable
}
}
}

// Convert this to a module instead of script (allows import/export)
export { }
export {}
Loading

0 comments on commit ad6ccd7

Please sign in to comment.