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

e2e/Install, config & test #1592

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .changeset/eleven-chairs-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"playwright": major
---

install microsoft/playwright in order to run E2E tests on the Talisman extension.
30 changes: 30 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Playwright Tests
on:
push:
branches: [ dev, e2e/install ]
jobs:
test:
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build wallet
run: pnpm run build:extension
- name: Install Playwright Browsers
run: pnpm exec playwright install chromium
- name: Run Playwright tests
run: npx playwright test
working-directory: ./config/playwright
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ yarn-error.log*
# extension
dist
apps/extension/public/locales/*

#playwright

/config/playwright/node_modules/
/config/playwright/test-results/
/config/playwright/playwright-report/
/config/playwright/blob-report/
/config/playwright/.cache/
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { InfoIcon } from "@talismn/icons"
import { Mnemonic } from "@ui/domains/Mnemonic/Mnemonic"
import { MnemonicWordCountSwitch } from "@ui/domains/Mnemonic/MnemonicWordCountSwitch"
import { useCallback, useState } from "react"
import { useTranslation } from "react-i18next"
import { Button, Checkbox, Tooltip, TooltipContent, TooltipTrigger } from "talisman-ui"

import { Mnemonic } from "@ui/domains/Mnemonic/Mnemonic"
import { MnemonicWordCountSwitch } from "@ui/domains/Mnemonic/MnemonicWordCountSwitch"

import { Stages, useMnemonicCreateModal } from "./context"
import { MnemonicCreateModalDialog } from "./Dialog"

Expand Down Expand Up @@ -58,6 +59,7 @@ const MnemonicFormInner = () => {
className="text-grey-300 hover:text-body flex h-11 cursor-pointer gap-5 self-center text-sm font-bold"
onClick={complete}
type="button"
data-testid="onboarding-mnemonic-skip-button"
>
{t("Skip Verification")}
</button>
Expand Down
15 changes: 8 additions & 7 deletions apps/extension/src/ui/apps/onboard/routes/Password.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { yupResolver } from "@hookform/resolvers/yup"
import { CapsLockWarningMessage } from "@talisman/components/CapsLockWarningMessage"
import { PasswordStrength } from "@talisman/components/PasswordStrength"
import imgPassword from "@talisman/theme/images/onboard_password_character.png"
import { classNames } from "@talismn/util"
import { AnalyticsPage, sendAnalyticsEvent } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"
import { useCallback, useEffect } from "react"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { FormFieldContainer, FormFieldInputText } from "talisman-ui"
import { Button } from "talisman-ui"
import { Button, FormFieldContainer, FormFieldInputText } from "talisman-ui"
import * as yup from "yup"

import { CapsLockWarningMessage } from "@talisman/components/CapsLockWarningMessage"
import { PasswordStrength } from "@talisman/components/PasswordStrength"
import imgPassword from "@talisman/theme/images/onboard_password_character.png"
import { AnalyticsPage, sendAnalyticsEvent } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"

import { OnboardDialog } from "../components/OnboardDialog"
import { useOnboard } from "../context"
import { OnboardLayout } from "../OnboardLayout"
Expand Down Expand Up @@ -180,6 +180,7 @@ export const PasswordPage = () => {
)}
disabled={!isValid}
processing={isSubmitting}
data-testid="onboarding-continue-button"
>
{t("Continue")}
</Button>
Expand Down
16 changes: 11 additions & 5 deletions apps/extension/src/ui/apps/onboard/routes/Privacy.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useCallback } from "react"
import { Trans, useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { Button } from "talisman-ui"

import { PRIVACY_POLICY_URL } from "@extension/shared"
import imgAnalyticsFlower from "@talisman/theme/images/onboard_analytics_flower.png"
import imgAnalyticsSwitch from "@talisman/theme/images/onboard_analytics_switch.png"
import { AnalyticsPage, sendAnalyticsEvent } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"
import { useIsLoggedIn } from "@ui/hooks/useIsLoggedIn"
import { useCallback } from "react"
import { Trans, useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { Button } from "talisman-ui"

import { OnboardDialog } from "../components/OnboardDialog"
import { useOnboard } from "../context"
Expand Down Expand Up @@ -79,7 +80,12 @@ export const PrivacyPage = () => {
</div>
</Trans>
<div className="mt-40 flex w-full gap-8">
<Button className="bg-transparent" fullWidth onClick={handleClick(false)}>
<Button
className="bg-transparent"
fullWidth
onClick={handleClick(false)}
data-testid="onboarding-no-thanks-button"
>
{t("No thanks")}
</Button>
<Button onClick={handleClick(true)} fullWidth primary>
Expand Down
5 changes: 3 additions & 2 deletions apps/extension/src/ui/apps/onboard/routes/Success.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Button } from "talisman-ui"

import imgHandOrb from "@talisman/theme/images/onboard_hand_orb.png"
import { AnalyticsPage } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"
import { Button } from "talisman-ui"

import { useOnboard } from "../context"
import { OnboardLayout } from "../OnboardLayout"
Expand All @@ -26,7 +27,7 @@ export const SuccessPage = () => {
<br />
You're ready to get started!
</div>
<Button primary onClick={completeOnboarding}>
<Button primary onClick={completeOnboarding} data-testid="onboarding-enter-talisman-button">
Enter Talisman
</Button>
</div>
Expand Down
16 changes: 11 additions & 5 deletions apps/extension/src/ui/apps/onboard/routes/Welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { PRIVACY_POLICY_URL, TERMS_OF_USE_URL } from "@extension/shared"
import { TalismanWhiteLogo } from "@talisman/theme/logos"
import { ArrowRightIcon } from "@talismn/icons"
import { AnalyticsPage, sendAnalyticsEvent } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"
import { useCallback, useEffect } from "react"
import { Trans, useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"
import { Button } from "talisman-ui"

import { PRIVACY_POLICY_URL, TERMS_OF_USE_URL } from "@extension/shared"
import { TalismanWhiteLogo } from "@talisman/theme/logos"
import { AnalyticsPage, sendAnalyticsEvent } from "@ui/api/analytics"
import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView"

import { useOnboard } from "../context"
import { OnboardLayout } from "../OnboardLayout"

Expand Down Expand Up @@ -72,7 +73,12 @@ export const WelcomePage = () => {
</div>
</div>
<div className="welcome-button flex w-[44rem] flex-col gap-8">
<Button primary icon={ArrowRightIcon} onClick={handleNextClick()}>
<Button
primary
icon={ArrowRightIcon}
onClick={handleNextClick()}
data-testid="onboarding-get-started-button"
>
{t("Get Started")}
</Button>
<div className="text-body-secondary text-center text-sm leading-[2rem]">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
import { AccountAddressType, RequestAccountCreateOptions } from "@extension/core"
import { AssetDiscoveryMode } from "@extension/core"
import { log } from "@extension/shared"
import { yupResolver } from "@hookform/resolvers/yup"
import { Accordion, AccordionIcon } from "@talisman/components/Accordion"
import { notify, notifyUpdate } from "@talisman/components/Notifications"
import { Spacer } from "@talisman/components/Spacer"
import { ArrowRightIcon } from "@talismn/icons"
import { classNames } from "@talismn/util"
import { sleep } from "@talismn/util"
import { classNames, sleep } from "@talismn/util"
import { useQuery } from "@tanstack/react-query"
import { api } from "@ui/api"
import {
MnemonicCreateModal,
MnemonicCreateModalProvider,
useMnemonicCreateModal,
} from "@ui/apps/dashboard/routes/Settings/Mnemonics/MnemonicCreateModal"
import { AccountTypeSelector } from "@ui/domains/Account/AccountTypeSelector"
import useAccounts from "@ui/hooks/useAccounts"
import { useMnemonics } from "@ui/hooks/useMnemonics"
import { FC, PropsWithChildren, useCallback, useEffect, useMemo } from "react"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
Expand All @@ -34,6 +18,25 @@ import {
} from "talisman-ui"
import * as yup from "yup"

import {
AccountAddressType,
AssetDiscoveryMode,
RequestAccountCreateOptions,
} from "@extension/core"
import { log } from "@extension/shared"
import { Accordion, AccordionIcon } from "@talisman/components/Accordion"
import { notify, notifyUpdate } from "@talisman/components/Notifications"
import { Spacer } from "@talisman/components/Spacer"
import { api } from "@ui/api"
import {
MnemonicCreateModal,
MnemonicCreateModalProvider,
useMnemonicCreateModal,
} from "@ui/apps/dashboard/routes/Settings/Mnemonics/MnemonicCreateModal"
import { AccountTypeSelector } from "@ui/domains/Account/AccountTypeSelector"
import useAccounts from "@ui/hooks/useAccounts"
import { useMnemonics } from "@ui/hooks/useMnemonics"

import { AccountIcon } from "../../AccountIcon"
import { AccountAddPageProps } from "../types"
import { AccountAddMnemonicDropdown } from "./AccountAddMnemonicDropdown"
Expand Down Expand Up @@ -263,6 +266,7 @@ const AccountAddDerivedFormInner: FC<AccountAddPageProps> = ({ onSuccess }) => {
<FormFieldInputText
{...register("name")}
placeholder={t("Choose a name")}
data-testid="onboarding-choose-name-input"
spellCheck={false}
autoComplete="off"
data-lpignore
Expand Down Expand Up @@ -313,6 +317,7 @@ const AccountAddDerivedFormInner: FC<AccountAddPageProps> = ({ onSuccess }) => {
primary
disabled={!isValid}
processing={isSubmitting}
data-testid="onboarding-create-button"
>
{t("Create")}
</Button>
Expand Down
13 changes: 8 additions & 5 deletions apps/extension/src/ui/domains/Account/AccountAdd/Container.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { IS_FIREFOX } from "@extension/shared"
import { SelectedIndicator } from "@talisman/components/SelectedIndicator"
import { EthereumCircleBorderedLogo, PolkadotCircleBorderedLogo } from "@talisman/theme/logos"
import { ChainIcon, EyePlusIcon, FilePlusIcon, PlusIcon } from "@talismn/icons"
import { classNames } from "@talismn/util"
import { getIsLedgerCapable } from "@ui/util/getIsLedgerCapable"
import { ReactNode, useCallback, useMemo } from "react"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom"

import { IS_FIREFOX } from "@extension/shared"
import { SelectedIndicator } from "@talisman/components/SelectedIndicator"
import { EthereumCircleBorderedLogo, PolkadotCircleBorderedLogo } from "@talisman/theme/logos"
import { getIsLedgerCapable } from "@ui/util/getIsLedgerCapable"

import { MethodTypes, useAccountCreateContext } from "./context"

type Props = {
Expand Down Expand Up @@ -88,7 +89,9 @@ const AccountCreateMethodButton = ({
: "text-body cursor-pointer hover:bg-opacity-10 focus:bg-opacity-10"
}`}
>
<span className={"flex justify-start"}>{title}</span>
<span className={"flex justify-start"} data-testid="onboarding-create-acc-button">
{title}
</span>
<span className={"text-body-secondary flex items-center gap-2 text-sm"}>
{networks.map((network, i) => (
<span key={network} className={i + 1 < networks.length ? "-mr-[0.8rem]" : ""}>
Expand Down
5 changes: 3 additions & 2 deletions apps/extension/src/ui/domains/Mnemonic/Acknowledgement.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { MNEMONIC_BACKUP_DOCS_URL } from "@extension/shared"
import { LockIcon, ShieldIcon, XIcon } from "@talismn/icons"
import { useTranslation } from "react-i18next"
import { Button } from "talisman-ui"

import { MNEMONIC_BACKUP_DOCS_URL } from "@extension/shared"

export const Acknowledgement = ({ onContinueClick }: { onContinueClick: () => void }) => {
const { t } = useTranslation("admin")

Expand Down Expand Up @@ -35,7 +36,7 @@ export const Acknowledgement = ({ onContinueClick }: { onContinueClick: () => vo
</span>
</div>
</div>
<Button primary onClick={onContinueClick}>
<Button primary onClick={onContinueClick} data-testid="onboarding-acknowledge-button">
{t("Acknowledge and Continue")}
</Button>
</div>
Expand Down
38 changes: 38 additions & 0 deletions config/playwright/e2e/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { BrowserContext } from "@playwright/test"
import { test as base, chromium } from "@playwright/test"

export const test = base.extend<{
context: BrowserContext
extensionId: string
}>({
// eslint-disable-next-line no-empty-pattern
context: async ({}, use) => {
const pathToExtension = "../../apps/extension/dist/chrome"
const context = await chromium.launchPersistentContext("", {
headless: false,
args: [
`--headless=new`,
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
],
})
await use(context)
//await context.close();
},
extensionId: async ({ context }, use) => {
/*
// for manifest v2:
let [background] = context.backgroundPages()
if (!background)
background = await context.waitForEvent('backgroundpage')
*/

// for manifest v3:
let [background] = context.serviceWorkers()
if (!background) background = await context.waitForEvent("serviceworker")

const extensionId = background.url().split("/")[2]
await use(extensionId)
},
})
export const expect = test.expect
43 changes: 43 additions & 0 deletions config/playwright/e2e/simple.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect, test } from "./fixtures"

test.beforeAll("popup page", async ({ page, extensionId, context }) => {
await page.goto(`chrome-extension://${extensionId}/onboarding.html`)
await expect(page.locator("body")).toContainText("Multi-chain made easy")
await page.getByTestId("onboarding-get-started-button").click()
await expect(page).toHaveURL(`chrome-extension://${extensionId}/onboarding.html#/password`)
await page.getByPlaceholder("Enter password").fill("123456")
await page.getByPlaceholder("Confirm password").fill("123456")
await page.getByTestId("onboarding-continue-button").click()
await expect(page).toHaveURL(`chrome-extension://${extensionId}/onboarding.html#/privacy`)
await page.getByTestId("onboarding-no-thanks-button").click()
await expect(page).toHaveURL(`chrome-extension://${extensionId}/onboarding.html#/accounts/add`)
await page.getByTestId("onboarding-create-acc-button").first().click()
await page.getByTestId("onboarding-choose-name-input").fill("E2E Test")
await page.getByTestId("onboarding-create-button").click()

const allPages = context.pages()
await allPages[0].close()
await allPages[2].close()

await page.getByTestId("onboarding-acknowledge-button").click()
await page.getByTestId("onboarding-mnemonic-skip-button").click()
await expect(page).toHaveURL(`chrome-extension://${extensionId}/onboarding.html#/success`)
await page.getByTestId("onboarding-enter-talisman-button").click()
await expect(page).toHaveURL(
`chrome-extension://${extensionId}/dashboard.html#/portfolio?onboarded`
)
})

test("This test will use the previously created wallet enviroment", async ({
extensionId,
page,
}) => {
await page.goto(`chrome-extension://${extensionId}/popup.html?embedded`)
})

test("This test will use the previously created wallet enviroment and will run in parallel", async ({
extensionId,
page,
}) => {
await page.goto(`chrome-extension://${extensionId}/popup.html?embedded`)
})
Loading