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

Cypress tests refactoring: PO model, safe app tests #2522

Merged
merged 18 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ concurrency:

jobs:
e2e:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
Copy link
Member

Choose a reason for hiding this comment

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

Why is this necessary? Latest is too new for Cypress? Or too old?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Our Cypress tests started to fail due to using latest runner image which conflicts with Cypress version. -latest tag uses image which might not be that stable as previous one, or be in pre-release mode.

Copy link
Member

Choose a reason for hiding this comment

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

Do we still need to pin the ubuntu version if we also upgraded cypress?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By specifying a version, we ensure that there will be some control over it. When this version is planned to become unavailable, we will hopefully receive notification that will give us enough time for updating to newer version of Cypress/resolve any conflicts instead of reacting to this when it was unexpected.

name: Smoke E2E tests
steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default defineConfig({

e2e: {
baseUrl: 'http://localhost:3000',
testIsolation: false,
},

chromeWebSecurity: false,
Expand Down
21 changes: 21 additions & 0 deletions cypress/e2e/pages/address_book.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export const acceptSelection = 'Accept selection'
export const addressBook = 'Address book'
const createEntryBtn = 'Create entry'

const beameriFrameContainer = '#beamerOverlay .iframeCointaner'
const beamerInput = 'input[id="beamer"]'
const nameInput = 'input[name="name"]'
const addressInput = 'input[name="address"]'
const saveBtn = 'Save'
Expand All @@ -13,6 +15,8 @@ const exportFileModalBtnSection = '.MuiDialogActions-root'
const exportFileModalExportBtn = 'Export'
const importBtn = 'Import'
const exportBtn = 'Export'
const whatsNewBtnStr = "What's new"
const beamrCookiesStr = 'accept the "Beamer" cookies'

export function clickOnImportFileBtn() {
cy.contains(importBtn).click()
Expand Down Expand Up @@ -91,3 +95,20 @@ export function clickDeleteEntryModalDeleteButton() {
export function verifyEditedNameNotExists(name) {
cy.get(name).should('not.exist')
}

export function clickOnWhatsNewBtn(force = false) {
cy.contains(whatsNewBtnStr).click({ force: force })
}

export function acceptBeamerCookies() {
cy.contains(beamrCookiesStr)
}

export function verifyBeamerIsChecked() {
cy.get(beamerInput).should('be.checked')
}

export function verifyBeameriFrameExists() {
cy.wait(1000)
cy.get(beameriFrameContainer).should('exist')
}
1 change: 1 addition & 0 deletions cypress/e2e/pages/balances.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const hideAssetBtn = 'button[aria-label="Hide asset"]'
const hiddeTokensBtn = '[data-testid="toggle-hidden-assets"]'
const hiddenTokenCheckbox = 'input[type="checkbox"]'
const paginationPageList = 'ul[role="listbox"]'
const currencyDropDown = 'div[id="currency"]'
const hiddenTokenSaveBtn = 'Save'
const hideTokenDefaultString = 'Hide tokens'

Expand Down
9 changes: 7 additions & 2 deletions cypress/e2e/pages/batches.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const tokenAddressInput = 'input[name="tokenAddress"]'
const listBox = 'ul[role="listbox"]'
const amountInput = '[name="amount"]'
const nonceInput = 'input[name="nonce"]'
const executeOptionsContainer = 'div[role="radiogroup"]'

export function addToBatch(EOA, currentNonce, amount, verify = false) {
fillTransactionData(EOA, amount)
Expand All @@ -49,8 +50,12 @@ function setNonceAndProceed(currentNonce) {
}

function executeTransaction() {
cy.contains(yesExecuteString, { timeout: 4000 }).click()
cy.contains(addToBatchBtn).should('not.exist')
cy.waitForSelector(() => {
return cy.get(executeOptionsContainer).then(() => {
cy.contains(yesExecuteString, { timeout: 4000 }).click()
cy.contains(addToBatchBtn).should('not.exist')
})
})
}

function addToBatchButton() {
Expand Down
42 changes: 41 additions & 1 deletion cypress/e2e/pages/create_tx.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const amountInput = 'input[name="amount"]'
const nonceInput = 'input[name="nonce"]'
const gasLimitInput = '[name="gasLimit"]'
const rotateLeftIcon = '[data-testid="RotateLeftIcon"]'
const transactionItemExpandable = 'div[id^="transfer"]'

const viewTransactionBtn = 'View transaction'
const transactionDetailsTitle = 'Transaction details'
Expand All @@ -26,6 +27,8 @@ const editBtnStr = 'Edit'
const executionParamsStr = 'Execution parameters'
const noLaterStr = 'No, later'
const signBtnStr = 'Sign'
const expandallbtnStr = 'Expand all'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const expandallbtnStr = 'Expand all'
const expandAllBtnStr = 'Expand all'

const collapseAllBtnStr = 'Collapse all'

export function clickOnNewtransactionBtn() {
// Assert that "New transaction" button is visible
Expand Down Expand Up @@ -90,7 +93,7 @@ export function changeNonce(value) {
}

export function verifyConfirmTransactionData() {
cy.contains(yesStr).should('exist')
cy.contains(yesStr).should('exist').click()
cy.contains(estimatedFeeStr).should('exist')

// Asserting the sponsored info is present
Expand Down Expand Up @@ -149,3 +152,40 @@ export function verifyQueueLabel() {
export function verifyTransactionSummary(sendValue) {
cy.contains(TransactionSummary + `${sendValue} ${constants.tokenAbbreviation.gor}`).should('exist')
}

export function verifyDateExists(date) {
cy.contains('div', date).should('exist')
}

export function verifyImageAlttxt(index, text) {
mike10ca marked this conversation as resolved.
Show resolved Hide resolved
cy.get('img').eq(index).should('have.attr', 'alt', text).should('be.visible')
}

export function verifyStatus(status) {
cy.contains('div', status).should('exist')
}

export function verifyTransactionStrExists(str) {
cy.contains(str).should('exist')
}

export function verifyTransactionStrNotVible(str) {
cy.contains(str).should('not.be.visible')
}

export function clickOnTransactionExpandableItem(name, actions) {
cy.contains('div', name)
.next()
.click()
.within(() => {
actions()
})
}

export function lickOnExpandAllBtn() {
mike10ca marked this conversation as resolved.
Show resolved Hide resolved
cy.contains(expandallbtnStr).click()
}

export function lickOnCollapseAllBtn() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export function lickOnCollapseAllBtn() {
export function clickOnCollapseAllBtn() {

cy.contains(collapseAllBtnStr).click()
}
5 changes: 5 additions & 0 deletions cypress/e2e/pages/load_safe.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export function selectGoerli() {
cy.contains('span', constants.networks.goerli)
}

export function selectPolygon() {
cy.get('ul li').contains(constants.networks.polygon).click()
cy.contains('span', constants.networks.polygon)
}

export function verifyNameInputHasPlceholder() {
cy.get(nameInput).should('have.attr', 'placeholder').should('match', constants.goerlySafeName)
}
Expand Down
10 changes: 10 additions & 0 deletions cypress/e2e/pages/main.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,13 @@ export function verifyGoerliWalletHeader() {
export function verifyHomeSafeUrl(safe) {
cy.location('href', { timeout: 10000 }).should('include', constants.homeUrl + safe)
}

export function checkTextsExistWithinElement(element, texts) {
texts.forEach((text) => {
cy.wrap(element).findByText(text).should('exist')
})
}

export function verifyCheckboxeState(element, index, state) {
cy.get(element).eq(index).should(state)
}
193 changes: 193 additions & 0 deletions cypress/e2e/pages/safeapps.pages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import * as constants from '../../support/constants'

const searchappInput = 'input[id="search-by-name"]'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const searchappInput = 'input[id="search-by-name"]'
const searchAppInput = 'input[id="search-by-name"]'

const appUrlInput = 'input[name="appUrl"]'
const closePreviewWindowBtn = 'button[aria-label*="Close"][aria-label*="preview"]'

const addBtnStr = /add/i
Copy link
Member

Choose a reason for hiding this comment

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

Nit: can we be a bit more specific that this is within the modal as there is also another add button in the list. (The same for the function which references this string.)

const noAppsStr = /no Safe Apps found/i
const bookmarkedAppsStr = /bookmarked Apps/i
const customAppsStr = /my custom Apps/i
const addCustomAppBtnStr = /add custom Safe App/i
const openSafeAppBtnStr = /open Safe App/i
const disclaimerTtle = /disclaimer/i
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const disclaimerTtle = /disclaimer/i
const disclaimerTitle = /disclaimer/i

const continueBtnStr = /continue/i
const cameraCheckBoxStr = /camera/i
const microfoneCheckBoxStr = /microphone/i
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
const microfoneCheckBoxStr = /microphone/i
const microphoneCheckBoxStr = /microphone/i

const permissionRequestStr = /permissions request/i
const accessToAddressBookStr = /access to your address book/i
const acceptBtnStr = /accept/i
const clearAllBtnStr = /clear all/i
const allowAllPermissions = /allow all/i

const appNotSupportedMsg = "The app doesn't support Safe App functionality"

export const pinWalletConnectStr = /pin walletconnect/i
export const transactionBuilderStr = /pin transaction builder/i
export const logoWalletConnect = /logo.*walletconnect/i
export const walletConnectHeadlinePreview = /walletconnect/i
export const availableNetworksPreview = /available networks/i
export const connecttextPreview = 'Connect your Safe to any dApp that supports WalletConnect'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export const connecttextPreview = 'Connect your Safe to any dApp that supports WalletConnect'
export const connectTextPreview = 'Connect your Safe to any dApp that supports WalletConnect'

export const localStorageItem =
'{"https://safe-test-app.com":[{"feature":"camera","status":"granted"},{"feature":"microphone","status":"denied"}]}'
export const gridItem = 'main .MuiPaper-root > .MuiGrid-item'
export const linkNames = {
logo: /logo/i,
}

export const permissionCheckboxes = {
camera: 'input[name="camera"]',
addressbook: 'input[name="requestAddressBook"]',
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
addressbook: 'input[name="requestAddressBook"]',
addressBook: 'input[name="requestAddressBook"]',

microphone: 'input[name="microphone"]',
geolocation: 'input[name="geolocation"]',
fullscreen: 'input[name="fullscreen"]',
}

export const permissionCheckboxNames = {
camera: 'Camera',
addressbook: 'Address Book',
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
addressbook: 'Address Book',
addressBook: 'Address Book',

microphone: 'Microphone',
geolocation: 'Geolocation',
fullscreen: 'Fullscreen',
}
export function typeAppName(name) {
cy.get(searchappInput).clear().type(name)
}

export function clearSearchAppInput() {
cy.get(searchappInput).clear()
}

export function verifyLinkName(name) {
cy.findAllByRole('link', { name: name }).should('have.length', 1)
}

export function clickOnApp(app) {
cy.findByRole('link', { name: app }).click()
}

export function verifyNoAppsTextPresent() {
cy.contains(noAppsStr).should('exist')
}

export function pinApp(app, pin = true) {
let str = 'Unpin'
if (!pin) str = 'Pin'
cy.findByLabelText(app)
.click()
.should(($el) => {
const ariaLabel = $el.attr('aria-label')
expect(ariaLabel).to.include(str)
})
}

export function clickOnBookmarkedAppsTab() {
cy.findByText(bookmarkedAppsStr).click()
}

export function verifyAppCount(count) {
cy.findByText(`ALL (${count})`).should('be.visible')
}

export function clickOnCustomAppsTab() {
cy.findByText(customAppsStr).click()
}

export function clickOnAddCustomApp() {
cy.findByText(addCustomAppBtnStr).click()
}

export function typeCustomAppUrl(url) {
cy.get(appUrlInput).clear().type(url)
}

export function verifyAppNotSupportedMsg() {
cy.contains(appNotSupportedMsg).should('be.visible')
}

export function verifyAppTitle(title) {
cy.findByRole('heading', { name: title }).should('exist')
}

export function acceptTC() {
cy.findByRole('checkbox').click()
}

export function clickOnAddBtn() {
cy.findByRole('button', { name: addBtnStr }).click()
}

export function verifyAppDescription(descr) {
cy.findByText(descr).should('exist')
}

export function clickOnOpenSafeAppBtn() {
cy.findByRole('link', { name: openSafeAppBtnStr }).click()
cy.wait(500)
verifyDisclaimerIsVisible()
cy.wait(500)
}

function verifyDisclaimerIsVisible() {
cy.findByRole('heading', { name: disclaimerTtle }).should('be.visible')
}

export function clickOnContinueBtn() {
return cy.findByRole('button', { name: continueBtnStr }).click()
}

export function verifyCameraCheckBoxExists() {
cy.findByRole('checkbox', { name: cameraCheckBoxStr }).should('exist')
}

export function verifyMicrofoneCheckBoxExists() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export function verifyMicrofoneCheckBoxExists() {
export function verifyMicrophoneCheckBoxExists() {

return cy.findByRole('checkbox', { name: microfoneCheckBoxStr }).should('exist')
}

export function storeAndVerifyPermissions() {
cy.waitForSelector(() => {
return cy
.findByRole('button', { name: continueBtnStr })
.click()
.wait(500)
.should(() => {
const storedBrowserPermissions = JSON.parse(localStorage.getItem(constants.BROWSER_PERMISSIONS_KEY))
const browserPermissions = Object.values(storedBrowserPermissions)[0][0]
const storedInfoModal = JSON.parse(localStorage.getItem(constants.INFO_MODAL_KEY))

expect(browserPermissions.feature).to.eq('camera')
expect(browserPermissions.status).to.eq('granted')
expect(storedInfoModal['5'].consentsAccepted).to.eq(true)
})
})
}

export function verifyPreviewWindow(str1, str2, str3) {
cy.findByRole('heading', { name: str1 }).should('exist')
cy.findByText(str2).should('exist')
cy.findByText(str3).should('exist')
}

export function closePreviewWindow() {
cy.get(closePreviewWindowBtn).click()
}

export function verifyPermissionsRequestExists() {
cy.findByRole('heading', { name: permissionRequestStr }).should('exist')
}

export function verifyAccessToAddressBookExists() {
cy.findByText(accessToAddressBookStr).should('exist')
}

export function clickOnAcceptBtn() {
cy.findByRole('button', { name: acceptBtnStr }).click()
}

export function uncheckAllPermissions(element) {
cy.wrap(element).findByText(clearAllBtnStr).click()
}

export function checkAllPermissions(element) {
cy.wrap(element).findByText(allowAllPermissions).click()
}
Loading