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

Update e2e tests #3775

Merged
merged 8 commits into from
Feb 14, 2025
Merged
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
7 changes: 5 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ jobs:
TEST_WALLET_JSON_PASSWORD: ${{ secrets.TEST_WALLET_JSON_PASSWORD }}
run: xvfb-run npx playwright test --grep @expensive
- uses: actions/upload-artifact@v4
if: failure()
if: ${{ failure() || cancelled() }}
with:
name: debug-output
path: |
Expand All @@ -221,6 +221,9 @@ jobs:
needs: [build, detect-if-flag-changed]
timeout-minutes: 60
runs-on: ubuntu-latest
env:
# https://playwright.dev/docs/service-workers-experimental
PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS: 1
steps:
- uses: actions/checkout@v3
- name: Read .nvmrc
Expand Down Expand Up @@ -269,7 +272,7 @@ jobs:
USE_MAINNET_FORK: true
run: xvfb-run npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
if: ${{ failure() || cancelled() }}
with:
name: fork-debug-output
path: |
Expand Down
4 changes: 2 additions & 2 deletions background/services/indexing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export default class IndexingService extends BaseService<Events> {
******************* */

private acceleratedTokenRefresh: {
timeout: number | undefined
timeout: ReturnType<typeof setTimeout> | undefined
assetLookups: {
asset: SmartContractFungibleAsset
addressOnNetwork: AddressOnNetwork
Expand Down Expand Up @@ -405,7 +405,7 @@ export default class IndexingService extends BaseService<Events> {
)

this.acceleratedTokenRefresh.assetLookups.push(...assetLookups)
this.acceleratedTokenRefresh.timeout ??= window.setTimeout(
this.acceleratedTokenRefresh.timeout ??= setTimeout(
Shadowfiend marked this conversation as resolved.
Show resolved Hide resolved
this.handleAcceleratedTokenRefresh.bind(this),
ACCELERATED_TOKEN_REFRESH_TIMEOUT,
)
Expand Down
57 changes: 21 additions & 36 deletions e2e-tests/regular/dapp-connect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,38 @@ test.describe("dApp Connections", () => {
const dappPage = await context.newPage()
await dappPage.goto("https://swap.cow.fi/")
await dappPage
.locator("#swap-button")
.getByRole("button", { name: "Connect Wallet" })
.first()
.click()

const popupPage = walletPageHelper.getConnectPopup()
// Get page after a specific action (e.g. clicking a link)
const [popupPage] = await Promise.all([
context.waitForEvent("page"),
await dappPage.locator("text=Injected").click(), // Opens a new tab
])
await popupPage.waitForLoadState()

// Clear the one-time informational popup, if present.
const connectingPopupTitle = popupPage.locator("h3", {
hasText: "Connecting with Taho",
})
await dappPage.locator("text=Injected").click() // Opens a new tab

expect(await connectingPopupTitle.count()).toBe(1)
await expect(connectingPopupTitle).toBeVisible()

// Clear the popover.
const popupCloseLocator = popupPage.getByRole("button", {
name: "Background close",
})
await popupPage.ready()

await popupCloseLocator.click()
await popupCloseLocator.waitFor({ state: "detached", timeout: 1000 })
await popupPage.hideDappConnectPopup()

await popupPage.locator("button", { hasText: "Reject" }).click()
await popupPage.rejectConnection()

await dappPage.close()

const dappPage2 = await context.newPage()
await dappPage2.goto("https://swap.cow.fi/")
await dappPage2
.locator("#swap-button")
.getByRole("button", { name: "Connect Wallet" })
.first()
.click()

const popup2 = walletPageHelper.getConnectPopup()

await dappPage2.locator("text=Injected").click() // Opens a new tab
// Get page after a specific action (e.g. clicking a link)
const [popupPage2] = await Promise.all([
context.waitForEvent("page"),
await dappPage2.locator("text=Injected").click(), // Opens a new tab
])
await popupPage2.waitForLoadState()

await popup2.ready()

// Check that the popup is no longer displayed.
const connectingPopupTitle2 = popupPage2.locator("h3", {
const connectingPopupTitle2 = popup2.page.locator("h3", {
hasText: "Connecting with Taho",
})
expect(await connectingPopupTitle2.count()).toBe(0)
Expand All @@ -68,23 +53,23 @@ test.describe("dApp Connections", () => {
walletPageHelper,
}) => {
await walletPageHelper.onboarding.addReadOnlyAccount("testertesting.eth")
await walletPageHelper.hideDappConnectPopup()

const dappPage = await context.newPage()
await dappPage.goto("https://swap.cow.fi/")

const popup = walletPageHelper.getConnectPopup()

await dappPage
.locator("#swap-button")
.getByRole("button", { name: "Connect Wallet" })
.first()
.click()

// Get page after a specific action (e.g. clicking a link)
const [popupPage] = await Promise.all([
context.waitForEvent("page"),
await dappPage.locator("text=Injected").click(), // Opens a new tab
])
await popupPage.waitForLoadState()
await dappPage.locator("text=Injected").click() // Opens a new tab

await popupPage.locator("button", { hasText: "Connect" }).click()
await popup.ready()
await popup.hideDappConnectPopup()
await popup.acceptConnection()

await walletPageHelper.goToStartPage()

Expand Down
28 changes: 21 additions & 7 deletions e2e-tests/regular/nfts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { wait } from "@tallyho/tally-background/lib/utils"
import { test, expect } from "../utils"
import { account1 } from "../utils/onboarding"

const makeStall = (label?: string) => {
let end: () => void = () => {
throw new Error(`Unable to set stall "${label}"`)
}

const stall = new Promise<void>((resolve) => {
end = resolve
}) as Promise<void> & { end: (label?: string) => void }

stall.end = end

return stall
}

test.describe("NFTs", () => {
test("User can view nft collections, poaps and badges", async ({
page,
Expand All @@ -10,11 +23,11 @@ test.describe("NFTs", () => {
walletPageHelper,
}) => {
await test.step("Shows loading state", async () => {
let shouldInterceptRequests = true
const stall = makeStall("Stall simplehash requests")

// Set a delay so we don't miss loading states
await context.route(/api\.simplehash\.com/i, async (route, request) => {
if (!shouldInterceptRequests || !isExtensionRequest(request)) {
if (!isExtensionRequest(request)) {
route.continue()
return
}
Expand All @@ -39,7 +52,7 @@ test.describe("NFTs", () => {
.locator(".active")
.waitFor({ state: "visible" })

await wait(5_000)
await stall
await route.fulfill({ response })
}
})
Expand All @@ -59,9 +72,8 @@ test.describe("NFTs", () => {

// Wait until load finishes
await expect(page.getByTestId("loading_doggo")).toBeVisible()
stall.end("Stop stalling simplehash")
await expect(page.getByTestId("loading_doggo")).not.toBeVisible()
Copy link
Contributor

Choose a reason for hiding this comment

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

I'mma say it: this test is wayy too convoluted lol. Someday perhaps we'll have time to figure out how to test what we want here without craziness...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah tbh I was just about to remove the loading state test because it was too flaky with the timeout, but somehow found a better way to set it up 😄


shouldInterceptRequests = false
})

// Header stats locators
Expand Down Expand Up @@ -141,6 +153,7 @@ test.describe("NFTs", () => {
.getByTestId("nft_collection_filters")
.getByTestId("toggle_item")
.filter({ hasText: "POAP" })
.first()
.getByRole("checkbox")
.click()

Expand All @@ -161,6 +174,7 @@ test.describe("NFTs", () => {
.getByTestId("nft_collection_filters")
.getByTestId("toggle_item")
.filter({ hasText: "POAP" })
.first()
.getByRole("checkbox")
.click()

Expand Down Expand Up @@ -188,7 +202,7 @@ test.describe("NFTs", () => {
const nftCollection = page
.getByTestId("nft_list_item")
.filter({ has: page.getByTestId("nft_list_item_collection") })
.filter({ hasText: "Notable Punks" })
.filter({ hasText: "Notable Crypto Punks" })
.first()

await nftCollection.hover()
Expand Down
23 changes: 10 additions & 13 deletions e2e-tests/regular/signing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,30 @@ test.describe("Signing", () => {
test("User can sign in with Ethereum", async ({
context,
walletPageHelper,
waitForExtensionPage,
}) => {
await walletPageHelper.onboarding.addNewWallet()
await walletPageHelper.hideDappConnectPopup()

const siwe = await context.newPage()
await siwe.goto("https://login.xyz")

await siwe.getByRole("button", { name: "SIGN-IN WITH ETHEREUM" }).click()

const connectPopupOpens = context.waitForEvent("page")
await siwe.getByText("Connect to your Web3 Wallet").click()
const connectPopup = walletPageHelper.getConnectPopup()
await siwe.getByTestId("component-wallet-button-taho").click()

await connectPopupOpens.then(async (popup) => {
await popup.waitForLoadState()
await popup.getByRole("button", { name: "Connect", exact: true }).click()
})
await connectPopup.ready()
await connectPopup.hideDappConnectPopup()

await connectPopup.acceptConnection()

const signDataPromptOpens = context.waitForEvent("page")
const signDataPromptOpens = waitForExtensionPage()

await signDataPromptOpens.then(async (prompt) => {
await prompt.waitForLoadState()
await prompt.getByRole("button", { name: "Sign" }).click()
})
// There's a bug on login.xyz that makes the test fail
// (https://discord.com/channels/862419652286218251/886997073650655232/1173226370776694794).
// We're adding the expectation of failure. Playwright will throw `Expected
// to fail, but passed.` when bug is fixed.
test.fail()
Copy link
Contributor

Choose a reason for hiding this comment

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

🔥


await expect(siwe.getByText("Vote for your favorite emoji")).toBeVisible()
})

Expand Down
8 changes: 7 additions & 1 deletion e2e-tests/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable no-empty-pattern */
import { test as base, chromium, Request, Worker } from "@playwright/test"
import { test as base, chromium, Page, Request, Worker } from "@playwright/test"
import path from "path"
import WalletPageHelper from "./utils/walletPageHelper"
import AssetsHelper from "./utils/assets"
Expand All @@ -15,6 +15,7 @@ type WalletTestFixtures = {
transactionsHelper: TransactionsHelper
backgroundPage: Worker
isExtensionRequest: (request: Request) => boolean
waitForExtensionPage: () => Promise<Page>
}

/**
Expand Down Expand Up @@ -52,6 +53,11 @@ export const test = base.extend<WalletTestFixtures>({
const extensionId = backgroundPage.url().split("/")[2]
await use(extensionId)
},
waitForExtensionPage: async ({ context, extensionId }, use) => {
await use(async () =>
context.waitForEvent("page", (page) => page.url().includes(extensionId)),
)
},
isExtensionRequest: async ({}, use) => {
const hasExtensionOrigin = (url: string) =>
/^chrome-extension:\/\//.test(url)
Expand Down
65 changes: 65 additions & 0 deletions e2e-tests/utils/connect-popup.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Yak shaving note: this really should be connect-popup-helper, onboarding should be onboarding-helper, etc.

For someday in the future heh.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { BrowserContext, Page, expect } from "@playwright/test"

export default class ConnectPopupHelper {
get page() {
if (this.#targetPage === null) {
throw new Error("Connection popup hasn't loaded yet")
}
return this.#targetPage
}

#targetPage: Page | null = null

#pagePromise: Promise<Page>

constructor(
private readonly context: BrowserContext,
extensionId: string,
) {
this.#pagePromise = this.context.waitForEvent("page", (page) =>
page.url().includes(extensionId),
)
}

async ready() {
const popup = await this.#pagePromise
await popup.waitForLoadState()
this.#targetPage = popup
}

/**
* Hides the dApp Connection "use Taho as default" informational popup so
* tests can proceed assuming dApp connection will be available without
* additional interactions.
*/
async hideDappConnectPopup(): Promise<void> {
// Clear the one-time informational popup, if present.
const connectingPopupTitle = this.page.locator("h3", {
hasText: "Connecting with Taho",
})

expect(await connectingPopupTitle.count()).toBe(1)

await expect(connectingPopupTitle).toBeVisible()

// Clear the popover.
const bgLocator = this.page
.locator(".bg")
.getByRole("button", { name: "Close" })

await bgLocator.click()
await bgLocator.waitFor({ state: "detached", timeout: 1000 })
}

async rejectConnection() {
await this.page.locator("button", { hasText: "Reject" }).click()
}

async acceptConnection() {
await this.page.getByRole("button", { name: "Connect" }).click()
}

async closeWindow() {
await this.page.close()
}
}
4 changes: 4 additions & 0 deletions e2e-tests/utils/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export default class OnboardingHelper {
await expect(
page.getByRole("heading", { name: "Welcome to Taho" }),
).toBeVisible()
await page.close()
})
}

Expand Down Expand Up @@ -104,6 +105,7 @@ export default class OnboardingHelper {
await expect(
page.getByRole("heading", { name: "Welcome to Taho" }),
).toBeVisible()
await page.close()
})
}

Expand Down Expand Up @@ -163,6 +165,7 @@ export default class OnboardingHelper {
await expect(
page.getByRole("heading", { name: "Welcome to Taho" }),
).toBeVisible()
await page.close()
})
}

Expand Down Expand Up @@ -227,5 +230,6 @@ export default class OnboardingHelper {
await expect(
page.getByRole("heading", { name: "Welcome to Taho" }),
).toBeVisible()
await page.close()
}
}
Loading
Loading