Skip to content

Commit

Permalink
Test/e2e phase 1 (#450)
Browse files Browse the repository at this point in the history
* chore: rename modalPage as it is not a modalPage

* test: add updatePreferences test

* chore: count subscribed dapps

* test: add message test

* chore: fix bugs in tests

* chore: expose env in workflow

* chore: pass duplex option for webkit

* Update tests/shared/helpers/notifyServer.ts

Co-authored-by: Ben Kremer <[email protected]>

* Apply suggestions from code review

Co-authored-by: Chris Smith <[email protected]>
Co-authored-by: Ben Kremer <[email protected]>

* chore: update env vars

* chore: remove need for clipboard, and stream in fetch

* chore: remove unused prop

* chore: wait for dapps to be subscribed

* chore: disable webkit

* chore: remove extra subscribe

* chore: remove unhelpful logs

* Update tests/shared/pages/InboxPage.ts

Co-authored-by: Enes <[email protected]>

* Update tests/shared/pages/InboxPage.ts

Co-authored-by: Enes <[email protected]>

* chore: remove empty space

* chore: refactor waitForSubscriptions

---------

Co-authored-by: Ben Kremer <[email protected]>
Co-authored-by: Chris Smith <[email protected]>
Co-authored-by: Enes <[email protected]>
  • Loading branch information
4 people authored Mar 1, 2024
1 parent 32d70f8 commit 441b7a8
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 31 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ui_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
env:
VITE_PROJECT_ID: ${{ secrets.VITE_DEV_PROJECT_ID }}
VITE_EXPLORER_API_URL: ${{ secrets.VITE_EXPLORER_API_URL }}
TEST_DAPP_PROJECT_ID: ${{ secrets.TEST_DAPP_PROJECT_ID }}
TEST_DAPP_PROJECT_SECRET: ${{ secrets.TEST_DAPP_PROJECT_SECRET }}
VITE_CI: true
- uses: actions/upload-artifact@v3
if: always()
Expand Down
4 changes: 0 additions & 4 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ export default defineConfig({
name: 'firefox',
use: { ...devices['Desktop Firefox'] }
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] }
}
],

/* Run your local dev server before starting the tests */
Expand Down
10 changes: 10 additions & 0 deletions tests/shared/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ export const DEFAULT_SESSION_PARAMS: SessionParams = {
optAccounts: ['1', '2'],
accept: true
}

export const CUSTOM_TEST_DAPP = {
description: "Test description",
icons: ["https://i.imgur.com/q9QDRXc.png"],
name: "Notify Swift Integration Tests Prod",
appDomain: "wc-notify-swift-integration-tests-prod.pages.dev",
projectSecret: process.env['TEST_DAPP_PROJECT_SECRET'],
projectId: process.env['TEST_DAPP_PROJECT_ID'],
messageType: "f173f231-a45c-4dc0-aa5d-956eb04f7360"
} as const;
36 changes: 25 additions & 11 deletions tests/shared/fixtures/fixture.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
import { test as base } from '@playwright/test'

import { ModalPage } from '../pages/InboxPage'
import { ModalValidator } from '../validators/ModalValidator'
import { InboxPage } from '../pages/InboxPage'
import { InboxValidator } from '../validators/ModalValidator'
import { SettingsPage } from '../pages/SettingsPage'
import { NotifyServer } from '../helpers/notifyServer'

// Declare the types of fixtures to use
export interface ModalFixture {
modalPage: ModalPage
modalValidator: ModalValidator
inboxPage: InboxPage
inboxValidator: InboxValidator
settingsPage: SettingsPage
notifyServer: NotifyServer
library: string
}

export const test = base.extend<ModalFixture>({
modalPage: async ({ page }, use) => {
const modalPage = new ModalPage(page)
await modalPage.load()
await use(modalPage)
inboxPage: async ({ page }, use) => {
const inboxPage = new InboxPage(page)
await inboxPage.load()
await use(inboxPage)
},
modalValidator: async ({ modalPage }, use) => {
const modalValidator = new ModalValidator(modalPage.page)
inboxValidator: async ({ inboxPage }, use) => {
const modalValidator = new InboxValidator(inboxPage.page)
await use(modalValidator)
}
},
// Have to pass same page object to maintain state between pages
settingsPage: async({ inboxPage }, use) => {
const settingsPage = new SettingsPage(inboxPage.page)
settingsPage.load()
use(settingsPage)
},
notifyServer: async({}, use) => {
const notifyServer = new NotifyServer();
use(notifyServer)
},
})
export { expect } from '@playwright/test'
53 changes: 53 additions & 0 deletions tests/shared/helpers/notifyServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { expect } from "@playwright/test"

export class NotifyServer {
private notifyBaseUrl = "https://notify.walletconnect.com"

public async sendMessage({
projectId,
projectSecret,
accounts,
url,
title,
body,
icon,
type
}: {
projectId: string,
projectSecret: string,
accounts: string[]
title: string,
body: string,
icon: string,
url: string
type: string
}) {
const request = JSON.stringify({
accounts,
notification: {
title,
body,
icon,
url,
type
}
})

const fetchUrl = `${this.notifyBaseUrl}/${projectId}/notify`

const headers = new Headers({
Authorization: `Bearer ${projectSecret}`,
"Content-Type": "application/json"
})

const fetchResults = await fetch(fetchUrl, {
method: "POST",
headers,
body: request
})

console.log({fetchResultsStatus: fetchResults.status, fetchResults: await fetchResults.text()})

expect(fetchResults.status).toEqual(200)
}
}
83 changes: 79 additions & 4 deletions tests/shared/pages/InboxPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type Locator, type Page, expect } from '@playwright/test'

import { BASE_URL } from '../constants'

export class ModalPage {
export class InboxPage {
private readonly baseURL = BASE_URL

private readonly connectButton: Locator
Expand All @@ -15,6 +15,13 @@ export class ModalPage {
await this.page.goto(this.baseURL)
}

async gotoDiscoverPage() {
await this.page.locator('.Sidebar__Navigation__Link[href="/notifications"]').click()
await this.page.getByText('Discover Apps').click();

await this.page.getByText('Discover Web3Inbox').isVisible();
}

async copyConnectUriToClipboard() {
await this.page.goto(this.baseURL)
await this.connectButton.click()
Expand All @@ -40,21 +47,89 @@ export class ModalPage {
await this.page.locator('.NotificationPwaModal__close-button').first().click()
}

async getAddress() {
await this.page.locator('.Avatar').first().click()
const address = await this.page.locator('wui-avatar').getAttribute('alt')
await this.page.locator('wui-icon[name=close]').first().click();

return address;
}

async subscribe(nth: number) {
await this.page.locator('.AppCard__body > .AppCard__body__subscribe').nth(nth).click()
await this.page.getByText('Subscribed to', { exact: false }).isVisible()
const appCard = this.page.locator('.AppCard__body').nth(nth)
await appCard.locator('.AppCard__body__subscribe').click()

await appCard.locator('.AppCard__body__subscribed').getByText('Subscribed', { exact: false }).isVisible()
}

async unsubscribe(nth: number) {
async navigateToNewSubscription(nth: number) {
await this.page.getByRole('button', { name: 'Subscribed' }).nth(nth).click()
await this.page.getByRole('button', { name: 'Subscribed' }).nth(nth).isHidden()
}

async subscribeAndNavigateToDapp(nth: number) {
await this.subscribe(nth);
await this.navigateToNewSubscription(nth);
}

async unsubscribe() {
await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
await this.page.getByRole('button', { name: 'Unsubscribe' }).click()
await this.page.getByRole('button', { name: 'Unsubscribe' }).nth(1).click()
await this.page.getByText('Unsubscribed from', { exact: false }).isVisible()
await this.page.waitForTimeout(2000)
}

async navigateToDappFromSidebar(nth: number) {
await this.page.locator('.AppSelector__notifications-link').nth(nth).click()
}

async countSubscribedDapps() {
const notificationsCount = await this.page.locator('.AppSelector__notifications').count()

return notificationsCount - 1;
}

/**
* Waits for a specific number of dApps to be subscribed.
*
* @param {number} expectedCount - The expected number of dApps to wait for.
* @returns {Promise<void>}
*/
async waitForSubscriptions(expectedCount: number): Promise<void> {
// Wait for a function that checks the length of a list or a set of elements
// matching a certain condition to equal the expectedCount.
await this.page.waitForFunction(([className, count]) => {
const elements = document.getElementsByClassName(className)[1].children;;
return elements.length === count;
}, ['AppSelector__list', expectedCount] as const, { timeout: 5000 });
}

async updatePreferences() {
await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
await this.page.getByRole('button', { name: 'Preferences' }).click()
// Ensure the modal is visible
await this.page.getByText('Preferences').nth(1).isVisible()
await this.page.getByText('Preferences').nth(1).click()

const firstCheckBoxIsChecked = await this.page.isChecked('.Toggle__checkbox:nth-of-type(1)')
await expect(this.page.locator('.Toggle__label').first()).toBeVisible()

await this.page.locator('.Toggle').first().click()

await this.page.getByRole('button', { name: 'Update' }).click()


await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
await this.page.getByRole('button', { name: 'Preferences' }).click()

const firstCheckBoxIsCheckedAfterUpdating = await this.page.isChecked('.Toggle__checkbox:nth-of-type(1)')

expect(firstCheckBoxIsChecked).not.toEqual(firstCheckBoxIsCheckedAfterUpdating)

await this.page.locator('.PreferencesModal__close').click();
}

async cancelSiwe() {
await this.page.getByTestId('w3m-connecting-siwe-cancel').click()
}
Expand Down
21 changes: 21 additions & 0 deletions tests/shared/pages/SettingsPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { type Locator, type Page, expect } from '@playwright/test'

import { BASE_URL } from '../../shared/constants'

export class SettingsPage {
private readonly baseURL = BASE_URL

constructor(public readonly page: Page) {}

async load() {}

async goToNotificationSettings() {
await this.page.locator('.Sidebar__Navigation__Link[href="/settings"]').click()
}

async displayCustomDapp(dappUrl: string) {
await this.page.getByPlaceholder('app.example.com').fill(dappUrl)
await this.page.getByRole('button', { name: "Save", exact: true}).click()
}

}
2 changes: 1 addition & 1 deletion tests/shared/validators/ModalValidator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test'
import type { Page } from '@playwright/test'

export class ModalValidator {
export class InboxValidator {
constructor(public readonly page: Page) {}

async expectConnected() {
Expand Down
Loading

0 comments on commit 441b7a8

Please sign in to comment.