-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: E2E test for Notifications Settings Syncing (#30243)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** * E2E Tests for notifications Syncing * Introduce a dataTestId prop to the NotificationsSettingsBox component to enhance testing capabilities. * Page objects for Notifications settings flow for validating and interacting with notifications setting * Updates unit and integration tests ## **Related issues** Fixes: ## **Manual testing steps** yarn build:test:webpack ENABLE_MV3=false yarn test:e2e:single test/e2e/tests/notifications/enable-notifications.spec.ts --browser=chrome yarn build:test yarn test:e2e:single test/e2e/tests/notifications/enable-notifications-with-accounts-sync.spec.ts --browser=chrome IS_ACCOUNT_SYNCING_ENABLED=true ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
- Loading branch information
Showing
19 changed files
with
766 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Driver } from '../../webdriver/driver'; | ||
|
||
class NotificationsListPage { | ||
private driver: Driver; | ||
|
||
private readonly notificationsListPageTitle = { | ||
text: 'Notifications', | ||
tag: 'p', | ||
}; | ||
|
||
private readonly notificationsSettingsButton = | ||
'[data-testid="notifications-settings-button"]'; | ||
|
||
constructor(driver: Driver) { | ||
this.driver = driver; | ||
} | ||
|
||
async check_pageIsLoaded(): Promise<void> { | ||
try { | ||
await this.driver.waitForMultipleSelectors([ | ||
this.notificationsListPageTitle, | ||
this.notificationsSettingsButton, | ||
]); | ||
} catch (e) { | ||
console.log( | ||
'Timeout while waiting for Notifications list page to be loaded', | ||
e, | ||
); | ||
throw e; | ||
} | ||
console.log('Notifications List page is loaded'); | ||
} | ||
|
||
/** | ||
* Navigates to the notifications settings page. | ||
* | ||
* This method clicks on the notifications settings button to navigate to the settings page. | ||
*/ | ||
async goToNotificationsSettings(): Promise<void> { | ||
console.log( | ||
`On notifications list page, navigating to notifications settings`, | ||
); | ||
await this.driver.clickElement(this.notificationsSettingsButton); | ||
} | ||
} | ||
|
||
export default NotificationsListPage; |
168 changes: 168 additions & 0 deletions
168
test/e2e/page-objects/pages/settings/notifications-settings-page.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { toChecksumHexAddress } from '@metamask/controller-utils'; | ||
import { Driver } from '../../../webdriver/driver'; | ||
import { shortenAddress } from '../../../../../ui/helpers/utils/util'; | ||
|
||
class NotificationsSettingsPage { | ||
private driver: Driver; | ||
|
||
private readonly notificationsSettingsPageTitle = { | ||
text: 'Notifications', | ||
tag: 'p', | ||
}; | ||
|
||
private readonly allowNotificationsToggle = | ||
'[data-testid="notifications-settings-allow-toggle-box"]'; | ||
|
||
private readonly allowNotificationsInput = | ||
'[data-testid="notifications-settings-allow-toggle-input"]'; | ||
|
||
private readonly allowNotificationsAddressToggle = ( | ||
address: string, | ||
elementType: 'input' | 'box', | ||
) => { | ||
const checksumAddress = toChecksumHexAddress(address.toLowerCase()); | ||
return `[data-testid="${shortenAddress( | ||
checksumAddress, | ||
)}-notifications-settings-toggle-${elementType}"]`; | ||
}; | ||
|
||
private readonly allowProductAnnouncementToggle = | ||
'[data-testid="product-announcements-toggle-box"]'; | ||
|
||
private readonly allowProductAnnouncementInput = | ||
'[data-testid="product-announcements-toggle-input"]'; | ||
|
||
constructor(driver: Driver) { | ||
this.driver = driver; | ||
} | ||
|
||
async check_pageIsLoaded(): Promise<void> { | ||
try { | ||
await this.driver.waitForMultipleSelectors([ | ||
this.notificationsSettingsPageTitle, | ||
this.allowNotificationsToggle, | ||
]); | ||
} catch (e) { | ||
console.log( | ||
'Timeout while waiting for notifications settings page to be loaded', | ||
e, | ||
); | ||
throw e; | ||
} | ||
console.log('Notifications Settings page is loaded'); | ||
} | ||
|
||
/** | ||
* Validates the state of any notification toggle. | ||
* | ||
* @param options - Configuration object | ||
* @param options.toggleType - The type of toggle to check ('general' | 'product' | 'address') | ||
* @param options.address - The ethereum address (required only when toggleType is 'address') | ||
* @param options.expectedState - The expected state of the toggle ('enabled' or 'disabled') | ||
* @throws {Error} If toggle state doesn't match expected state or if the toggle element cannot be found | ||
*/ | ||
async check_notificationState({ | ||
toggleType, | ||
address, | ||
expectedState, | ||
}: { | ||
toggleType: 'general' | 'product' | 'address'; | ||
address?: string; | ||
expectedState: 'enabled' | 'disabled'; | ||
}): Promise<void> { | ||
let selector: string; | ||
const description = | ||
toggleType === 'address' ? `for address ${address}` : ''; | ||
|
||
switch (toggleType) { | ||
case 'general': | ||
selector = this.allowNotificationsInput; | ||
break; | ||
case 'product': | ||
selector = this.allowProductAnnouncementInput; | ||
break; | ||
case 'address': | ||
if (!address) { | ||
throw new Error( | ||
'Address is required when checking address notifications', | ||
); | ||
} | ||
selector = this.allowNotificationsAddressToggle(address, 'input'); | ||
break; | ||
default: | ||
throw new Error(`Invalid toggle type: ${toggleType}`); | ||
} | ||
|
||
console.log( | ||
`Checking if ${toggleType} notifications ${description} are ${expectedState}`, | ||
); | ||
const expectedValue = expectedState === 'enabled' ? 'true' : 'false'; | ||
|
||
try { | ||
await this.driver.waitForElementToStopMoving(selector); | ||
await this.driver.wait(async () => { | ||
const toggle = await this.driver.findElement(selector); | ||
return (await toggle.getAttribute('value')) === expectedValue; | ||
}); | ||
console.log( | ||
`Successfully verified ${toggleType} notifications ${description} to be ${expectedState}`, | ||
); | ||
} catch (error) { | ||
throw new Error( | ||
`Expected ${toggleType} notifications ${description} state to be: ${expectedState}`, | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Clicks a notification toggle and verifies its new state. | ||
* | ||
* @param options - Configuration object | ||
* @param options.toggleType - The type of toggle to click ('general' | 'product' | 'address') | ||
* @param options.address - The ethereum address (required only when toggleType is 'address') | ||
* @throws {Error} If toggle element cannot be found or if address is missing when required | ||
*/ | ||
async clickNotificationToggle({ | ||
toggleType, | ||
address, | ||
}: { | ||
toggleType: 'general' | 'product' | 'address'; | ||
address?: string; | ||
}): Promise<void> { | ||
let selector: string; | ||
|
||
switch (toggleType) { | ||
case 'general': | ||
selector = this.allowNotificationsToggle; | ||
console.log('Clicking general notifications toggle'); | ||
break; | ||
case 'product': | ||
selector = this.allowProductAnnouncementToggle; | ||
console.log('Clicking product announcement toggle'); | ||
break; | ||
case 'address': | ||
if (!address) { | ||
throw new Error( | ||
'Address is required when toggling address notifications', | ||
); | ||
} | ||
selector = this.allowNotificationsAddressToggle(address, 'box'); | ||
console.log(`Clicking notifications toggle for address ${address}`); | ||
break; | ||
default: | ||
throw new Error(`Invalid toggle type: ${toggleType}`); | ||
} | ||
|
||
try { | ||
await this.driver.waitForElementToStopMoving(selector); | ||
await this.driver.clickElement(selector); | ||
await this.driver.waitForElementToStopMoving(selector); | ||
console.log(`Successfully clicked ${toggleType} notifications toggle`); | ||
} catch (error) { | ||
console.error(`Error clicking ${toggleType} notifications toggle`, error); | ||
throw error; | ||
} | ||
} | ||
} | ||
|
||
export default NotificationsSettingsPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.