diff --git a/.github/workflows/goodwallet-pr.yml b/.github/workflows/goodwallet-pr.yml index 777f005..f6144a5 100644 --- a/.github/workflows/goodwallet-pr.yml +++ b/.github/workflows/goodwallet-pr.yml @@ -45,3 +45,20 @@ jobs: uses: borales/actions-yarn@v5 with: cmd: test + + - name: Install Playwright Chromium + run: yarn playwright install --with-deps chromium + + - name: Run Playwright screenshots + uses: borales/actions-yarn@v5 + with: + cmd: test:e2e + - name: Upload Playwright screenshots and failure artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-artifacts + path: | + tests-playwright/screenshots/ + tests-playwright/artifacts/ + if-no-files-found: warn diff --git a/.gitignore b/.gitignore index 483384c..4530833 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ node_modules # testing coverage +/tests-playwright/artifacts/ # next.js .next/ diff --git a/config.ts b/config.ts index a98b082..07f586c 100644 --- a/config.ts +++ b/config.ts @@ -77,6 +77,10 @@ const enabledLoginOptions: EnabledLoginOptions = { const includeTestnetTokens = process.env.NEXT_PUBLIC_INCLUDE_TESTNET_TOKENS === "true" +// Enables deterministic UI states exclusively for the Playwright test server. +const playwrightTestMode = + process.env.NEXT_PUBLIC_PLAYWRIGHT_TEST_MODE === "true" + const lifiConfig = { apiUrl: "https://li.quest/v1", chainTypes: ["EVM", "UTXO", "SVM"], @@ -215,6 +219,7 @@ export const config = Object.freeze({ vercelConfig, env, includeTestnetTokens, + playwrightTestMode, enabledLoginOptions, lifiConfig, alchemyConfig, diff --git a/package.json b/package.json index 072598e..42829a4 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "start": "next start -p 80", "lint": "next lint", "test": "vitest run", + "test:e2e": "playwright test", + "test:e2e:screenshots": "playwright test --update-snapshots", "biome:verify:all": "biome check", "biome:fix:staged": "biome check --write --no-errors-on-unmatched --staged", "biome:fix:all": "biome check --write --no-errors-on-unmatched", @@ -69,6 +71,7 @@ }, "devDependencies": { "@biomejs/biome": "^2.5.3", + "@playwright/test": "1.61.1", "@types/async-retry": "^1.4.9", "@types/hdkey": "^2.1.0", "@types/node": "26.1.1", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..c2dfae4 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,45 @@ +import { defineConfig, devices } from "@playwright/test" + +const testWalletSeed = + "4c4d6a7e5f6a8b9c0d1e2f30415263748596a7b8c9d0e1f2031425364758697a" + +export default defineConfig({ + testDir: "./tests-playwright", + testMatch: "**/*.e2e.ts", + outputDir: "tests-playwright/artifacts", + snapshotPathTemplate: "{testDir}/screenshots/{projectName}/{arg}{ext}", + fullyParallel: false, + workers: 1, + reporter: "list", + use: { + baseURL: "http://localhost:3000", + trace: "retain-on-failure", + video: "retain-on-failure", + }, + projects: [ + { + name: "desktop", + use: { ...devices["Desktop Chrome"] }, + }, + { + name: "mobile", + use: { ...devices["iPhone 13"], browserName: "chromium" }, + }, + ], + webServer: { + command: "yarn next dev --turbo -p 3000", + url: "http://localhost:3000", + reuseExistingServer: false, + env: { + ...process.env, + NEXT_PUBLIC_PLAYWRIGHT_TEST_MODE: "true", + NEXT_PUBLIC_LOGIN_GOOGLE_ENABLED: "false", + NEXT_PUBLIC_LOGIN_FACEBOOK_ENABLED: "false", + NEXT_PUBLIC_LOGIN_PWLESS_ENABLED: "false", + NEXT_PUBLIC_TEST_LOGIN_ENABLED: "true", + NEXT_PUBLIC_TEST_LOGIN_MASTER_SEED: testWalletSeed, + NEXT_PUBLIC_TEST_LOGIN_USER_NAME: "Playwright test wallet", + NEXT_PUBLIC_TEST_LOGIN_PROFILE_IMAGE: "/icon.svg", + }, + }, +}) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f46a66b..ae535eb 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,18 +1,10 @@ import type { Metadata, Viewport } from "next" -import { Inter } from "next/font/google" - import "@/ui/styles.css" import { Dialog, Toast } from "ui" import { PreloadResources } from "./preload-resources.tsx" -const inter = Inter({ - subsets: ["latin"], - display: "swap", - variable: "--font-inter", -}) - export const viewport: Viewport = { themeColor: "#000", width: "device-width", @@ -53,7 +45,7 @@ export default function RootLayout({ children: React.ReactNode }) { return ( - + diff --git a/src/sections/GoodDollar/components/Claim/ClaimView.tsx b/src/sections/GoodDollar/components/Claim/ClaimView.tsx index da89d85..c38d9ec 100644 --- a/src/sections/GoodDollar/components/Claim/ClaimView.tsx +++ b/src/sections/GoodDollar/components/Claim/ClaimView.tsx @@ -23,6 +23,7 @@ import { getChainName } from "@/chain/chains" import { setBottomSheetProps } from "@/components/Snippet/BottomSheet/bottomSheetStore" import { LoadingSpinner } from "@/components/Snippet/LoadingSpinner" import { formatTokenAmount } from "@/components/Utils/tokenFormat" +import { config } from "@/config" import { topWallet } from "@/gooddollar/methods/faucet" import { collectBountyStore } from "@/gooddollar/stores/collectBountyStore" import { @@ -105,6 +106,14 @@ const getDailyStats = (claims: Record) => { } export default function ClaimView() { + if (config.playwrightTestMode) { + return undefined} /> + } + + return +} + +function ClaimViewContent() { const invitedChainId = useInvitedChainId() const { locale, translations } = useTranslation() diff --git a/src/sections/Home/components/WalletSection.tsx b/src/sections/Home/components/WalletSection.tsx index 1181c76..a5fa8da 100644 --- a/src/sections/Home/components/WalletSection.tsx +++ b/src/sections/Home/components/WalletSection.tsx @@ -258,8 +258,12 @@ export default function WalletSection({
{goodDollarLink} {sendLink} @@ -276,7 +281,10 @@ export default function WalletSection({ {walletConnectLink}
{hasMultipleActionRows ? ( -
+