-
Notifications
You must be signed in to change notification settings - Fork 5
feat(frontend-main): add e2e testing with Keplr integration #478
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
Merged
Merged
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
5471896
feat(frontend-main): add e2e testing with Keplr integration
luciorubeens 4b0a05d
feat: ci test
luciorubeens ea9fc88
feat: e2e workflow
luciorubeens 14d197d
fix: install playwright
luciorubeens a9120d0
ci: cache extension
luciorubeens e7f0049
ci: headless test
luciorubeens 1cd9d39
ci: headed test
luciorubeens 26ee03c
ci: xvfb-run
luciorubeens c783bcb
ci: no-channel
luciorubeens d4eedd9
ci: start xvfb
luciorubeens 71a672c
fix: docker container
luciorubeens 61bd4a1
ci: pnpm install
luciorubeens 73c1c34
ci: xvfb-run
luciorubeens a5980c0
ci: run xvfb
luciorubeens 4c02ecf
ci: test with container
luciorubeens c572427
ci: headless
luciorubeens 788a2ed
ci: headed
luciorubeens 743af2d
ci: vnc image
luciorubeens e46ece8
ci: remove xvfb
luciorubeens 121f14d
ci: remove browser installation
luciorubeens 2fd6592
ci: xvfb
luciorubeens 5097879
ci: xvfb-run
luciorubeens 3053f25
ci: -e arg
luciorubeens 49f09dc
wip
luciorubeens fc06d41
wip
luciorubeens 7fffa62
wip
luciorubeens 9098cae
refactor: headless mode
luciorubeens 0be18f2
fix: slow down
luciorubeens 370cca7
fix: csp
luciorubeens 005d09e
fix: env variables
luciorubeens f5f2d2f
fix: approve suggest chain
luciorubeens 348d868
Merge remote-tracking branch 'origin/main' into feat/e2e-with-keplr
luciorubeens 5dd2034
fix: remove interpolation
luciorubeens c731dd3
fix: remove pnpm letfover
luciorubeens File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| name: Frontend E2E Tests | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main | ||
| push: | ||
| branches: | ||
| - main | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| detect-changes: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| changed: ${{ steps.changes.outputs.frontend-main }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v3 | ||
|
|
||
| - name: Detect frontend-main changes | ||
| uses: dorny/paths-filter@v3 | ||
| id: changes | ||
| with: | ||
| filters: | | ||
| frontend-main: | ||
| - 'packages/frontend-main/**' | ||
|
|
||
| e2e-tests: | ||
| needs: detect-changes | ||
| if: needs.detect-changes.outputs.changed == 'true' | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v3 | ||
|
|
||
| - name: Install pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| run_install: false | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version-file: .nvmrc | ||
| cache: pnpm | ||
|
|
||
| - name: Install dependencies with pnpm | ||
| run: pnpm install | ||
|
|
||
| - name: Store Playwright's Version | ||
| id: playwright-version | ||
| run: | | ||
| PLAYWRIGHT_VERSION=$(npx playwright --version | sed 's/Version //') | ||
| echo "Playwright's Version: $PLAYWRIGHT_VERSION" | ||
| echo "version=${PLAYWRIGHT_VERSION}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Cache Playwright browsers | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.cache/ms-playwright | ||
| key: ${{ steps.playwright-version.outputs.version }}-${{ runner.os }}-playwright-browsers | ||
|
|
||
| - name: Cache Playwright user data | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ./packages/frontend-main/playwright/.user-data | ||
| key: playwright-user-data-${{ hashFiles('packages/frontend-main/e2e/setup/*.ts', 'packages/frontend-main/e2e/config/keplr.ts') }} | ||
|
|
||
| - name: Cache Keplr extension | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ./packages/frontend-main/playwright/.cache | ||
| key: playwright-cache-${{ hashFiles('packages/frontend-main/e2e/config/keplr.ts') }} | ||
|
|
||
| - name: Install Playwright | ||
| run: npx playwright install --with-deps chromium | ||
|
|
||
| - name: Run Playwright Tests | ||
| working-directory: packages/frontend-main | ||
| run: pnpm test:e2e | ||
| env: | ||
| VITE_ENVIRONMENT_TYPE: testnet | ||
| VITE_API_ROOT_TESTNET: https://api.testnet.dither.chat/v1 | ||
| VITE_COMMUNITY_WALLET_TESTNET: atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep | ||
| VITE_AUTHZ_GRANTEE_TESTNET: atone1uq6zjslvsa29cy6uu75y8txnl52mw06j6fzlep | ||
|
|
||
| - name: Upload playwright results | ||
| uses: actions/upload-artifact@v4 | ||
| if: ${{ failure() }} | ||
| with: | ||
| name: playwright-results | ||
| path: | | ||
| packages/frontend-main/test-results/ | ||
| packages/frontend-main/playwright-report/ | ||
| retention-days: 1 | ||
| if-no-files-found: ignore | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| export const keplrData = { | ||
| account: { | ||
| seed: `source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast`, | ||
| name: 'Test', | ||
| password: '!Dither12345678', | ||
| }, | ||
| extensionPath: './playwright/.cache/keplr-wallet-extension', | ||
| repository: 'https://github.com/chainapsis/keplr-wallet', | ||
| version: 'v0.12.287', | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { mergeTests, test } from '@playwright/test'; | ||
|
|
||
| import { testWithDither } from './dither.fixture'; | ||
| import { testWithKeplr } from './keplr.fixture'; | ||
|
|
||
| const base = mergeTests(testWithKeplr, testWithDither); | ||
|
|
||
| export const baseTest = base.extend<{ | ||
| connectWallet: () => Promise<void>; | ||
| }>({ | ||
| connectWallet: async ({ homePage, keplrPopup }, use) => { | ||
| await use(async () => { | ||
| await test.step('Navigate to home page', async () => { | ||
| await homePage.page.waitForTimeout(1500); | ||
| await homePage.navigate(); | ||
| }); | ||
|
|
||
| await test.step('Open wallet connection dialog', async () => { | ||
| const walletDialog = await homePage.openConnectWalletDialog(); | ||
| await walletDialog.selectKeplrWallet(); | ||
| }); | ||
|
|
||
| await test.step('Unlock Keplr wallet', async () => { | ||
| await keplrPopup.invoke(async (k) => { | ||
| await k.unlockWalletIfNeeded(); | ||
| await k.approveSuggestChainIfNeeded(); | ||
| }); | ||
| }); | ||
|
|
||
| let connApproved = false; | ||
| await test.step('Approve connection or signature', async () => { | ||
| await keplrPopup.invoke(async (k) => { | ||
| connApproved = await k.approveConnectionIfNeeded(); | ||
| await k.approveSignatureIfNeeded(); | ||
| }); | ||
| }); | ||
|
|
||
| if (connApproved) { | ||
| await test.step('Approve signature', async () => { | ||
| await keplrPopup.invoke(k => k.approveSignatureIfNeeded()); | ||
| }); | ||
| } | ||
| }); | ||
| }, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { test as base } from '@playwright/test'; | ||
|
|
||
| import { HomePage } from '../pom/home.pom'; | ||
|
|
||
| export const testWithDither = base.extend<{ | ||
| homePage: HomePage; | ||
| }>({ | ||
| homePage: async ({ page }, use) => { | ||
| await use(new HomePage(page)); | ||
| }, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import type { BrowserContext } from '@playwright/test'; | ||
|
|
||
| import { test as base, chromium } from '@playwright/test'; | ||
|
|
||
| import { keplrData } from '../config/keplr'; | ||
| import { KeplrExtensionPage } from '../pom/keplr-extension.pom'; | ||
|
|
||
| export interface KeplrPopupAPI { | ||
| popup: () => Promise<KeplrExtensionPage>; | ||
| invoke: (callback: (page: KeplrExtensionPage) => Promise<any>) => Promise<void>; | ||
| } | ||
|
|
||
| export const testWithKeplr = base.extend<{ | ||
| context: BrowserContext; | ||
| extensionId: string; | ||
| keplrPopup: KeplrPopupAPI; | ||
| keplrExtension: KeplrExtensionPage; | ||
| }>({ | ||
| context: async ({ launchOptions }, use) => { | ||
| const userDataDir = launchOptions.env?.userDataDir ?? ''; | ||
| const args = [ | ||
| `--disable-web-security`, | ||
| '--disable-setuid-sandbox', | ||
| `--disable-extensions-except=${keplrData.extensionPath}`, | ||
| `--load-extension=${keplrData.extensionPath}`, | ||
| ]; | ||
|
|
||
| const context = await chromium.launchPersistentContext(userDataDir, { | ||
| recordVideo: { | ||
| dir: 'test-results/videos', | ||
| }, | ||
| devtools: false, | ||
| serviceWorkers: 'allow', | ||
| args, | ||
| }); | ||
|
|
||
| await use(context); | ||
| await context.close(); | ||
| }, | ||
|
|
||
| extensionId: async ({ context }, use) => { | ||
| let [background] = context.serviceWorkers(); | ||
|
|
||
| if (!background) background = await context.waitForEvent('serviceworker'); | ||
|
|
||
| const extensionId = background.url().split('/')[2]; | ||
| await use(extensionId); | ||
| }, | ||
|
|
||
| keplrPopup: async ({ context, extensionId }, use) => { | ||
| const openPopup = () => KeplrExtensionPage.popupFromContext(context, extensionId); | ||
|
|
||
| const invoke = async (callback: (page: KeplrExtensionPage) => Promise<void>): Promise<void> => { | ||
| let closed = false; | ||
| const keplrPage = await openPopup(); | ||
| keplrPage.page.on('close', () => { | ||
| closed = true; | ||
| }); | ||
|
|
||
| await callback(keplrPage); | ||
| await new Promise(r => setTimeout(r, 500)); | ||
|
|
||
| if (!closed) { | ||
| await keplrPage.page.close(); | ||
| } | ||
| }; | ||
|
|
||
| await use({ popup: openPopup, invoke }); | ||
| }, | ||
|
|
||
| keplrExtension: async ({ context, extensionId }, use) => { | ||
| const page = await context.newPage(); | ||
| const keplrPage = new KeplrExtensionPage(page, extensionId); | ||
| await use(keplrPage); | ||
| }, | ||
| }); |
16 changes: 16 additions & 0 deletions
16
packages/frontend-main/e2e/pom/connect-wallet-dialog.pom.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import type { Locator, Page } from '@playwright/test'; | ||
|
|
||
| export class ConnectWalletDialogPage { | ||
| readonly page: Page; | ||
| readonly modalLocator: Locator; | ||
|
|
||
| constructor(page: Page) { | ||
| this.page = page; | ||
| this.modalLocator = this.page.locator('[role=dialog]:has-text("Connect Wallet")'); | ||
| } | ||
|
|
||
| async selectKeplrWallet() { | ||
| await this.modalLocator.waitFor({ state: 'visible' }); | ||
| await this.page.getByRole('button', { name: 'Keplr Wallet' }).click(); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import type { Page } from '@playwright/test'; | ||
|
|
||
| import { ConnectWalletDialogPage } from './connect-wallet-dialog.pom'; | ||
|
|
||
| export class HomePage { | ||
| readonly page: Page; | ||
|
|
||
| constructor(page: Page) { | ||
| this.page = page; | ||
| } | ||
|
|
||
| async navigate() { | ||
| await this.page.goto('/'); | ||
| await this.page.waitForLoadState(); | ||
| } | ||
|
|
||
| async openNewPostDialog() { | ||
| await this.page.getByRole('button', { name: 'New post' }).click(); | ||
| } | ||
|
|
||
| async openConnectWalletDialog() { | ||
| await this.page.getByRole('button', { name: 'Connect Wallet' }).click(); | ||
| return new ConnectWalletDialogPage(this.page); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.