From 1a23b7854943768b908527555a3006009c592914 Mon Sep 17 00:00:00 2001 From: Derek Date: Thu, 28 Dec 2023 19:58:18 -0500 Subject: [PATCH 1/3] feat(ui-test): cover siwe --- .github/workflows/ui_tests.yml | 1 + apps/laboratory/src/constants.ts | 1 + .../src/pages/library/ethers-siwe.tsx | 3 ++- .../src/pages/library/wagmi-siwe.tsx | 3 ++- .../tests/shared/fixtures/w3m-fixture.ts | 14 +++++++++- .../shared/fixtures/w3m-wallet-fixture.ts | 19 +++++++++++++- .../tests/shared/pages/ModalPage.ts | 15 ++++++++--- .../tests/shared/validators/ModalValidator.ts | 4 +++ apps/laboratory/tests/siwe.spec.ts | 26 +++++++++++++++++++ .../views/w3m-connecting-siwe-view/index.ts | 9 ++++++- 10 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 apps/laboratory/tests/siwe.spec.ts diff --git a/.github/workflows/ui_tests.yml b/.github/workflows/ui_tests.yml index e23a7b7bb4..de3d6693c4 100644 --- a/.github/workflows/ui_tests.yml +++ b/.github/workflows/ui_tests.yml @@ -43,6 +43,7 @@ jobs: - name: Run Playwright tests env: NEXT_PUBLIC_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_PROJECT_ID }} + NEXTAUTH_SECRET: ${{ secrets.TESTS_NEXTAUTH_SECRET }} working-directory: ./apps/laboratory/ run: npm run playwright:test - uses: actions/upload-artifact@v3 diff --git a/apps/laboratory/src/constants.ts b/apps/laboratory/src/constants.ts index 3e953fa98a..666456db8c 100644 --- a/apps/laboratory/src/constants.ts +++ b/apps/laboratory/src/constants.ts @@ -1,2 +1,3 @@ export const SigningSucceededToastTitle = 'Signing Succeeded' export const SigningFailedToastTitle = 'Signing Failed' +export const TestIdSiweAuthenticationStatus = 'w3m-authentication-status' diff --git a/apps/laboratory/src/pages/library/ethers-siwe.tsx b/apps/laboratory/src/pages/library/ethers-siwe.tsx index 2caf26c92c..4373ddc636 100644 --- a/apps/laboratory/src/pages/library/ethers-siwe.tsx +++ b/apps/laboratory/src/pages/library/ethers-siwe.tsx @@ -21,6 +21,7 @@ import { } from '../../utils/ChainsUtil' import type { SIWECreateMessageArgs, SIWESession, SIWEVerifyMessageArgs } from '@web3modal/core' import { createSIWEConfig } from '@web3modal/siwe' +import { TestIdSiweAuthenticationStatus } from '../../constants' const projectId = process.env['NEXT_PUBLIC_PROJECT_ID'] if (!projectId) { @@ -133,7 +134,7 @@ export default function EthersSiwe() {
- SIWE Status: {status} + SIWE Status: {status} {session && ( <> Network: eip155:{session.chainId} diff --git a/apps/laboratory/src/pages/library/wagmi-siwe.tsx b/apps/laboratory/src/pages/library/wagmi-siwe.tsx index 18c0a5657b..82aa01a96f 100644 --- a/apps/laboratory/src/pages/library/wagmi-siwe.tsx +++ b/apps/laboratory/src/pages/library/wagmi-siwe.tsx @@ -23,6 +23,7 @@ import { NetworksButton } from '../../components/NetworksButton' import { ThemeStore } from '../../utils/StoreUtil' import type { SIWEVerifyMessageArgs, SIWECreateMessageArgs, SIWESession } from '@web3modal/core' import { createSIWEConfig } from '@web3modal/siwe' +import { TestIdSiweAuthenticationStatus } from '../../constants' // 1. Get projectId const projectId = process.env['NEXT_PUBLIC_PROJECT_ID'] @@ -145,7 +146,7 @@ export default function Wagmi() {
- Status: {status} + Status: {status} {session && ( <> Network: eip155:{session.chainId} diff --git a/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts index a19d813a01..1365ecacb5 100644 --- a/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts +++ b/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts @@ -13,7 +13,19 @@ export interface ModalFixture { export const testM = base.extend({ library: ['wagmi', { option: true }], modalPage: async ({ page, library }, use) => { - const modalPage = new ModalPage(page, library) + const modalPage = new ModalPage(page, library, false) + await modalPage.load() + await use(modalPage) + }, + modalValidator: async ({ modalPage }, use) => { + const modalValidator = new ModalValidator(modalPage.page) + await use(modalValidator) + } +}) +export const testMSiwe = base.extend({ + library: ['wagmi', { option: true }], + modalPage: async ({ page, library }, use) => { + const modalPage = new ModalPage(page, library, true) await modalPage.load() await use(modalPage) }, diff --git a/apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts index 0c1a57067e..e8fab9c619 100644 --- a/apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts +++ b/apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts @@ -1,4 +1,4 @@ -import { testM as base } from './w3m-fixture' +import { testM as base, testMSiwe as siwe } from './w3m-fixture' import { WalletPage } from '../pages/WalletPage' import { WalletValidator } from '../validators/WalletValidator' @@ -26,4 +26,21 @@ export const testMW = base.extend({ await use(walletValidator) } }) +export const testMWSiwe = siwe.extend({ + walletPage: async ({ context, browserName }, use) => { + // WalletPage needs clipboard permissions with chromium to paste URI + if (browserName === 'chromium') { + await context.grantPermissions(['clipboard-read', 'clipboard-write']) + } + + // Use a new page, to open alongside the modal + const walletPage = new WalletPage(await context.newPage()) + await walletPage.load() + await use(walletPage) + }, + walletValidator: async ({ walletPage }, use) => { + const walletValidator = new WalletValidator(walletPage.page) + await use(walletValidator) + } +}) export { expect } from '@playwright/test' diff --git a/apps/laboratory/tests/shared/pages/ModalPage.ts b/apps/laboratory/tests/shared/pages/ModalPage.ts index bcfde2ce5b..183236d079 100644 --- a/apps/laboratory/tests/shared/pages/ModalPage.ts +++ b/apps/laboratory/tests/shared/pages/ModalPage.ts @@ -5,20 +5,25 @@ export class ModalPage { private readonly baseURL = BASE_URL private readonly connectButton: Locator + private readonly url: string constructor( public readonly page: Page, - public readonly library: string + public readonly library: string, + public readonly siwe: boolean ) { this.connectButton = this.page.getByTestId('connect-button') + this.url = this.siwe + ? `${this.baseURL}library/${this.library}-siwe/` + : `${this.baseURL}library/${this.library}/` } async load() { - await this.page.goto(`${this.baseURL}library/${this.library}/`) + await this.page.goto(this.url) } async copyConnectUriToClipboard() { - await this.page.goto(`${this.baseURL}library/${this.library}/`) + await this.page.goto(this.url) await this.connectButton.click() await this.page.getByTestId('wallet-selector-walletconnect').click() await this.page.waitForTimeout(2000) @@ -34,6 +39,10 @@ export class ModalPage { await this.page.getByTestId('sign-message-button').click() } + async promptSiwe() { + await this.page.getByTestId('w3m-connecting-siwe-sign').click() + } + async switchNetwork(network: string) { await this.page.getByTestId('account-button').click() await this.page.getByTestId('w3m-account-select-network').click() diff --git a/apps/laboratory/tests/shared/validators/ModalValidator.ts b/apps/laboratory/tests/shared/validators/ModalValidator.ts index 87bcc38082..a309394b76 100644 --- a/apps/laboratory/tests/shared/validators/ModalValidator.ts +++ b/apps/laboratory/tests/shared/validators/ModalValidator.ts @@ -9,6 +9,10 @@ export class ModalValidator { await expect(this.page.getByTestId('account-button')).toBeVisible() } + async expectAuthenticated() { + await expect(this.page.getByTestId('w3m-authentication-status')).toContainText('authenticated') + } + async expectDisconnected() { await expect(this.page.getByTestId('account-button')).not.toBeVisible() } diff --git a/apps/laboratory/tests/siwe.spec.ts b/apps/laboratory/tests/siwe.spec.ts new file mode 100644 index 0000000000..b56f2ede34 --- /dev/null +++ b/apps/laboratory/tests/siwe.spec.ts @@ -0,0 +1,26 @@ +import { DEFAULT_SESSION_PARAMS } from './shared/constants' +import { testMWSiwe } from './shared/fixtures/w3m-wallet-fixture' + +testMWSiwe.beforeEach(async ({ modalPage, walletPage }) => { + await modalPage.copyConnectUriToClipboard() + await walletPage.connect() + await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS) +}) + +testMWSiwe.afterEach(async ({ modalPage, modalValidator, walletValidator }) => { + await modalPage.disconnect() + await modalValidator.expectDisconnected() + await walletValidator.expectDisconnected() +}) + +testMWSiwe( + 'it should sign in with ethereum', + async ({ modalPage, walletPage, modalValidator, walletValidator }) => { + await modalPage.promptSiwe() + await walletValidator.expectReceivedSign({}) + await walletPage.handleRequest({ accept: true }) + await modalValidator.expectAuthenticated() + await modalValidator.expectConnected() + await walletValidator.expectConnected() + } +) diff --git a/packages/scaffold/src/views/w3m-connecting-siwe-view/index.ts b/packages/scaffold/src/views/w3m-connecting-siwe-view/index.ts index f892155890..155e1d1079 100644 --- a/packages/scaffold/src/views/w3m-connecting-siwe-view/index.ts +++ b/packages/scaffold/src/views/w3m-connecting-siwe-view/index.ts @@ -45,7 +45,13 @@ export class W3mConnectingSiweView extends LitElement { > - + Cancel ${this.isSigning ? 'Signing...' : 'Sign'} From 953ffbf893bfad71a4824348b7738b3d0e5d0cad Mon Sep 17 00:00:00 2001 From: Derek Date: Thu, 28 Dec 2023 21:05:05 -0500 Subject: [PATCH 2/3] feat: add decline --- apps/laboratory/playwright.config.ts | 2 +- .../tests/shared/fixtures/w3m-fixture.ts | 4 ++-- apps/laboratory/tests/shared/pages/ModalPage.ts | 15 +++++++++++---- .../tests/shared/validators/ModalValidator.ts | 14 +++++++++++++- .../tests/shared/validators/WalletValidator.ts | 2 +- apps/laboratory/tests/siwe.spec.ts | 16 ++++++++++++++-- 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/apps/laboratory/playwright.config.ts b/apps/laboratory/playwright.config.ts index fccd3d052f..6231eb6133 100644 --- a/apps/laboratory/playwright.config.ts +++ b/apps/laboratory/playwright.config.ts @@ -14,7 +14,7 @@ export default defineConfig({ reporter: [['list'], ['html']], expect: { - timeout: (process.env['CI'] ? 60 : 5) * 1000 + timeout: (process.env['CI'] ? 60 : 15) * 1000 }, timeout: 60 * 1000, diff --git a/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts index 1365ecacb5..68e49bb8a2 100644 --- a/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts +++ b/apps/laboratory/tests/shared/fixtures/w3m-fixture.ts @@ -13,7 +13,7 @@ export interface ModalFixture { export const testM = base.extend({ library: ['wagmi', { option: true }], modalPage: async ({ page, library }, use) => { - const modalPage = new ModalPage(page, library, false) + const modalPage = new ModalPage(page, library, 'default') await modalPage.load() await use(modalPage) }, @@ -25,7 +25,7 @@ export const testM = base.extend({ export const testMSiwe = base.extend({ library: ['wagmi', { option: true }], modalPage: async ({ page, library }, use) => { - const modalPage = new ModalPage(page, library, true) + const modalPage = new ModalPage(page, library, 'siwe') await modalPage.load() await use(modalPage) }, diff --git a/apps/laboratory/tests/shared/pages/ModalPage.ts b/apps/laboratory/tests/shared/pages/ModalPage.ts index 183236d079..10a94e3f03 100644 --- a/apps/laboratory/tests/shared/pages/ModalPage.ts +++ b/apps/laboratory/tests/shared/pages/ModalPage.ts @@ -1,6 +1,8 @@ import type { Locator, Page } from '@playwright/test' import { BASE_URL } from '../constants' +export type ModalFlavor = 'default' | 'siwe' + export class ModalPage { private readonly baseURL = BASE_URL @@ -10,12 +12,13 @@ export class ModalPage { constructor( public readonly page: Page, public readonly library: string, - public readonly siwe: boolean + public readonly flavor: ModalFlavor ) { this.connectButton = this.page.getByTestId('connect-button') - this.url = this.siwe - ? `${this.baseURL}library/${this.library}-siwe/` - : `${this.baseURL}library/${this.library}/` + this.url = + flavor === 'siwe' + ? `${this.baseURL}library/${this.library}-siwe/` + : `${this.baseURL}library/${this.library}/` } async load() { @@ -43,6 +46,10 @@ export class ModalPage { await this.page.getByTestId('w3m-connecting-siwe-sign').click() } + async cancelSiwe() { + await this.page.getByTestId('w3m-connecting-siwe-cancel').click() + } + async switchNetwork(network: string) { await this.page.getByTestId('account-button').click() await this.page.getByTestId('w3m-account-select-network').click() diff --git a/apps/laboratory/tests/shared/validators/ModalValidator.ts b/apps/laboratory/tests/shared/validators/ModalValidator.ts index a309394b76..243c277e05 100644 --- a/apps/laboratory/tests/shared/validators/ModalValidator.ts +++ b/apps/laboratory/tests/shared/validators/ModalValidator.ts @@ -10,7 +10,19 @@ export class ModalValidator { } async expectAuthenticated() { - await expect(this.page.getByTestId('w3m-authentication-status')).toContainText('authenticated') + await expect(this.page.getByTestId('w3m-authentication-status')).toContainText( + 'Status: authenticated' + ) + } + + async expectUnauthenticated() { + await expect(this.page.getByTestId('w3m-authentication-status')).toContainText( + 'Status: unauthenticated' + ) + } + + async expectSignatureDeclined() { + await expect(this.page.getByText('Signature declined')).toBeVisible() } async expectDisconnected() { diff --git a/apps/laboratory/tests/shared/validators/WalletValidator.ts b/apps/laboratory/tests/shared/validators/WalletValidator.ts index 9cedbadf47..bcdb838b9a 100644 --- a/apps/laboratory/tests/shared/validators/WalletValidator.ts +++ b/apps/laboratory/tests/shared/validators/WalletValidator.ts @@ -15,7 +15,7 @@ export class WalletValidator { } async expectDisconnected() { - await this.page.waitForTimeout(1000) + await this.page.waitForTimeout(2000) await this.page.reload() await this.gotoSessions.click() await expect(this.page.getByTestId('session-card')).not.toBeVisible() diff --git a/apps/laboratory/tests/siwe.spec.ts b/apps/laboratory/tests/siwe.spec.ts index b56f2ede34..51ecb622d8 100644 --- a/apps/laboratory/tests/siwe.spec.ts +++ b/apps/laboratory/tests/siwe.spec.ts @@ -7,8 +7,7 @@ testMWSiwe.beforeEach(async ({ modalPage, walletPage }) => { await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS) }) -testMWSiwe.afterEach(async ({ modalPage, modalValidator, walletValidator }) => { - await modalPage.disconnect() +testMWSiwe.afterEach(async ({ modalValidator, walletValidator }) => { await modalValidator.expectDisconnected() await walletValidator.expectDisconnected() }) @@ -22,5 +21,18 @@ testMWSiwe( await modalValidator.expectAuthenticated() await modalValidator.expectConnected() await walletValidator.expectConnected() + await modalPage.disconnect() + } +) + +testMWSiwe( + 'it should reject sign in with ethereum', + async ({ modalPage, walletPage, modalValidator, walletValidator }) => { + await modalPage.promptSiwe() + await walletValidator.expectReceivedSign({}) + await walletPage.handleRequest({ accept: false }) + await modalValidator.expectSignatureDeclined() + await modalPage.cancelSiwe() + await modalValidator.expectUnauthenticated() } ) From 0d0835b34d847163f9025b6cd005a60bbc003083 Mon Sep 17 00:00:00 2001 From: Derek Date: Thu, 28 Dec 2023 21:08:26 -0500 Subject: [PATCH 3/3] chore: reset timeout --- apps/laboratory/tests/shared/validators/WalletValidator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/laboratory/tests/shared/validators/WalletValidator.ts b/apps/laboratory/tests/shared/validators/WalletValidator.ts index bcdb838b9a..9cedbadf47 100644 --- a/apps/laboratory/tests/shared/validators/WalletValidator.ts +++ b/apps/laboratory/tests/shared/validators/WalletValidator.ts @@ -15,7 +15,7 @@ export class WalletValidator { } async expectDisconnected() { - await this.page.waitForTimeout(2000) + await this.page.waitForTimeout(1000) await this.page.reload() await this.gotoSessions.click() await expect(this.page.getByTestId('session-card')).not.toBeVisible()