Skip to content
This repository was archived by the owner on Dec 8, 2025. It is now read-only.

Commit 441b7a8

Browse files
devcelinebkremchris13524enesozturk
authored
Test/e2e phase 1 (#450)
* 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]>
1 parent 32d70f8 commit 441b7a8

File tree

9 files changed

+311
-31
lines changed

9 files changed

+311
-31
lines changed

.github/workflows/ui_test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
env:
3030
VITE_PROJECT_ID: ${{ secrets.VITE_DEV_PROJECT_ID }}
3131
VITE_EXPLORER_API_URL: ${{ secrets.VITE_EXPLORER_API_URL }}
32+
TEST_DAPP_PROJECT_ID: ${{ secrets.TEST_DAPP_PROJECT_ID }}
33+
TEST_DAPP_PROJECT_SECRET: ${{ secrets.TEST_DAPP_PROJECT_SECRET }}
3234
VITE_CI: true
3335
- uses: actions/upload-artifact@v3
3436
if: always()

playwright.config.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ export default defineConfig({
3737
name: 'firefox',
3838
use: { ...devices['Desktop Firefox'] }
3939
},
40-
{
41-
name: 'webkit',
42-
use: { ...devices['Desktop Safari'] }
43-
}
4440
],
4541

4642
/* Run your local dev server before starting the tests */

tests/shared/constants/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ export const DEFAULT_SESSION_PARAMS: SessionParams = {
88
optAccounts: ['1', '2'],
99
accept: true
1010
}
11+
12+
export const CUSTOM_TEST_DAPP = {
13+
description: "Test description",
14+
icons: ["https://i.imgur.com/q9QDRXc.png"],
15+
name: "Notify Swift Integration Tests Prod",
16+
appDomain: "wc-notify-swift-integration-tests-prod.pages.dev",
17+
projectSecret: process.env['TEST_DAPP_PROJECT_SECRET'],
18+
projectId: process.env['TEST_DAPP_PROJECT_ID'],
19+
messageType: "f173f231-a45c-4dc0-aa5d-956eb04f7360"
20+
} as const;

tests/shared/fixtures/fixture.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
11
import { test as base } from '@playwright/test'
22

3-
import { ModalPage } from '../pages/InboxPage'
4-
import { ModalValidator } from '../validators/ModalValidator'
3+
import { InboxPage } from '../pages/InboxPage'
4+
import { InboxValidator } from '../validators/ModalValidator'
5+
import { SettingsPage } from '../pages/SettingsPage'
6+
import { NotifyServer } from '../helpers/notifyServer'
57

68
// Declare the types of fixtures to use
79
export interface ModalFixture {
8-
modalPage: ModalPage
9-
modalValidator: ModalValidator
10+
inboxPage: InboxPage
11+
inboxValidator: InboxValidator
12+
settingsPage: SettingsPage
13+
notifyServer: NotifyServer
1014
library: string
1115
}
1216

1317
export const test = base.extend<ModalFixture>({
14-
modalPage: async ({ page }, use) => {
15-
const modalPage = new ModalPage(page)
16-
await modalPage.load()
17-
await use(modalPage)
18+
inboxPage: async ({ page }, use) => {
19+
const inboxPage = new InboxPage(page)
20+
await inboxPage.load()
21+
await use(inboxPage)
1822
},
19-
modalValidator: async ({ modalPage }, use) => {
20-
const modalValidator = new ModalValidator(modalPage.page)
23+
inboxValidator: async ({ inboxPage }, use) => {
24+
const modalValidator = new InboxValidator(inboxPage.page)
2125
await use(modalValidator)
22-
}
26+
},
27+
// Have to pass same page object to maintain state between pages
28+
settingsPage: async({ inboxPage }, use) => {
29+
const settingsPage = new SettingsPage(inboxPage.page)
30+
settingsPage.load()
31+
use(settingsPage)
32+
},
33+
notifyServer: async({}, use) => {
34+
const notifyServer = new NotifyServer();
35+
use(notifyServer)
36+
},
2337
})
2438
export { expect } from '@playwright/test'
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { expect } from "@playwright/test"
2+
3+
export class NotifyServer {
4+
private notifyBaseUrl = "https://notify.walletconnect.com"
5+
6+
public async sendMessage({
7+
projectId,
8+
projectSecret,
9+
accounts,
10+
url,
11+
title,
12+
body,
13+
icon,
14+
type
15+
}: {
16+
projectId: string,
17+
projectSecret: string,
18+
accounts: string[]
19+
title: string,
20+
body: string,
21+
icon: string,
22+
url: string
23+
type: string
24+
}) {
25+
const request = JSON.stringify({
26+
accounts,
27+
notification: {
28+
title,
29+
body,
30+
icon,
31+
url,
32+
type
33+
}
34+
})
35+
36+
const fetchUrl = `${this.notifyBaseUrl}/${projectId}/notify`
37+
38+
const headers = new Headers({
39+
Authorization: `Bearer ${projectSecret}`,
40+
"Content-Type": "application/json"
41+
})
42+
43+
const fetchResults = await fetch(fetchUrl, {
44+
method: "POST",
45+
headers,
46+
body: request
47+
})
48+
49+
console.log({fetchResultsStatus: fetchResults.status, fetchResults: await fetchResults.text()})
50+
51+
expect(fetchResults.status).toEqual(200)
52+
}
53+
}

tests/shared/pages/InboxPage.ts

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type Locator, type Page, expect } from '@playwright/test'
22

33
import { BASE_URL } from '../constants'
44

5-
export class ModalPage {
5+
export class InboxPage {
66
private readonly baseURL = BASE_URL
77

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

18+
async gotoDiscoverPage() {
19+
await this.page.locator('.Sidebar__Navigation__Link[href="/notifications"]').click()
20+
await this.page.getByText('Discover Apps').click();
21+
22+
await this.page.getByText('Discover Web3Inbox').isVisible();
23+
}
24+
1825
async copyConnectUriToClipboard() {
1926
await this.page.goto(this.baseURL)
2027
await this.connectButton.click()
@@ -40,21 +47,89 @@ export class ModalPage {
4047
await this.page.locator('.NotificationPwaModal__close-button').first().click()
4148
}
4249

50+
async getAddress() {
51+
await this.page.locator('.Avatar').first().click()
52+
const address = await this.page.locator('wui-avatar').getAttribute('alt')
53+
await this.page.locator('wui-icon[name=close]').first().click();
54+
55+
return address;
56+
}
57+
4358
async subscribe(nth: number) {
44-
await this.page.locator('.AppCard__body > .AppCard__body__subscribe').nth(nth).click()
45-
await this.page.getByText('Subscribed to', { exact: false }).isVisible()
59+
const appCard = this.page.locator('.AppCard__body').nth(nth)
60+
await appCard.locator('.AppCard__body__subscribe').click()
61+
62+
await appCard.locator('.AppCard__body__subscribed').getByText('Subscribed', { exact: false }).isVisible()
4663
}
4764

48-
async unsubscribe(nth: number) {
65+
async navigateToNewSubscription(nth: number) {
4966
await this.page.getByRole('button', { name: 'Subscribed' }).nth(nth).click()
5067
await this.page.getByRole('button', { name: 'Subscribed' }).nth(nth).isHidden()
68+
}
69+
70+
async subscribeAndNavigateToDapp(nth: number) {
71+
await this.subscribe(nth);
72+
await this.navigateToNewSubscription(nth);
73+
}
74+
75+
async unsubscribe() {
5176
await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
5277
await this.page.getByRole('button', { name: 'Unsubscribe' }).click()
5378
await this.page.getByRole('button', { name: 'Unsubscribe' }).nth(1).click()
5479
await this.page.getByText('Unsubscribed from', { exact: false }).isVisible()
5580
await this.page.waitForTimeout(2000)
5681
}
5782

83+
async navigateToDappFromSidebar(nth: number) {
84+
await this.page.locator('.AppSelector__notifications-link').nth(nth).click()
85+
}
86+
87+
async countSubscribedDapps() {
88+
const notificationsCount = await this.page.locator('.AppSelector__notifications').count()
89+
90+
return notificationsCount - 1;
91+
}
92+
93+
/**
94+
* Waits for a specific number of dApps to be subscribed.
95+
*
96+
* @param {number} expectedCount - The expected number of dApps to wait for.
97+
* @returns {Promise<void>}
98+
*/
99+
async waitForSubscriptions(expectedCount: number): Promise<void> {
100+
// Wait for a function that checks the length of a list or a set of elements
101+
// matching a certain condition to equal the expectedCount.
102+
await this.page.waitForFunction(([className, count]) => {
103+
const elements = document.getElementsByClassName(className)[1].children;;
104+
return elements.length === count;
105+
}, ['AppSelector__list', expectedCount] as const, { timeout: 5000 });
106+
}
107+
108+
async updatePreferences() {
109+
await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
110+
await this.page.getByRole('button', { name: 'Preferences' }).click()
111+
// Ensure the modal is visible
112+
await this.page.getByText('Preferences').nth(1).isVisible()
113+
await this.page.getByText('Preferences').nth(1).click()
114+
115+
const firstCheckBoxIsChecked = await this.page.isChecked('.Toggle__checkbox:nth-of-type(1)')
116+
await expect(this.page.locator('.Toggle__label').first()).toBeVisible()
117+
118+
await this.page.locator('.Toggle').first().click()
119+
120+
await this.page.getByRole('button', { name: 'Update' }).click()
121+
122+
123+
await this.page.locator('.AppNotificationsHeader__wrapper > .Dropdown').click()
124+
await this.page.getByRole('button', { name: 'Preferences' }).click()
125+
126+
const firstCheckBoxIsCheckedAfterUpdating = await this.page.isChecked('.Toggle__checkbox:nth-of-type(1)')
127+
128+
expect(firstCheckBoxIsChecked).not.toEqual(firstCheckBoxIsCheckedAfterUpdating)
129+
130+
await this.page.locator('.PreferencesModal__close').click();
131+
}
132+
58133
async cancelSiwe() {
59134
await this.page.getByTestId('w3m-connecting-siwe-cancel').click()
60135
}

tests/shared/pages/SettingsPage.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { type Locator, type Page, expect } from '@playwright/test'
2+
3+
import { BASE_URL } from '../../shared/constants'
4+
5+
export class SettingsPage {
6+
private readonly baseURL = BASE_URL
7+
8+
constructor(public readonly page: Page) {}
9+
10+
async load() {}
11+
12+
async goToNotificationSettings() {
13+
await this.page.locator('.Sidebar__Navigation__Link[href="/settings"]').click()
14+
}
15+
16+
async displayCustomDapp(dappUrl: string) {
17+
await this.page.getByPlaceholder('app.example.com').fill(dappUrl)
18+
await this.page.getByRole('button', { name: "Save", exact: true}).click()
19+
}
20+
21+
}

tests/shared/validators/ModalValidator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from '@playwright/test'
22
import type { Page } from '@playwright/test'
33

4-
export class ModalValidator {
4+
export class InboxValidator {
55
constructor(public readonly page: Page) {}
66

77
async expectConnected() {

0 commit comments

Comments
 (0)