From 0ce23e7b0539c10d1e648bee527636719acec640 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 28 Aug 2025 16:08:06 +1000 Subject: [PATCH 01/32] fix: tests do not fail immediately --- tests/automation/create_user.spec.ts | 2 +- tests/automation/delete_account.spec.ts | 4 ++-- tests/automation/linked_device_group.spec.ts | 2 +- tests/automation/linked_device_requests.spec.ts | 4 ++-- tests/automation/linked_device_user.spec.ts | 2 +- tests/automation/message_requests.spec.ts | 2 +- tests/automation/password.spec.ts | 12 ++++++------ tests/automation/setup/new_user.ts | 4 ++-- tests/automation/types/testing.ts | 3 ++- tests/automation/user_actions.spec.ts | 12 ++++++------ 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index cebc6a9..ea820ff 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -19,7 +19,7 @@ sessionTestOneWindow('Create User', async ([window]) => { // exit profile modal await clickOnTestIdWithText(window, 'modal-close-button'); // go to settings section - await clickOnTestIdWithText(window, 'settings-section'); + await clickOnTestIdWithText(window, 'invalid-data-testid'); // check recovery phrase matches await clickOnTestIdWithText(window, 'recovery-password-settings-menu-item'); await waitForTestIdWithText( diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index e5a16cc..04bb29e 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -36,7 +36,7 @@ sessionTestTwoWindows( ]); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, 'settings-section'); + await clickOnTestIdWithText(windowA, 'invalid-data-testid'); // Click on clear all data await clickOnTestIdWithText( windowA, @@ -126,7 +126,7 @@ sessionTestTwoWindows( await createContact(windowA, windowB, userA, userB); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, 'settings-section'); + await clickOnTestIdWithText(windowA, 'invalid-data-testid'); // Click on clear all data await clickOnTestIdWithText( windowA, diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index da8dd8a..18f8fdd 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -127,7 +127,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); async function clearDataOnWindow(window: Page) { - await clickOnTestIdWithText(window, 'settings-section'); + await clickOnTestIdWithText(window, 'invalid-data-testid'); // Click on clear data option on left pane await clickOnTestIdWithText( window, diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 1c41ec9..5dd9f33 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -134,7 +134,7 @@ test_Alice_2W_Bob_1W( // Need to wait for the blocked status to sync await sleepFor(2000); // Check blocked status in blocked contacts list - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow1, 'conversations-settings-menu-item', @@ -144,7 +144,7 @@ test_Alice_2W_Bob_1W( // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list await sleepFor(5000); - await clickOnTestIdWithText(aliceWindow2, 'settings-section'); + await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow2, 'conversations-settings-menu-item', diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index ea3ddec..ddf5219 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -330,7 +330,7 @@ test_Alice_2W_Bob_1W( // reveal-blocked-user-settings is not updated once opened // Check linked device for blocked contact in settings screen // Click on settings tab - await clickOnTestIdWithText(aliceWindow2, 'settings-section'); + await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow2, 'conversations-settings-menu-item', diff --git a/tests/automation/message_requests.spec.ts b/tests/automation/message_requests.spec.ts index 86fb331..a239c30 100644 --- a/tests/automation/message_requests.spec.ts +++ b/tests/automation/message_requests.spec.ts @@ -142,7 +142,7 @@ test_Alice_1W_Bob_1W( englishStrippedStr('clear').toString(), ); // Navigate back to message request folder to check - await clickOnTestIdWithText(bobWindow1, 'settings-section'); + await clickOnTestIdWithText(bobWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( bobWindow1, diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index af22dad..2a4e09f 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -28,7 +28,7 @@ async function expectRecoveryPhraseToBeVisible( test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); // Click on privacy await clickOnTestIdWithText(aliceWindow1, 'privacy-settings-menu-item'); // Click set password @@ -50,7 +50,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { ); // Click on settings tab await sleepFor(300, true); - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', @@ -67,7 +67,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // check that the seed is visible now await expectRecoveryPhraseToBeVisible(aliceWindow1, alice.recoveryPassword); - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); // Change password await clickOnTestIdWithText(aliceWindow1, 'change-password-settings-button'); @@ -97,7 +97,7 @@ test_Alice_1W_no_network( async ({ alice: { recoveryPassword }, aliceWindow1 }) => { // Check if incorrect password works // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); // Click on privacy await clickOnMatchingText( aliceWindow1, @@ -118,7 +118,7 @@ test_Alice_1W_no_network( await sleepFor(100); // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', @@ -134,7 +134,7 @@ test_Alice_1W_no_network( await clickOnTestIdWithText(aliceWindow1, 'message-section'); // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await sleepFor(500); // Click on recovery phrase tab await clickOnTestIdWithText( diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 5653922..03fff94 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -30,7 +30,7 @@ export const newUser = async ( // const recoveryPhrase = await window.innerText( // '[data-testid=recovery-password-seed-modal]', // ); - // await clickOnTestIdWithText(window, 'modal-close-button'); + await clickOnTestIdWithText(window, 'modal-close-button'); await clickOnTestIdWithText(window, 'leftpane-primary-avatar'); // Save Account ID to a variable @@ -46,6 +46,6 @@ export const newUser = async ( if (awaitOnionPath) { await checkPathLight(window); } - await clickOnTestIdWithText(window, 'message-section'); + // await clickOnTestIdWithText(window, 'message-section'); return { userName, accountid, recoveryPassword }; }; diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 0ef2b8d..a7131e3 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -91,7 +91,7 @@ export type DataTestId = | 'disappear-control-message' | 'disappearing-messages-indicator' | 'conversation-options-avatar' - | 'settings-section' + | 'invalid-data-testid' | 'clear-data-settings-menu-item' | 'message-requests-settings-menu-item' | 'restore-using-recovery' @@ -147,6 +147,7 @@ export type DataTestId = | 'header-conversation-name' | 'copy-button-profile-update' | 'loading-spinner' + | 'invalid-data-testid' // SES-4499, temporary fix to make the tests run again | 'empty-conversation-notification' | 'your-profile-name' | 'mentions-popup-row' diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index c71aba0..f1f3fd1 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -108,7 +108,7 @@ test_Alice_1W_Bob_1W( ); // Verify the user was moved to the blocked contact list // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); // click on settings section 'conversation' await clickOnTestIdWithText( aliceWindow1, @@ -287,7 +287,7 @@ test_Alice_1W_Bob_1W( await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', - selector: 'settings-section', + selector: 'invalid-data-testid', }); await clickOnElement({ window: aliceWindow1, @@ -307,7 +307,7 @@ test_Alice_1W_Bob_1W( await clickOnElement({ window: bobWindow1, strategy: 'data-testid', - selector: 'settings-section', + selector: 'invalid-data-testid', }); await clickOnElement({ window: bobWindow1, @@ -401,7 +401,7 @@ test_Alice_1W_Bob_1W( test_Alice_2W( 'Hide recovery password', async ({ aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', @@ -439,7 +439,7 @@ test_Alice_2W( 'recovery-password-settings-menu-item', ); // Check linked device if Recovery Password is still visible (it should be) - await clickOnTestIdWithText(aliceWindow2, 'settings-section'); + await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); await waitForTestIdWithText( aliceWindow2, 'recovery-password-settings-menu-item', @@ -537,7 +537,7 @@ test_Alice_1W_no_network( ); test_Alice_1W_no_network('Toggle password', async ({ aliceWindow1 }) => { - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', From b71e6b6309c7cbb63ed34fe953faf62ada368a34 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 28 Aug 2025 16:36:42 +1000 Subject: [PATCH 02/32] fix: only keep hex when getting accountid --- tests/automation/setup/new_user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 03fff94..7eea649 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -35,7 +35,7 @@ export const newUser = async ( // Save Account ID to a variable let accountid = await window.innerText('[data-testid=your-account-id]'); - accountid = accountid.replace(/(\r\n|\n|\r)/gm, ''); // remove the new line in the Account ID as it is rendered with one forced + accountid = accountid.replace(/[^0-9a-fA-F]/g, ''); // keep only hex characters console.log( `${userName}: Account ID: "${chalk.blue( From d3d87d3333d737899bd872b497cd35e736622da7 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 28 Aug 2025 17:16:26 +1000 Subject: [PATCH 03/32] feat: begin adding locator classes --- tests/automation/community_tests.spec.ts | 22 +++++++--- tests/automation/create_user.spec.ts | 15 ++++--- tests/automation/locators/index.ts | 54 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 tests/automation/locators/index.ts diff --git a/tests/automation/community_tests.spec.ts b/tests/automation/community_tests.spec.ts index 28cf523..0eee5fe 100644 --- a/tests/automation/community_tests.spec.ts +++ b/tests/automation/community_tests.spec.ts @@ -5,15 +5,19 @@ import { sendMessage } from './utilities/message'; import { replyTo } from './utilities/reply_message'; import { sendMedia } from './utilities/send_media'; import { clickOnTestIdWithText } from './utilities/utils'; +import { Conversation, HomeScreen } from './locators'; test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => { await joinCommunity(aliceWindow1); - await clickOnTestIdWithText(aliceWindow1, 'scroll-to-bottom-button'); + await clickOnTestIdWithText( + aliceWindow1, + Conversation.scrollToBottomButton.selector, + ); await sendMessage(aliceWindow1, 'Hello, community!'); // Check linked device for community await clickOnTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItem.selector, testCommunityName, ); }); @@ -29,15 +33,19 @@ test_Alice_1W_Bob_1W( // waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'), // waitForLoadingAnimationToFinish(bobWindow1, 'loading-spinner'), // ]); - await Promise.all([ - clickOnTestIdWithText(aliceWindow1, 'scroll-to-bottom-button'), - clickOnTestIdWithText(bobWindow1, 'scroll-to-bottom-button'), - ]); + await Promise.all( + [aliceWindow1, bobWindow1].map((window) => + clickOnTestIdWithText( + window, + Conversation.scrollToBottomButton.selector, + ), + ), + ); await sendMessage(aliceWindow1, testMessage); // Check linked device for community await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItem.selector, testCommunityName, ); await sendMedia( diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index ea820ff..bfa7917 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -5,26 +5,27 @@ import { clickOnTestIdWithText, waitForTestIdWithText, } from './utilities/utils'; +import { Global, LeftPane, Settings } from './locators'; sessionTestOneWindow('Create User', async ([window]) => { // Create User const userA = await newUser(window, 'Alice', false); // Open profile tab - await clickOnTestIdWithText(window, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(window, LeftPane.profileButton.selector); await sleepFor(100, true); // check username matches - await waitForTestIdWithText(window, 'your-profile-name', userA.userName); + await waitForTestIdWithText(window, Settings.displayName.selector, userA.userName); // check Account ID matches - await waitForTestIdWithText(window, 'your-account-id', userA.accountid); + await waitForTestIdWithText(window, Settings.accountId.selector, userA.accountid); // exit profile modal - await clickOnTestIdWithText(window, 'modal-close-button'); + await clickOnTestIdWithText(window, Global.modalCloseButton.selector); // go to settings section - await clickOnTestIdWithText(window, 'invalid-data-testid'); + await clickOnTestIdWithText(window, LeftPane.settingsButton.selector); // check recovery phrase matches - await clickOnTestIdWithText(window, 'recovery-password-settings-menu-item'); + await clickOnTestIdWithText(window, Settings.recoveryPasswordMenuItem.selector); await waitForTestIdWithText( window, - 'recovery-password-seed-modal', + Settings.recoveryPasswordContainer.selector, userA.recoveryPassword, ); }); diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts new file mode 100644 index 0000000..6f84eb2 --- /dev/null +++ b/tests/automation/locators/index.ts @@ -0,0 +1,54 @@ +/* eslint-disable @typescript-eslint/lines-between-class-members */ +import { DataTestId, StrategyExtractionObj } from '../types/testing'; + +export abstract class Locator { + protected static testId(selector: DataTestId) { + return { + strategy: 'data-testid', + selector, + }; + } + + protected static hasText(selector: string): StrategyExtractionObj { + return { + strategy: ':has-text', + selector, + }; + } + + protected static className(selector: string): StrategyExtractionObj { + return { + strategy: 'class', + selector, + }; + } +} + +export class LeftPane extends Locator { + static readonly profileButton = this.testId('leftpane-primary-avatar'); + static readonly settingsButton = this.testId('invalid-data-testid'); // SES--4499 +} + +export class HomeScreen extends Locator { + static readonly conversationItem = this.testId( + 'module-conversation__user__profile-name', + ); +} + +export class Conversation extends Locator { + static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); +} + +export class Settings extends Locator { + // Profile + static readonly displayName = this.testId('your-profile-name'); + static readonly accountId = this.testId('your-account-id'); + // Menu items + static readonly recoveryPasswordMenuItem = this.testId('recovery-password-settings-menu-item'); + // Recovery Password + static readonly recoveryPasswordContainer = this.testId('recovery-password-seed-modal'); +} + +export class Global extends Locator { + static readonly modalCloseButton = this.testId('modal-close-button'); +} \ No newline at end of file From afde6370f6697f0d9c6298561ff92f805b9e7ab9 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Fri, 29 Aug 2025 15:52:36 +1000 Subject: [PATCH 04/32] chore: continue using locator classes --- tests/automation/community_tests.spec.ts | 4 +- tests/automation/delete_account.spec.ts | 33 +++--- .../automation/enforce_localized_str.spec.ts | 2 + tests/automation/locators/index.ts | 24 ++++- tests/automation/password.spec.ts | 102 +++++++++--------- tests/automation/types/testing.ts | 4 +- 6 files changed, 95 insertions(+), 74 deletions(-) diff --git a/tests/automation/community_tests.spec.ts b/tests/automation/community_tests.spec.ts index 0eee5fe..b565ab7 100644 --- a/tests/automation/community_tests.spec.ts +++ b/tests/automation/community_tests.spec.ts @@ -17,7 +17,7 @@ test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => { // Check linked device for community await clickOnTestIdWithText( aliceWindow2, - HomeScreen.conversationItem.selector, + HomeScreen.conversationItemName.selector, testCommunityName, ); }); @@ -45,7 +45,7 @@ test_Alice_1W_Bob_1W( // Check linked device for community await clickOnTestIdWithText( aliceWindow1, - HomeScreen.conversationItem.selector, + HomeScreen.conversationItemName.selector, testCommunityName, ); await sendMedia( diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 04bb29e..7e564f8 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -17,6 +17,7 @@ import { } from './utilities/utils'; import { recoverFromSeed } from './setup/recovery_using_seed'; import { englishStrippedStr } from '../localization/englishStrippedStr'; +import { Global, HomeScreen, LeftPane, Onboarding, Settings } from './locators'; sessionTestTwoWindows( 'Delete account from swarm', @@ -36,17 +37,17 @@ sessionTestTwoWindows( ]); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, 'invalid-data-testid'); + await clickOnTestIdWithText(windowA, LeftPane.settingsButton.selector); // Click on clear all data await clickOnTestIdWithText( windowA, - 'clear-data-settings-menu-item', + Settings.clearDataMenuItem.selector, englishStrippedStr('sessionClearData').toString(), ); // Select entire account await clickOnTestIdWithText( windowA, - 'label-device_and_network', + Settings.clearDeviceAndNetworkRadial.selector, englishStrippedStr('clearDeviceAndNetwork').toString(), ); // Confirm deletion by clicking Clear, twice @@ -66,15 +67,15 @@ sessionTestTwoWindows( restoringWindows = await openApp(1); // not using sessionTest here as we need to close and reopen one of the window const [restoringWindow] = restoringWindows; // Sign in with deleted account and check that nothing restores - await clickOnTestIdWithText(restoringWindow, 'existing-account-button'); + await clickOnTestIdWithText(restoringWindow, Onboarding.iHaveAnAccountButton.selector); // Fill in recovery phrase await typeIntoInput( restoringWindow, - 'recovery-phrase-input', + Onboarding.recoveryPhraseInput.selector, userA.recoveryPassword, ); // Enter display name - await clickOnTestIdWithText(restoringWindow, 'continue-button'); + await clickOnTestIdWithText(restoringWindow, Global.continueButton.selector); await waitForLoadingAnimationToFinish( restoringWindow, 'loading-animation', @@ -82,11 +83,11 @@ sessionTestTwoWindows( await typeIntoInput( restoringWindow, - 'display-name-input', + Onboarding.displayNameInput.selector, userA.userName, ); // Click continue - await clickOnTestIdWithText(restoringWindow, 'continue-button'); + await clickOnTestIdWithText(restoringWindow, Global.continueButton.selector); await sleepFor(5000, true); // just to allow any messages from our swarm to show up // Need to verify that no conversation is found at all @@ -94,15 +95,15 @@ sessionTestTwoWindows( await hasElementBeenDeleted( restoringWindow, 'data-testid', - 'conversation-list-item', + HomeScreen.conversationItemName.selector, ); - await clickOnTestIdWithText(restoringWindow, 'new-conversation-button'); // Expect contacts list to be empty + await clickOnTestIdWithText(restoringWindow, HomeScreen.newConversationButton.selector); // Expect contacts list to be empty await hasElementBeenDeleted( restoringWindow, 'data-testid', - 'module-conversation__user_profile', + HomeScreen.contactItemName.selector, 10000, ); } finally { @@ -126,11 +127,11 @@ sessionTestTwoWindows( await createContact(windowA, windowB, userA, userB); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, 'invalid-data-testid'); + await clickOnTestIdWithText(windowA, LeftPane.settingsButton.selector); // Click on clear all data await clickOnTestIdWithText( windowA, - 'clear-data-settings-menu-item', + Settings.clearDataMenuItem.selector, englishStrippedStr('sessionClearData').toString(), ); // Keep 'Clear Device only' selection @@ -155,7 +156,7 @@ sessionTestTwoWindows( await waitForElement( restoringWindow, 'data-testid', - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, 10000, userB.userName, ); @@ -163,12 +164,12 @@ sessionTestTwoWindows( await clickOnElement({ window: restoringWindow, strategy: 'data-testid', - selector: 'new-conversation-button', + selector: HomeScreen.newConversationButton.selector, }); await waitForElement( restoringWindow, 'data-testid', - 'module-conversation__user__profile-name', + HomeScreen.contactItemName.selector, 1000, userB.userName, ); diff --git a/tests/automation/enforce_localized_str.spec.ts b/tests/automation/enforce_localized_str.spec.ts index a2617ea..24a94b0 100644 --- a/tests/automation/enforce_localized_str.spec.ts +++ b/tests/automation/enforce_localized_str.spec.ts @@ -249,6 +249,8 @@ function getExpectedStringFromKey( return 'Without your recovery password, you cannot load your account on new devices. We strongly recommend you save your recovery password in a safe and secure place before continuing.'; case 'recoveryPasswordHidePermanentlyDescription2': return 'Are you sure you want to permanently hide your recovery password on this device? This cannot be undone.'; + case 'enter': + return 'Enter'; default: // returning null means we don't have an expected string yet for this key. // This will make the test fail diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 6f84eb2..38c3464 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -24,15 +24,23 @@ export abstract class Locator { } } +export class Onboarding extends Locator { + static readonly iHaveAnAccountButton = this.testId('existing-account-button'); + static readonly displayNameInput = this.testId('display-name-input'); + static readonly recoveryPhraseInput = this.testId('recovery-phrase-input'); +} + export class LeftPane extends Locator { static readonly profileButton = this.testId('leftpane-primary-avatar'); static readonly settingsButton = this.testId('invalid-data-testid'); // SES--4499 } export class HomeScreen extends Locator { - static readonly conversationItem = this.testId( + static readonly newConversationButton = this.testId('new-conversation-button'); + static readonly conversationItemName = this.testId( 'module-conversation__user__profile-name', ); + static readonly contactItemName = this.testId('module-contact-name__profile-name') } export class Conversation extends Locator { @@ -44,11 +52,25 @@ export class Settings extends Locator { static readonly displayName = this.testId('your-profile-name'); static readonly accountId = this.testId('your-account-id'); // Menu items + static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); static readonly recoveryPasswordMenuItem = this.testId('recovery-password-settings-menu-item'); + static readonly clearDataMenuItem = this.testId('clear-data-settings-menu-item'); + // Privacy + static readonly setPasswordButton = this.testId('set-password-settings-button'); + static readonly changePasswordButton = this.testId('change-password-settings-button') + static readonly passwordInput = this.testId('password-input'); + static readonly confirmPasswordInput = this.testId('password-input-confirm'); + static readonly reConfirmPasswordInput = this.testId('password-input-reconfirm'); // Recovery Password static readonly recoveryPasswordContainer = this.testId('recovery-password-seed-modal'); + // Clear Data + static readonly clearDeviceAndNetworkRadial = this.testId('label-device_and_network'); } export class Global extends Locator { static readonly modalCloseButton = this.testId('modal-close-button'); + static readonly continueButton = this.testId('continue-button'); + static readonly toast = this.testId('session-toast'); + static readonly confirmButton = this.testId('session-confirm-ok-button'); + static readonly errorMessage = this.testId('error-message'); } \ No newline at end of file diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 2a4e09f..2384466 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -10,6 +10,7 @@ import { waitForTestIdWithText, } from './utilities/utils'; import { englishStrippedStr } from '../localization/englishStrippedStr'; +import { Global, LeftPane, Settings } from './locators'; const testPassword = '123456'; const newTestPassword = '789101112'; @@ -20,7 +21,7 @@ async function expectRecoveryPhraseToBeVisible( ) { await waitForTestIdWithText( window, - 'recovery-password-seed-modal', + Settings.recoveryPasswordContainer.selector, recoveryPhrase, 1000, ); @@ -28,58 +29,57 @@ async function expectRecoveryPhraseToBeVisible( test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); // Click on privacy - await clickOnTestIdWithText(aliceWindow1, 'privacy-settings-menu-item'); + await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); // Click set password - await clickOnTestIdWithText(aliceWindow1, 'set-password-button'); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector); // Enter password - await typeIntoInput(aliceWindow1, 'password-input', testPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Confirm password - await typeIntoInput(aliceWindow1, 'password-input-confirm', testPassword); - // Click Done - await clickOnMatchingText( - aliceWindow1, - englishStrippedStr('save').toString(), - ); + await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); + // NOTE make this click the button once SES-4504 is resolved + await aliceWindow1.keyboard.press('Enter'); // Check toast notification await waitForTestIdWithText( aliceWindow1, - 'session-toast', + Global.toast.selector, englishStrippedStr('passwordSetDescriptionToast').toString(), ); // Click on settings tab await sleepFor(300, true); - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); await sleepFor(300, true); // Type password into input field and validate it - await typeIntoInput(aliceWindow1, 'password-input', testPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Click Done await clickOnMatchingText( aliceWindow1, - englishStrippedStr('done').toString(), + englishStrippedStr('enter').toString(), ); // check that the seed is visible now await expectRecoveryPhraseToBeVisible(aliceWindow1, alice.recoveryPassword); - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector) // Change password - await clickOnTestIdWithText(aliceWindow1, 'change-password-settings-button'); + await clickOnTestIdWithText(aliceWindow1, Settings.changePasswordButton.selector); // Enter old password - await typeIntoInput(aliceWindow1, 'password-input', testPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Enter new password - await typeIntoInput(aliceWindow1, 'password-input-confirm', newTestPassword); - // await window.keyboard.press('Tab'); + await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, newTestPassword); // Confirm new password await typeIntoInput( aliceWindow1, - 'password-input-reconfirm', + Settings.reConfirmPasswordInput.selector, newTestPassword, ); // Press enter on keyboard @@ -87,7 +87,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Check toast notification for 'changed password' await waitForTestIdWithText( aliceWindow1, - 'session-toast', + Global.toast.selector, englishStrippedStr('passwordChangedDescriptionToast').toString(), ); }); @@ -97,85 +97,79 @@ test_Alice_1W_no_network( async ({ alice: { recoveryPassword }, aliceWindow1 }) => { // Check if incorrect password works // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); // Click on privacy - await clickOnMatchingText( + await clickOnTestIdWithText( aliceWindow1, - englishStrippedStr('sessionPrivacy').toString(), + Settings.privacyMenuItem.selector, ); // Click set password - await clickOnTestIdWithText(aliceWindow1, 'set-password-button'); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector); // Enter password - await typeIntoInput(aliceWindow1, 'password-input', testPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Confirm password - await typeIntoInput(aliceWindow1, 'password-input-confirm', testPassword); + await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); // Click Done - await clickOnMatchingText( - aliceWindow1, - englishStrippedStr('save').toString(), - ); + // NOTE make this click the button once SES-4504 is resolved + await aliceWindow1.keyboard.press('Enter'); // Click on recovery phrase tab - await sleepFor(100); + await sleepFor(5000); // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); // Type password into input field - await typeIntoInput(aliceWindow1, 'password-input', testPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Confirm the password - await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // this should print the recovery phrase await expectRecoveryPhraseToBeVisible(aliceWindow1, recoveryPassword); - // move away from the settings tab (otherwise the settings doesn't lock right away) - await clickOnTestIdWithText(aliceWindow1, 'message-section'); - // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await sleepFor(500); // Click on recovery phrase tab await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); // Try with incorrect password - await typeIntoInput(aliceWindow1, 'password-input', newTestPassword); + await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, newTestPassword); // Confirm the password - await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // this should NOT print the recovery phrase await hasElementPoppedUpThatShouldnt( aliceWindow1, 'data-testid', - 'recovery-password-seed-modal', + Settings.recoveryPasswordContainer.selector, recoveryPassword, ); // Incorrect password below input showing? await waitForTestIdWithText( aliceWindow1, - 'error-message', + Global.errorMessage.selector, englishStrippedStr('passwordIncorrect').toString(), ); - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); await sleepFor(100); // Click on recovery phrase tab await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); // No password entered - await clickOnMatchingText( - aliceWindow1, - englishStrippedStr('done').toString(), - ); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // Banner should ask for password to be entered await waitForTestIdWithText( aliceWindow1, - 'error-message', + Global.errorMessage.selector, englishStrippedStr('passwordIncorrect').toString(), ); }, diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index a7131e3..109efb7 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -191,4 +191,6 @@ export type DataTestId = | 'session-confirm-cancel-button' | 'session-recovery-password' | 'invite-contacts-menu-option' - | 'clear-group-info-name-button'; + | 'clear-group-info-name-button' + | 'module-contact-name__profile-name' + | 'set-password-settings-button'; From 12baf5a0bd1a3cb3e90d8a05e5e7508ecb9e145f Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Fri, 29 Aug 2025 16:20:13 +1000 Subject: [PATCH 05/32] fix: remove message-section from create group util --- tests/automation/setup/create_group.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/automation/setup/create_group.ts b/tests/automation/setup/create_group.ts index 21ba3e7..5dadbd2 100644 --- a/tests/automation/setup/create_group.ts +++ b/tests/automation/setup/create_group.ts @@ -83,11 +83,6 @@ export const createGroup = async ( .withArgs({ name: firstUser, other_name: secondUser }) .toString(), ); - // Click on message section - await Promise.all([ - clickOnTestIdWithText(windowB, 'message-section'), - clickOnTestIdWithText(windowC, 'message-section'), - ]); // Click on test group await Promise.all([ clickOnTestIdWithText( From abe3d6f2663f38c69f860f3b2165c74a51285cca Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 13:35:17 +1000 Subject: [PATCH 06/32] fix: settings is called settings-section again --- tests/automation/linked_device_group.spec.ts | 3 ++- tests/automation/linked_device_requests.spec.ts | 5 +++-- tests/automation/linked_device_user.spec.ts | 3 ++- tests/automation/locators/index.ts | 2 +- tests/automation/message_requests.spec.ts | 3 ++- tests/automation/types/testing.ts | 3 +-- tests/automation/user_actions.spec.ts | 13 +++++++------ 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 18f8fdd..14d349c 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -14,6 +14,7 @@ import { waitForLoadingAnimationToFinish, waitForTestIdWithText, } from './utilities/utils'; +import { LeftPane } from './locators'; test_group_Alice_2W_Bob_1W_Charlie_1W( 'Leaving group syncs', @@ -127,7 +128,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); async function clearDataOnWindow(window: Page) { - await clickOnTestIdWithText(window, 'invalid-data-testid'); + await clickOnTestIdWithText(window, LeftPane.settingsButton.selector); // Click on clear data option on left pane await clickOnTestIdWithText( window, diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 5dd9f33..f53d2ae 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -1,5 +1,6 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; +import { LeftPane } from './locators'; import { test_Alice_2W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -134,7 +135,7 @@ test_Alice_2W_Bob_1W( // Need to wait for the blocked status to sync await sleepFor(2000); // Check blocked status in blocked contacts list - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, 'conversations-settings-menu-item', @@ -144,7 +145,7 @@ test_Alice_2W_Bob_1W( // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list await sleepFor(5000); - await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow2, 'conversations-settings-menu-item', diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index ddf5219..a08fa1b 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -28,6 +28,7 @@ import { waitForTestIdWithText, waitForTextMessage, } from './utilities/utils'; +import { LeftPane } from './locators'; sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { let aliceWindow2: Page | undefined; @@ -330,7 +331,7 @@ test_Alice_2W_Bob_1W( // reveal-blocked-user-settings is not updated once opened // Check linked device for blocked contact in settings screen // Click on settings tab - await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow2, 'conversations-settings-menu-item', diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 38c3464..03905e9 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -32,7 +32,7 @@ export class Onboarding extends Locator { export class LeftPane extends Locator { static readonly profileButton = this.testId('leftpane-primary-avatar'); - static readonly settingsButton = this.testId('invalid-data-testid'); // SES--4499 + static readonly settingsButton = this.testId('settings-section'); } export class HomeScreen extends Locator { diff --git a/tests/automation/message_requests.spec.ts b/tests/automation/message_requests.spec.ts index a239c30..c129330 100644 --- a/tests/automation/message_requests.spec.ts +++ b/tests/automation/message_requests.spec.ts @@ -1,4 +1,5 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; +import { LeftPane } from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -142,7 +143,7 @@ test_Alice_1W_Bob_1W( englishStrippedStr('clear').toString(), ); // Navigate back to message request folder to check - await clickOnTestIdWithText(bobWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(bobWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( bobWindow1, diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 109efb7..5c16ee0 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -91,7 +91,6 @@ export type DataTestId = | 'disappear-control-message' | 'disappearing-messages-indicator' | 'conversation-options-avatar' - | 'invalid-data-testid' | 'clear-data-settings-menu-item' | 'message-requests-settings-menu-item' | 'restore-using-recovery' @@ -147,7 +146,7 @@ export type DataTestId = | 'header-conversation-name' | 'copy-button-profile-update' | 'loading-spinner' - | 'invalid-data-testid' // SES-4499, temporary fix to make the tests run again + | 'settings-section' | 'empty-conversation-notification' | 'your-profile-name' | 'mentions-popup-row' diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index f1f3fd1..d94bcba 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -21,6 +21,7 @@ import { waitForMatchingText, waitForTestIdWithText, } from './utilities/utils'; +import { LeftPane } from './locators'; // Send message in one to one conversation with new contact sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { @@ -108,7 +109,7 @@ test_Alice_1W_Bob_1W( ); // Verify the user was moved to the blocked contact list // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); // click on settings section 'conversation' await clickOnTestIdWithText( aliceWindow1, @@ -287,7 +288,7 @@ test_Alice_1W_Bob_1W( await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', - selector: 'invalid-data-testid', + selector: 'settings-section', }); await clickOnElement({ window: aliceWindow1, @@ -307,7 +308,7 @@ test_Alice_1W_Bob_1W( await clickOnElement({ window: bobWindow1, strategy: 'data-testid', - selector: 'invalid-data-testid', + selector: 'settings-section', }); await clickOnElement({ window: bobWindow1, @@ -401,7 +402,7 @@ test_Alice_1W_Bob_1W( test_Alice_2W( 'Hide recovery password', async ({ aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, 'settings-section'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', @@ -439,7 +440,7 @@ test_Alice_2W( 'recovery-password-settings-menu-item', ); // Check linked device if Recovery Password is still visible (it should be) - await clickOnTestIdWithText(aliceWindow2, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow2, 'settings-section'); await waitForTestIdWithText( aliceWindow2, 'recovery-password-settings-menu-item', @@ -537,7 +538,7 @@ test_Alice_1W_no_network( ); test_Alice_1W_no_network('Toggle password', async ({ aliceWindow1 }) => { - await clickOnTestIdWithText(aliceWindow1, 'invalid-data-testid'); + await clickOnTestIdWithText(aliceWindow1, 'settings-section'); await clickOnTestIdWithText( aliceWindow1, 'recovery-password-settings-menu-item', From 20d86c5665e684f4bcaf8b19dc840b0e7e3e806e Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 13:51:10 +1000 Subject: [PATCH 07/32] fix: password tests have correct ids now --- tests/automation/locators/index.ts | 5 +++-- tests/automation/password.spec.ts | 13 +++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 03905e9..e2c15f7 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -56,8 +56,9 @@ export class Settings extends Locator { static readonly recoveryPasswordMenuItem = this.testId('recovery-password-settings-menu-item'); static readonly clearDataMenuItem = this.testId('clear-data-settings-menu-item'); // Privacy - static readonly setPasswordButton = this.testId('set-password-settings-button'); - static readonly changePasswordButton = this.testId('change-password-settings-button') + static readonly setPasswordSettingsButton = this.testId('set-password-settings-button'); + static readonly changePasswordSettingsButton = this.testId('change-password-settings-button') + static readonly setPasswordButton = this.testId('set-password-button'); static readonly passwordInput = this.testId('password-input'); static readonly confirmPasswordInput = this.testId('password-input-confirm'); static readonly reConfirmPasswordInput = this.testId('password-input-reconfirm'); diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 2384466..2e64ad5 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -33,13 +33,12 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on privacy await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); // Click set password - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordSettingsButton.selector); // Enter password await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Confirm password await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); - // NOTE make this click the button once SES-4504 is resolved - await aliceWindow1.keyboard.press('Enter'); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector) // Check toast notification await waitForTestIdWithText( aliceWindow1, @@ -70,7 +69,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector) // Change password - await clickOnTestIdWithText(aliceWindow1, Settings.changePasswordButton.selector); + await clickOnTestIdWithText(aliceWindow1, Settings.changePasswordSettingsButton.selector); // Enter old password await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); @@ -104,14 +103,12 @@ test_Alice_1W_no_network( Settings.privacyMenuItem.selector, ); // Click set password - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordSettingsButton.selector); // Enter password await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); // Confirm password await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); - // Click Done - // NOTE make this click the button once SES-4504 is resolved - await aliceWindow1.keyboard.press('Enter'); + await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector) // Click on recovery phrase tab await sleepFor(5000); From e3ade7f29e5826d347b1a2391f985ee1bc3fe0b9 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 14:23:44 +1000 Subject: [PATCH 08/32] refactor: add locators to linked device requests file --- .../automation/linked_device_requests.spec.ts | 53 ++++++++----------- tests/automation/locators/index.ts | 10 ++++ tests/automation/password.spec.ts | 9 +--- tests/automation/setup/open.ts | 3 +- tests/automation/types/testing.ts | 2 + 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index f53d2ae..7be8a6b 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -1,6 +1,6 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; -import { LeftPane } from './locators'; +import { Conversation, Global, HomeScreen, LeftPane, Settings } from './locators'; import { test_Alice_2W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -19,17 +19,17 @@ test_Alice_2W_Bob_1W( const testReply = `${alice.userName} accepting message request from ${bob.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Accept request in aliceWindow1 - await clickOnTestIdWithText(aliceWindow1, 'message-request-banner'); - await clickOnTestIdWithText(aliceWindow2, 'message-request-banner'); + await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); + await clickOnTestIdWithText(aliceWindow2, HomeScreen.messageRequestBanner.selector); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); - await clickOnTestIdWithText(aliceWindow1, 'accept-message-request'); + await clickOnTestIdWithText(aliceWindow1, Conversation.acceptMessageRequestButton.selector); await waitForTestIdWithText( aliceWindow1, - 'message-request-response-message', + Conversation.messageRequestAcceptControlMessage.selector, englishStrippedStr('messageRequestYouHaveAccepted') .withArgs({ name: bob.userName, @@ -46,10 +46,11 @@ test_Alice_2W_Bob_1W( ); await sendMessage(aliceWindow1, testReply); await waitForTextMessage(bobWindow1, testReply); - await clickOnTestIdWithText(aliceWindow2, 'new-conversation-button'); + await clickOnTestIdWithText(aliceWindow2, Global.backButton.selector) + await clickOnTestIdWithText(aliceWindow2, HomeScreen.newConversationButton.selector); await waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.contactItemName.selector, bob.userName, ); }, @@ -61,37 +62,29 @@ test_Alice_2W_Bob_1W( const testMessage = `${bob.userName} sending message request to ${alice.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Decline request in aliceWindow1 - await clickOnTestIdWithText(aliceWindow1, 'message-request-banner'); + await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); - await clickOnTestIdWithText(aliceWindow2, 'message-request-banner'); + await clickOnTestIdWithText(aliceWindow2, HomeScreen.messageRequestBanner.selector); await waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); await sleepFor(1000); await clickOnTestIdWithText( aliceWindow1, - 'delete-message-request', + Conversation.deleteMessageRequestButton.selector, englishStrippedStr('delete').toString(), ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('delete').toString(), ); - - // Note: this test is broken currently but this is a known issue. - // It happens because we have a race condition between the update from libsession and the update from the swarm, both with the same seqno. - // See SES-1563 - console.info( - 'This test is subject to a race condition and so is most of the times, broken. See SES-2518', - ); - await waitForMatchingText( aliceWindow1, englishStrippedStr('messageRequestsNonePending').toString(), @@ -110,17 +103,17 @@ test_Alice_2W_Bob_1W( // send a message to Bob to Alice await sendNewMessage(bobWindow1, alice.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(aliceWindow1, 'message-request-banner'); + await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); // Select message request from Bob await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); // Block Bob await clickOnTestIdWithText( aliceWindow1, - 'decline-and-block-message-request', + Conversation.blockMessageRequestButton.selector, ); // Check modal strings await checkModalStrings( @@ -131,16 +124,16 @@ test_Alice_2W_Bob_1W( .toString(), ); // Confirm block - await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // Need to wait for the blocked status to sync await sleepFor(2000); // Check blocked status in blocked contacts list await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'conversations-settings-menu-item', + Settings.conversationsMenuItem.selector, ); - await clickOnTestIdWithText(aliceWindow1, 'reveal-blocked-user-settings'); + await clickOnTestIdWithText(aliceWindow1, Settings.blockedContactsButton.selector); await waitForTestIdWithText(aliceWindow1, 'contact', bob.userName); // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list @@ -148,9 +141,9 @@ test_Alice_2W_Bob_1W( await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow2, - 'conversations-settings-menu-item', + Settings.conversationsMenuItem.selector, ); - await clickOnTestIdWithText(aliceWindow2, 'reveal-blocked-user-settings'); + await clickOnTestIdWithText(aliceWindow2, Settings.blockedContactsButton.selector); await waitForTestIdWithText(aliceWindow2, 'contact', bob.userName); await waitForMatchingText(aliceWindow2, bob.userName); }, diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index e2c15f7..deadafe 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -37,6 +37,7 @@ export class LeftPane extends Locator { export class HomeScreen extends Locator { static readonly newConversationButton = this.testId('new-conversation-button'); + static readonly messageRequestBanner = this.testId('message-request-banner'); static readonly conversationItemName = this.testId( 'module-conversation__user__profile-name', ); @@ -44,6 +45,10 @@ export class HomeScreen extends Locator { } export class Conversation extends Locator { + static readonly acceptMessageRequestButton = this.testId('accept-message-request'); + static readonly deleteMessageRequestButton = this.testId('delete-message-request') + static readonly blockMessageRequestButton = this.testId('decline-and-block-message-request'); + static readonly messageRequestAcceptControlMessage = this.testId('message-request-response-message') static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } @@ -53,6 +58,7 @@ export class Settings extends Locator { static readonly accountId = this.testId('your-account-id'); // Menu items static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); + static readonly conversationsMenuItem = this.testId('conversations-settings-menu-item'); static readonly recoveryPasswordMenuItem = this.testId('recovery-password-settings-menu-item'); static readonly clearDataMenuItem = this.testId('clear-data-settings-menu-item'); // Privacy @@ -62,6 +68,8 @@ export class Settings extends Locator { static readonly passwordInput = this.testId('password-input'); static readonly confirmPasswordInput = this.testId('password-input-confirm'); static readonly reConfirmPasswordInput = this.testId('password-input-reconfirm'); + // Conversations + static readonly blockedContactsButton = this.testId('reveal-blocked-user-settings'); // Recovery Password static readonly recoveryPasswordContainer = this.testId('recovery-password-seed-modal'); // Clear Data @@ -70,7 +78,9 @@ export class Settings extends Locator { export class Global extends Locator { static readonly modalCloseButton = this.testId('modal-close-button'); + static readonly modalBackButton = this.testId('modal-back-button'); static readonly continueButton = this.testId('continue-button'); + static readonly backButton = this.testId('back-button') static readonly toast = this.testId('session-toast'); static readonly confirmButton = this.testId('session-confirm-ok-button'); static readonly errorMessage = this.testId('error-message'); diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 2e64ad5..dba7fc7 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -111,10 +111,7 @@ test_Alice_1W_no_network( await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector) // Click on recovery phrase tab await sleepFor(5000); - - // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector ) await clickOnTestIdWithText( aliceWindow1, Settings.recoveryPasswordMenuItem.selector, @@ -126,9 +123,7 @@ test_Alice_1W_no_network( // this should print the recovery phrase await expectRecoveryPhraseToBeVisible(aliceWindow1, recoveryPassword); - // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector ) await sleepFor(500); // Click on recovery phrase tab await clickOnTestIdWithText( diff --git a/tests/automation/setup/open.ts b/tests/automation/setup/open.ts index b31b8ff..ac238e6 100644 --- a/tests/automation/setup/open.ts +++ b/tests/automation/setup/open.ts @@ -25,8 +25,9 @@ const openElectronAppOnly = async (multi: string) => { process.env.NODE_APP_INSTANCE = `${MULTI_PREFIX}-devprod-${uniqueId}-${process.env.MULTI}`; process.env.NODE_ENV = NODE_ENV; process.env.SESSION_DEBUG = '1'; - process.env.LOCAL_DEVNET_SEED_URL = 'http://sesh-net.local:1280'; + process.env.LOCAL_DEVNET_SEED_URL = 'http://seed2.getsession.org:38157/' + console.info(`. ${process.env.LOCAL_DEVNET_SEED_URL}`); console.info(` NON CI RUN`); console.info(' NODE_ENV', process.env.NODE_ENV); console.info(' NODE_APP_INSTANCE', process.env.NODE_APP_INSTANCE); diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 5c16ee0..4743368 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -179,6 +179,8 @@ export type DataTestId = | 'modal-heading' | 'call-notification-answered-a-call' | 'call-notification-started-call' + | 'modal-back-button' + | 'back-button' | 'audio-player' | 'chooser-invite-friend' | 'your-account-id' From 8dc26afe14e803239c9efd9cdf6f204db15cc8e3 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 15:12:02 +1000 Subject: [PATCH 09/32] feat: target specific modals in checkModalStrings --- tests/automation/utilities/utils.ts | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index c0e4db6..d483a7e 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -8,6 +8,7 @@ import { DMTimeOption, DataTestId, LoaderType, + ModalId, Strategy, StrategyExtractionObj, WithMaxWait, @@ -501,13 +502,28 @@ export async function checkModalStrings( window: Page, expectedHeading: string, expectedDescription: string, + modalId?: ModalId, ) { - const heading = await waitForElement(window, 'data-testid', 'modal-heading'); - const description = await waitForElement( - window, - 'data-testid', - 'modal-description', - ); + let modalSelector = '[data-modal-id]'; // Base selector for modals + + // If a specific modal ID is provided, target that one + if (modalId) { + modalSelector = `[data-modal-id="${modalId}"]`; + } + + // Find the target modal + const targetModal = window.locator(modalSelector).first(); + + // Wait for the modal to be visible + await targetModal.waitFor({ state: 'visible' }); + + // Get elements within this specific modal + const heading = targetModal.locator('[data-testid="modal-heading"]'); + const description = targetModal.locator('[data-testid="modal-description"]'); + + // Wait for these elements to be visible + await heading.waitFor({ state: 'visible' }); + await description.waitFor({ state: 'visible' }); const headingText = await heading.innerText(); const descriptionText = await description.innerText(); From 3d6dd5e887602f895b064c4cc0fad8d21821085f Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 15:54:40 +1000 Subject: [PATCH 10/32] refactor: update more tests to use locators --- .../avatar-updated-blue-darwin.jpeg | 4 +- tests/automation/create_user.spec.ts | 17 ++- tests/automation/delete_account.spec.ts | 24 +++- tests/automation/group_testing.spec.ts | 18 +-- .../automation/linked_device_requests.spec.ts | 57 +++++++-- tests/automation/linked_device_user.spec.ts | 34 +++--- tests/automation/locators/index.ts | 114 ++++++++++++------ tests/automation/password.spec.ts | 85 ++++++++++--- tests/automation/setup/new_user.ts | 1 - tests/automation/setup/open.ts | 5 +- tests/automation/types/testing.ts | 7 +- tests/automation/user_actions.spec.ts | 79 ++++++------ tests/automation/utilities/send_media.ts | 1 - tests/automation/utilities/utils.ts | 8 +- tests/automation/utilities/voice_call.ts | 2 - 15 files changed, 290 insertions(+), 166 deletions(-) diff --git a/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg b/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg index 0d83659..b3548a9 100644 --- a/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg +++ b/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02b450cb82f4004714d796c79a45787329fc1dc68f6c371795bac9664e107f1e -size 944 +oid sha256:bfda79de8430bec68485159710f2832b4959056e3a464fa342047b65529f9c29 +size 1851 diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index bfa7917..2704b48 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -14,15 +14,26 @@ sessionTestOneWindow('Create User', async ([window]) => { await clickOnTestIdWithText(window, LeftPane.profileButton.selector); await sleepFor(100, true); // check username matches - await waitForTestIdWithText(window, Settings.displayName.selector, userA.userName); + await waitForTestIdWithText( + window, + Settings.displayName.selector, + userA.userName, + ); // check Account ID matches - await waitForTestIdWithText(window, Settings.accountId.selector, userA.accountid); + await waitForTestIdWithText( + window, + Settings.accountId.selector, + userA.accountid, + ); // exit profile modal await clickOnTestIdWithText(window, Global.modalCloseButton.selector); // go to settings section await clickOnTestIdWithText(window, LeftPane.settingsButton.selector); // check recovery phrase matches - await clickOnTestIdWithText(window, Settings.recoveryPasswordMenuItem.selector); + await clickOnTestIdWithText( + window, + Settings.recoveryPasswordMenuItem.selector, + ); await waitForTestIdWithText( window, Settings.recoveryPasswordContainer.selector, diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 7e564f8..d0d15b9 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -67,7 +67,10 @@ sessionTestTwoWindows( restoringWindows = await openApp(1); // not using sessionTest here as we need to close and reopen one of the window const [restoringWindow] = restoringWindows; // Sign in with deleted account and check that nothing restores - await clickOnTestIdWithText(restoringWindow, Onboarding.iHaveAnAccountButton.selector); + await clickOnTestIdWithText( + restoringWindow, + Onboarding.iHaveAnAccountButton.selector, + ); // Fill in recovery phrase await typeIntoInput( restoringWindow, @@ -75,7 +78,10 @@ sessionTestTwoWindows( userA.recoveryPassword, ); // Enter display name - await clickOnTestIdWithText(restoringWindow, Global.continueButton.selector); + await clickOnTestIdWithText( + restoringWindow, + Global.continueButton.selector, + ); await waitForLoadingAnimationToFinish( restoringWindow, 'loading-animation', @@ -87,7 +93,10 @@ sessionTestTwoWindows( userA.userName, ); // Click continue - await clickOnTestIdWithText(restoringWindow, Global.continueButton.selector); + await clickOnTestIdWithText( + restoringWindow, + Global.continueButton.selector, + ); await sleepFor(5000, true); // just to allow any messages from our swarm to show up // Need to verify that no conversation is found at all @@ -98,12 +107,15 @@ sessionTestTwoWindows( HomeScreen.conversationItemName.selector, ); - await clickOnTestIdWithText(restoringWindow, HomeScreen.newConversationButton.selector); // Expect contacts list to be empty + await clickOnTestIdWithText( + restoringWindow, + HomeScreen.newConversationButton.selector, + ); // Expect contacts list to be empty await hasElementBeenDeleted( restoringWindow, 'data-testid', - HomeScreen.contactItemName.selector, + Global.contactItem.selector, 10000, ); } finally { @@ -169,7 +181,7 @@ sessionTestTwoWindows( await waitForElement( restoringWindow, 'data-testid', - HomeScreen.contactItemName.selector, + Global.contactItem.selector, 1000, userB.userName, ); diff --git a/tests/automation/group_testing.spec.ts b/tests/automation/group_testing.spec.ts index 7bdebf2..70e4d2b 100644 --- a/tests/automation/group_testing.spec.ts +++ b/tests/automation/group_testing.spec.ts @@ -1,5 +1,6 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { doForAll, sleepFor } from '../promise_utils'; +import { Global, HomeScreen } from './locators'; import { createGroup } from './setup/create_group'; import { newUser } from './setup/new_user'; import { @@ -54,17 +55,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W_Dracula_1W( draculaWindow1, groupCreated, }) => { - // Check config messages in all windows - await sleepFor(1000); await createContact(aliceWindow1, draculaWindow1, alice, dracula); - await clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'message-section', - }); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); await clickOnElement({ @@ -98,14 +92,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W_Dracula_1W( }, [aliceWindow1, bobWindow1, charlieWindow1], ); - await clickOnElement({ - window: draculaWindow1, - strategy: 'data-testid', - selector: 'message-section', - }); + await clickOnTestIdWithText(draculaWindow1, Global.backButton.selector); await clickOnTestIdWithText( draculaWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); }, diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 7be8a6b..67af5b8 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -1,6 +1,12 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; -import { Conversation, Global, HomeScreen, LeftPane, Settings } from './locators'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; import { test_Alice_2W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -19,14 +25,23 @@ test_Alice_2W_Bob_1W( const testReply = `${alice.userName} accepting message request from ${bob.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Accept request in aliceWindow1 - await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); - await clickOnTestIdWithText(aliceWindow2, HomeScreen.messageRequestBanner.selector); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.messageRequestBanner.selector, + ); + await clickOnTestIdWithText( + aliceWindow2, + HomeScreen.messageRequestBanner.selector, + ); await clickOnTestIdWithText( aliceWindow1, HomeScreen.conversationItemName.selector, bob.userName, ); - await clickOnTestIdWithText(aliceWindow1, Conversation.acceptMessageRequestButton.selector); + await clickOnTestIdWithText( + aliceWindow1, + Conversation.acceptMessageRequestButton.selector, + ); await waitForTestIdWithText( aliceWindow1, Conversation.messageRequestAcceptControlMessage.selector, @@ -46,11 +61,14 @@ test_Alice_2W_Bob_1W( ); await sendMessage(aliceWindow1, testReply); await waitForTextMessage(bobWindow1, testReply); - await clickOnTestIdWithText(aliceWindow2, Global.backButton.selector) - await clickOnTestIdWithText(aliceWindow2, HomeScreen.newConversationButton.selector); + await clickOnTestIdWithText(aliceWindow2, Global.backButton.selector); + await clickOnTestIdWithText( + aliceWindow2, + HomeScreen.newConversationButton.selector, + ); await waitForTestIdWithText( aliceWindow2, - HomeScreen.contactItemName.selector, + Global.contactItem.selector, bob.userName, ); }, @@ -62,13 +80,19 @@ test_Alice_2W_Bob_1W( const testMessage = `${bob.userName} sending message request to ${alice.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Decline request in aliceWindow1 - await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.messageRequestBanner.selector, + ); await clickOnTestIdWithText( aliceWindow1, HomeScreen.conversationItemName.selector, bob.userName, ); - await clickOnTestIdWithText(aliceWindow2, HomeScreen.messageRequestBanner.selector); + await clickOnTestIdWithText( + aliceWindow2, + HomeScreen.messageRequestBanner.selector, + ); await waitForTestIdWithText( aliceWindow2, HomeScreen.conversationItemName.selector, @@ -103,7 +127,10 @@ test_Alice_2W_Bob_1W( // send a message to Bob to Alice await sendNewMessage(bobWindow1, alice.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(aliceWindow1, HomeScreen.messageRequestBanner.selector); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.messageRequestBanner.selector, + ); // Select message request from Bob await clickOnTestIdWithText( aliceWindow1, @@ -133,7 +160,10 @@ test_Alice_2W_Bob_1W( aliceWindow1, Settings.conversationsMenuItem.selector, ); - await clickOnTestIdWithText(aliceWindow1, Settings.blockedContactsButton.selector); + await clickOnTestIdWithText( + aliceWindow1, + Settings.blockedContactsButton.selector, + ); await waitForTestIdWithText(aliceWindow1, 'contact', bob.userName); // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list @@ -143,7 +173,10 @@ test_Alice_2W_Bob_1W( aliceWindow2, Settings.conversationsMenuItem.selector, ); - await clickOnTestIdWithText(aliceWindow2, Settings.blockedContactsButton.selector); + await clickOnTestIdWithText( + aliceWindow2, + Settings.blockedContactsButton.selector, + ); await waitForTestIdWithText(aliceWindow2, 'contact', bob.userName); await waitForMatchingText(aliceWindow2, bob.userName); }, diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index a08fa1b..f5980fd 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -28,7 +28,13 @@ import { waitForTestIdWithText, waitForTextMessage, } from './utilities/utils'; -import { LeftPane } from './locators'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { let aliceWindow2: Page | undefined; @@ -299,14 +305,14 @@ test_Alice_2W_Bob_1W( // Navigate to conversation on linked device and check for message from user A to user B await clickOnTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, true, ); // Select block await clickOnTestIdWithText( aliceWindow2, - 'context-menu-item', + Global.contextMenuItem.selector, englishStrippedStr('block').toString(), ); // Check modal strings @@ -319,33 +325,36 @@ test_Alice_2W_Bob_1W( ); await clickOnTestIdWithText( aliceWindow2, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('block').toString(), ); // Verify the user was moved to the blocked contact list await waitForMatchingPlaceholder( aliceWindow1, - 'message-input-text-area', + Conversation.messageInput.selector, englishStrippedStr('blockBlockedDescription').toString(), ); - // reveal-blocked-user-settings is not updated once opened // Check linked device for blocked contact in settings screen // Click on settings tab await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow2, - 'conversations-settings-menu-item', + Settings.conversationsMenuItem.selector, ); // a conf sync job can take 30s (if the last one failed) + 10s polling to show a change on a linked device. await clickOnTestIdWithText( aliceWindow2, - 'reveal-blocked-user-settings', + Settings.blockedContactsButton.selector, undefined, undefined, 50000, ); // Check if user B is in blocked contact list - await waitForTestIdWithText(aliceWindow2, 'contact', bob.userName); + await waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + bob.userName, + ); }, ); @@ -354,12 +363,6 @@ test_Alice_2W_Bob_1W( async ({ alice, aliceWindow1, aliceWindow2, bob, bobWindow1 }) => { // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); - // Confirm contact by checking Messages tab (name should appear in list) - await Promise.all([ - clickOnTestIdWithText(aliceWindow1, 'message-section'), - clickOnTestIdWithText(bobWindow1, 'message-section'), - clickOnTestIdWithText(aliceWindow2, 'message-section'), - ]); await Promise.all([ clickOnElement({ window: aliceWindow1, @@ -395,7 +398,6 @@ test_Alice_2W_Bob_1W( ), ]); // Delete contact - await clickOnTestIdWithText(aliceWindow1, 'message-section'); await clickOnTestIdWithText( aliceWindow1, 'module-conversation__user__profile-name', diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index deadafe..306e874 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -25,9 +25,9 @@ export abstract class Locator { } export class Onboarding extends Locator { - static readonly iHaveAnAccountButton = this.testId('existing-account-button'); - static readonly displayNameInput = this.testId('display-name-input'); - static readonly recoveryPhraseInput = this.testId('recovery-phrase-input'); + static readonly iHaveAnAccountButton = this.testId('existing-account-button'); + static readonly displayNameInput = this.testId('display-name-input'); + static readonly recoveryPhraseInput = this.testId('recovery-phrase-input'); } export class LeftPane extends Locator { @@ -36,52 +36,90 @@ export class LeftPane extends Locator { } export class HomeScreen extends Locator { - static readonly newConversationButton = this.testId('new-conversation-button'); + static readonly newConversationButton = this.testId( + 'new-conversation-button', + ); static readonly messageRequestBanner = this.testId('message-request-banner'); static readonly conversationItemName = this.testId( 'module-conversation__user__profile-name', ); - static readonly contactItemName = this.testId('module-contact-name__profile-name') } export class Conversation extends Locator { - static readonly acceptMessageRequestButton = this.testId('accept-message-request'); - static readonly deleteMessageRequestButton = this.testId('delete-message-request') - static readonly blockMessageRequestButton = this.testId('decline-and-block-message-request'); - static readonly messageRequestAcceptControlMessage = this.testId('message-request-response-message') + static readonly messageInput = this.testId('message-input-text-area'); + static readonly acceptMessageRequestButton = this.testId( + 'accept-message-request', + ); + static readonly deleteMessageRequestButton = this.testId( + 'delete-message-request', + ); + static readonly blockMessageRequestButton = this.testId( + 'decline-and-block-message-request', + ); + static readonly messageRequestAcceptControlMessage = this.testId( + 'message-request-response-message', + ); + static readonly conversationSettingsIcon = this.testId( + 'conversation-options-avatar', + ); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } export class Settings extends Locator { - // Profile - static readonly displayName = this.testId('your-profile-name'); - static readonly accountId = this.testId('your-account-id'); - // Menu items - static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); - static readonly conversationsMenuItem = this.testId('conversations-settings-menu-item'); - static readonly recoveryPasswordMenuItem = this.testId('recovery-password-settings-menu-item'); - static readonly clearDataMenuItem = this.testId('clear-data-settings-menu-item'); - // Privacy - static readonly setPasswordSettingsButton = this.testId('set-password-settings-button'); - static readonly changePasswordSettingsButton = this.testId('change-password-settings-button') - static readonly setPasswordButton = this.testId('set-password-button'); - static readonly passwordInput = this.testId('password-input'); - static readonly confirmPasswordInput = this.testId('password-input-confirm'); - static readonly reConfirmPasswordInput = this.testId('password-input-reconfirm'); - // Conversations - static readonly blockedContactsButton = this.testId('reveal-blocked-user-settings'); - // Recovery Password - static readonly recoveryPasswordContainer = this.testId('recovery-password-seed-modal'); - // Clear Data - static readonly clearDeviceAndNetworkRadial = this.testId('label-device_and_network'); + // Profile + static readonly displayName = this.testId('your-profile-name'); + static readonly accountId = this.testId('your-account-id'); + // Update Profile Information + static readonly displayNameInput = this.testId('update-profile-info-name-input') + // Menu items + static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); + static readonly conversationsMenuItem = this.testId( + 'conversations-settings-menu-item', + ); + static readonly recoveryPasswordMenuItem = this.testId( + 'recovery-password-settings-menu-item', + ); + static readonly clearDataMenuItem = this.testId( + 'clear-data-settings-menu-item', + ); + // Privacy + static readonly setPasswordSettingsButton = this.testId( + 'set-password-settings-button', + ); + static readonly changePasswordSettingsButton = this.testId( + 'change-password-settings-button', + ); + static readonly setPasswordButton = this.testId('set-password-button'); + static readonly passwordInput = this.testId('password-input'); + static readonly confirmPasswordInput = this.testId('password-input-confirm'); + static readonly reConfirmPasswordInput = this.testId( + 'password-input-reconfirm', + ); + // Conversations + static readonly blockedContactsButton = this.testId( + 'blocked-contacts-settings-row', + ); + static readonly unblockButton = this.testId('unblock-button-settings-screen'); + // Recovery Password + static readonly recoveryPasswordContainer = this.testId( + 'recovery-password-seed-modal', + ); + // Clear Data + static readonly clearDeviceAndNetworkRadial = this.testId( + 'label-device_and_network', + ); } export class Global extends Locator { - static readonly modalCloseButton = this.testId('modal-close-button'); - static readonly modalBackButton = this.testId('modal-back-button'); - static readonly continueButton = this.testId('continue-button'); - static readonly backButton = this.testId('back-button') - static readonly toast = this.testId('session-toast'); - static readonly confirmButton = this.testId('session-confirm-ok-button'); - static readonly errorMessage = this.testId('error-message'); -} \ No newline at end of file + static readonly modalCloseButton = this.testId('modal-close-button'); + static readonly modalBackButton = this.testId('modal-back-button'); + static readonly continueButton = this.testId('continue-button'); + static readonly backButton = this.testId('back-button'); + static readonly toast = this.testId('session-toast'); + static readonly confirmButton = this.testId('session-confirm-ok-button'); + static readonly errorMessage = this.testId('error-message'); + static readonly contactItem = this.testId( + 'module-contact-name__profile-name', + ); + static readonly contextMenuItem = this.testId('context-menu-item'); +} diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index dba7fc7..4e6b462 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -33,12 +33,26 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on privacy await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); // Click set password - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordSettingsButton.selector); + await clickOnTestIdWithText( + aliceWindow1, + Settings.setPasswordSettingsButton.selector, + ); // Enter password - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + testPassword, + ); // Confirm password - await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector) + await typeIntoInput( + aliceWindow1, + Settings.confirmPasswordInput.selector, + testPassword, + ); + await clickOnTestIdWithText( + aliceWindow1, + Settings.setPasswordButton.selector, + ); // Check toast notification await waitForTestIdWithText( aliceWindow1, @@ -56,7 +70,11 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { await sleepFor(300, true); // Type password into input field and validate it - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + testPassword, + ); // Click Done await clickOnMatchingText( aliceWindow1, @@ -67,14 +85,25 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { await expectRecoveryPhraseToBeVisible(aliceWindow1, alice.recoveryPassword); await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector) + await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); // Change password - await clickOnTestIdWithText(aliceWindow1, Settings.changePasswordSettingsButton.selector); + await clickOnTestIdWithText( + aliceWindow1, + Settings.changePasswordSettingsButton.selector, + ); // Enter old password - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + testPassword, + ); // Enter new password - await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, newTestPassword); + await typeIntoInput( + aliceWindow1, + Settings.confirmPasswordInput.selector, + newTestPassword, + ); // Confirm new password await typeIntoInput( aliceWindow1, @@ -103,27 +132,45 @@ test_Alice_1W_no_network( Settings.privacyMenuItem.selector, ); // Click set password - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordSettingsButton.selector); + await clickOnTestIdWithText( + aliceWindow1, + Settings.setPasswordSettingsButton.selector, + ); // Enter password - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + testPassword, + ); // Confirm password - await typeIntoInput(aliceWindow1, Settings.confirmPasswordInput.selector, testPassword); - await clickOnTestIdWithText(aliceWindow1, Settings.setPasswordButton.selector) + await typeIntoInput( + aliceWindow1, + Settings.confirmPasswordInput.selector, + testPassword, + ); + await clickOnTestIdWithText( + aliceWindow1, + Settings.setPasswordButton.selector, + ); // Click on recovery phrase tab await sleepFor(5000); - await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector ) + await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector); await clickOnTestIdWithText( aliceWindow1, Settings.recoveryPasswordMenuItem.selector, ); // Type password into input field - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, testPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + testPassword, + ); // Confirm the password await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // this should print the recovery phrase await expectRecoveryPhraseToBeVisible(aliceWindow1, recoveryPassword); - await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector ) + await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector); await sleepFor(500); // Click on recovery phrase tab await clickOnTestIdWithText( @@ -131,7 +178,11 @@ test_Alice_1W_no_network( Settings.recoveryPasswordMenuItem.selector, ); // Try with incorrect password - await typeIntoInput(aliceWindow1, Settings.passwordInput.selector, newTestPassword); + await typeIntoInput( + aliceWindow1, + Settings.passwordInput.selector, + newTestPassword, + ); // Confirm the password await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // this should NOT print the recovery phrase diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 7eea649..5024d60 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -46,6 +46,5 @@ export const newUser = async ( if (awaitOnionPath) { await checkPathLight(window); } - // await clickOnTestIdWithText(window, 'message-section'); return { userName, accountid, recoveryPassword }; }; diff --git a/tests/automation/setup/open.ts b/tests/automation/setup/open.ts index ac238e6..0ad2a46 100644 --- a/tests/automation/setup/open.ts +++ b/tests/automation/setup/open.ts @@ -25,9 +25,10 @@ const openElectronAppOnly = async (multi: string) => { process.env.NODE_APP_INSTANCE = `${MULTI_PREFIX}-devprod-${uniqueId}-${process.env.MULTI}`; process.env.NODE_ENV = NODE_ENV; process.env.SESSION_DEBUG = '1'; - process.env.LOCAL_DEVNET_SEED_URL = 'http://seed2.getsession.org:38157/' + process.env.LOCAL_DEVNET_SEED_URL = 'http://seed2.getsession.org:38157/'; + // process.env.LOCAL_DEVNET_SEED_URL = 'http://sesh-net:1280' - console.info(`. ${process.env.LOCAL_DEVNET_SEED_URL}`); + console.info(` ${process.env.LOCAL_DEVNET_SEED_URL}`); console.info(` NON CI RUN`); console.info(' NODE_ENV', process.env.NODE_ENV); console.info(' NODE_APP_INSTANCE', process.env.NODE_APP_INSTANCE); diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 4743368..9fa65c3 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -108,10 +108,7 @@ export type DataTestId = | 'accept-message-request' | 'set-nickname-confirm-button' | 'nickname-input' - | 'three-dots-conversation-options' - | 'message-section' | 'conversations-settings-menu-item' - | 'reveal-blocked-user-settings' | 'unblock-button-settings-screen' | 'leftpane-primary-avatar' | 'edit-profile-icon' @@ -183,6 +180,7 @@ export type DataTestId = | 'back-button' | 'audio-player' | 'chooser-invite-friend' + | 'blocked-contacts-settings-row' | 'your-account-id' | 'copy-button-account-id' | 'link-preview-image' @@ -194,4 +192,7 @@ export type DataTestId = | 'invite-contacts-menu-option' | 'clear-group-info-name-button' | 'module-contact-name__profile-name' + | 'update-profile-info-name-input' | 'set-password-settings-button'; + +export type ModalId = 'blockOrUnblockModal' | 'userSettingsModal'; diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index d94bcba..6344dbf 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -18,10 +18,11 @@ import { doesElementExist, hasElementBeenDeleted, typeIntoInput, + waitForLoadingAnimationToFinish, waitForMatchingText, waitForTestIdWithText, } from './utilities/utils'; -import { LeftPane } from './locators'; +import { Global, HomeScreen, LeftPane, Settings } from './locators'; // Send message in one to one conversation with new contact sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { @@ -73,18 +74,21 @@ test_Alice_1W_Bob_1W( // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); // Check to see if User B is a contact - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newConversationButton.selector, + ); await waitForTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + Global.contactItem.selector, bob.userName, ); // he is a contact, close the new conversation button tab as there is no right click allowed on it - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); + await clickOnTestIdWithText(aliceWindow1, Global.backButton.selector); // then right click on the contact conversation list item to show the menu await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, true, ); @@ -104,7 +108,7 @@ test_Alice_1W_Bob_1W( ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('block').toString(), ); // Verify the user was moved to the blocked contact list @@ -113,14 +117,21 @@ test_Alice_1W_Bob_1W( // click on settings section 'conversation' await clickOnTestIdWithText( aliceWindow1, - 'conversations-settings-menu-item', + Settings.conversationsMenuItem.selector, ); // Navigate to blocked users tab' - await clickOnTestIdWithText(aliceWindow1, 'reveal-blocked-user-settings'); + await clickOnTestIdWithText( + aliceWindow1, + Settings.blockedContactsButton.selector, + ); // select the contact to unblock by clicking on it by name - await clickOnTestIdWithText(aliceWindow1, 'contact', bob.userName); + await clickOnTestIdWithText( + aliceWindow1, + Global.contactItem.selector, + bob.userName, + ); // Unblock user by clicking on unblock - await clickOnTestIdWithText(aliceWindow1, 'unblock-button-settings-screen'); + await clickOnTestIdWithText(aliceWindow1, Settings.unblockButton.selector); // make sure the confirm dialogs shows up await checkModalStrings( aliceWindow1, @@ -128,11 +139,12 @@ test_Alice_1W_Bob_1W( englishStrippedStr('blockUnblockName') .withArgs({ name: bob.userName }) .toString(), + 'blockOrUnblockModal', ); // click on the unblock button await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('blockUnblock').toString(), ); // make sure no blocked contacts are listed @@ -146,21 +158,20 @@ test_Alice_1W_Bob_1W( test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { const newUsername = 'Tiny bubble'; // Open Profile - await clickOnTestIdWithText(aliceWindow1, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Click on current username to open edit field - await clickOnTestIdWithText(aliceWindow1, 'edit-profile-icon'); + await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); // Type in new username - await typeIntoInput(aliceWindow1, 'profile-name-input', newUsername); - // Press enter to confirm username input - await aliceWindow1.keyboard.press('Enter'); + await typeIntoInput(aliceWindow1, Settings.displayNameInput.selector, newUsername); + await clickOnMatchingText(aliceWindow1, englishStrippedStr('save').toString()); // Wait for Copy button to appear to verify username change await aliceWindow1.isVisible(`'${englishStrippedStr('copy').toString()}'`); // verify name change - expect(await aliceWindow1.innerText('[data-testid=your-profile-name]')).toBe( + expect(await aliceWindow1.innerText(`[data-testid=${Settings.displayName.selector}]`)).toBe( newUsername, ); // Exit profile modal - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); }); // TODO: Normalize screenshot dimensions before comparison to handle different pixel densities (e.g. with sharp) @@ -173,20 +184,18 @@ test_Alice_1W_no_network( 'Change avatar', async ({ aliceWindow1 }, testInfo) => { // Open profile - await clickOnTestIdWithText(aliceWindow1, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Click on current profile picture - await waitForTestIdWithText( - aliceWindow1, - 'copy-button-profile-update', - englishStrippedStr('copy').toString(), - ); + await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); await clickOnTestIdWithText(aliceWindow1, 'image-upload-section'); await clickOnTestIdWithText(aliceWindow1, 'image-upload-click'); // allow for the image to be resized before we try to save it await sleepFor(500); await clickOnTestIdWithText(aliceWindow1, 'save-button-profile-update'); - await waitForTestIdWithText(aliceWindow1, 'loading-spinner'); + await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); + await clickOnMatchingText(aliceWindow1, englishStrippedStr('save').toString()); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector) // if we were asked to update the snapshots, make sure we wait for the change to be received before taking a screenshot. if (testInfo.config.updateSnapshots === 'all') { await sleepFor(15000); @@ -236,11 +245,6 @@ test_Alice_1W_Bob_1W( const nickname = 'new nickname for Bob'; await createContact(aliceWindow1, bobWindow1, alice, bob); - await clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'message-section', - }); await clickOnTestIdWithText( aliceWindow1, 'module-conversation__user__profile-name', @@ -295,11 +299,6 @@ test_Alice_1W_Bob_1W( strategy: 'data-testid', selector: 'enable-read-receipts', }); - await clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'message-section', - }); await clickOnTestIdWithText( aliceWindow1, 'module-conversation__user__profile-name', @@ -315,11 +314,6 @@ test_Alice_1W_Bob_1W( strategy: 'data-testid', selector: 'enable-read-receipts', }); - await clickOnElement({ - window: bobWindow1, - strategy: 'data-testid', - selector: 'message-section', - }); await clickOnTestIdWithText( bobWindow1, 'module-conversation__user__profile-name', @@ -335,10 +329,6 @@ test_Alice_1W_Bob_1W( // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); // Confirm contact by checking Messages tab (name should appear in list) - await Promise.all([ - clickOnTestIdWithText(aliceWindow1, 'message-section'), - clickOnTestIdWithText(bobWindow1, 'message-section'), - ]); await Promise.all([ clickOnElement({ window: aliceWindow1, @@ -364,7 +354,6 @@ test_Alice_1W_Bob_1W( ), ]); // Delete contact - await clickOnTestIdWithText(aliceWindow1, 'message-section'); await clickOnTestIdWithText( aliceWindow1, 'module-conversation__user__profile-name', diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index 6533f6e..4fe9e3f 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -33,7 +33,6 @@ export const sendVoiceMessage = async (window: Page) => { await clickOnTestIdWithText(window, 'microphone-button'); await clickOnTestIdWithText(window, 'session-toast'); await clickOnTestIdWithText(window, 'enable-microphone'); - await clickOnTestIdWithText(window, 'message-section'); await clickOnTestIdWithText(window, 'microphone-button'); await sleepFor(5000); await clickOnTestIdWithText(window, 'end-voice-message'); diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index d483a7e..34baed1 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -505,22 +505,22 @@ export async function checkModalStrings( modalId?: ModalId, ) { let modalSelector = '[data-modal-id]'; // Base selector for modals - + // If a specific modal ID is provided, target that one if (modalId) { modalSelector = `[data-modal-id="${modalId}"]`; } - + // Find the target modal const targetModal = window.locator(modalSelector).first(); - + // Wait for the modal to be visible await targetModal.waitFor({ state: 'visible' }); // Get elements within this specific modal const heading = targetModal.locator('[data-testid="modal-heading"]'); const description = targetModal.locator('[data-testid="modal-description"]'); - + // Wait for these elements to be visible await heading.waitFor({ state: 'visible' }); await description.waitFor({ state: 'visible' }); diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index 537819b..785e2a5 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -23,7 +23,6 @@ export const makeVoiceCall = async ( englishStrippedStr('callsVoiceAndVideoModalDescription').toString(), ); await clickOnTestIdWithText(callerWindow, 'session-confirm-ok-button'); - await clickOnTestIdWithText(callerWindow, 'message-section'); await clickOnTestIdWithText( callerWindow, 'module-conversation__user__profile-name', @@ -44,7 +43,6 @@ export const makeVoiceCall = async ( receiverWindow, englishStrippedStr('accept').toString(), ); - await clickOnTestIdWithText(receiverWindow, 'message-section'); await clickOnTestIdWithText( receiverWindow, 'module-conversation__user__profile-name', From d171c2d9e76c0959593d11c31798f28144a940bc Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 16:41:42 +1000 Subject: [PATCH 11/32] feat: add perfectionist, enforce sorting --- .eslintrc.js | 26 ++- eslint.config.mjs | 2 +- global.setup.ts | 3 +- package.json | 1 + playwright.config.ts | 2 +- sessionReporter.ts | 13 +- tests/automation/community_tests.spec.ts | 2 +- tests/automation/constants/variables.ts | 4 +- tests/automation/create_user.spec.ts | 2 +- tests/automation/delete_account.spec.ts | 7 +- tests/automation/linked_device_group.spec.ts | 3 +- tests/automation/linked_device_user.spec.ts | 17 +- tests/automation/locators/index.ts | 4 +- tests/automation/password.spec.ts | 4 +- tests/automation/setup/closeWindows.ts | 1 + tests/automation/setup/create_group.ts | 3 +- tests/automation/setup/new_user.ts | 1 + tests/automation/setup/open.ts | 1 - tests/automation/setup/recovery_using_seed.ts | 1 + tests/automation/setup/sessionTest.ts | 9 +- tests/automation/switching_theme.spec.ts | 1 + tests/automation/types/testing.ts | 218 +++++++++--------- tests/automation/user_actions.spec.ts | 29 ++- tests/automation/utilities/create_contact.ts | 1 + tests/automation/utilities/join_community.ts | 1 + tests/automation/utilities/leave_group.ts | 3 +- tests/automation/utilities/message.ts | 1 + tests/automation/utilities/rename_group.ts | 3 +- tests/automation/utilities/reply_message.ts | 1 + tests/automation/utilities/send_media.ts | 5 +- tests/automation/utilities/send_message.ts | 1 + .../utilities/set_disappearing_messages.ts | 5 +- tests/automation/utilities/utils.ts | 18 +- tests/automation/utilities/voice_call.ts | 1 + yarn.lock | 149 ++++++++++++ 35 files changed, 377 insertions(+), 166 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3322e35..b779df9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,7 +9,7 @@ module.exports = { extends: ['airbnb-base', 'airbnb-typescript/base', 'prettier', 'plugin:@typescript-eslint/recommended'], - plugins: ['mocha', 'more', '@typescript-eslint'], + plugins: ['mocha', 'more', '@typescript-eslint', 'perfectionist'], parser: '@typescript-eslint/parser', parserOptions: { project: ['./tsconfig.json'] }, @@ -54,6 +54,30 @@ module.exports = { 'import/order': 'off', 'no-useless-catch': 'off', + 'perfectionist/sort-imports': 'error', + 'perfectionist/sort-named-imports': 'error', + 'perfectionist/sort-union-types': [ + 'error', + { + // This ensures null/undefined come after other types for better readability + groups: [ + 'named', + 'keyword', + 'operator', + 'literal', + 'function', + 'import', + 'conditional', + 'object', + 'tuple', + 'intersection', + 'union', + 'nullish', + ], + } + ], + + quotes: [ 'error', 'single', diff --git a/eslint.config.mjs b/eslint.config.mjs index 9a033b2..f5e4e6d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,5 +1,5 @@ import eslint from '@eslint/js'; -import tseslint from 'typescript-eslint'; +import tseslint from '@typescript-eslint/eslint-plugin'; import globals from 'globals'; export default tseslint.config( diff --git a/global.setup.ts b/global.setup.ts index a779208..3d83252 100644 --- a/global.setup.ts +++ b/global.setup.ts @@ -1,9 +1,10 @@ import { readdirSync, rm } from 'fs-extra'; +import { isEmpty } from 'lodash'; import { homedir } from 'os'; import { join } from 'path'; + import { MULTI_PREFIX, NODE_ENV } from './tests/automation/setup/open'; import { isLinux, isMacOS } from './tests/os_utils'; -import { isEmpty } from 'lodash'; const getDirectoriesOfSessionDataPath = (source: string) => readdirSync(source, { withFileTypes: true }) diff --git a/package.json b/package.json index 1649382..69022bc 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "eslint-plugin-import": "^2.28.0", "eslint-plugin-mocha": "^10.1.0", "eslint-plugin-more": "^1.0.5", + "eslint-plugin-perfectionist": "^4.15.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", "prettier": "^3.0.1", diff --git a/playwright.config.ts b/playwright.config.ts index a274990..e48316b 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from '@playwright/test'; +import dotenv from 'dotenv'; import { toNumber } from 'lodash'; -import dotenv from 'dotenv'; import { screenshotFolder } from './tests/automation/constants/variables'; dotenv.config(); diff --git a/sessionReporter.ts b/sessionReporter.ts index e153a06..3765d4d 100644 --- a/sessionReporter.ts +++ b/sessionReporter.ts @@ -7,6 +7,7 @@ import type { TestError, TestResult, } from '@playwright/test/reporter'; + import chalk from 'chalk'; import { Dictionary, groupBy, isString, mean, sortBy } from 'lodash'; @@ -220,9 +221,9 @@ class SessionReporter implements Reporter { } onStdOut?( - chunk: string | Buffer, - test: void | TestCase, - _result: void | TestResult, + chunk: Buffer | string, + test: TestCase | void, + _result: TestResult | void, ) { if (printOngoingTestLogs()) { process.stdout.write( @@ -234,9 +235,9 @@ class SessionReporter implements Reporter { } onStdErr?( - chunk: string | Buffer, - test: void | TestCase, - _result: void | TestResult, + chunk: Buffer | string, + test: TestCase | void, + _result: TestResult | void, ) { if (printOngoingTestLogs()) { process.stdout.write( diff --git a/tests/automation/community_tests.spec.ts b/tests/automation/community_tests.spec.ts index b565ab7..e0ce330 100644 --- a/tests/automation/community_tests.spec.ts +++ b/tests/automation/community_tests.spec.ts @@ -1,11 +1,11 @@ import { testCommunityName } from './constants/community'; +import { Conversation, HomeScreen } from './locators'; import { test_Alice_1W_Bob_1W, test_Alice_2W } from './setup/sessionTest'; import { joinCommunity } from './utilities/join_community'; import { sendMessage } from './utilities/message'; import { replyTo } from './utilities/reply_message'; import { sendMedia } from './utilities/send_media'; import { clickOnTestIdWithText } from './utilities/utils'; -import { Conversation, HomeScreen } from './locators'; test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => { await joinCommunity(aliceWindow1); diff --git a/tests/automation/constants/variables.ts b/tests/automation/constants/variables.ts index 471638f..198d235 100644 --- a/tests/automation/constants/variables.ts +++ b/tests/automation/constants/variables.ts @@ -1,8 +1,8 @@ import { - DMTimeOption, DisappearActions, DisappearGroupType, DisappearType, + DMTimeOption, MediaType, } from '../types/testing'; @@ -42,7 +42,7 @@ export const mediaArray = [ type DisappearingOption = { timeOption: DMTimeOption; - disappearingMessagesType: DisappearType | DisappearGroupType; + disappearingMessagesType: DisappearGroupType | DisappearType; disappearAction: DisappearActions; }; diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index 2704b48..aedb23f 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -1,11 +1,11 @@ import { sleepFor } from '../promise_utils'; +import { Global, LeftPane, Settings } from './locators'; import { newUser } from './setup/new_user'; import { sessionTestOneWindow } from './setup/sessionTest'; import { clickOnTestIdWithText, waitForTestIdWithText, } from './utilities/utils'; -import { Global, LeftPane, Settings } from './locators'; sessionTestOneWindow('Create User', async ([window]) => { // Create User diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index d0d15b9..54fc3b5 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -1,8 +1,12 @@ import { Page } from '@playwright/test'; + +import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; +import { Global, HomeScreen, LeftPane, Onboarding, Settings } from './locators'; import { forceCloseAllWindows } from './setup/closeWindows'; import { newUser } from './setup/new_user'; import { openApp } from './setup/open'; +import { recoverFromSeed } from './setup/recovery_using_seed'; import { sessionTestTwoWindows } from './setup/sessionTest'; import { createContact } from './utilities/create_contact'; import { sendNewMessage } from './utilities/send_message'; @@ -15,9 +19,6 @@ import { waitForElement, waitForLoadingAnimationToFinish, } from './utilities/utils'; -import { recoverFromSeed } from './setup/recovery_using_seed'; -import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { Global, HomeScreen, LeftPane, Onboarding, Settings } from './locators'; sessionTestTwoWindows( 'Delete account from swarm', diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 14d349c..6937486 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -1,5 +1,7 @@ import type { Page } from '@playwright/test'; + import { englishStrippedStr } from '../localization/englishStrippedStr'; +import { LeftPane } from './locators'; import { openApp } from './setup/open'; import { recoverFromSeed } from './setup/recovery_using_seed'; import { @@ -14,7 +16,6 @@ import { waitForLoadingAnimationToFinish, waitForTestIdWithText, } from './utilities/utils'; -import { LeftPane } from './locators'; test_group_Alice_2W_Bob_1W_Charlie_1W( 'Leaving group syncs', diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index f5980fd..c2c5e46 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -1,7 +1,15 @@ /* eslint-disable no-await-in-loop */ -import { Page, expect } from '@playwright/test'; +import { expect, Page } from '@playwright/test'; + import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; import { forceCloseAllWindows } from './setup/closeWindows'; import { newUser } from './setup/new_user'; import { @@ -28,13 +36,6 @@ import { waitForTestIdWithText, waitForTextMessage, } from './utilities/utils'; -import { - Conversation, - Global, - HomeScreen, - LeftPane, - Settings, -} from './locators'; sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { let aliceWindow2: Page | undefined; diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 306e874..0beba47 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -70,7 +70,9 @@ export class Settings extends Locator { static readonly displayName = this.testId('your-profile-name'); static readonly accountId = this.testId('your-account-id'); // Update Profile Information - static readonly displayNameInput = this.testId('update-profile-info-name-input') + static readonly displayNameInput = this.testId( + 'update-profile-info-name-input', + ); // Menu items static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); static readonly conversationsMenuItem = this.testId( diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 4e6b462..957bcdc 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -1,6 +1,8 @@ import { Page } from '@playwright/test'; +import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; +import { Global, LeftPane, Settings } from './locators'; import { test_Alice_1W_no_network } from './setup/sessionTest'; import { clickOnMatchingText, @@ -9,8 +11,6 @@ import { typeIntoInput, waitForTestIdWithText, } from './utilities/utils'; -import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { Global, LeftPane, Settings } from './locators'; const testPassword = '123456'; const newTestPassword = '789101112'; diff --git a/tests/automation/setup/closeWindows.ts b/tests/automation/setup/closeWindows.ts index a4a358a..357cd79 100644 --- a/tests/automation/setup/closeWindows.ts +++ b/tests/automation/setup/closeWindows.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { sleepFor } from '../../promise_utils'; export const forceCloseAllWindows = async (windows: Array) => { diff --git a/tests/automation/setup/create_group.ts b/tests/automation/setup/create_group.ts index 5dadbd2..3b0aa5d 100644 --- a/tests/automation/setup/create_group.ts +++ b/tests/automation/setup/create_group.ts @@ -1,5 +1,7 @@ import { Page } from '@playwright/test'; + import { englishStrippedStr } from '../../localization/englishStrippedStr'; +import { sortByPubkey } from '../../pubkey'; import { Group, User } from '../types/testing'; import { sendMessage } from '../utilities/message'; import { sendNewMessage } from '../utilities/send_message'; @@ -10,7 +12,6 @@ import { waitForTestIdWithText, waitForTextMessages, } from '../utilities/utils'; -import { sortByPubkey } from '../../pubkey'; export const createGroup = async ( userName: string, diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 5024d60..01b995a 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -1,5 +1,6 @@ import { Page } from '@playwright/test'; import chalk from 'chalk'; + import { User } from '../types/testing'; import { checkPathLight, diff --git a/tests/automation/setup/open.ts b/tests/automation/setup/open.ts index 0ad2a46..bb05590 100644 --- a/tests/automation/setup/open.ts +++ b/tests/automation/setup/open.ts @@ -1,5 +1,4 @@ import { _electron as electron } from '@playwright/test'; - import chalk from 'chalk'; import { isEmpty } from 'lodash'; import { join } from 'path'; diff --git a/tests/automation/setup/recovery_using_seed.ts b/tests/automation/setup/recovery_using_seed.ts index 50b95b9..232fa9a 100644 --- a/tests/automation/setup/recovery_using_seed.ts +++ b/tests/automation/setup/recovery_using_seed.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { clickOnTestIdWithText, doesElementExist, diff --git a/tests/automation/setup/sessionTest.ts b/tests/automation/setup/sessionTest.ts index ab701e2..3b4e2c2 100644 --- a/tests/automation/setup/sessionTest.ts +++ b/tests/automation/setup/sessionTest.ts @@ -2,14 +2,15 @@ /* eslint-disable @typescript-eslint/array-type */ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/naming-convention */ -import { Page, TestInfo, test } from '@playwright/test'; +import { Page, test, TestInfo } from '@playwright/test'; +import chalk from 'chalk'; + import { Group, User } from '../types/testing'; import { linkedDevice } from '../utilities/linked_device'; import { forceCloseAllWindows } from './closeWindows'; import { createGroup } from './create_group'; import { newUser } from './new_user'; import { openApp } from './open'; -import chalk from 'chalk'; // This is not ideal, most of our test needs to open a specific number of windows and close them once the test is done or failed. // This file contains a bunch of utility function to use to open those windows and clean them afterwards. @@ -105,8 +106,8 @@ type LessThan< * This type can cause type checking performance issues, so only use it with small values. */ type NumericRange = - | Exclude> - | Exclude, LessThan>; + | Exclude, LessThan> + | Exclude>; function sessionTestGeneric< UserCount extends 1 | 2 | 3 | 4, diff --git a/tests/automation/switching_theme.spec.ts b/tests/automation/switching_theme.spec.ts index 86f9c25..06e436c 100644 --- a/tests/automation/switching_theme.spec.ts +++ b/tests/automation/switching_theme.spec.ts @@ -1,4 +1,5 @@ import { expect } from '@playwright/test'; + import { test_Alice_1W_no_network } from './setup/sessionTest'; import { clickOnTestIdWithText } from './utilities/utils'; diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 9fa65c3..dfe2d09 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -13,24 +13,24 @@ export type Group = { userThree: User; }; -export type ConversationType = '1:1' | 'group' | 'community' | 'note-to-self'; +export type ConversationType = '1:1' | 'community' | 'group' | 'note-to-self'; export type DMTimeOption = + | 'disappear-off-option' + | 'input-10-seconds' | 'time-option-0-seconds' - | 'time-option-5-seconds' + | 'time-option-1-days' + | 'time-option-1-hours' | 'time-option-10-seconds' + | 'time-option-12-hours' + | 'time-option-14-days' + | 'time-option-30-minutes' | 'time-option-30-seconds' - | 'time-option-60-seconds' | 'time-option-5-minutes' - | 'time-option-30-minutes' - | 'time-option-1-hours' + | 'time-option-5-seconds' | 'time-option-6-hours' - | 'time-option-12-hours' - | 'time-option-1-days' - | 'time-option-7-days' - | 'time-option-14-days' - | 'input-10-seconds' - | 'disappear-off-option'; + | 'time-option-60-seconds' + | 'time-option-7-days'; type DisappearOpts1o1 = [ '1:1', @@ -73,126 +73,126 @@ export type WithMaxWait = { maxWait?: number }; export type WithRightButton = { rightButton?: boolean }; export type LoaderType = 'loading-animation' | 'loading-spinner'; -export type MediaType = 'image' | 'video' | 'audio' | 'file'; -export type Strategy = 'data-testid' | 'class' | ':has-text'; +export type MediaType = 'audio' | 'file' | 'image' | 'video'; +export type Strategy = ':has-text' | 'class' | 'data-testid'; // Would be good to find a way to sort those with prettier // TODO sort with eslint plugin perfectionist export type DataTestId = - | 'session-id-signup' - | 'display-name-input' - | 'recovery-password-seed-modal' - | 'path-light-container' - | 'new-conversation-button' + | DMTimeOption + | 'accept-message-request' + | 'audio-player' + | 'back-button' + | 'blocked-contacts-settings-row' + | 'call-button' + | 'call-notification-answered-a-call' + | 'call-notification-started-call' + | 'change-password-settings-button' + | 'chooser-invite-friend' + | 'chooser-new-community' | 'chooser-new-conversation-button' - | 'new-session-conversation' - | 'next-new-conversation-button' - | 'control-message' - | 'disappear-control-message' - | 'disappearing-messages-indicator' - | 'conversation-options-avatar' + | 'chooser-new-group' | 'clear-data-settings-menu-item' - | 'message-requests-settings-menu-item' - | 'restore-using-recovery' - | 'reveal-recovery-phrase' - | 'recovery-phrase-input' + | 'clear-group-info-name-button' + | 'contact' + | 'context-menu-item' + | 'continue-button' | 'continue-session-button' - | 'label-device_and_network' - | 'message-request-banner' - | 'module-conversation__user__profile-name' + | 'control-message' + | 'conversation-options-avatar' + | 'conversations-settings-menu-item' + | 'copy-button-account-id' + | 'copy-button-profile-update' + | 'create-account-button' + | 'create-group-button' + | 'decline-and-block-message-request' | 'delete-message-request' - | 'session-confirm-ok-button' - | 'dropdownitem-5-seconds' + | 'disappear-after-read-option' + | 'disappear-after-send-option' + | 'disappear-control-message' + | 'disappear-messages-type-and-time' + | 'disappear-set-button' + | 'disappear-set-button' | 'disappearing-messages-dropdown' - | 'session-toast' - | 'accept-message-request' - | 'set-nickname-confirm-button' - | 'nickname-input' - | 'conversations-settings-menu-item' - | 'unblock-button-settings-screen' - | 'leftpane-primary-avatar' - | 'edit-profile-icon' + | 'disappearing-messages-indicator' + | 'disappearing-messages-menu-option' + | 'display-name-input' + | 'dropdownitem-5-seconds' | 'edit-group-name' - | 'profile-name-input' - | 'image-upload-section' - | 'save-button-profile-update' - | 'modal-close-button' - | 'send-message-button' - | 'message-input-text-area' - | 'end-voice-message' - | 'microphone-button' - | 'enable-microphone' - | 'theme-section' - | 'call-button' + | 'edit-profile-icon' + | 'empty-conversation-notification' | 'enable-calls' + | 'enable-microphone' + | 'enable-read-receipts' | 'end-call' - | 'privacy-settings-menu-item' - | 'set-password-button' - | 'password-input' - | 'password-input-confirm' - | 'change-password-settings-button' - | 'password-input-reconfirm' - | 'recovery-password-settings-menu-item' - | 'messages-container' - | 'chooser-new-group' - | 'new-closed-group-name' - | 'create-group-button' - | 'link-device' - | 'update-group-info-name-input' + | 'end-voice-message' + | 'error-message' + | 'existing-account-button' | 'group-name' + | 'group-update-message' | 'header-conversation-name' - | 'copy-button-profile-update' + | 'hide-recovery-password-button' + | 'image-upload-click' + | 'image-upload-section' + | 'invite-contacts-menu-option' + | 'join-community-button' + | 'join-community-conversation' + | 'label-device_and_network' + | 'leave-group-button' + | 'leftpane-primary-avatar' + | 'link-device' + | 'link-preview-image' + | 'link-preview-title' | 'loading-spinner' - | 'settings-section' - | 'empty-conversation-notification' - | 'your-profile-name' + | 'manage-members-menu-option' | 'mentions-popup-row' - | 'enable-read-receipts' - | 'disappear-set-button' - | 'disappear-after-read-option' - | 'disappearing-messages-menu-option' - | 'disappear-after-send-option' - | 'disappear-set-button' | 'message-content' - | 'group-update-message' + | 'message-input-text-area' + | 'message-request-banner' | 'message-request-response-message' - | 'image-upload-click' - | 'leave-group-button' - | 'create-account-button' - | 'continue-button' - | 'existing-account-button' - | 'context-menu-item' + | 'message-requests-settings-menu-item' + | 'messages-container' + | 'microphone-button' + | 'modal-back-button' + | 'modal-close-button' | 'modal-description' - | DMTimeOption - | `input-${DMTimeOption}` - | 'disappear-messages-type-and-time' - | 'hide-recovery-password-button' - | 'chooser-new-community' - | 'join-community-conversation' - | 'join-community-button' - | 'scroll-to-bottom-button' - | 'decline-and-block-message-request' - | 'contact' | 'modal-heading' - | 'call-notification-answered-a-call' - | 'call-notification-started-call' - | 'modal-back-button' - | 'back-button' - | 'audio-player' - | 'chooser-invite-friend' - | 'blocked-contacts-settings-row' - | 'your-account-id' - | 'copy-button-account-id' - | 'link-preview-image' - | 'link-preview-title' - | 'error-message' - | 'manage-members-menu-option' + | 'module-contact-name__profile-name' + | 'module-conversation__user__profile-name' + | 'new-closed-group-name' + | 'new-conversation-button' + | 'new-session-conversation' + | 'next-new-conversation-button' + | 'nickname-input' + | 'password-input-confirm' + | 'password-input-reconfirm' + | 'password-input' + | 'path-light-container' + | 'privacy-settings-menu-item' + | 'profile-name-input' + | 'recovery-password-seed-modal' + | 'recovery-password-settings-menu-item' + | 'recovery-phrase-input' + | 'restore-using-recovery' + | 'reveal-recovery-phrase' + | 'save-button-profile-update' + | 'scroll-to-bottom-button' + | 'send-message-button' | 'session-confirm-cancel-button' + | 'session-confirm-ok-button' + | 'session-id-signup' | 'session-recovery-password' - | 'invite-contacts-menu-option' - | 'clear-group-info-name-button' - | 'module-contact-name__profile-name' + | 'session-toast' + | 'set-nickname-confirm-button' + | 'set-password-button' + | 'set-password-settings-button' + | 'settings-section' + | 'theme-section' + | 'unblock-button-settings-screen' + | 'update-group-info-name-input' | 'update-profile-info-name-input' - | 'set-password-settings-button'; + | 'your-account-id' + | 'your-profile-name' + | `input-${DMTimeOption}`; export type ModalId = 'blockOrUnblockModal' | 'userSettingsModal'; diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index 6344dbf..0d785a3 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -1,6 +1,8 @@ import { expect } from '@playwright/test'; + import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; +import { Global, HomeScreen, LeftPane, Settings } from './locators'; import { newUser } from './setup/new_user'; import { sessionTestTwoWindows, @@ -22,7 +24,6 @@ import { waitForMatchingText, waitForTestIdWithText, } from './utilities/utils'; -import { Global, HomeScreen, LeftPane, Settings } from './locators'; // Send message in one to one conversation with new contact sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { @@ -162,14 +163,23 @@ test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { // Click on current username to open edit field await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); // Type in new username - await typeIntoInput(aliceWindow1, Settings.displayNameInput.selector, newUsername); - await clickOnMatchingText(aliceWindow1, englishStrippedStr('save').toString()); + await typeIntoInput( + aliceWindow1, + Settings.displayNameInput.selector, + newUsername, + ); + await clickOnMatchingText( + aliceWindow1, + englishStrippedStr('save').toString(), + ); // Wait for Copy button to appear to verify username change await aliceWindow1.isVisible(`'${englishStrippedStr('copy').toString()}'`); // verify name change - expect(await aliceWindow1.innerText(`[data-testid=${Settings.displayName.selector}]`)).toBe( - newUsername, - ); + expect( + await aliceWindow1.innerText( + `[data-testid=${Settings.displayName.selector}]`, + ), + ).toBe(newUsername); // Exit profile modal await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); }); @@ -194,8 +204,11 @@ test_Alice_1W_no_network( await sleepFor(500); await clickOnTestIdWithText(aliceWindow1, 'save-button-profile-update'); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); - await clickOnMatchingText(aliceWindow1, englishStrippedStr('save').toString()); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector) + await clickOnMatchingText( + aliceWindow1, + englishStrippedStr('save').toString(), + ); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); // if we were asked to update the snapshots, make sure we wait for the change to be received before taking a screenshot. if (testInfo.config.updateSnapshots === 'all') { await sleepFor(15000); diff --git a/tests/automation/utilities/create_contact.ts b/tests/automation/utilities/create_contact.ts index 28c6adc..46b6651 100644 --- a/tests/automation/utilities/create_contact.ts +++ b/tests/automation/utilities/create_contact.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { User } from '../types/testing'; import { replyTo } from './reply_message'; import { sendNewMessage } from './send_message'; diff --git a/tests/automation/utilities/join_community.ts b/tests/automation/utilities/join_community.ts index f31c0d9..550a685 100644 --- a/tests/automation/utilities/join_community.ts +++ b/tests/automation/utilities/join_community.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { testCommunityLink } from '../constants/community'; import { clickOnTestIdWithText, diff --git a/tests/automation/utilities/leave_group.ts b/tests/automation/utilities/leave_group.ts index a6defcf..803f515 100644 --- a/tests/automation/utilities/leave_group.ts +++ b/tests/automation/utilities/leave_group.ts @@ -1,11 +1,12 @@ import { Page } from '@playwright/test'; + +import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { Group } from '../types/testing'; import { clickOnMatchingText, clickOnTestIdWithText, hasElementBeenDeleted, } from './utils'; -import { englishStrippedStr } from '../../localization/englishStrippedStr'; export const leaveGroup = async (window: Page, group: Group) => { // go to three dots menu diff --git a/tests/automation/utilities/message.ts b/tests/automation/utilities/message.ts index 7bb03bd..67ea326 100644 --- a/tests/automation/utilities/message.ts +++ b/tests/automation/utilities/message.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + // eslint-disable-next-line import/no-cycle import { clickOnElement, typeIntoInput } from './utils'; diff --git a/tests/automation/utilities/rename_group.ts b/tests/automation/utilities/rename_group.ts index 741e1e7..1fadc5c 100644 --- a/tests/automation/utilities/rename_group.ts +++ b/tests/automation/utilities/rename_group.ts @@ -1,4 +1,6 @@ import { Page } from '@playwright/test'; + +import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { clickOnMatchingText, clickOnTestIdWithText, @@ -6,7 +8,6 @@ import { waitForMatchingText, waitForTestIdWithText, } from './utils'; -import { englishStrippedStr } from '../../localization/englishStrippedStr'; export const renameGroup = async ( window: Page, diff --git a/tests/automation/utilities/reply_message.ts b/tests/automation/utilities/reply_message.ts index b257d1f..0c3046c 100644 --- a/tests/automation/utilities/reply_message.ts +++ b/tests/automation/utilities/reply_message.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; import { Strategy } from '../types/testing'; diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index 4fe9e3f..0915d63 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -1,6 +1,9 @@ import { Page } from '@playwright/test'; + import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; +import { MediaType } from '../types/testing'; +import { waitForSentTick } from './message'; import { checkModalStrings, clickOnElement, @@ -10,8 +13,6 @@ import { waitForLoadingAnimationToFinish, waitForTestIdWithText, } from './utils'; -import { MediaType } from '../types/testing'; -import { waitForSentTick } from './message'; export const sendMedia = async ( window: Page, diff --git a/tests/automation/utilities/send_message.ts b/tests/automation/utilities/send_message.ts index 01a5ed9..c86d222 100644 --- a/tests/automation/utilities/send_message.ts +++ b/tests/automation/utilities/send_message.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { sendMessage } from './message'; import { clickOnTestIdWithText, typeIntoInput } from './utils'; diff --git a/tests/automation/utilities/set_disappearing_messages.ts b/tests/automation/utilities/set_disappearing_messages.ts index 71fdf2f..8108118 100644 --- a/tests/automation/utilities/set_disappearing_messages.ts +++ b/tests/automation/utilities/set_disappearing_messages.ts @@ -1,10 +1,12 @@ import { Page } from '@playwright/test'; + +import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { ConversationType, DataTestId, DisappearOptions, } from '../types/testing'; -import { englishStrippedStr } from '../../localization/englishStrippedStr'; +import { isChecked } from './checked'; import { checkModalStrings, clickOnElement, @@ -15,7 +17,6 @@ import { waitForElement, waitForTestIdWithText, } from './utils'; -import { isChecked } from './checked'; export const setDisappearingMessages = async ( windowA: Page, diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index 34baed1..9382992 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -3,10 +3,16 @@ /* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable no-await-in-loop */ import { ElementHandle, Page } from '@playwright/test'; +import fs from 'fs'; +import path from 'path'; + +import type { ElementState } from '../types/landing_page_states'; + import { sleepFor } from '../../promise_utils'; +import { screenshotFolder } from '../constants/variables'; import { - DMTimeOption, DataTestId, + DMTimeOption, LoaderType, ModalId, Strategy, @@ -16,10 +22,6 @@ import { WithRightButton, } from '../types/testing'; import { sendMessage } from './message'; -import fs from 'fs'; -import path from 'path'; -import { screenshotFolder } from '../constants/variables'; -import type { ElementState } from '../types/landing_page_states'; // WAIT FOR FUNCTIONS @@ -166,7 +168,7 @@ export async function waitForLoadingAnimationToFinish( loader: LoaderType, maxWait?: number, ) { - let loadingAnimation: ElementHandle | undefined; + let loadingAnimation: ElementHandle | undefined; await waitForElement(window, 'data-testid', `${loader}`, maxWait); @@ -391,7 +393,7 @@ export async function hasElementBeenDeleted( ) { const start = Date.now(); - let el: ElementHandle | undefined; + let el: ElementHandle | undefined; do { try { el = await waitForElement(window, strategy, selector, maxWait, text); @@ -569,7 +571,7 @@ async function deleteDifferenceFile( } export async function compareScreenshot( - element: ElementHandle, + element: ElementHandle, testTitle: string, elementState: ElementState, os: string, diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index 785e2a5..94b5247 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -1,4 +1,5 @@ import { Page } from '@playwright/test'; + import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; import { User } from '../types/testing'; diff --git a/yarn.lock b/yarn.lock index 41ee1c7..692d8cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,6 +29,13 @@ dependencies: eslint-visitor-keys "^3.3.0" +"@eslint-community/eslint-utils@^4.7.0": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz#0e3b5e45566d1bce1ec47d8aae2fc2ad77ad0894" + integrity sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q== + dependencies: + eslint-visitor-keys "^3.4.3" + "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.6.2" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" @@ -230,6 +237,15 @@ "@typescript-eslint/visitor-keys" "6.2.1" debug "^4.3.4" +"@typescript-eslint/project-service@8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.42.0.tgz#636eb3418b6c42c98554dce884943708bf41a583" + integrity sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.42.0" + "@typescript-eslint/types" "^8.42.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.2.1.tgz#b6f43a867b84e5671fe531f2b762e0b68f7cf0c4" @@ -238,6 +254,19 @@ "@typescript-eslint/types" "6.2.1" "@typescript-eslint/visitor-keys" "6.2.1" +"@typescript-eslint/scope-manager@8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz#36016757bc85b46ea42bae47b61f9421eddedde3" + integrity sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw== + dependencies: + "@typescript-eslint/types" "8.42.0" + "@typescript-eslint/visitor-keys" "8.42.0" + +"@typescript-eslint/tsconfig-utils@8.42.0", "@typescript-eslint/tsconfig-utils@^8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz#21a3e74396fd7443ff930bc41b27789ba7e9236e" + integrity sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ== + "@typescript-eslint/type-utils@6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.2.1.tgz#8eb8a2cccdf39cd7cf93e02bd2c3782dc90b0525" @@ -253,6 +282,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.2.1.tgz#7fcdeceb503aab601274bf5e210207050d88c8ab" integrity sha512-528bGcoelrpw+sETlyM91k51Arl2ajbNT9L4JwoXE2dvRe1yd8Q64E4OL7vHYw31mlnVsf+BeeLyAZUEQtqahQ== +"@typescript-eslint/types@8.42.0", "@typescript-eslint/types@^8.34.1", "@typescript-eslint/types@^8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.42.0.tgz#ae15c09cebda20473772902033328e87372db008" + integrity sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw== + "@typescript-eslint/typescript-estree@6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.1.tgz#2af6e90c1e91cb725a5fe1682841a3f74549389e" @@ -266,6 +300,22 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz#593c3af87d4462252c0d7239d1720b84a1b56864" + integrity sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ== + dependencies: + "@typescript-eslint/project-service" "8.42.0" + "@typescript-eslint/tsconfig-utils" "8.42.0" + "@typescript-eslint/types" "8.42.0" + "@typescript-eslint/visitor-keys" "8.42.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.1.0" + "@typescript-eslint/utils@6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.2.1.tgz#2aa4279ec13053d05615bcbde2398e1e8f08c334" @@ -279,6 +329,16 @@ "@typescript-eslint/typescript-estree" "6.2.1" semver "^7.5.4" +"@typescript-eslint/utils@^8.34.1": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.42.0.tgz#95f8e0c697ff2f7da5f72e16135011f878d815c0" + integrity sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.42.0" + "@typescript-eslint/types" "8.42.0" + "@typescript-eslint/typescript-estree" "8.42.0" + "@typescript-eslint/visitor-keys@6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.1.tgz#442e7c09fe94b715a54ebe30e967987c3c41fbf4" @@ -287,6 +347,14 @@ "@typescript-eslint/types" "6.2.1" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@8.42.0": + version "8.42.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz#87c6caaa1ac307bc73a87c1fc469f88f0162f27e" + integrity sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ== + dependencies: + "@typescript-eslint/types" "8.42.0" + eslint-visitor-keys "^4.2.1" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -434,6 +502,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -441,6 +516,13 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -769,6 +851,15 @@ eslint-plugin-more@^1.0.5: resolved "https://registry.yarnpkg.com/eslint-plugin-more/-/eslint-plugin-more-1.0.5.tgz#667bffc2a64bde2d48b98c8faa111e213b2f873f" integrity sha512-zjDza5jeNBHWf8ZezyW2Llk99abndcGlSz9GIKgVOGwISx0m+f4QoZAapjSmUjKSxHvmOa7Lt68Pk8XbRzWb7w== +eslint-plugin-perfectionist@^4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.15.0.tgz#320029162b0ec439af522d5b146903f0e47bfbd4" + integrity sha512-pC7PgoXyDnEXe14xvRUhBII8A3zRgggKqJFx2a82fjrItDs1BSI7zdZnQtM2yQvcyod6/ujmzb7ejKPx8lZTnw== + dependencies: + "@typescript-eslint/types" "^8.34.1" + "@typescript-eslint/utils" "^8.34.1" + natural-orderby "^5.0.0" + eslint-scope@^7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" @@ -794,6 +885,16 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f" integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw== +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + eslint@^8.46.0: version "8.46.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.46.0.tgz#a06a0ff6974e53e643acc42d1dcf2e7f797b3552" @@ -897,6 +998,17 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -935,6 +1047,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -1472,6 +1591,14 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -1489,6 +1616,13 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -1514,6 +1648,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +natural-orderby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-5.0.0.tgz#bb655f669ee9c84e82cdc6cddbba25eb263cd9f4" + integrity sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -1820,6 +1959,11 @@ semver@^7.3.2, semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -1938,6 +2082,11 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== +ts-api-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + tsconfig-paths@^3.14.2: version "3.14.2" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" From 41492e04b4226b88d2aff2199fd8d4a387926cd3 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 17:08:14 +1000 Subject: [PATCH 12/32] chore: update strings --- .../automation/enforce_localized_str.spec.ts | 2 +- tests/localization/constants.ts | 2 + tests/localization/locales.ts | 523 +++++++++++++++++- 3 files changed, 511 insertions(+), 16 deletions(-) diff --git a/tests/automation/enforce_localized_str.spec.ts b/tests/automation/enforce_localized_str.spec.ts index 24a94b0..546f636 100644 --- a/tests/automation/enforce_localized_str.spec.ts +++ b/tests/automation/enforce_localized_str.spec.ts @@ -206,7 +206,7 @@ function getExpectedStringFromKey( case 'callsVoiceAndVideoBeta': return 'Voice and Video Calls (Beta)'; case 'callsVoiceAndVideoModalDescription': - return 'Your IP is visible to your call partner and a Session Technology Foundation server while using beta calls.'; + return 'Your IP is visible to your call partner and a Session Foundation server while using beta calls.'; case 'blockDescription': return 'Are you sure you want to block {name}? Blocked users cannot send you message requests, group invites or call you.'; case 'noteToSelfHide': diff --git a/tests/localization/constants.ts b/tests/localization/constants.ts index fd7dc29..dd2717d 100644 --- a/tests/localization/constants.ts +++ b/tests/localization/constants.ts @@ -9,6 +9,8 @@ export enum LOCALE_DEFAULTS { token_name_short = 'SESH', usd_name_short = 'USD', app_pro = 'Session Pro', + session_foundation = 'Session Foundation', + pro = 'Pro', } export const rtlLocales = ['ar', 'fa', 'he', 'ps', 'ur']; diff --git a/tests/localization/locales.ts b/tests/localization/locales.ts index 94b497a..e842e2e 100644 --- a/tests/localization/locales.ts +++ b/tests/localization/locales.ts @@ -41,7 +41,7 @@ type WithStoreVariant = {storevariant: string}; type WithMin = {min: string}; type WithMax = {max: string}; -export type TokenSimpleNoArgs = +export type TokenSimpleNoArgs = 'about' | 'accept' | 'accountIDCopy' | @@ -81,12 +81,15 @@ export type TokenSimpleNoArgs = 'appIconEnableIconAndName' | 'appIconSelect' | 'appIconSelectionTitle' | + 'appName' | 'appNameCalculator' | 'appNameMeetingSE' | 'appNameNews' | 'appNameNotes' | 'appNameStocks' | 'appNameWeather' | + 'appPro' | + 'appProBadge' | 'appearanceAutoDarkMode' | 'appearanceHideMenuBar' | 'appearanceLanguage' | @@ -198,6 +201,7 @@ export type TokenSimpleNoArgs = 'cameraGrantAccessDescription' | 'cameraGrantAccessQr' | 'cancel' | + 'cancelPlan' | 'change' | 'changePasswordFail' | 'changePasswordModalDescription' | @@ -286,6 +290,8 @@ export type TokenSimpleNoArgs = 'copy' | 'create' | 'creatingCall' | + 'currentPassword' | + 'currentPlan' | 'cut' | 'darkMode' | 'databaseErrorClearDataWarning' | @@ -449,12 +455,16 @@ export type TokenSimpleNoArgs = 'hideOthers' | 'image' | 'images' | + 'important' | 'incognitoKeyboard' | 'incognitoKeyboardDescription' | 'info' | 'invalidShortcut' | 'join' | 'later' | + 'launchOnStartDescriptionDesktop' | + 'launchOnStartDesktop' | + 'launchOnStartupDisabledDesktop' | 'learnMore' | 'leave' | 'leaving' | @@ -472,6 +482,7 @@ export type TokenSimpleNoArgs = 'linkPreviewsSendModalDescription' | 'linkPreviewsTurnedOff' | 'linkPreviewsTurnedOffDescription' | + 'links' | 'loadAccount' | 'loadAccountProgressMessage' | 'loading' | @@ -484,7 +495,9 @@ export type TokenSimpleNoArgs = 'lockAppStatus' | 'lockAppUnlock' | 'lockAppUnlocked' | + 'logs' | 'manageMembers' | + 'managePro' | 'max' | 'media' | 'membersAddAccountIdOrOns' | @@ -534,7 +547,10 @@ export type TokenSimpleNoArgs = 'modalMessageCharacterDisplayTitle' | 'modalMessageCharacterTooLongTitle' | 'modalMessageTooLongTitle' | + 'networkName' | + 'newPassword' | 'next' | + 'nextSteps' | 'nicknameEnter' | 'nicknameErrorShorter' | 'nicknameRemove' | @@ -607,6 +623,7 @@ export type TokenSimpleNoArgs = 'open' | 'openSurvey' | 'other' | + 'oxenFoundation' | 'password' | 'passwordChange' | 'passwordChangeShortDescription' | @@ -630,8 +647,8 @@ export type TokenSimpleNoArgs = 'passwordSetShortDescription' | 'passwordStrengthCharLength' | 'passwordStrengthIncludeNumber' | - 'passwordStrengthIncludesLetter' | 'passwordStrengthIncludesLowercase' | + 'passwordStrengthIncludesSymbol' | 'passwordStrengthIncludesUppercase' | 'passwordStrengthIndicator' | 'passwordStrengthIndicatorDescription' | @@ -675,31 +692,68 @@ export type TokenSimpleNoArgs = 'pinConversation' | 'pinUnpin' | 'pinUnpinConversation' | + 'plusLoadsMore' | 'preferences' | 'preview' | 'previewNotification' | + 'pro' | 'proActivated' | + 'proAllSet' | 'proAlreadyPurchased' | 'proAnimatedDisplayPicture' | 'proAnimatedDisplayPictureCallToActionDescription' | 'proAnimatedDisplayPictureFeature' | 'proAnimatedDisplayPictureModalDescription' | + 'proAnimatedDisplayPictures' | + 'proAnimatedDisplayPicturesDescription' | 'proAnimatedDisplayPicturesNonProModalDescription' | 'proBadge' | + 'proBadgeVisible' | + 'proBadges' | + 'proBadgesDescription' | 'proCallToActionLongerMessages' | 'proCallToActionPinnedConversations' | 'proCallToActionPinnedConversationsMoreThan' | + 'proExpired' | + 'proExpiredDescription' | + 'proExpiringSoon' | + 'proFaq' | + 'proFaqDescription' | 'proFeatureListAnimatedDisplayPicture' | 'proFeatureListLargerGroups' | 'proFeatureListLoadsMore' | 'proFeatureListLongerMessages' | 'proFeatureListPinnedConversations' | + 'proFeatures' | 'proGroupActivated' | 'proGroupActivatedDescription' | + 'proImportantDescription' | 'proIncreasedAttachmentSizeFeature' | 'proIncreasedMessageLengthFeature' | + 'proLargerGroups' | + 'proLargerGroupsDescription' | + 'proLongerMessages' | + 'proLongerMessagesDescription' | 'proMessageInfoFeatures' | + 'proPlanNotFound' | + 'proPlanNotFoundDescription' | + 'proPlanRecover' | + 'proPlanRenew' | + 'proPlanRenewStart' | + 'proPlanRenewSupport' | + 'proPlanRestored' | + 'proPlanRestoredDescription' | + 'proRefundDescription' | + 'proRefundRequestSessionSupport' | + 'proRefunding' | + 'proRequestedRefund' | 'proSendMore' | + 'proSettings' | + 'proStats' | + 'proStatsTooltip' | + 'proSupportDescription' | + 'proUnlimitedPins' | + 'proUnlimitedPinsDescription' | 'proUserProfileModalCallToAction' | 'profile' | 'profileDisplayPicture' | @@ -750,7 +804,9 @@ export type TokenSimpleNoArgs = 'remove' | 'removePasswordFail' | 'removePasswordModalDescription' | + 'renew' | 'reply' | + 'requestRefund' | 'resend' | 'resolving' | 'restart' | @@ -784,6 +840,8 @@ export type TokenSimpleNoArgs = 'sessionAppearance' | 'sessionClearData' | 'sessionConversations' | + 'sessionDownloadUrl' | + 'sessionFoundation' | 'sessionHelp' | 'sessionInviteAFriend' | 'sessionMessageRequests' | @@ -799,12 +857,15 @@ export type TokenSimpleNoArgs = 'sessionNotifications' | 'sessionPermissions' | 'sessionPrivacy' | + 'sessionProBeta' | 'sessionRecoveryPassword' | 'sessionSettings' | 'set' | 'setCommunityDisplayPicture' | 'setPasswordModalDescription' | + 'settingsCannotChangeDesktop' | 'settingsRestartDescription' | + 'settingsStartCategoryDesktop' | 'share' | 'shareAccountIdDescription' | 'shareAccountIdDescriptionCopied' | @@ -817,6 +878,7 @@ export type TokenSimpleNoArgs = 'showNoteToSelf' | 'showNoteToSelfDescription' | 'spellChecker' | + 'stakingRewardPool' | 'stickers' | 'strength' | 'supportDescription' | @@ -825,7 +887,10 @@ export type TokenSimpleNoArgs = 'theContinue' | 'theDefault' | 'theError' | + 'theReturn' | 'themePreview' | + 'tokenNameLong' | + 'tokenNameShort' | 'tooltipBlindedIdCommunities' | 'translate' | 'tray' | @@ -847,6 +912,8 @@ export type TokenSimpleNoArgs = 'updateGroupInformationDescription' | 'updateGroupInformationEnterShorterDescription' | 'updateNewVersion' | + 'updatePlan' | + 'updatePlanTwo' | 'updateProfileInformation' | 'updateProfileInformationDescription' | 'updateReleaseNotes' | @@ -858,6 +925,8 @@ export type TokenSimpleNoArgs = 'urlCopy' | 'urlOpen' | 'urlOpenBrowser' | + 'urlOpenDescriptionAlternative' | + 'usdNameShort' | 'useFastMode' | 'video' | 'videoErrorPlay' | @@ -1018,13 +1087,49 @@ export type TokensSimpleAndArgs = { notificationsMutedFor: WithTimeLarge, notificationsMutedForTime: WithDateTime, notificationsSystem: WithMessageCount & WithConversationCount, + onDevice: { device_type: string }, + onDeviceDescription: { device_type: string, platform_account: string }, onboardingBubbleCreatingAnAccountIsEasy: WithEmoji, onboardingBubbleWelcomeToSession: WithEmoji, + openStoreWebsite: { platform_store: string }, passwordErrorLength: WithMin & WithMax, + plusLoadsMoreDescription: WithIcon, + proAllSetDescription: WithDate, + proAutoRenewTime: WithTime, + proBilledAnnually: { price: string }, + proBilledMonthly: { price: string }, + proBilledQuarterly: { price: string }, + proDiscountTooltip: { percent: string }, + proExpiringSoonDescription: WithTime, + proExpiringTime: WithTime, + proPercentOff: { percent: string }, + proPlanActivatedAuto: WithDate & { current_plan: string }, + proPlanActivatedAutoShort: WithDate & { current_plan: string }, + proPlanActivatedNotAuto: WithDate, + proPlanExpireDate: WithDate, + proPlanPlatformRefund: { platform_store: string, platform_account: string }, + proPlanPlatformRefundLong: { platform_store: string }, + proPlanRenewDesktop: { platform_store: string }, + proPlanRenewDesktopLinked: { platform_store: string }, + proPlanRenewDesktopStore: { platform_store: string, platform_account: string }, + proPlanSignUp: { platform_store: string, platform_account: string }, + proPriceOneMonth: { monthly_price: string }, + proPriceThreeMonths: { monthly_price: string }, + proPriceTwelveMonths: { monthly_price: string }, + proRefundNextSteps: { platform_account: string }, + proRefundRequestStorePolicies: { platform_account: string }, + proRefundSupport: { platform_account: string, platform_store: string }, + proRefundingDescription: { platform_account: string, platform_store: string }, + proTosPrivacy: WithIcon, + proUpdatePlanDescription: WithDate & { current_plan: string, selected_plan: string }, + proUpdatePlanExpireDescription: WithDate & { selected_plan: string }, + processingRefundRequest: { platform_account: string }, rateSessionModalDescription: WithStoreVariant, + refundPlanNonOriginatorApple: { platform_account: string }, remainingCharactersOverTooltip: WithCount, screenshotTaken: WithName, searchMatchesNoneSpecific: WithQuery, + sessionNetworkDataPrice: WithDateTime, sessionNetworkDescription: WithIcon, systemInformationDesktop: WithInformation, tooltipAccountIdVisible: WithName, @@ -1033,7 +1138,8 @@ export type TokensSimpleAndArgs = { updateVersion: WithVersion, updated: WithRelativeTime, urlOpenDescription: WithUrl, - sessionNetworkDataPrice: WithDateTime + viaStoreWebsite: { platform_store: string }, + viaStoreWebsiteDescription: { platform_account: string, platform_store: string } }; export type TokensPluralAndArgs = { @@ -1059,13 +1165,17 @@ export type TokensPluralAndArgs = { messageNewYouveGot: WithCount, messageNewYouveGotGroup: WithGroupName & WithCount, modalMessageCharacterDisplayDescription: WithLimit & WithCount, + proBadgesSent: WithCount & { total: string }, + proGroupsUpgraded: WithCount & { total: string }, + proLongerMessagesSent: WithCount & { total: string }, + proPinnedConversations: WithCount & { total: string }, promotionFailed: WithCount, promotionFailedDescription: WithCount, remainingCharactersTooltip: WithCount, searchMatches: WithFoundCount & WithCount }; -export type TokenSimpleWithArgs = +export type TokenSimpleWithArgs = 'accountIdShare' | 'adminMorePromotedToAdmin' | 'adminPromoteDescription' | @@ -1209,13 +1319,49 @@ export type TokenSimpleWithArgs = 'notificationsMutedFor' | 'notificationsMutedForTime' | 'notificationsSystem' | + 'onDevice' | + 'onDeviceDescription' | 'onboardingBubbleCreatingAnAccountIsEasy' | 'onboardingBubbleWelcomeToSession' | + 'openStoreWebsite' | 'passwordErrorLength' | + 'plusLoadsMoreDescription' | + 'proAllSetDescription' | + 'proAutoRenewTime' | + 'proBilledAnnually' | + 'proBilledMonthly' | + 'proBilledQuarterly' | + 'proDiscountTooltip' | + 'proExpiringSoonDescription' | + 'proExpiringTime' | + 'proPercentOff' | + 'proPlanActivatedAuto' | + 'proPlanActivatedAutoShort' | + 'proPlanActivatedNotAuto' | + 'proPlanExpireDate' | + 'proPlanPlatformRefund' | + 'proPlanPlatformRefundLong' | + 'proPlanRenewDesktop' | + 'proPlanRenewDesktopLinked' | + 'proPlanRenewDesktopStore' | + 'proPlanSignUp' | + 'proPriceOneMonth' | + 'proPriceThreeMonths' | + 'proPriceTwelveMonths' | + 'proRefundNextSteps' | + 'proRefundRequestStorePolicies' | + 'proRefundSupport' | + 'proRefundingDescription' | + 'proTosPrivacy' | + 'proUpdatePlanDescription' | + 'proUpdatePlanExpireDescription' | + 'processingRefundRequest' | 'rateSessionModalDescription' | + 'refundPlanNonOriginatorApple' | 'remainingCharactersOverTooltip' | 'screenshotTaken' | 'searchMatchesNoneSpecific' | + 'sessionNetworkDataPrice' | 'sessionNetworkDescription' | 'systemInformationDesktop' | 'tooltipAccountIdVisible' | @@ -1224,9 +1370,10 @@ export type TokenSimpleWithArgs = 'updateVersion' | 'updated' | 'urlOpenDescription' | - 'sessionNetworkDataPrice' + 'viaStoreWebsite' | + 'viaStoreWebsiteDescription' -export type TokenPluralWithArgs = +export type TokenPluralWithArgs = 'adminSendingPromotion' | 'clearDataErrorDescription' | 'deleteMessage' | @@ -1249,6 +1396,10 @@ export type TokenPluralWithArgs = 'messageNewYouveGot' | 'messageNewYouveGotGroup' | 'modalMessageCharacterDisplayDescription' | + 'proBadgesSent' | + 'proGroupsUpgraded' | + 'proLongerMessagesSent' | + 'proPinnedConversations' | 'promotionFailed' | 'promotionFailedDescription' | 'remainingCharactersTooltip' | @@ -1375,6 +1526,9 @@ export const simpleDictionaryNoArgs: Record< appIconSelectionTitle: { en: "Icon", }, + appName: { + en: "Session", + }, appNameCalculator: { en: "Calculator", }, @@ -1393,6 +1547,12 @@ export const simpleDictionaryNoArgs: Record< appNameWeather: { en: "Weather", }, + appPro: { + en: "Session Pro", + }, + appProBadge: { + en: "Session Pro Badge", + }, appearanceAutoDarkMode: { en: "Auto Dark Mode", }, @@ -1700,7 +1860,7 @@ export const simpleDictionaryNoArgs: Record< en: "Voice and Video Calls (Beta)", }, callsVoiceAndVideoModalDescription: { - en: "Your IP is visible to your call partner and a Session Technology Foundation server while using beta calls.", + en: "Your IP is visible to your call partner and a Session Foundation server while using beta calls.", }, callsVoiceAndVideoToggleDescription: { en: "Enables voice and video calls to and from other users.", @@ -1726,6 +1886,9 @@ export const simpleDictionaryNoArgs: Record< cancel: { en: "Cancel", }, + cancelPlan: { + en: "Cancel Plan", + }, change: { en: "Change", }, @@ -1931,7 +2094,7 @@ export const simpleDictionaryNoArgs: Record< en: "Enter Key", }, conversationsEnterDescription: { - en: "Function of the enter key when typing in a conversation.", + en: "Define how the Enter and Shift+Enter keys function in conversations.", }, conversationsEnterNewLine: { en: "SHIFT + ENTER sends a message, ENTER starts a new line.", @@ -1990,6 +2153,12 @@ export const simpleDictionaryNoArgs: Record< creatingCall: { en: "Creating Call", }, + currentPassword: { + en: "Current Password", + }, + currentPlan: { + en: "Current Plan", + }, cut: { en: "Cut", }, @@ -2479,6 +2648,9 @@ export const simpleDictionaryNoArgs: Record< images: { en: "images", }, + important: { + en: "Important", + }, incognitoKeyboard: { en: "Incognito Keyboard", }, @@ -2497,6 +2669,15 @@ export const simpleDictionaryNoArgs: Record< later: { en: "Later", }, + launchOnStartDescriptionDesktop: { + en: "Launch Session automatically when your computer starts up.", + }, + launchOnStartDesktop: { + en: "Launch on Startup", + }, + launchOnStartupDisabledDesktop: { + en: "This setting is managed by your system on Linux. To enable automatic startup, add Session to your startup applications in system settings.", + }, learnMore: { en: "Learn More", }, @@ -2548,6 +2729,9 @@ export const simpleDictionaryNoArgs: Record< linkPreviewsTurnedOffDescription: { en: "Session must contact linked websites to generate previews of links you send and receive.

You can turn them on in Session's settings.", }, + links: { + en: "Links", + }, loadAccount: { en: "Load Account", }, @@ -2584,9 +2768,15 @@ export const simpleDictionaryNoArgs: Record< lockAppUnlocked: { en: "Session is unlocked", }, + logs: { + en: "Logs", + }, manageMembers: { en: "Manage Members", }, + managePro: { + en: "Manage Pro", + }, max: { en: "Max", }, @@ -2734,9 +2924,18 @@ export const simpleDictionaryNoArgs: Record< modalMessageTooLongTitle: { en: "Message Too Long", }, + networkName: { + en: "Session Network", + }, + newPassword: { + en: "New Password", + }, next: { en: "Next", }, + nextSteps: { + en: "Next Steps", + }, nicknameEnter: { en: "Enter nickname", }, @@ -2953,6 +3152,9 @@ export const simpleDictionaryNoArgs: Record< other: { en: "Other", }, + oxenFoundation: { + en: "Oxen Foundation", + }, password: { en: "Password", }, @@ -3022,12 +3224,12 @@ export const simpleDictionaryNoArgs: Record< passwordStrengthIncludeNumber: { en: "Includes a number", }, - passwordStrengthIncludesLetter: { - en: "Includes a letter", - }, passwordStrengthIncludesLowercase: { en: "Includes a lowercase letter", }, + passwordStrengthIncludesSymbol: { + en: "Includes a symbol", + }, passwordStrengthIncludesUppercase: { en: "Includes a uppercase letter", }, @@ -3157,6 +3359,9 @@ export const simpleDictionaryNoArgs: Record< pinUnpinConversation: { en: "Unpin Conversation", }, + plusLoadsMore: { + en: "Plus Loads More...", + }, preferences: { en: "Preferences", }, @@ -3166,9 +3371,15 @@ export const simpleDictionaryNoArgs: Record< previewNotification: { en: "Preview Notification", }, + pro: { + en: "Pro", + }, proActivated: { en: "Activated", }, + proAllSet: { + en: "You're all set!", + }, proAlreadyPurchased: { en: "You’ve already got", }, @@ -3184,11 +3395,26 @@ export const simpleDictionaryNoArgs: Record< proAnimatedDisplayPictureModalDescription: { en: "users can upload GIFs", }, + proAnimatedDisplayPictures: { + en: "Animated Display Pictures", + }, + proAnimatedDisplayPicturesDescription: { + en: "Set animated GIFs and WebP images as your display picture.", + }, proAnimatedDisplayPicturesNonProModalDescription: { en: "Upload GIFs with", }, proBadge: { - en: "Session Pro Badge", + en: "Pro Badge", + }, + proBadgeVisible: { + en: "Show Session Pro badge to other users", + }, + proBadges: { + en: "Badges", + }, + proBadgesDescription: { + en: "Show your support for Session with an exclusive badge next to your display name.", }, proCallToActionLongerMessages: { en: "Want to send longer messages? Send more text and unlock premium features with Session Pro", @@ -3199,6 +3425,21 @@ export const simpleDictionaryNoArgs: Record< proCallToActionPinnedConversationsMoreThan: { en: "Want more than 5 pins? Organize your chats and unlock premium features with Session Pro", }, + proExpired: { + en: "Expired", + }, + proExpiredDescription: { + en: "Unfortunately, your Pro plan has expired. Renew to keep accessing the exclusive perks and features of Session Pro.", + }, + proExpiringSoon: { + en: "Expiring Soon", + }, + proFaq: { + en: "Pro FAQ", + }, + proFaqDescription: { + en: "Find answers to common questions in the Session FAQ.", + }, proFeatureListAnimatedDisplayPicture: { en: "Upload GIF and WebP display pictures", }, @@ -3214,24 +3455,96 @@ export const simpleDictionaryNoArgs: Record< proFeatureListPinnedConversations: { en: "Pin unlimited conversations", }, + proFeatures: { + en: "Pro Features", + }, proGroupActivated: { en: "Group Activated", }, proGroupActivatedDescription: { en: "This group has expanded capacity! It can support up to 300 members because a group admin has", }, + proImportantDescription: { + en: "Requesting a refund is final. If approved, your Pro plan will be canceled immediately and you will lose access to all Pro features.", + }, proIncreasedAttachmentSizeFeature: { en: "Increased Attachment Size", }, proIncreasedMessageLengthFeature: { en: "Increased Message Length", }, + proLargerGroups: { + en: "Larger Groups", + }, + proLargerGroupsDescription: { + en: "Groups you are an admin in are automatically upgraded to support 300 members.", + }, + proLongerMessages: { + en: "Longer Messages", + }, + proLongerMessagesDescription: { + en: "You can send messages up to 10,000 characters in all conversations.", + }, proMessageInfoFeatures: { en: "This message used the following Session Pro features:", }, + proPlanNotFound: { + en: "Pro Plan Not Found", + }, + proPlanNotFoundDescription: { + en: "No active plan was found for your account. If you believe this is a mistake, please reach out to Session support for assistance.", + }, + proPlanRecover: { + en: "Recover Pro Plan", + }, + proPlanRenew: { + en: "Renew Pro Plan", + }, + proPlanRenewStart: { + en: "Renew your Session Pro plan to start using powerful Session Pro features again.", + }, + proPlanRenewSupport: { + en: "Your Session Pro plan has been renewed! Thank you for supporting the Session Network.", + }, + proPlanRestored: { + en: "Pro Plan Restored", + }, + proPlanRestoredDescription: { + en: "A valid plan for Session Pro was detected and your Pro status has been restored!", + }, + proRefundDescription: { + en: "We’re sorry to see you go. Here's what you need to know before requesting a refund.", + }, + proRefundRequestSessionSupport: { + en: "Your refund request will be handled by Session Support.

Request a refund by hitting the button below and completing the refund request form.

While Session Support strives to process refund requests within 24-72 hours, processing may take longer during times of high request volume.", + }, + proRefunding: { + en: "Refunding Pro", + }, + proRequestedRefund: { + en: "Refund Requested", + }, proSendMore: { en: "Send more with", }, + proSettings: { + en: "Pro Settings", + }, + proStats: { + en: "Your Pro Stats", + }, + proStatsTooltip: { + en: "Pro stats reflect usage on this device and may appear differently on linked devices", + }, + proSupportDescription: { + en: "Need help with your Pro plan? Submit a request to the support team.", + }, + proUnlimitedPins: { + en: "Unlimited Pins", + }, + proUnlimitedPinsDescription: { + en: "Organize all your chats with unlimited pinned conversations.", + }, proUserProfileModalCallToAction: { en: "Want to get more out of Session? Upgrade to Session Pro for a more powerful messaging experience.", }, @@ -3359,7 +3672,7 @@ export const simpleDictionaryNoArgs: Record< en: "Enter your recovery password to load your account. If you haven't saved it, you can find it in your app settings.", }, recoveryPasswordView: { - en: "View Password", + en: "View Recovery Password", }, recoveryPasswordVisibility: { en: "Recovery Password Visibility", @@ -3382,9 +3695,15 @@ export const simpleDictionaryNoArgs: Record< removePasswordModalDescription: { en: "Remove your current password for Session. Locally stored data will be re-encrypted with a randomly generated key, stored on your device.", }, + renew: { + en: "Renew", + }, reply: { en: "Reply", }, + requestRefund: { + en: "Request Refund", + }, resend: { en: "Resend", }, @@ -3484,6 +3803,12 @@ export const simpleDictionaryNoArgs: Record< sessionConversations: { en: "Conversations", }, + sessionDownloadUrl: { + en: "https://getsession.org/download", + }, + sessionFoundation: { + en: "Session Foundation", + }, sessionHelp: { en: "Help", }, @@ -3529,6 +3854,9 @@ export const simpleDictionaryNoArgs: Record< sessionPrivacy: { en: "Privacy", }, + sessionProBeta: { + en: "Session Pro Beta", + }, sessionRecoveryPassword: { en: "Recovery Password", }, @@ -3544,9 +3872,15 @@ export const simpleDictionaryNoArgs: Record< setPasswordModalDescription: { en: "Set a password for Session. Locally stored data will be encrypted with this password. You will be asked to enter this password each time Session starts.", }, + settingsCannotChangeDesktop: { + en: "Cannot Update Setting", + }, settingsRestartDescription: { en: "You must restart Session to apply your new settings.", }, + settingsStartCategoryDesktop: { + en: "Startup", + }, share: { en: "Share", }, @@ -3583,6 +3917,9 @@ export const simpleDictionaryNoArgs: Record< spellChecker: { en: "Spell Checker", }, + stakingRewardPool: { + en: "Staking Reward Pool", + }, stickers: { en: "Stickers", }, @@ -3607,9 +3944,18 @@ export const simpleDictionaryNoArgs: Record< theError: { en: "Error", }, + theReturn: { + en: "Return", + }, themePreview: { en: "Theme Preview", }, + tokenNameLong: { + en: "Session Token", + }, + tokenNameShort: { + en: "SESH", + }, tooltipBlindedIdCommunities: { en: "Blinded IDs are used in communities to reduce spam and increase privacy", }, @@ -3673,6 +4019,12 @@ export const simpleDictionaryNoArgs: Record< updateNewVersion: { en: "A new version of Session is available, tap to update", }, + updatePlan: { + en: "Update Plan", + }, + updatePlanTwo: { + en: "Two ways to update your plan:", + }, updateProfileInformation: { en: "Update Profile Information", }, @@ -3706,6 +4058,12 @@ export const simpleDictionaryNoArgs: Record< urlOpenBrowser: { en: "This will open in your browser.", }, + urlOpenDescriptionAlternative: { + en: "Links will open in your browser.", + }, + usdNameShort: { + en: "USD", + }, useFastMode: { en: "Use Fast Mode", }, @@ -4186,18 +4544,123 @@ export const simpleDictionaryWithArgs: Record< }, notificationsSystem: { en: "{message_count} new messages in {conversation_count} conversations", + }, + onDevice: { + en: "On your {device_type} device", + }, + onDeviceDescription: { + en: "Open this Session account on an {device_type} device logged into the {platform_account} you originally signed up with. Then, change your plan via the Session Pro settings.", }, onboardingBubbleCreatingAnAccountIsEasy: { en: "Creating an account is instant, free, and anonymous {emoji}", }, onboardingBubbleWelcomeToSession: { en: "Welcome to Session {emoji}", + }, + openStoreWebsite: { + en: "Open {platform_store} Website", }, passwordErrorLength: { en: "Password must be between {min} and {max} characters long", + }, + plusLoadsMoreDescription: { + en: "New features coming soon to Pro. Discover what's next on the Pro Roadmap {icon}", + }, + proAllSetDescription: { + en: "Your Session Pro plan was updated! You will be billed when your current Pro plan is automatically renewed on {date}.", + }, + proAutoRenewTime: { + en: "Pro auto-renewing in {time}", + }, + proBilledAnnually: { + en: "{price} Billed Annually", + }, + proBilledMonthly: { + en: "{price} Billed Monthly", + }, + proBilledQuarterly: { + en: "{price} Billed Quarterly", + }, + proDiscountTooltip: { + en: "Your current plan is already discounted by {percent}% of the full Session Pro price.", + }, + proExpiringSoonDescription: { + en: "Your Pro plan is expiring in {time}. Update your plan to keep accessing the exclusive perks and features of Session Pro.", + }, + proExpiringTime: { + en: "Pro expiring in {time}", + }, + proPercentOff: { + en: "{percent}% Off", + }, + proPlanActivatedAuto: { + en: "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}. Updates to your plan take effect when Pro is next renewed.", + }, + proPlanActivatedAutoShort: { + en: "Your Session Pro plan is active!

Your plan will automatically renew for another {current_plan} on {date}.", + }, + proPlanActivatedNotAuto: { + en: "Your Session Pro plan will expire on {date}.

Update your plan now to ensure uninterrupted access to exclusive Pro features.", + }, + proPlanExpireDate: { + en: "Your Session Pro plan will expire on {date}.", + }, + proPlanPlatformRefund: { + en: "Because you originally signed up for Session Pro via the {platform_store} Store, you'll need to use the same {platform_account} to request a refund.", + }, + proPlanPlatformRefundLong: { + en: "Because you originally signed up for Session Pro via the {platform_store} Store, your refund request will be processed by Session Support.

Request a refund by hitting the button below and completing the refund request form.

While Session Support strives to process refund requests within 24-72 hours, processing may take longer during times of high request volume.", + }, + proPlanRenewDesktop: { + en: "Currently, Pro plans can only be purchased and renewed via the {platform_store} or {platform_store} Stores. Because you are using Session Desktop, you're not able to renew your plan here.

Session Pro developers are working hard on alternative payment options to allow users to purchase Pro plans outside of the {platform_store} and {platform_store} Stores. Pro Roadmap", + }, + proPlanRenewDesktopLinked: { + en: "Renew your plan in the Session Pro settings on a linked device with Session installed via the {platform_store} or {platform_store} Store.", + }, + proPlanRenewDesktopStore: { + en: "Renew your plan on the {platform_store} website using the {platform_account} you signed up for Pro with.", + }, + proPlanSignUp: { + en: "Because you originally signed up for Session Pro via the {platform_store} Store, you'll need to use your {platform_account} to update your plan.", + }, + proPriceOneMonth: { + en: "1 Month - {monthly_price} / Month", + }, + proPriceThreeMonths: { + en: "3 Months - {monthly_price} / Month", + }, + proPriceTwelveMonths: { + en: "12 Months - {monthly_price} / Month", + }, + proRefundNextSteps: { + en: "{platform_account} is now processing your refund request. This typically takes 24-48 hours. Depending on their decision, you may see your Pro status change in Session.", + }, + proRefundRequestStorePolicies: { + en: "Your refund request will be handled exclusively by {platform_account} through the {platform_account} website.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + }, + proRefundSupport: { + en: "Please contact {platform_account} for further updates on your refund request. Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests.

{platform_store} Refund Support", + }, + proRefundingDescription: { + en: "Refunds for Session Pro plans are handled exclusively by {platform_account} through the {platform_store} Store.

Due to {platform_account} refund policies, Session developers have no ability to influence the outcome of refund requests. This includes whether the request is approved or denied, as well as whether a full or partial refund is issued.", + }, + proTosPrivacy: { + en: "By updating, you agree to the Session Pro Terms of Service {icon} and Privacy Policy {icon}", + }, + proUpdatePlanDescription: { + en: "You are currently on the {current_plan} Plan. Are you sure you want to switch to the {selected_plan} Plan?

By updating, your plan will automatically renew on {date} for an additional {selected_plan} of Pro access.", + }, + proUpdatePlanExpireDescription: { + en: "Your plan will expire on {date}.

By updating, your plan will automatically renew on {date} for an additional {selected_plan} of Pro access.", + }, + processingRefundRequest: { + en: "{platform_account} is processing your refund request", }, rateSessionModalDescription: { en: "We're glad you're enjoying Session, if you have a moment, rating us in the {storevariant} helps others discover private, secure messaging!", + }, + refundPlanNonOriginatorApple: { + en: "Because you originally signed up for Session Pro via a different {platform_account}, you'll need to use that {platform_account} to update your plan.", }, remainingCharactersOverTooltip: { en: "Reduce message length by {count}", @@ -4207,6 +4670,9 @@ export const simpleDictionaryWithArgs: Record< }, searchMatchesNoneSpecific: { en: "No results found for {query}", + }, + sessionNetworkDataPrice: { + en: "Price data powered by CoinGecko
Accurate at {date_time}", }, sessionNetworkDescription: { en: "Messages are sent using the Session Network. The network is comprised of nodes incentivized with Session Token, which keeps Session decentralized and secure. Learn More {icon}", @@ -4232,8 +4698,11 @@ export const simpleDictionaryWithArgs: Record< urlOpenDescription: { en: "Are you sure you want to open this URL in your browser?

{url}", }, - sessionNetworkDataPrice: { - en: "Price data powered by CoinGecko
Accurate at {date_time}", + viaStoreWebsite: { + en: "Via the {platform_store} website", + }, + viaStoreWebsiteDescription: { + en: "Change your plan using the {platform_account} you used to sign up with, via the {platform_store} website.", }, } as const; @@ -4370,6 +4839,30 @@ export const pluralsDictionaryWithArgs = { other: "Messages have a character limit of {limit} characters. You have {count} characters remaining." }, }, + proBadgesSent: { + en:{ + one: "{total} Pro Badge Sent", + other: "{total} Pro Badges Sent" + }, + }, + proGroupsUpgraded: { + en:{ + one: "{total} Group Upgraded", + other: "{total} Groups Upgraded" + }, + }, + proLongerMessagesSent: { + en:{ + one: "{total} Longer Message Sent", + other: "{total} Longer Messages Sent" + }, + }, + proPinnedConversations: { + en:{ + one: "{total} Pinned Conversation", + other: "{total} Pinned Conversations" + }, + }, promotionFailed: { en:{ one: "Promotion Failed", From 7ae3649a8c954aafc926c5951fdd9050d51bc21d Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 3 Sep 2025 17:10:38 +1000 Subject: [PATCH 13/32] refactor: keep fixing them tests --- tests/automation/call_checks.spec.ts | 2 +- .../disappearing_message_checks.spec.ts | 2 +- tests/automation/locators/index.ts | 5 +++ tests/automation/message_checks.spec.ts | 13 +++---- tests/automation/types/testing.ts | 6 ++-- tests/automation/utilities/send_media.ts | 12 ++++--- tests/automation/utilities/voice_call.ts | 35 +++++++------------ 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/tests/automation/call_checks.spec.ts b/tests/automation/call_checks.spec.ts index 9bf75d3..d4216a9 100644 --- a/tests/automation/call_checks.spec.ts +++ b/tests/automation/call_checks.spec.ts @@ -8,7 +8,7 @@ test_Alice_1W_Bob_1W( 'Voice calls', async ({ alice, aliceWindow1, bob, bobWindow1 }) => { await createContact(aliceWindow1, bobWindow1, alice, bob); - await makeVoiceCall(aliceWindow1, bobWindow1, alice, bob); + await makeVoiceCall(aliceWindow1, bobWindow1); // In the receivers window, the message is 'Call in progress' await waitForTestIdWithText( bobWindow1, diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index 3a4c3e4..87068bc 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -327,7 +327,7 @@ test_Alice_1W_Bob_1W( .toString(), ), ]); - await makeVoiceCall(aliceWindow1, bobWindow1, alice, bob); + await makeVoiceCall(aliceWindow1, bobWindow1); // In the receivers window, the message is 'Call in progress' await Promise.all([ waitForTestIdWithText( diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 0beba47..996d922 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -47,6 +47,8 @@ export class HomeScreen extends Locator { export class Conversation extends Locator { static readonly messageInput = this.testId('message-input-text-area'); + static readonly microphoneButton = this.testId('microphone-button'); + static readonly endVoiceMessageButton = this.testId('end-voice-message'); static readonly acceptMessageRequestButton = this.testId( 'accept-message-request', ); @@ -59,6 +61,7 @@ export class Conversation extends Locator { static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', ); + static readonly callButton = this.testId('call-button') static readonly conversationSettingsIcon = this.testId( 'conversation-options-avatar', ); @@ -85,6 +88,8 @@ export class Settings extends Locator { 'clear-data-settings-menu-item', ); // Privacy + static readonly enableCalls = this.testId('enable-calls-settings-row'); + static readonly enableMicrophone = this.testId('enable-microphone-settings-row') static readonly setPasswordSettingsButton = this.testId( 'set-password-settings-button', ); diff --git a/tests/automation/message_checks.spec.ts b/tests/automation/message_checks.spec.ts index 36797e2..c3c5008 100644 --- a/tests/automation/message_checks.spec.ts +++ b/tests/automation/message_checks.spec.ts @@ -2,6 +2,7 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; import { testCommunityName } from './constants/community'; import { longText, mediaArray, testLink } from './constants/variables'; +import { Conversation, Global, HomeScreen } from './locators'; import { newUser } from './setup/new_user'; import { sessionTestTwoWindows, @@ -121,25 +122,25 @@ test_Alice_1W_Bob_1W( async ({ alice, aliceWindow1, bob, bobWindow1 }) => { await createContact(aliceWindow1, bobWindow1, alice, bob); await joinCommunity(aliceWindow1); - await clickOnTestIdWithText(aliceWindow1, 'conversation-options-avatar'); + await clickOnTestIdWithText(aliceWindow1, Conversation.conversationSettingsIcon.selector); await clickOnTestIdWithText(aliceWindow1, 'invite-contacts-menu-option'); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnTestIdWithText(aliceWindow1, 'contact', bob.userName); - await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); + await clickOnTestIdWithText(aliceWindow1, Global.contactItem.selector, bob.userName); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // For lack of a unique ID we use native Playwright methods await aliceWindow1 .getByTestId('invite-contacts-dialog') - .getByTestId('modal-close-button') + .getByTestId(Global.modalCloseButton.selector) .click(); // Close UCS modal - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); await Promise.all([ diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index dfe2d09..84a4e64 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -121,8 +121,8 @@ export type DataTestId = | 'edit-group-name' | 'edit-profile-icon' | 'empty-conversation-notification' - | 'enable-calls' - | 'enable-microphone' + | 'enable-calls-settings-row' + | 'enable-microphone-settings-row' | 'enable-read-receipts' | 'end-call' | 'end-voice-message' @@ -195,4 +195,4 @@ export type DataTestId = | 'your-profile-name' | `input-${DMTimeOption}`; -export type ModalId = 'blockOrUnblockModal' | 'userSettingsModal'; +export type ModalId = 'blockOrUnblockModal' | 'confirmModal' | 'userSettingsModal'; diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index 0915d63..9085e2a 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -2,6 +2,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; +import { Conversation, Global, Settings } from '../locators'; import { MediaType } from '../types/testing'; import { waitForSentTick } from './message'; import { @@ -31,12 +32,13 @@ export const sendMedia = async ( }; export const sendVoiceMessage = async (window: Page) => { - await clickOnTestIdWithText(window, 'microphone-button'); - await clickOnTestIdWithText(window, 'session-toast'); - await clickOnTestIdWithText(window, 'enable-microphone'); - await clickOnTestIdWithText(window, 'microphone-button'); + await clickOnTestIdWithText(window, Conversation.microphoneButton.selector); + await clickOnTestIdWithText(window, Global.toast.selector); + await clickOnTestIdWithText(window, Settings.enableMicrophone.selector); + await clickOnTestIdWithText(window, Global.modalCloseButton.selector); + await clickOnTestIdWithText(window, Conversation.microphoneButton.selector); await sleepFor(5000); - await clickOnTestIdWithText(window, 'end-voice-message'); + await clickOnTestIdWithText(window, Conversation.endVoiceMessageButton.selector); await sleepFor(4000); await clickOnElement({ window, diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index 94b5247..1059753 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -2,7 +2,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; -import { User } from '../types/testing'; +import { Conversation, Global, Settings } from '../locators'; import { checkModalStrings, clickOnMatchingText, @@ -12,43 +12,34 @@ import { export const makeVoiceCall = async ( callerWindow: Page, receiverWindow: Page, - caller: User, - receiver: User, ) => { - await clickOnTestIdWithText(callerWindow, 'call-button'); - await clickOnTestIdWithText(callerWindow, 'session-toast'); - await clickOnTestIdWithText(callerWindow, 'enable-calls'); + await clickOnTestIdWithText(callerWindow, Conversation.callButton.selector); + await clickOnTestIdWithText(callerWindow, Global.toast.selector); + await clickOnTestIdWithText(callerWindow, Settings.enableCalls.selector); await checkModalStrings( callerWindow, englishStrippedStr('callsVoiceAndVideoBeta').toString(), englishStrippedStr('callsVoiceAndVideoModalDescription').toString(), + 'confirmModal', ); - await clickOnTestIdWithText(callerWindow, 'session-confirm-ok-button'); - await clickOnTestIdWithText( - callerWindow, - 'module-conversation__user__profile-name', - receiver.userName, - ); - await clickOnTestIdWithText(callerWindow, 'call-button'); + await clickOnTestIdWithText(callerWindow, Global.confirmButton.selector); + await clickOnTestIdWithText(callerWindow, Global.modalCloseButton.selector); + await clickOnTestIdWithText(callerWindow, Conversation.callButton.selector); // Enable calls in window B - await clickOnTestIdWithText(receiverWindow, 'session-toast'); - await clickOnTestIdWithText(receiverWindow, 'enable-calls'); - // Getting wrong strings from locales.ts file + await clickOnTestIdWithText(receiverWindow, Global.toast.selector); + await clickOnTestIdWithText(receiverWindow, Settings.enableCalls.selector); await checkModalStrings( receiverWindow, englishStrippedStr('callsVoiceAndVideoBeta').toString(), englishStrippedStr('callsVoiceAndVideoModalDescription').toString(), + 'confirmModal', ); - await clickOnTestIdWithText(receiverWindow, 'session-confirm-ok-button'); + await clickOnTestIdWithText(receiverWindow, Global.confirmButton.selector); await clickOnMatchingText( receiverWindow, englishStrippedStr('accept').toString(), ); - await clickOnTestIdWithText( - receiverWindow, - 'module-conversation__user__profile-name', - caller.userName, - ); + await clickOnTestIdWithText(receiverWindow, Global.modalCloseButton.selector); await sleepFor(5000); await clickOnTestIdWithText(callerWindow, 'end-call'); }; From 00eb0b795013498b075146d9f807551856a6c39c Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 11:24:28 +1000 Subject: [PATCH 14/32] chore: more refactoring tests --- tests/automation/linked_device_group.spec.ts | 114 +++++++++++++------ tests/automation/linked_device_user.spec.ts | 29 ++--- tests/automation/locators/index.ts | 11 +- tests/automation/message_checks.spec.ts | 11 +- tests/automation/types/testing.ts | 6 +- tests/automation/user_actions.spec.ts | 66 +++++------ tests/automation/utilities/send_media.ts | 5 +- 7 files changed, 157 insertions(+), 85 deletions(-) diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 6937486..0800836 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -1,7 +1,13 @@ import type { Page } from '@playwright/test'; import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { LeftPane } from './locators'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; import { openApp } from './setup/open'; import { recoverFromSeed } from './setup/recovery_using_seed'; import { @@ -13,7 +19,6 @@ import { checkModalStrings, clickOnMatchingText, clickOnTestIdWithText, - waitForLoadingAnimationToFinish, waitForTestIdWithText, } from './utilities/utils'; @@ -133,26 +138,27 @@ async function clearDataOnWindow(window: Page) { // Click on clear data option on left pane await clickOnTestIdWithText( window, - 'clear-data-settings-menu-item', + Settings.clearDataMenuItem.selector, englishStrippedStr('sessionClearData').toString(), ); await checkModalStrings( window, englishStrippedStr('clearDataAll').toString(), englishStrippedStr('clearDataAllDescription').toString(), + 'deleteAccountModal', ); await clickOnTestIdWithText( window, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('clear').toString(), ); await checkModalStrings( window, englishStrippedStr('clearDataAll').toString(), englishStrippedStr('clearDeviceDescription').toString(), + 'deleteAccountModal', ); await clickOnMatchingText(window, englishStrippedStr('clear').toString()); - await waitForLoadingAnimationToFinish(window, 'loading-spinner'); } // Delete device data > Restore account @@ -166,36 +172,50 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Does group appear? await waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check group for members, conversation name and messages await clickOnTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check header name await waitForTestIdWithText( aliceWindow2, - 'header-conversation-name', + Conversation.conversationHeader.selector, groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText(aliceWindow2, 'conversation-options-avatar'); - await clickOnTestIdWithText(aliceWindow2, 'manage-members-menu-option'); + await clickOnTestIdWithText( + aliceWindow2, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + aliceWindow2, + Conversation.manageMembersOption.selector, + ); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( aliceWindow2, - 'contact', + Global.contactItem.selector, englishStrippedStr('you').toString(), ), - waitForTestIdWithText(aliceWindow2, 'contact', bob.userName), - waitForTestIdWithText(aliceWindow2, 'contact', charlie.userName), + waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + bob.userName, + ), + waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + charlie.userName, + ), ]); - await clickOnTestIdWithText(aliceWindow2, 'session-confirm-cancel-button'); - await clickOnTestIdWithText(aliceWindow2, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow2, Global.cancelButton.selector); + await clickOnTestIdWithText(aliceWindow2, Global.modalCloseButton.selector); // Delete device data on alicewindow2 await clearDataOnWindow(aliceWindow2); const [restoredWindow] = await openApp(1); @@ -203,40 +223,54 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Does group appear? await waitForTestIdWithText( restoredWindow, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check group for members, conversation name and messages await clickOnTestIdWithText( restoredWindow, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check header name await waitForTestIdWithText( restoredWindow, - 'header-conversation-name', + Conversation.conversationHeader.selector, groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText(restoredWindow, 'conversation-options-avatar'); - await clickOnTestIdWithText(restoredWindow, 'manage-members-menu-option'); + await clickOnTestIdWithText( + restoredWindow, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + restoredWindow, + Conversation.manageMembersOption.selector, + ); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( restoredWindow, - 'contact', + Global.contactItem.selector, englishStrippedStr('you').toString(), ), - waitForTestIdWithText(restoredWindow, 'contact', bob.userName), - waitForTestIdWithText(restoredWindow, 'contact', charlie.userName), + waitForTestIdWithText( + restoredWindow, + Global.contactItem.selector, + bob.userName, + ), + waitForTestIdWithText( + restoredWindow, + Global.contactItem.selector, + charlie.userName, + ), ]); // Do it all again + await clickOnTestIdWithText(restoredWindow, Global.cancelButton.selector); await clickOnTestIdWithText( restoredWindow, - 'session-confirm-cancel-button', + Global.modalCloseButton.selector, ); - await clickOnTestIdWithText(restoredWindow, 'modal-close-button'); // Delete device data on restoredWindow await clearDataOnWindow(restoredWindow); const [restoredWindow2] = await openApp(1); @@ -244,33 +278,47 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Does group appear? await waitForTestIdWithText( restoredWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check group for members, conversation name and messages await clickOnTestIdWithText( restoredWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check header name await waitForTestIdWithText( restoredWindow2, - 'header-conversation-name', + Conversation.conversationHeader.selector, groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText(restoredWindow2, 'conversation-options-avatar'); - await clickOnTestIdWithText(restoredWindow2, 'manage-members-menu-option'); + await clickOnTestIdWithText( + restoredWindow2, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + restoredWindow2, + Conversation.manageMembersOption.selector, + ); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( restoredWindow2, - 'contact', + Global.contactItem.selector, englishStrippedStr('you').toString(), ), - waitForTestIdWithText(restoredWindow2, 'contact', bob.userName), - waitForTestIdWithText(restoredWindow2, 'contact', charlie.userName), + waitForTestIdWithText( + restoredWindow2, + Global.contactItem.selector, + bob.userName, + ), + waitForTestIdWithText( + restoredWindow2, + Global.contactItem.selector, + charlie.userName, + ), ]); }, ); diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index c2c5e46..3e63154 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -30,7 +30,6 @@ import { hasElementBeenDeleted, hasTextMessageBeenDeleted, typeIntoInput, - waitForLoadingAnimationToFinish, waitForMatchingPlaceholder, waitForMatchingText, waitForTestIdWithText, @@ -86,19 +85,20 @@ test_Alice_2W( 'Changed username syncs', async ({ aliceWindow1, aliceWindow2 }) => { const newUsername = 'Tiny bubble'; - await clickOnTestIdWithText(aliceWindow1, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Click on pencil icon - await clickOnTestIdWithText(aliceWindow1, 'edit-profile-icon'); + await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); // Replace old username with new username - await typeIntoInput(aliceWindow1, 'profile-name-input', newUsername); + await typeIntoInput( + aliceWindow1, + Settings.displayNameInput.selector, + newUsername, + ); // Press enter to confirm change - await clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'save-button-profile-update', - }); - // Wait for loading animation - await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); + await clickOnMatchingText( + aliceWindow1, + englishStrippedStr('save').toString(), + ); // Check username change in window B // Click on profile settings in window B @@ -108,12 +108,15 @@ test_Alice_2W( 500, 'waiting for updated username in profile dialog', async () => { - await clickOnTestIdWithText(aliceWindow2, 'leftpane-primary-avatar'); + await clickOnTestIdWithText( + aliceWindow2, + LeftPane.profileButton.selector, + ); // Verify username has changed to new username try { await waitForTestIdWithText( aliceWindow2, - 'your-profile-name', + Settings.displayName.selector, newUsername, 100, ); diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 996d922..b64a97a 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -46,6 +46,7 @@ export class HomeScreen extends Locator { } export class Conversation extends Locator { + static readonly conversationHeader = this.testId('header-conversation-name'); static readonly messageInput = this.testId('message-input-text-area'); static readonly microphoneButton = this.testId('microphone-button'); static readonly endVoiceMessageButton = this.testId('end-voice-message'); @@ -61,10 +62,13 @@ export class Conversation extends Locator { static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', ); - static readonly callButton = this.testId('call-button') + static readonly callButton = this.testId('call-button'); static readonly conversationSettingsIcon = this.testId( 'conversation-options-avatar', ); + static readonly manageMembersOption = this.testId( + 'manage-members-menu-option', + ); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } @@ -89,7 +93,9 @@ export class Settings extends Locator { ); // Privacy static readonly enableCalls = this.testId('enable-calls-settings-row'); - static readonly enableMicrophone = this.testId('enable-microphone-settings-row') + static readonly enableMicrophone = this.testId( + 'enable-microphone-settings-row', + ); static readonly setPasswordSettingsButton = this.testId( 'set-password-settings-button', ); @@ -124,6 +130,7 @@ export class Global extends Locator { static readonly backButton = this.testId('back-button'); static readonly toast = this.testId('session-toast'); static readonly confirmButton = this.testId('session-confirm-ok-button'); + static readonly cancelButton = this.testId('session-confirm-cancel-button'); static readonly errorMessage = this.testId('error-message'); static readonly contactItem = this.testId( 'module-contact-name__profile-name', diff --git a/tests/automation/message_checks.spec.ts b/tests/automation/message_checks.spec.ts index c3c5008..2105ec6 100644 --- a/tests/automation/message_checks.spec.ts +++ b/tests/automation/message_checks.spec.ts @@ -122,14 +122,21 @@ test_Alice_1W_Bob_1W( async ({ alice, aliceWindow1, bob, bobWindow1 }) => { await createContact(aliceWindow1, bobWindow1, alice, bob); await joinCommunity(aliceWindow1); - await clickOnTestIdWithText(aliceWindow1, Conversation.conversationSettingsIcon.selector); + await clickOnTestIdWithText( + aliceWindow1, + Conversation.conversationSettingsIcon.selector, + ); await clickOnTestIdWithText(aliceWindow1, 'invite-contacts-menu-option'); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnTestIdWithText(aliceWindow1, Global.contactItem.selector, bob.userName); + await clickOnTestIdWithText( + aliceWindow1, + Global.contactItem.selector, + bob.userName, + ); await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // For lack of a unique ID we use native Playwright methods await aliceWindow1 diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 84a4e64..9511cb5 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -195,4 +195,8 @@ export type DataTestId = | 'your-profile-name' | `input-${DMTimeOption}`; -export type ModalId = 'blockOrUnblockModal' | 'confirmModal' | 'userSettingsModal'; +export type ModalId = + | 'blockOrUnblockModal' + | 'confirmModal' + | 'deleteAccountModal' + | 'userSettingsModal'; diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index 0d785a3..3085b19 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -2,7 +2,13 @@ import { expect } from '@playwright/test'; import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; -import { Global, HomeScreen, LeftPane, Settings } from './locators'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; import { newUser } from './setup/new_user'; import { sessionTestTwoWindows, @@ -36,13 +42,14 @@ sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { // Navigate to contacts tab in User B's window await waitForTestIdWithText( windowB, - 'message-request-response-message', + Conversation.messageRequestAcceptControlMessage.selector, englishStrippedStr('messageRequestYouHaveAccepted') .withArgs({ name: userA.userName, }) .toString(), ); + await clickOnTestIdWithText(windowB, Global.backButton.selector); await Promise.all([ clickOnElement({ window: windowA, @@ -56,16 +63,8 @@ sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { }), ]); await Promise.all([ - waitForTestIdWithText( - windowA, - 'module-conversation__user__profile-name', - userB.userName, - ), - waitForTestIdWithText( - windowB, - 'module-conversation__user__profile-name', - userA.userName, - ), + waitForTestIdWithText(windowA, Global.contactItem.selector, userB.userName), + waitForTestIdWithText(windowB, Global.contactItem.selector, userA.userName), ]); }); @@ -172,8 +171,7 @@ test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { aliceWindow1, englishStrippedStr('save').toString(), ); - // Wait for Copy button to appear to verify username change - await aliceWindow1.isVisible(`'${englishStrippedStr('copy').toString()}'`); + await sleepFor(1000); // verify name change expect( await aliceWindow1.innerText( @@ -341,41 +339,43 @@ test_Alice_1W_Bob_1W( async ({ aliceWindow1, bobWindow1, alice, bob }) => { // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); - // Confirm contact by checking Messages tab (name should appear in list) - await Promise.all([ - clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'new-conversation-button', - }), - clickOnElement({ - window: bobWindow1, - strategy: 'data-testid', - selector: 'new-conversation-button', - }), - ]); + await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); + await Promise.all( + [aliceWindow1, bobWindow1].map((w) => + clickOnElement({ + window: w, + strategy: 'data-testid', + selector: 'new-conversation-button', + }), + ), + ); await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + Global.contactItem.selector, bob.userName, ), waitForTestIdWithText( bobWindow1, - 'module-conversation__user__profile-name', + Global.contactItem.selector, alice.userName, ), ]); + await Promise.all( + [aliceWindow1, bobWindow1].map((w) => + clickOnTestIdWithText(w, Global.backButton.selector), + ), + ); // Delete contact await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, true, ); await clickOnTestIdWithText( aliceWindow1, - 'context-menu-item', + Global.contextMenuItem.selector, englishStrippedStr('conversationsDelete').toString(), ); await checkModalStrings( @@ -387,14 +387,14 @@ test_Alice_1W_Bob_1W( ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('delete').toString(), ); // Check if conversation is deleted await hasElementBeenDeleted( aliceWindow1, 'data-testid', - 'module-conversation__user__profile-name', + Global.contactItem.selector, 1000, bob.userName, ); diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index 9085e2a..e36c50b 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -38,7 +38,10 @@ export const sendVoiceMessage = async (window: Page) => { await clickOnTestIdWithText(window, Global.modalCloseButton.selector); await clickOnTestIdWithText(window, Conversation.microphoneButton.selector); await sleepFor(5000); - await clickOnTestIdWithText(window, Conversation.endVoiceMessageButton.selector); + await clickOnTestIdWithText( + window, + Conversation.endVoiceMessageButton.selector, + ); await sleepFor(4000); await clickOnElement({ window, From af6e4d3b512249ffbd62314c46219d0953b6f8d6 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 13:58:08 +1000 Subject: [PATCH 15/32] feat: add perfectionist/sort-classes rule --- .eslintrc.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index b779df9..5bb1d0c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -56,6 +56,12 @@ module.exports = { 'perfectionist/sort-imports': 'error', 'perfectionist/sort-named-imports': 'error', + 'perfectionist/sort-classes': [ + 'error', + { + partitionByComment: true, + }, + ], 'perfectionist/sort-union-types': [ 'error', { From cba535b3aaad8e9ac01c82a55f98ad31f9311a61 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 14:19:41 +1000 Subject: [PATCH 16/32] refactor: keep fixing them tests --- .../avatar-updated-blue-darwin.jpeg | 4 +- sessionReporter.ts | 106 +++++++++--------- .../automation/enforce_localized_str.spec.ts | 2 +- .../automation/linked_device_requests.spec.ts | 12 +- tests/automation/linked_device_user.spec.ts | 96 ++++++++-------- tests/automation/locators/index.ts | 89 +++++++++------ tests/automation/types/testing.ts | 2 +- tests/automation/user_actions.spec.ts | 63 +++++++---- tests/automation/utilities/message.ts | 15 +++ tests/automation/utilities/utils.ts | 10 +- 10 files changed, 226 insertions(+), 173 deletions(-) diff --git a/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg b/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg index 0d83659..b3548a9 100644 --- a/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg +++ b/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02b450cb82f4004714d796c79a45787329fc1dc68f6c371795bac9664e107f1e -size 944 +oid sha256:bfda79de8430bec68485159710f2832b4959056e3a464fa342047b65529f9c29 +size 1851 diff --git a/sessionReporter.ts b/sessionReporter.ts index 3765d4d..4c6e4ef 100644 --- a/sessionReporter.ts +++ b/sessionReporter.ts @@ -75,14 +75,14 @@ function printFailedTestLogs() { } class SessionReporter implements Reporter { - private startTime = 0; + private allResults: Array = []; private allTestsCount = 0; - private allResults: Array = []; - private countWorkers = 1; + private startTime = 0; + onBegin(config: FullConfig, suite: Suite) { this.allTestsCount = suite.allTests().length; this.countWorkers = config.workers; @@ -93,6 +93,56 @@ class SessionReporter implements Reporter { this.startTime = Date.now(); } + onEnd(result: FullResult) { + console.log( + chalk.bgWhiteBright.black( + `\n\n\n\t\tFinished the run: ${result.status}, count of tests run: ${ + this.allResults.length + }, took ${Math.floor( + (Date.now() - this.startTime) / (60 * 1000), + )} minute(s)`, + ), + ); + const { allFailedSoFar, allPassedSoFar, partiallyPassed } = + this.groupResultsByTestName(); + + sortByTitle(allPassedSoFar).forEach((m) => formatGroupedByResults(m)); + sortByTitle(partiallyPassed).forEach((m) => formatGroupedByResults(m)); + sortByTitle(allFailedSoFar).forEach((m) => formatGroupedByResults(m)); + } + + onError?(error: TestError) { + console.info('global error:', error); + } + + onStdErr?( + chunk: Buffer | string, + test: TestCase | void, + _result: TestResult | void, + ) { + if (printOngoingTestLogs()) { + process.stdout.write( + `"${test ? `${chalk.cyanBright(test.title)}` : ''}":err: ${ + isString(chunk) ? chunk : chunk.toString('utf-8') + }`, + ); + } + } + + onStdOut?( + chunk: Buffer | string, + test: TestCase | void, + _result: TestResult | void, + ) { + if (printOngoingTestLogs()) { + process.stdout.write( + `"${test ? `${chalk.cyanBright(test.title)}` : ''}": ${ + isString(chunk) ? chunk : chunk.toString('utf-8') + }`, + ); + } + } + onTestBegin(test: TestCase, result: TestResult) { console.log( chalk.magenta( @@ -201,56 +251,6 @@ class SessionReporter implements Reporter { ), }; } - - onEnd(result: FullResult) { - console.log( - chalk.bgWhiteBright.black( - `\n\n\n\t\tFinished the run: ${result.status}, count of tests run: ${ - this.allResults.length - }, took ${Math.floor( - (Date.now() - this.startTime) / (60 * 1000), - )} minute(s)`, - ), - ); - const { allFailedSoFar, allPassedSoFar, partiallyPassed } = - this.groupResultsByTestName(); - - sortByTitle(allPassedSoFar).forEach((m) => formatGroupedByResults(m)); - sortByTitle(partiallyPassed).forEach((m) => formatGroupedByResults(m)); - sortByTitle(allFailedSoFar).forEach((m) => formatGroupedByResults(m)); - } - - onStdOut?( - chunk: Buffer | string, - test: TestCase | void, - _result: TestResult | void, - ) { - if (printOngoingTestLogs()) { - process.stdout.write( - `"${test ? `${chalk.cyanBright(test.title)}` : ''}": ${ - isString(chunk) ? chunk : chunk.toString('utf-8') - }`, - ); - } - } - - onStdErr?( - chunk: Buffer | string, - test: TestCase | void, - _result: TestResult | void, - ) { - if (printOngoingTestLogs()) { - process.stdout.write( - `"${test ? `${chalk.cyanBright(test.title)}` : ''}":err: ${ - isString(chunk) ? chunk : chunk.toString('utf-8') - }`, - ); - } - } - - onError?(error: TestError) { - console.info('global error:', error); - } } export default SessionReporter; diff --git a/tests/automation/enforce_localized_str.spec.ts b/tests/automation/enforce_localized_str.spec.ts index 546f636..1a5812b 100644 --- a/tests/automation/enforce_localized_str.spec.ts +++ b/tests/automation/enforce_localized_str.spec.ts @@ -240,7 +240,7 @@ function getExpectedStringFromKey( case 'qrView': return 'View QR'; case 'recoveryPasswordView': - return 'View Password'; + return 'View Recovery Password'; case 'deleteConversationDescription': return 'Are you sure you want to delete your conversation with {name}? This will permanently delete all messages and attachments.'; case 'manageMembers': diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 67af5b8..2e7fa7b 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -164,7 +164,11 @@ test_Alice_2W_Bob_1W( aliceWindow1, Settings.blockedContactsButton.selector, ); - await waitForTestIdWithText(aliceWindow1, 'contact', bob.userName); + await waitForTestIdWithText( + aliceWindow1, + Global.contactItem.selector, + bob.userName, + ); // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list await sleepFor(5000); @@ -177,7 +181,11 @@ test_Alice_2W_Bob_1W( aliceWindow2, Settings.blockedContactsButton.selector, ); - await waitForTestIdWithText(aliceWindow2, 'contact', bob.userName); + await waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + bob.userName, + ); await waitForMatchingText(aliceWindow2, bob.userName); }, ); diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index 3e63154..c6d9762 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -30,6 +30,7 @@ import { hasElementBeenDeleted, hasTextMessageBeenDeleted, typeIntoInput, + waitForLoadingAnimationToFinish, waitForMatchingPlaceholder, waitForMatchingText, waitForTestIdWithText, @@ -139,20 +140,20 @@ test_Alice_2W( test_Alice_2W( 'Profile picture syncs', async ({ aliceWindow1, aliceWindow2 }, testinfo) => { - await clickOnTestIdWithText(aliceWindow1, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Click on current profile picture - await waitForTestIdWithText( - aliceWindow1, - 'copy-button-profile-update', - englishStrippedStr('copy').toString(), - ); - + await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); await clickOnTestIdWithText(aliceWindow1, 'image-upload-section'); await clickOnTestIdWithText(aliceWindow1, 'image-upload-click'); // allow for the image to be resized before we try to save it await sleepFor(500); await clickOnTestIdWithText(aliceWindow1, 'save-button-profile-update'); - await waitForTestIdWithText(aliceWindow1, 'loading-spinner'); + await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); + await clickOnMatchingText( + aliceWindow1, + englishStrippedStr('save').toString(), + ); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); if (testinfo.config.updateSnapshots === 'all') { await sleepFor(15000, true); // long time to be sure a poll happened when we want to update the snapshot @@ -161,7 +162,7 @@ test_Alice_2W( } const leftpaneAvatarContainer = await waitForTestIdWithText( aliceWindow2, - 'leftpane-primary-avatar', + LeftPane.profileButton.selector, ); const start = Date.now(); let correctScreenshot = false; @@ -242,11 +243,11 @@ test_Alice_2W_Bob_1W( .withArgs({ count: 1 }) .toString(), ); - await hasTextMessageBeenDeleted(aliceWindow1, messageToDelete, 6000); + await hasTextMessageBeenDeleted(aliceWindow1, messageToDelete, 6_000); // linked device for deleted message // Waiting for message to be removed // Check for linked device - await hasTextMessageBeenDeleted(aliceWindow2, messageToDelete, 10000); + await hasTextMessageBeenDeleted(aliceWindow2, messageToDelete, 30_000); // Still should exist for user B await waitForMatchingText(bobWindow1, messageToDelete); }, @@ -367,50 +368,48 @@ test_Alice_2W_Bob_1W( async ({ alice, aliceWindow1, aliceWindow2, bob, bobWindow1 }) => { // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); - await Promise.all([ - clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'new-conversation-button', - }), - clickOnElement({ - window: bobWindow1, - strategy: 'data-testid', - selector: 'new-conversation-button', - }), - clickOnElement({ - window: aliceWindow2, - strategy: 'data-testid', - selector: 'new-conversation-button', - }), - ]); + await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); + await Promise.all( + [aliceWindow1, aliceWindow2, bobWindow1].map((w) => + clickOnElement({ + window: w, + strategy: 'data-testid', + selector: 'new-conversation-button', + }), + ), + ); await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + Global.contactItem.selector, bob.userName, ), waitForTestIdWithText( bobWindow1, - 'module-conversation__user__profile-name', + Global.contactItem.selector, alice.userName, ), waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + Global.contactItem.selector, bob.userName, ), ]); + await Promise.all( + [aliceWindow1, aliceWindow2, bobWindow1].map((w) => + clickOnTestIdWithText(w, Global.backButton.selector), + ), + ); // Delete contact await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, true, ); await clickOnTestIdWithText( aliceWindow1, - 'context-menu-item', + Global.contextMenuItem.selector, englishStrippedStr('conversationsDelete').toString(), ); await checkModalStrings( @@ -422,29 +421,22 @@ test_Alice_2W_Bob_1W( ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('delete').toString(), ); - // Need to close 'New Conversation' screen - await clickOnTestIdWithText(aliceWindow2, 'new-conversation-button'); // Check if conversation is deleted // Need to wait for deletion to propagate to linked device - await Promise.all([ - hasElementBeenDeleted( - aliceWindow1, - 'data-testid', - 'module-conversation__user__profile-name', - 1000, - bob.userName, - ), - hasElementBeenDeleted( - aliceWindow2, - 'data-testid', - 'module-conversation__user__profile-name', - 10000, - bob.userName, + await Promise.all( + [aliceWindow1, aliceWindow2].map((w) => + hasElementBeenDeleted( + w, + 'data-testid', + HomeScreen.conversationItemName.selector, + 10_000, + bob.userName, + ), ), - ]); + ); }, ); @@ -510,7 +502,7 @@ test_Alice_2W( aliceWindow2, 'data-testid', 'module-conversation__user__profile-name', - 10000, + 15_000, englishStrippedStr('noteToSelf').toString(), ), ]); diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index b64a97a..65ab4a1 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -2,9 +2,9 @@ import { DataTestId, StrategyExtractionObj } from '../types/testing'; export abstract class Locator { - protected static testId(selector: DataTestId) { + protected static className(selector: string): StrategyExtractionObj { return { - strategy: 'data-testid', + strategy: 'class', selector, }; } @@ -16,17 +16,17 @@ export abstract class Locator { }; } - protected static className(selector: string): StrategyExtractionObj { + protected static testId(selector: DataTestId) { return { - strategy: 'class', + strategy: 'data-testid', selector, }; } } export class Onboarding extends Locator { - static readonly iHaveAnAccountButton = this.testId('existing-account-button'); static readonly displayNameInput = this.testId('display-name-input'); + static readonly iHaveAnAccountButton = this.testId('existing-account-button'); static readonly recoveryPhraseInput = this.testId('recovery-phrase-input'); } @@ -36,78 +36,95 @@ export class LeftPane extends Locator { } export class HomeScreen extends Locator { - static readonly newConversationButton = this.testId( - 'new-conversation-button', + // New Conversation + static readonly createGroupOption = this.testId('chooser-new-group'); + static readonly inviteAFriendOption = this.testId('chooser-invite-friend'); + static readonly joinCommunityOption = this.testId('chooser-new-community'); + static readonly newMessageAccountIDInput = this.testId( + 'new-session-conversation', ); - static readonly messageRequestBanner = this.testId('message-request-banner'); + static readonly newMessageNextButton = this.testId( + 'next-new-conversation-button', + ); + static readonly newMessageOption = this.testId( + 'chooser-new-conversation-button', + ); + // Home Screen items static readonly conversationItemName = this.testId( 'module-conversation__user__profile-name', ); + static readonly messageRequestBanner = this.testId('message-request-banner'); + static readonly newConversationButton = this.testId( + 'new-conversation-button', + ); } export class Conversation extends Locator { - static readonly conversationHeader = this.testId('header-conversation-name'); - static readonly messageInput = this.testId('message-input-text-area'); - static readonly microphoneButton = this.testId('microphone-button'); - static readonly endVoiceMessageButton = this.testId('end-voice-message'); static readonly acceptMessageRequestButton = this.testId( 'accept-message-request', ); - static readonly deleteMessageRequestButton = this.testId( - 'delete-message-request', - ); static readonly blockMessageRequestButton = this.testId( 'decline-and-block-message-request', ); - static readonly messageRequestAcceptControlMessage = this.testId( - 'message-request-response-message', - ); static readonly callButton = this.testId('call-button'); + static readonly conversationHeader = this.testId('header-conversation-name'); static readonly conversationSettingsIcon = this.testId( 'conversation-options-avatar', ); + static readonly deleteMessageRequestButton = this.testId( + 'delete-message-request', + ); + static readonly endVoiceMessageButton = this.testId('end-voice-message'); static readonly manageMembersOption = this.testId( 'manage-members-menu-option', ); + static readonly messageInput = this.testId('message-input-text-area'); + static readonly messageRequestAcceptControlMessage = this.testId( + 'message-request-response-message', + ); + static readonly microphoneButton = this.testId('microphone-button'); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } export class Settings extends Locator { // Profile - static readonly displayName = this.testId('your-profile-name'); static readonly accountId = this.testId('your-account-id'); + static readonly displayName = this.testId('your-profile-name'); // Update Profile Information static readonly displayNameInput = this.testId( 'update-profile-info-name-input', ); // Menu items - static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); + static readonly clearDataMenuItem = this.testId( + 'clear-data-settings-menu-item', + ); static readonly conversationsMenuItem = this.testId( 'conversations-settings-menu-item', ); + static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); static readonly recoveryPasswordMenuItem = this.testId( 'recovery-password-settings-menu-item', ); - static readonly clearDataMenuItem = this.testId( - 'clear-data-settings-menu-item', - ); // Privacy + static readonly changePasswordSettingsButton = this.testId( + 'change-password-settings-button', + ); + static readonly confirmPasswordInput = this.testId('password-input-confirm'); static readonly enableCalls = this.testId('enable-calls-settings-row'); static readonly enableMicrophone = this.testId( 'enable-microphone-settings-row', ); - static readonly setPasswordSettingsButton = this.testId( - 'set-password-settings-button', - ); - static readonly changePasswordSettingsButton = this.testId( - 'change-password-settings-button', + static readonly enableReadReceipts = this.testId( + 'enable-read-receipts-settings-row', ); - static readonly setPasswordButton = this.testId('set-password-button'); static readonly passwordInput = this.testId('password-input'); - static readonly confirmPasswordInput = this.testId('password-input-confirm'); static readonly reConfirmPasswordInput = this.testId( 'password-input-reconfirm', ); + static readonly setPasswordButton = this.testId('set-password-button'); + static readonly setPasswordSettingsButton = this.testId( + 'set-password-settings-button', + ); // Conversations static readonly blockedContactsButton = this.testId( 'blocked-contacts-settings-row', @@ -124,16 +141,16 @@ export class Settings extends Locator { } export class Global extends Locator { - static readonly modalCloseButton = this.testId('modal-close-button'); - static readonly modalBackButton = this.testId('modal-back-button'); - static readonly continueButton = this.testId('continue-button'); static readonly backButton = this.testId('back-button'); - static readonly toast = this.testId('session-toast'); - static readonly confirmButton = this.testId('session-confirm-ok-button'); static readonly cancelButton = this.testId('session-confirm-cancel-button'); - static readonly errorMessage = this.testId('error-message'); + static readonly confirmButton = this.testId('session-confirm-ok-button'); static readonly contactItem = this.testId( 'module-contact-name__profile-name', ); static readonly contextMenuItem = this.testId('context-menu-item'); + static readonly continueButton = this.testId('continue-button'); + static readonly errorMessage = this.testId('error-message'); + static readonly modalBackButton = this.testId('modal-back-button'); + static readonly modalCloseButton = this.testId('modal-close-button'); + static readonly toast = this.testId('session-toast'); } diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 9511cb5..23879a6 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -123,7 +123,7 @@ export type DataTestId = | 'empty-conversation-notification' | 'enable-calls-settings-row' | 'enable-microphone-settings-row' - | 'enable-read-receipts' + | 'enable-read-receipts-settings-row' | 'end-call' | 'end-voice-message' | 'error-message' diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index 3085b19..4ade2c2 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -17,7 +17,7 @@ import { test_Alice_2W, } from './setup/sessionTest'; import { createContact } from './utilities/create_contact'; -import { sendMessage } from './utilities/message'; +import { sendMessage, waitForReadTick } from './utilities/message'; import { checkModalStrings, clickOnElement, @@ -216,7 +216,7 @@ test_Alice_1W_no_network( await sleepFor(500); const leftpaneAvatarContainer = await waitForTestIdWithText( aliceWindow1, - 'leftpane-primary-avatar', + LeftPane.profileButton.selector, ); const start = Date.now(); let correctScreenshot = false; @@ -303,34 +303,40 @@ test_Alice_1W_Bob_1W( await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', - selector: 'settings-section', + selector: LeftPane.settingsButton.selector, }); + await clickOnTestIdWithText( + aliceWindow1, + Settings.privacyMenuItem.selector, + ); await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', - selector: 'enable-read-receipts', + selector: Settings.enableReadReceipts.selector, }); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); await clickOnElement({ window: bobWindow1, strategy: 'data-testid', - selector: 'settings-section', + selector: LeftPane.settingsButton.selector, }); + await clickOnTestIdWithText(bobWindow1, Settings.privacyMenuItem.selector); + await clickOnElement({ window: bobWindow1, strategy: 'data-testid', - selector: 'enable-read-receipts', + selector: Settings.enableReadReceipts.selector, }); - await clickOnTestIdWithText( - bobWindow1, - 'module-conversation__user__profile-name', - alice.userName, - ); + await clickOnTestIdWithText(bobWindow1, Global.modalCloseButton.selector); await sendMessage(aliceWindow1, 'Testing read receipts'); + await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); + await clickOnTestIdWithText(bobWindow1, HomeScreen.conversationItemName.selector, alice.userName); + await waitForReadTick(aliceWindow1, 'Testing read receipts'); }, ); @@ -451,14 +457,20 @@ test_Alice_2W( ); test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); - await clickOnTestIdWithText(aliceWindow1, 'chooser-invite-friend'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newConversationButton.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.inviteAFriendOption.selector, + ); await waitForTestIdWithText(aliceWindow1, 'your-account-id', alice.accountid); await clickOnTestIdWithText(aliceWindow1, 'copy-button-account-id'); // Toast await waitForTestIdWithText( aliceWindow1, - 'session-toast', + Global.toast.selector, englishStrippedStr('copied').toString(), ); // Wait for copy to resolve @@ -472,19 +484,26 @@ test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { englishStrippedStr('shareAccountIdDescriptionCopied').toString(), ); // To exit invite a friend - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); - // To create note to self - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); + await clickOnTestIdWithText(aliceWindow1, Global.backButton.selector); // New message - await clickOnTestIdWithText(aliceWindow1, 'chooser-new-conversation-button'); - await clickOnTestIdWithText(aliceWindow1, 'new-session-conversation'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageOption.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageAccountIDInput.selector, + ); const isMac = process.platform === 'darwin'; await aliceWindow1.keyboard.press(`${isMac ? 'Meta' : 'Control'}+V`); - await clickOnTestIdWithText(aliceWindow1, 'next-new-conversation-button'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageNextButton.selector, + ); // Did the copied text create note to self? await waitForTestIdWithText( aliceWindow1, - 'header-conversation-name', + Conversation.conversationHeader.selector, englishStrippedStr('noteToSelf').toString(), ); }); diff --git a/tests/automation/utilities/message.ts b/tests/automation/utilities/message.ts index 67ea326..f42dff4 100644 --- a/tests/automation/utilities/message.ts +++ b/tests/automation/utilities/message.ts @@ -18,6 +18,21 @@ export const waitForSentTick = async (window: Page, message: string) => { ); }; +export const waitForReadTick = async (window: Page, message: string) => { + // wait for confirmation tick to send reply message + const selc = `css=[data-testid=message-content]:has-text("${message}"):has([data-testid=msg-status][data-testtype=read])`; + console.info('waiting for read tick of message: ', message); + + const tickMessageRead = await window.waitForSelector(selc, { + timeout: 30000, + }); + console.info( + 'found the tick of message read: ', + message, + Boolean(tickMessageRead), + ); +}; + export const sendMessage = async (window: Page, message: string) => { // type into message input box await typeIntoInput(window, 'message-input-text-area', message); diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index 9382992..2d795a1 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -424,7 +424,7 @@ export async function hasTextMessageBeenDeleted( maxWait: number = 5000, ) { await doWhileWithMax( - 15000, + maxWait, 500, 'waiting for text message to be deleted', async () => { @@ -592,7 +592,7 @@ export async function compareScreenshot( ); // If screenshot does not exist, save it to the folder if (!fs.existsSync(previousScreenshotFilePath)) { - fs.writeFileSync(previousScreenshotFilePath, elementScreenshot); + fs.writeFileSync(previousScreenshotFilePath, elementScreenshot as any); // TS really hates this unless its cast as any } // If screenshot does exist, compare it to previous screenshot in the folder const previousScreenshot = fs.readFileSync(previousScreenshotFilePath); @@ -601,9 +601,11 @@ export async function compareScreenshot( `${elementState}-${os}-difference.png`, ); // If screenshots are different, then create a difference screenshot - if (!elementScreenshot.equals(previousScreenshot)) { + if ( + Buffer.compare(elementScreenshot as any, previousScreenshot as any) !== 0 + ) { // If elements do not match, then take the elementScreenshot and save it to same folder but with a new name of 'difference.png' - fs.writeFileSync(diffFilePath, elementScreenshot); + fs.writeFileSync(diffFilePath, elementScreenshot as any); throw new Error( `Screenshots do not match, see ${screenshotFolder} > ${testTitle} folder > \n\t\t diff: ${diffFilePath}\n\t\t previous: ${previousScreenshotFilePath}`, ); From 9c287e49a255bf83c35eea9128f1cadaf641cbbb Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 14:46:00 +1000 Subject: [PATCH 17/32] chore: keep on keeping on --- .../disappearing_message_checks.spec.ts | 23 ++++++----- tests/automation/linked_device_group.spec.ts | 32 +++++++++++----- tests/automation/locators/index.ts | 16 ++++++-- tests/automation/user_actions.spec.ts | 6 ++- .../utilities/set_disappearing_messages.ts | 38 +++++++------------ 5 files changed, 67 insertions(+), 48 deletions(-) diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index 87068bc..433c349 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -7,6 +7,7 @@ import { mediaArray, testLink, } from './constants/variables'; +import { Conversation, Global } from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { createContact } from './utilities/create_contact'; import { joinCommunity } from './utilities/join_community'; @@ -52,7 +53,7 @@ mediaArray.forEach(({ mediaType, path, attachmentType }) => { await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSetYou') .withArgs({ time: formattedTime, @@ -62,7 +63,7 @@ mediaArray.forEach(({ mediaType, path, attachmentType }) => { ), waitForTestIdWithText( bobWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSet') .withArgs({ time: formattedTime, @@ -110,7 +111,7 @@ test_Alice_1W_Bob_1W( await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSetYou') .withArgs({ time: formattedTime, @@ -120,7 +121,7 @@ test_Alice_1W_Bob_1W( ), waitForTestIdWithText( bobWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSet') .withArgs({ time: formattedTime, @@ -159,7 +160,7 @@ test_Alice_1W_Bob_1W( await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSetYou') .withArgs({ time: formattedTime, @@ -169,7 +170,7 @@ test_Alice_1W_Bob_1W( ), waitForTestIdWithText( bobWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSet') .withArgs({ time: formattedTime, @@ -213,7 +214,7 @@ test_Alice_1W_Bob_1W( await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSetYou') .withArgs({ time: formattedTime, @@ -223,7 +224,7 @@ test_Alice_1W_Bob_1W( ), waitForTestIdWithText( bobWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSet') .withArgs({ time: formattedTime, @@ -243,7 +244,11 @@ test_Alice_1W_Bob_1W( 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnTestIdWithText(aliceWindow1, 'contact', bob.userName); + await clickOnTestIdWithText( + aliceWindow1, + Global.contactItem.selector, + bob.userName, + ); await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); // For lack of a unique ID we use native Playwright methods await aliceWindow1 diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 0800836..49664d5 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -3,6 +3,7 @@ import type { Page } from '@playwright/test'; import { englishStrippedStr } from '../localization/englishStrippedStr'; import { Conversation, + ConversationSettings, Global, HomeScreen, LeftPane, @@ -95,23 +96,26 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Does group appear? await waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check group for members, conversation name and messages await clickOnTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, groupCreated.userName, ); // Check header name await waitForTestIdWithText( aliceWindow2, - 'header-conversation-name', + Conversation.conversationHeader.selector, groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText(aliceWindow2, 'conversation-options-avatar'); + await clickOnTestIdWithText( + aliceWindow2, + Conversation.conversationSettingsIcon.selector, + ); // Check right panel has correct name await waitForTestIdWithText(aliceWindow2, 'group-name'); await clickOnTestIdWithText(aliceWindow2, 'manage-members-menu-option'); @@ -124,11 +128,19 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( await Promise.all([ waitForTestIdWithText( aliceWindow2, - 'contact', + Global.contactItem.selector, englishStrippedStr('you').toString(), ), - waitForTestIdWithText(aliceWindow2, 'contact', bob.userName), - waitForTestIdWithText(aliceWindow2, 'contact', charlie.userName), + waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + bob.userName, + ), + waitForTestIdWithText( + aliceWindow2, + Global.contactItem.selector, + charlie.userName, + ), ]); }, ); @@ -194,7 +206,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); await clickOnTestIdWithText( aliceWindow2, - Conversation.manageMembersOption.selector, + ConversationSettings.manageMembersOption.selector, ); // Check for You, Bob and Charlie await Promise.all([ @@ -245,7 +257,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); await clickOnTestIdWithText( restoredWindow, - Conversation.manageMembersOption.selector, + ConversationSettings.manageMembersOption.selector, ); // Check for You, Bob and Charlie await Promise.all([ @@ -300,7 +312,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); await clickOnTestIdWithText( restoredWindow2, - Conversation.manageMembersOption.selector, + ConversationSettings.manageMembersOption.selector, ); // Check for You, Bob and Charlie await Promise.all([ diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 65ab4a1..32fb47d 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -74,10 +74,11 @@ export class Conversation extends Locator { static readonly deleteMessageRequestButton = this.testId( 'delete-message-request', ); - static readonly endVoiceMessageButton = this.testId('end-voice-message'); - static readonly manageMembersOption = this.testId( - 'manage-members-menu-option', + static readonly disappearingControlMessage = this.testId( + 'disappear-control-message', ); + static readonly endVoiceMessageButton = this.testId('end-voice-message'); + static readonly messageInput = this.testId('message-input-text-area'); static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', @@ -86,6 +87,15 @@ export class Conversation extends Locator { static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } +export class ConversationSettings extends Locator { + static readonly disappearingMessagesOption = this.testId( + 'disappearing-messages-menu-option', + ); + static readonly manageMembersOption = this.testId( + 'manage-members-menu-option', + ); +} + export class Settings extends Locator { // Profile static readonly accountId = this.testId('your-account-id'); diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index 4ade2c2..a4fc184 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -335,7 +335,11 @@ test_Alice_1W_Bob_1W( await clickOnTestIdWithText(bobWindow1, Global.modalCloseButton.selector); await sendMessage(aliceWindow1, 'Testing read receipts'); await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); - await clickOnTestIdWithText(bobWindow1, HomeScreen.conversationItemName.selector, alice.userName); + await clickOnTestIdWithText( + bobWindow1, + HomeScreen.conversationItemName.selector, + alice.userName, + ); await waitForReadTick(aliceWindow1, 'Testing read receipts'); }, ); diff --git a/tests/automation/utilities/set_disappearing_messages.ts b/tests/automation/utilities/set_disappearing_messages.ts index 8108118..ee1f0d1 100644 --- a/tests/automation/utilities/set_disappearing_messages.ts +++ b/tests/automation/utilities/set_disappearing_messages.ts @@ -1,6 +1,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; +import { Conversation, ConversationSettings } from '../locators'; import { ConversationType, DataTestId, @@ -12,7 +13,6 @@ import { clickOnElement, clickOnMatchingText, clickOnTestIdWithText, - doWhileWithMax, formatTimeOption, waitForElement, waitForTestIdWithText, @@ -29,30 +29,18 @@ export const setDisappearingMessages = async ( windowB?: Page, ) => { const enforcedType: ConversationType = conversationType; - await doWhileWithMax(5000, 1000, 'setDisappearingMessages', async () => { - try { - await clickOnTestIdWithText( - windowA, - 'conversation-options-avatar', - undefined, - undefined, - 1000, - ); - await clickOnElement({ - window: windowA, - strategy: 'data-testid', - selector: 'disappearing-messages-menu-option', - maxWait: 100, - }); - return true; - } catch (e) { - console.log( - 'setDisappearingMessages doWhileWithMax action threw:', - e.message, - ); - - return false; - } + await clickOnTestIdWithText( + windowA, + Conversation.conversationSettingsIcon.selector, + undefined, + undefined, + 5_000, + ); + await clickOnElement({ + window: windowA, + strategy: 'data-testid', + selector: ConversationSettings.disappearingMessagesOption.selector, + maxWait: 5_000, }); if (enforcedType === '1:1') { From 8faa8ba5744b6a3e76f0d7eb9fa0648fee5ca3d2 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 15:48:35 +1000 Subject: [PATCH 18/32] chore: replace all clickOnTestIdWithText instances with locators --- tests/automation/delete_account.spec.ts | 4 +- .../disappearing_message_checks.spec.ts | 27 ++++-- tests/automation/group_testing.spec.ts | 28 ++++-- tests/automation/input_validations.spec.ts | 17 ++-- tests/automation/linked_device_group.spec.ts | 5 +- .../automation/linked_device_requests.spec.ts | 2 +- tests/automation/linked_device_user.spec.ts | 49 +++++++---- tests/automation/locators/index.ts | 52 +++++++++-- tests/automation/message_checks.spec.ts | 12 ++- tests/automation/message_requests.spec.ts | 33 +++++-- tests/automation/setup/create_group.ts | 26 +++--- tests/automation/setup/new_user.ts | 33 +++++-- tests/automation/setup/recovery_using_seed.ts | 5 +- tests/automation/switching_theme.spec.ts | 5 +- tests/automation/test.spec.ts | 3 +- tests/automation/types/testing.ts | 1 + tests/automation/user_actions.spec.ts | 78 ++++++++++++----- tests/automation/utilities/join_community.ts | 16 +++- tests/automation/utilities/leave_group.ts | 8 +- tests/automation/utilities/rename_group.ts | 13 ++- tests/automation/utilities/send_media.ts | 6 +- tests/automation/utilities/send_message.ts | 7 +- tests/automation/utilities/utils.ts | 86 +++++++++++++------ tests/automation/utilities/voice_call.ts | 2 +- 24 files changed, 366 insertions(+), 152 deletions(-) diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 54fc3b5..77080fc 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -110,7 +110,7 @@ sessionTestTwoWindows( await clickOnTestIdWithText( restoringWindow, - HomeScreen.newConversationButton.selector, + HomeScreen.plusButton.selector, ); // Expect contacts list to be empty await hasElementBeenDeleted( @@ -177,7 +177,7 @@ sessionTestTwoWindows( await clickOnElement({ window: restoringWindow, strategy: 'data-testid', - selector: HomeScreen.newConversationButton.selector, + selector: HomeScreen.plusButton.selector, }); await waitForElement( restoringWindow, diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index 433c349..90b5a34 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -7,7 +7,12 @@ import { mediaArray, testLink, } from './constants/variables'; -import { Conversation, Global } from './locators'; +import { + Conversation, + ConversationSettings, + Global, + HomeScreen, +} from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { createContact } from './utilities/create_contact'; import { joinCommunity } from './utilities/join_community'; @@ -237,8 +242,14 @@ test_Alice_1W_Bob_1W( await joinCommunity(aliceWindow1); // To stop the layout shift await sleepFor(500); - await clickOnTestIdWithText(aliceWindow1, 'conversation-options-avatar'); - await clickOnTestIdWithText(aliceWindow1, 'invite-contacts-menu-option'); + await clickOnTestIdWithText( + aliceWindow1, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + ConversationSettings.inviteContactsOption.selector, + ); await waitForTestIdWithText( aliceWindow1, 'modal-heading', @@ -249,16 +260,16 @@ test_Alice_1W_Bob_1W( Global.contactItem.selector, bob.userName, ); - await clickOnTestIdWithText(aliceWindow1, 'session-confirm-ok-button'); + await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); // For lack of a unique ID we use native Playwright methods await aliceWindow1 .getByTestId('invite-contacts-dialog') .getByTestId('modal-close-button') .click(); - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, bob.userName, ); await Promise.all([ @@ -312,7 +323,7 @@ test_Alice_1W_Bob_1W( await Promise.all([ waitForTestIdWithText( aliceWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSetYou') .withArgs({ time: formattedTime, @@ -322,7 +333,7 @@ test_Alice_1W_Bob_1W( ), waitForTestIdWithText( bobWindow1, - 'disappear-control-message', + Conversation.disappearingControlMessage.selector, englishStrippedStr('disappearingMessagesSet') .withArgs({ time: formattedTime, diff --git a/tests/automation/group_testing.spec.ts b/tests/automation/group_testing.spec.ts index 70e4d2b..be3a50d 100644 --- a/tests/automation/group_testing.spec.ts +++ b/tests/automation/group_testing.spec.ts @@ -1,6 +1,11 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { doForAll, sleepFor } from '../promise_utils'; -import { Global, HomeScreen } from './locators'; +import { + Conversation, + ConversationSettings, + Global, + HomeScreen, +} from './locators'; import { createGroup } from './setup/create_group'; import { newUser } from './setup/new_user'; import { @@ -128,14 +133,23 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Click on conversation options // Check to see that you can't change group name to empty string // Click on edit group name - await clickOnTestIdWithText(aliceWindow1, 'conversation-options-avatar'); - await clickOnTestIdWithText(aliceWindow1, 'edit-group-name'); - await clickOnTestIdWithText(aliceWindow1, 'clear-group-info-name-button'); - await waitForTestIdWithText(aliceWindow1, 'error-message'); + await clickOnTestIdWithText( + aliceWindow1, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + ConversationSettings.editGroupButton.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + ConversationSettings.clearGroupNameButton.selector, + ); + await waitForTestIdWithText(aliceWindow1, Global.errorMessage.selector); const actualError = await grabTextFromElement( aliceWindow1, 'data-testid', - 'error-message', + Global.errorMessage.selector, ); if (actualError !== expectedError) { throw new Error( @@ -146,7 +160,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( aliceWindow1, englishStrippedStr('cancel').toString(), ); - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); }, ); diff --git a/tests/automation/input_validations.spec.ts b/tests/automation/input_validations.spec.ts index 1d015ea..e0cddc2 100644 --- a/tests/automation/input_validations.spec.ts +++ b/tests/automation/input_validations.spec.ts @@ -1,6 +1,8 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; +import { Global, Onboarding } from './locators'; import { sessionTestOneWindow } from './setup/sessionTest'; import { + clickOn, clickOnTestIdWithText, grabTextFromElement, typeIntoInput, @@ -35,9 +37,9 @@ import { }, ].forEach(({ testName, incorrectSeed, expectedError }) => { sessionTestOneWindow(`Seed validation: "${testName}"`, async ([window]) => { - await clickOnTestIdWithText(window, 'existing-account-button'); + await clickOn(window, Onboarding.iHaveAnAccountButton); await typeIntoInput(window, 'recovery-phrase-input', incorrectSeed); - await clickOnTestIdWithText(window, 'continue-button'); + await clickOn(window, Global.continueButton); await waitForTestIdWithText(window, 'error-message'); const actualError = await grabTextFromElement( window, @@ -71,14 +73,17 @@ import { sessionTestOneWindow( `Display name validation: "${testName}"`, async ([window]) => { - await clickOnTestIdWithText(window, 'create-account-button'); + await clickOnTestIdWithText( + window, + Onboarding.createAccountButton.selector, + ); await typeIntoInput(window, 'display-name-input', displayName); - await clickOnTestIdWithText(window, 'continue-button'); - await waitForTestIdWithText(window, 'error-message'); + await clickOnTestIdWithText(window, Global.continueButton.selector); + await waitForTestIdWithText(window, Global.errorMessage.selector); const actualError = await grabTextFromElement( window, 'data-testid', - 'error-message', + Global.errorMessage.selector, ); if (testName === 'No name') { console.log('Expected failure: see SES-2832'); diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 49664d5..322c17c 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -118,7 +118,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); // Check right panel has correct name await waitForTestIdWithText(aliceWindow2, 'group-name'); - await clickOnTestIdWithText(aliceWindow2, 'manage-members-menu-option'); + await clickOnTestIdWithText( + aliceWindow2, + ConversationSettings.manageMembersOption.selector, + ); await waitForTestIdWithText( aliceWindow2, 'modal-heading', diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 2e7fa7b..d33f53d 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -64,7 +64,7 @@ test_Alice_2W_Bob_1W( await clickOnTestIdWithText(aliceWindow2, Global.backButton.selector); await clickOnTestIdWithText( aliceWindow2, - HomeScreen.newConversationButton.selector, + HomeScreen.plusButton.selector, ); await waitForTestIdWithText( aliceWindow2, diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index c6d9762..f6dda8e 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -42,21 +42,21 @@ sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { try { const userA = await newUser(aliceWindow1, 'Alice'); aliceWindow2 = await linkedDevice(userA.recoveryPassword); // not using fixture here as we want to check the behavior finely - await clickOnTestIdWithText(aliceWindow1, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Verify Username await waitForTestIdWithText( aliceWindow1, - 'your-profile-name', + Settings.displayName.selector, userA.userName, ); // Verify Account ID await waitForTestIdWithText( aliceWindow1, - 'your-account-id', + Settings.accountId.selector, userA.accountid, ); // exit profile modal - await clickOnTestIdWithText(aliceWindow1, 'modal-close-button'); + await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); // You're almost finished isn't displayed const errorDesc = 'Should not be found'; try { @@ -143,11 +143,20 @@ test_Alice_2W( await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); // Click on current profile picture await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); - await clickOnTestIdWithText(aliceWindow1, 'image-upload-section'); - await clickOnTestIdWithText(aliceWindow1, 'image-upload-click'); + await clickOnTestIdWithText( + aliceWindow1, + Settings.imageUploadSection.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + Settings.imageUploadClick.selector, + ); // allow for the image to be resized before we try to save it await sleepFor(500); - await clickOnTestIdWithText(aliceWindow1, 'save-button-profile-update'); + await clickOnTestIdWithText( + aliceWindow1, + Settings.saveProfileUpdateButton.selector, + ); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); await clickOnMatchingText( aliceWindow1, @@ -443,17 +452,23 @@ test_Alice_2W_Bob_1W( test_Alice_2W( 'Hide note to self syncs', async ({ alice, aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); await clickOnTestIdWithText( aliceWindow1, - 'chooser-new-conversation-button', + HomeScreen.plusButton.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageOption.selector, ); await typeIntoInput( aliceWindow1, - 'new-session-conversation', + HomeScreen.newMessageAccountIDInput.selector, alice.accountid, ); - await clickOnTestIdWithText(aliceWindow1, 'next-new-conversation-button'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageNextButton.selector, + ); await waitForTestIdWithText( aliceWindow1, 'header-conversation-name', @@ -464,18 +479,18 @@ test_Alice_2W( await sleepFor(1000); await waitForTestIdWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, englishStrippedStr('noteToSelf').toString(), ); await clickOnTestIdWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, englishStrippedStr('noteToSelf').toString(), true, ); await clickOnTestIdWithText( aliceWindow1, - 'context-menu-item', + Global.contextMenuItem.selector, englishStrippedStr('noteToSelfHide').toString(), ); await checkModalStrings( @@ -485,7 +500,7 @@ test_Alice_2W( ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('hide').toString(), ); // Check linked device for hidden note to self @@ -494,14 +509,14 @@ test_Alice_2W( hasElementBeenDeleted( aliceWindow1, 'data-testid', - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, 5000, englishStrippedStr('noteToSelf').toString(), ), hasElementBeenDeleted( aliceWindow2, 'data-testid', - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, 15_000, englishStrippedStr('noteToSelf').toString(), ), diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 32fb47d..d475ecc 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -1,30 +1,31 @@ /* eslint-disable @typescript-eslint/lines-between-class-members */ import { DataTestId, StrategyExtractionObj } from '../types/testing'; -export abstract class Locator { +abstract class Locator { protected static className(selector: string): StrategyExtractionObj { return { strategy: 'class', selector, - }; + } as const; } protected static hasText(selector: string): StrategyExtractionObj { return { strategy: ':has-text', selector, - }; + } as const; } protected static testId(selector: DataTestId) { return { strategy: 'data-testid', selector, - }; + } as const; } } export class Onboarding extends Locator { + static readonly createAccountButton = this.testId('create-account-button'); static readonly displayNameInput = this.testId('display-name-input'); static readonly iHaveAnAccountButton = this.testId('existing-account-button'); static readonly recoveryPhraseInput = this.testId('recovery-phrase-input'); @@ -33,6 +34,7 @@ export class Onboarding extends Locator { export class LeftPane extends Locator { static readonly profileButton = this.testId('leftpane-primary-avatar'); static readonly settingsButton = this.testId('settings-section'); + static readonly themeButton = this.testId('theme-section'); } export class HomeScreen extends Locator { @@ -40,26 +42,43 @@ export class HomeScreen extends Locator { static readonly createGroupOption = this.testId('chooser-new-group'); static readonly inviteAFriendOption = this.testId('chooser-invite-friend'); static readonly joinCommunityOption = this.testId('chooser-new-community'); + static readonly newMessageOption = this.testId( + 'chooser-new-conversation-button', + ); + // New Message static readonly newMessageAccountIDInput = this.testId( 'new-session-conversation', ); static readonly newMessageNextButton = this.testId( 'next-new-conversation-button', ); - static readonly newMessageOption = this.testId( - 'chooser-new-conversation-button', + // Create Group + static readonly createGroupCreateButton = this.testId('create-group-button'); + static readonly createGroupGroupName = this.testId('new-closed-group-name'); + // Invite A Friend + static readonly inviteAFriendCopyButton = this.testId( + 'copy-button-account-id', + ); + // Join Community + static readonly joinCommunityButton = this.testId('join-community-button'); + static readonly joinCommunityInput = this.testId( + 'join-community-conversation', ); // Home Screen items static readonly conversationItemName = this.testId( 'module-conversation__user__profile-name', ); static readonly messageRequestBanner = this.testId('message-request-banner'); - static readonly newConversationButton = this.testId( + static readonly plusButton = this.testId( 'new-conversation-button', ); + static readonly revealRecoveryPhraseButton = this.testId( + 'reveal-recovery-phrase', + ); } export class Conversation extends Locator { + static readonly messageContent = this.testId('message-content') static readonly acceptMessageRequestButton = this.testId( 'accept-message-request', ); @@ -83,14 +102,22 @@ export class Conversation extends Locator { static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', ); + static readonly endCallButton = this.testId('end-call') static readonly microphoneButton = this.testId('microphone-button'); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } export class ConversationSettings extends Locator { + static readonly clearGroupNameButton = this.testId( + 'clear-group-info-name-button', + ); static readonly disappearingMessagesOption = this.testId( 'disappearing-messages-menu-option', ); + static readonly editGroupButton = this.testId('edit-group-name'); + static readonly inviteContactsOption = this.testId( + 'invite-contacts-menu-option', + ); static readonly manageMembersOption = this.testId( 'manage-members-menu-option', ); @@ -104,6 +131,11 @@ export class Settings extends Locator { static readonly displayNameInput = this.testId( 'update-profile-info-name-input', ); + static readonly imageUploadClick = this.testId('image-upload-click'); + static readonly imageUploadSection = this.testId('image-upload-section'); + static readonly saveProfileUpdateButton = this.testId( + 'save-button-profile-update', + ); // Menu items static readonly clearDataMenuItem = this.testId( 'clear-data-settings-menu-item', @@ -141,9 +173,15 @@ export class Settings extends Locator { ); static readonly unblockButton = this.testId('unblock-button-settings-screen'); // Recovery Password + static readonly hideRecoveryPasswordButton = this.testId( + 'hide-recovery-password-button', + ); static readonly recoveryPasswordContainer = this.testId( 'recovery-password-seed-modal', ); + static readonly recoveryPasswordQRCode = this.testId( + 'session-recovery-password', + ); // Clear Data static readonly clearDeviceAndNetworkRadial = this.testId( 'label-device_and_network', diff --git a/tests/automation/message_checks.spec.ts b/tests/automation/message_checks.spec.ts index 2105ec6..558fb77 100644 --- a/tests/automation/message_checks.spec.ts +++ b/tests/automation/message_checks.spec.ts @@ -2,7 +2,12 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; import { testCommunityName } from './constants/community'; import { longText, mediaArray, testLink } from './constants/variables'; -import { Conversation, Global, HomeScreen } from './locators'; +import { + Conversation, + ConversationSettings, + Global, + HomeScreen, +} from './locators'; import { newUser } from './setup/new_user'; import { sessionTestTwoWindows, @@ -126,7 +131,10 @@ test_Alice_1W_Bob_1W( aliceWindow1, Conversation.conversationSettingsIcon.selector, ); - await clickOnTestIdWithText(aliceWindow1, 'invite-contacts-menu-option'); + await clickOnTestIdWithText( + aliceWindow1, + ConversationSettings.inviteContactsOption.selector, + ); await waitForTestIdWithText( aliceWindow1, 'modal-heading', diff --git a/tests/automation/message_requests.spec.ts b/tests/automation/message_requests.spec.ts index c129330..73e1acf 100644 --- a/tests/automation/message_requests.spec.ts +++ b/tests/automation/message_requests.spec.ts @@ -1,5 +1,5 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { LeftPane } from './locators'; +import { Conversation, HomeScreen, LeftPane } from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -19,15 +19,21 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(bobWindow1, 'message-request-banner'); + await clickOnTestIdWithText( + bobWindow1, + HomeScreen.messageRequestBanner.selector, + ); // Select message request from User A await clickOnTestIdWithText( bobWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, alice.userName, ); // Check that using the accept button has intended use - await clickOnTestIdWithText(bobWindow1, 'accept-message-request'); + await clickOnTestIdWithText( + bobWindow1, + Conversation.acceptMessageRequestButton.selector, + ); // Check config message of message request acceptance await waitForTestIdWithText( bobWindow1, @@ -53,11 +59,14 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(bobWindow1, 'message-request-banner'); + await clickOnTestIdWithText( + bobWindow1, + HomeScreen.messageRequestBanner.selector, + ); // Select message request from User A await clickOnTestIdWithText( bobWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, alice.userName, ); await sendMessage(bobWindow1, testReply); @@ -86,11 +95,14 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(bobWindow1, 'message-request-banner'); + await clickOnTestIdWithText( + bobWindow1, + HomeScreen.messageRequestBanner.selector, + ); // Select message request from User A await clickOnTestIdWithText( bobWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName.selector, alice.userName, ); @@ -125,7 +137,10 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText(bobWindow1, 'message-request-banner'); + await clickOnTestIdWithText( + bobWindow1, + HomeScreen.messageRequestBanner.selector, + ); // Select 'Clear All' button await clickOnMatchingText( bobWindow1, diff --git a/tests/automation/setup/create_group.ts b/tests/automation/setup/create_group.ts index 3b0aa5d..343b0a4 100644 --- a/tests/automation/setup/create_group.ts +++ b/tests/automation/setup/create_group.ts @@ -2,6 +2,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sortByPubkey } from '../../pubkey'; +import { HomeScreen } from '../locators'; import { Group, User } from '../types/testing'; import { sendMessage } from '../utilities/message'; import { sendNewMessage } from '../utilities/send_message'; @@ -51,21 +52,27 @@ export const createGroup = async ( userOne.accountid, `${messageCA} Time: ${Date.now()}`, ); - // Focus screen on window C to allow user C to become contact - await clickOnTestIdWithText(windowC, 'messages-container'); - // wait for user C to be contact before moving to create group - // Create group with existing contact and session ID (of non-contact) // Click new closed group tab - await clickOnTestIdWithText(windowA, 'new-conversation-button'); - await clickOnTestIdWithText(windowA, 'chooser-new-group'); + await clickOnTestIdWithText( + windowA, + HomeScreen.plusButton.selector, + ); + await clickOnTestIdWithText(windowA, HomeScreen.createGroupOption.selector); // Enter group name - await typeIntoInput(windowA, 'new-closed-group-name', group.userName); + await typeIntoInput( + windowA, + HomeScreen.createGroupGroupName.selector, + group.userName, + ); // Select user B await clickOnMatchingText(windowA, userTwo.userName); // Select user C await clickOnMatchingText(windowA, userThree.userName); // Click Next - await clickOnTestIdWithText(windowA, 'create-group-button'); + await clickOnTestIdWithText( + windowA, + HomeScreen.createGroupCreateButton.selector, + ); // Check group was successfully created await clickOnMatchingText(windowB, group.userName); await waitForTestIdWithText( @@ -138,8 +145,5 @@ export const createGroup = async ( // windowC must see the message from A and the message from B await waitForTextMessages(windowC, [msgAToGroup, msgBToGroup]); - // Focus screen - // await clickOnTestIdWithText(windowB, 'scroll-to-bottom-button'); - return { userName, userOne, userTwo, userThree }; }; diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 01b995a..11c4c44 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -1,6 +1,13 @@ import { Page } from '@playwright/test'; import chalk from 'chalk'; +import { + Global, + HomeScreen, + LeftPane, + Onboarding, + Settings, +} from '../locators'; import { User } from '../types/testing'; import { checkPathLight, @@ -16,13 +23,19 @@ export const newUser = async ( awaitOnionPath = true, ): Promise => { // Create User - await clickOnTestIdWithText(window, 'create-account-button'); + await clickOnTestIdWithText(window, Onboarding.createAccountButton.selector); // Input username = testuser - await typeIntoInput(window, 'display-name-input', userName); - await clickOnTestIdWithText(window, 'continue-button'); + await typeIntoInput(window, Onboarding.displayNameInput.selector, userName); + await clickOnTestIdWithText(window, Global.continueButton.selector); // save recovery phrase - await clickOnTestIdWithText(window, 'reveal-recovery-phrase'); - await waitForTestIdWithText(window, 'recovery-password-seed-modal'); + await clickOnTestIdWithText( + window, + HomeScreen.revealRecoveryPhraseButton.selector, + ); + await waitForTestIdWithText( + window, + Settings.recoveryPasswordContainer.selector, + ); const recoveryPassword = await grabTextFromElement( window, 'data-testid', @@ -31,11 +44,13 @@ export const newUser = async ( // const recoveryPhrase = await window.innerText( // '[data-testid=recovery-password-seed-modal]', // ); - await clickOnTestIdWithText(window, 'modal-close-button'); - await clickOnTestIdWithText(window, 'leftpane-primary-avatar'); + await clickOnTestIdWithText(window, Global.modalCloseButton.selector); + await clickOnTestIdWithText(window, LeftPane.profileButton.selector); // Save Account ID to a variable - let accountid = await window.innerText('[data-testid=your-account-id]'); + let accountid = await window.innerText( + `[data-testid=${Settings.accountId.selector}]`, + ); accountid = accountid.replace(/[^0-9a-fA-F]/g, ''); // keep only hex characters console.log( @@ -43,7 +58,7 @@ export const newUser = async ( accountid, )}" and Recovery password: "${chalk.green(recoveryPassword)}"`, ); - await clickOnTestIdWithText(window, 'modal-close-button'); + await clickOnTestIdWithText(window, Global.modalCloseButton.selector); if (awaitOnionPath) { await checkPathLight(window); } diff --git a/tests/automation/setup/recovery_using_seed.ts b/tests/automation/setup/recovery_using_seed.ts index 232fa9a..1a31039 100644 --- a/tests/automation/setup/recovery_using_seed.ts +++ b/tests/automation/setup/recovery_using_seed.ts @@ -1,5 +1,6 @@ import { Page } from '@playwright/test'; +import { Global, Onboarding } from '../locators'; import { clickOnTestIdWithText, doesElementExist, @@ -8,9 +9,9 @@ import { } from '../utilities/utils'; export async function recoverFromSeed(window: Page, recoveryPhrase: string) { - await clickOnTestIdWithText(window, 'existing-account-button'); + await clickOnTestIdWithText(window, Onboarding.iHaveAnAccountButton.selector); await typeIntoInput(window, 'recovery-phrase-input', recoveryPhrase); - await clickOnTestIdWithText(window, 'continue-button'); + await clickOnTestIdWithText(window, Global.continueButton.selector); await waitForLoadingAnimationToFinish(window, 'loading-animation'); const displayName = await doesElementExist( window, diff --git a/tests/automation/switching_theme.spec.ts b/tests/automation/switching_theme.spec.ts index 06e436c..cc5a7ec 100644 --- a/tests/automation/switching_theme.spec.ts +++ b/tests/automation/switching_theme.spec.ts @@ -1,5 +1,6 @@ import { expect } from '@playwright/test'; +import { LeftPane } from './locators'; import { test_Alice_1W_no_network } from './setup/sessionTest'; import { clickOnTestIdWithText } from './utilities/utils'; @@ -10,7 +11,7 @@ test_Alice_1W_no_network('Switch themes', async ({ aliceWindow1 }) => { await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)'); // Click theme button and change to dark theme - await clickOnTestIdWithText(aliceWindow1, 'theme-section'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.themeButton.selector); // Check background colour of background to verify dark theme const lightThemeColor = aliceWindow1.locator('.inbox.index'); await expect(lightThemeColor).toHaveCSS( @@ -19,7 +20,7 @@ test_Alice_1W_no_network('Switch themes', async ({ aliceWindow1 }) => { ); // Toggle back to light theme - await clickOnTestIdWithText(aliceWindow1, 'theme-section'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.themeButton.selector); // Check background colour again await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)'); }); diff --git a/tests/automation/test.spec.ts b/tests/automation/test.spec.ts index 167c617..afd0258 100644 --- a/tests/automation/test.spec.ts +++ b/tests/automation/test.spec.ts @@ -1,6 +1,7 @@ +import { Onboarding } from './locators'; import { sessionTestOneWindow } from './setup/sessionTest'; import { clickOnTestIdWithText } from './utilities/utils'; sessionTestOneWindow('Tiny test', async ([windowA]) => { - await clickOnTestIdWithText(windowA, 'create-account-button'); + await clickOnTestIdWithText(windowA, Onboarding.createAccountButton.selector); }); diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index 23879a6..f215d60 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -199,4 +199,5 @@ export type ModalId = | 'blockOrUnblockModal' | 'confirmModal' | 'deleteAccountModal' + | 'hideRecoveryPasswordModal' | 'userSettingsModal'; diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index a4fc184..7737439 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -76,7 +76,7 @@ test_Alice_1W_Bob_1W( // Check to see if User B is a contact await clickOnTestIdWithText( aliceWindow1, - HomeScreen.newConversationButton.selector, + HomeScreen.plusButton.selector, ); await waitForTestIdWithText( aliceWindow1, @@ -196,11 +196,20 @@ test_Alice_1W_no_network( // Click on current profile picture await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); - await clickOnTestIdWithText(aliceWindow1, 'image-upload-section'); - await clickOnTestIdWithText(aliceWindow1, 'image-upload-click'); + await clickOnTestIdWithText( + aliceWindow1, + Settings.imageUploadSection.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + Settings.imageUploadClick.selector, + ); // allow for the image to be resized before we try to save it await sleepFor(500); - await clickOnTestIdWithText(aliceWindow1, 'save-button-profile-update'); + await clickOnTestIdWithText( + aliceWindow1, + Settings.saveProfileUpdateButton.selector, + ); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); await clickOnMatchingText( aliceWindow1, @@ -414,12 +423,15 @@ test_Alice_1W_Bob_1W( test_Alice_2W( 'Hide recovery password', async ({ aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + Settings.hideRecoveryPasswordButton.selector, ); - await clickOnTestIdWithText(aliceWindow1, 'hide-recovery-password-button'); // Check first modal await checkModalStrings( aliceWindow1, @@ -427,10 +439,11 @@ test_Alice_2W( englishStrippedStr( 'recoveryPasswordHidePermanentlyDescription1', ).toString(), + 'hideRecoveryPasswordModal', ); await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('theContinue').toString(), ); await checkModalStrings( @@ -439,23 +452,24 @@ test_Alice_2W( englishStrippedStr( 'recoveryPasswordHidePermanentlyDescription2', ).toString(), + 'hideRecoveryPasswordModal', ); // Click yes await clickOnTestIdWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('yes').toString(), ); await doesElementExist( aliceWindow1, 'data-testid', - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); // Check linked device if Recovery Password is still visible (it should be) - await clickOnTestIdWithText(aliceWindow2, 'settings-section'); + await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); await waitForTestIdWithText( aliceWindow2, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, ); }, ); @@ -463,14 +477,17 @@ test_Alice_2W( test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { await clickOnTestIdWithText( aliceWindow1, - HomeScreen.newConversationButton.selector, + HomeScreen.plusButton.selector, ); await clickOnTestIdWithText( aliceWindow1, HomeScreen.inviteAFriendOption.selector, ); await waitForTestIdWithText(aliceWindow1, 'your-account-id', alice.accountid); - await clickOnTestIdWithText(aliceWindow1, 'copy-button-account-id'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.inviteAFriendCopyButton.selector, + ); // Toast await waitForTestIdWithText( aliceWindow1, @@ -515,20 +532,26 @@ test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { test_Alice_1W_no_network( 'Hide note to self', async ({ aliceWindow1, alice }) => { - await clickOnTestIdWithText(aliceWindow1, 'new-conversation-button'); await clickOnTestIdWithText( aliceWindow1, - 'chooser-new-conversation-button', + HomeScreen.plusButton.selector, + ); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageOption.selector, ); await typeIntoInput( aliceWindow1, 'new-session-conversation', alice.accountid, ); - await clickOnTestIdWithText(aliceWindow1, 'next-new-conversation-button'); + await clickOnTestIdWithText( + aliceWindow1, + HomeScreen.newMessageNextButton.selector, + ); await waitForTestIdWithText( aliceWindow1, - 'header-conversation-name', + Conversation.conversationHeader.selector, englishStrippedStr('noteToSelf').toString(), ); await clickOnTestIdWithText( @@ -563,24 +586,33 @@ test_Alice_1W_no_network( ); test_Alice_1W_no_network('Toggle password', async ({ aliceWindow1 }) => { - await clickOnTestIdWithText(aliceWindow1, 'settings-section'); + await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); await clickOnTestIdWithText( aliceWindow1, - 'recovery-password-settings-menu-item', + Settings.recoveryPasswordMenuItem.selector, + ); + await waitForTestIdWithText( + aliceWindow1, + Settings.recoveryPasswordContainer.selector, ); - await waitForTestIdWithText(aliceWindow1, 'recovery-password-seed-modal'); await clickOnMatchingText( aliceWindow1, englishStrippedStr('qrView').toString(), ); // Wait for QR code to be visible - await waitForTestIdWithText(aliceWindow1, 'session-recovery-password'); + await waitForTestIdWithText( + aliceWindow1, + Settings.recoveryPasswordQRCode.selector, + ); // Then toggle back to text seed password await clickOnMatchingText( aliceWindow1, englishStrippedStr('recoveryPasswordView').toString(), ); - await waitForTestIdWithText(aliceWindow1, 'recovery-password-seed-modal'); + await waitForTestIdWithText( + aliceWindow1, + Settings.recoveryPasswordContainer.selector, + ); }); test_Alice_2W( diff --git a/tests/automation/utilities/join_community.ts b/tests/automation/utilities/join_community.ts index 550a685..7596019 100644 --- a/tests/automation/utilities/join_community.ts +++ b/tests/automation/utilities/join_community.ts @@ -1,6 +1,7 @@ import { Page } from '@playwright/test'; import { testCommunityLink } from '../constants/community'; +import { HomeScreen } from '../locators'; import { clickOnTestIdWithText, typeIntoInput, @@ -8,10 +9,17 @@ import { } from './utils'; export const joinCommunity = async (window: Page) => { - await clickOnTestIdWithText(window, 'new-conversation-button'); - await clickOnTestIdWithText(window, 'chooser-new-community'); + await clickOnTestIdWithText( + window, + HomeScreen.plusButton.selector, + ); + await clickOnTestIdWithText(window, HomeScreen.joinCommunityOption.selector); // The follow two test tags are pending implementation - await typeIntoInput(window, 'join-community-conversation', testCommunityLink); - await clickOnTestIdWithText(window, 'join-community-button'); + await typeIntoInput( + window, + HomeScreen.joinCommunityInput.selector, + testCommunityLink, + ); + await clickOnTestIdWithText(window, HomeScreen.joinCommunityButton.selector); await waitForLoadingAnimationToFinish(window, 'loading-spinner'); }; diff --git a/tests/automation/utilities/leave_group.ts b/tests/automation/utilities/leave_group.ts index 803f515..466cb3c 100644 --- a/tests/automation/utilities/leave_group.ts +++ b/tests/automation/utilities/leave_group.ts @@ -1,6 +1,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; +import { Conversation, Global } from '../locators'; import { Group } from '../types/testing'; import { clickOnMatchingText, @@ -10,7 +11,10 @@ import { export const leaveGroup = async (window: Page, group: Group) => { // go to three dots menu - await clickOnTestIdWithText(window, 'conversation-options-avatar'); + await clickOnTestIdWithText( + window, + Conversation.conversationSettingsIcon.selector, + ); // Select Leave Group await clickOnMatchingText( window, @@ -19,7 +23,7 @@ export const leaveGroup = async (window: Page, group: Group) => { // Confirm leave group await clickOnTestIdWithText( window, - 'session-confirm-ok-button', + Global.confirmButton.selector, englishStrippedStr('leave').toString(), ); // check config message diff --git a/tests/automation/utilities/rename_group.ts b/tests/automation/utilities/rename_group.ts index 1fadc5c..758b43e 100644 --- a/tests/automation/utilities/rename_group.ts +++ b/tests/automation/utilities/rename_group.ts @@ -1,6 +1,7 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; +import { Conversation, ConversationSettings, Global } from '../locators'; import { clickOnMatchingText, clickOnTestIdWithText, @@ -15,13 +16,19 @@ export const renameGroup = async ( newGroupName: string, ) => { await clickOnMatchingText(window, oldGroupName); - await clickOnTestIdWithText(window, 'conversation-options-avatar'); - await clickOnTestIdWithText(window, 'edit-group-name'); + await clickOnTestIdWithText( + window, + Conversation.conversationSettingsIcon.selector, + ); + await clickOnTestIdWithText( + window, + ConversationSettings.editGroupButton.selector, + ); await typeIntoInput(window, 'update-group-info-name-input', newGroupName); await window.keyboard.press('Enter'); await clickOnMatchingText(window, englishStrippedStr('save').toString()); await waitForTestIdWithText(window, 'group-name', newGroupName); - await clickOnTestIdWithText(window, 'modal-close-button'); + await clickOnTestIdWithText(window, Global.modalCloseButton.selector); // Check config message await waitForMatchingText( window, diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index e36c50b..82bd153 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -61,7 +61,7 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { strategy: 'data-testid', selector: 'send-message-button', }); - await clickOnTestIdWithText(window, 'message-content', testLink, true); + await clickOnTestIdWithText(window, Conversation.messageContent.selector, testLink, true); // Need to copy link to clipboard, as the enable link preview modal // doesn't pop up if manually typing link (needs to be pasted) // Need to have a nth(0) here to account for Copy Account ID, Appium was getting confused @@ -78,9 +78,9 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { englishStrippedStr('copied').toString(), ); // click on the toast and wait for it to be closed to avoid the layout shift - await clickOnTestIdWithText(window, 'session-toast'); + await clickOnTestIdWithText(window, Global.toast.selector); await sleepFor(1000); - await clickOnTestIdWithText(window, 'message-input-text-area'); + await clickOnTestIdWithText(window, Conversation.messageInput.selector); const isMac = process.platform === 'darwin'; await window.keyboard.press(`${isMac ? 'Meta' : 'Control'}+V`); await checkModalStrings( diff --git a/tests/automation/utilities/send_message.ts b/tests/automation/utilities/send_message.ts index c86d222..d9ef8e6 100644 --- a/tests/automation/utilities/send_message.ts +++ b/tests/automation/utilities/send_message.ts @@ -1,5 +1,6 @@ import { Page } from '@playwright/test'; +import { HomeScreen } from '../locators'; import { sendMessage } from './message'; import { clickOnTestIdWithText, typeIntoInput } from './utils'; @@ -8,11 +9,11 @@ export const sendNewMessage = async ( sessionid: string, message: string, ) => { - await clickOnTestIdWithText(window, 'new-conversation-button'); - await clickOnTestIdWithText(window, 'chooser-new-conversation-button'); + await clickOnTestIdWithText(window, HomeScreen.plusButton.selector); + await clickOnTestIdWithText(window, HomeScreen.newMessageOption.selector); // Enter session ID of USER B await typeIntoInput(window, 'new-session-conversation', sessionid); // click next - await clickOnTestIdWithText(window, 'next-new-conversation-button'); + await clickOnTestIdWithText(window, HomeScreen.newMessageNextButton.selector); await sendMessage(window, message); }; diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index 2d795a1..2fb98e6 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -23,6 +23,11 @@ import { } from '../types/testing'; import { sendMessage } from './message'; +type ElementOptions = { + maxWait?: number; + rightButton?: boolean; +}; + // WAIT FOR FUNCTIONS export async function waitForTestIdWithText( @@ -245,19 +250,59 @@ export async function checkPathLight(window: Page, maxWait?: number) { // ACTIONS +export async function clickOn( + window: Page, + locator: StrategyExtractionObj, + options?: ElementOptions, +) { + let builtSelector: string; + + if (locator.strategy === 'class') { + builtSelector = `css=.${locator.selector}`; + } else { + builtSelector = `css=[${locator.strategy}=${locator.selector}]`; + } + + const sharedOpts = { timeout: options?.maxWait, strict: true }; + await window.click( + builtSelector, + options?.rightButton ? { ...sharedOpts, button: 'right' } : sharedOpts, + ); +} + +export async function clickOnWithText( + window: Page, + locator: StrategyExtractionObj, + text: string, + options?: ElementOptions, +) { + let builtSelector: string; + + if (locator.strategy === 'class') { + builtSelector = `css=.${locator.selector}:has-text("${text.replace( + /"/g, + '\\"', + )}")`; + } else { + builtSelector = `css=[${locator.strategy}=${ + locator.selector + }]:has-text("${text.replace(/"/g, '\\"')}")`; + } + + const sharedOpts = { timeout: options?.maxWait, strict: true }; + await window.click( + builtSelector, + options?.rightButton ? { ...sharedOpts, button: 'right' } : sharedOpts, + ); +} +// Legacy wrapper for backwards compatibility export async function clickOnElement({ window, maxWait, rightButton, ...obj }: WithPage & StrategyExtractionObj & WithMaxWait & WithRightButton) { - const builtSelector = `css=[${obj.strategy}=${obj.selector}]`; - console.info(`clickOnElement: looking for selector ${builtSelector}`); - const sharedOpts = { timeout: maxWait }; - await window.click( - builtSelector, - rightButton ? { ...sharedOpts, button: 'right' } : sharedOpts, - ); + return clickOn(window, obj, { maxWait, rightButton }); } export async function lookForPartialTestId( @@ -279,8 +324,6 @@ export async function lookForPartialTestId( return builtSelector; } -// - export async function clickOnMatchingText( window: Page, text: string, @@ -296,6 +339,7 @@ export async function clickOnMatchingText( ); } +// Legacy wrapper for backwards compatibility export async function clickOnTestIdWithText( window: Page, dataTestId: DataTestId, @@ -303,26 +347,12 @@ export async function clickOnTestIdWithText( rightButton?: boolean, maxWait?: number, ) { - const sharedOpts = { timeout: maxWait, strict: true }; - console.info( - `clickOnTestIdWithText with testId:${dataTestId} and text:${ - text || 'none' - }, rightButton:${!!rightButton}`, - ); + const locator = { strategy: 'data-testid' as const, selector: dataTestId }; - const builtSelector = !text - ? `css=[data-testid=${dataTestId}]` - : `css=[data-testid=${dataTestId}]:has-text("${text}")`; - - await window.click( - builtSelector, - rightButton ? { ...sharedOpts, button: 'right' } : sharedOpts, - ); - console.info( - `clickOnTestIdWithText:clicked! testId:${dataTestId} and text:${ - text || 'none' - }`, - ); + if (text) { + return clickOnWithText(window, locator, text, { rightButton, maxWait }); + } + return clickOn(window, locator, { rightButton, maxWait }); } export async function clickOnTextMessage( diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index 1059753..c102533 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -41,5 +41,5 @@ export const makeVoiceCall = async ( ); await clickOnTestIdWithText(receiverWindow, Global.modalCloseButton.selector); await sleepFor(5000); - await clickOnTestIdWithText(callerWindow, 'end-call'); + await clickOnTestIdWithText(callerWindow, Conversation.endCallButton.selector); }; From 23b799fa3de588618fca490665129e181bfef602 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 16:17:45 +1000 Subject: [PATCH 19/32] wip: replace all clickOnTestIdWithText with explicit functions --- tests/automation/community_tests.spec.ts | 18 +-- tests/automation/create_user.spec.ts | 12 +- tests/automation/delete_account.spec.ts | 35 +++--- .../disappearing_message_checks.spec.ts | 23 ++-- .../automation/disappearing_messages.spec.ts | 32 ++--- tests/automation/group_testing.spec.ts | 51 ++++---- tests/automation/input_validations.spec.ts | 7 +- tests/automation/linked_device_group.spec.ts | 79 ++++++------ .../automation/linked_device_requests.spec.ts | 79 ++++++------ tests/automation/linked_device_user.spec.ts | 117 +++++++++--------- tests/automation/locators/index.ts | 6 +- tests/automation/message_checks.spec.ts | 23 ++-- tests/automation/message_requests.spec.ts | 55 ++++---- tests/automation/password.spec.ts | 70 +++++------ tests/automation/switching_theme.spec.ts | 6 +- tests/automation/test.spec.ts | 4 +- 16 files changed, 312 insertions(+), 305 deletions(-) diff --git a/tests/automation/community_tests.spec.ts b/tests/automation/community_tests.spec.ts index e0ce330..4a73eed 100644 --- a/tests/automation/community_tests.spec.ts +++ b/tests/automation/community_tests.spec.ts @@ -5,19 +5,19 @@ import { joinCommunity } from './utilities/join_community'; import { sendMessage } from './utilities/message'; import { replyTo } from './utilities/reply_message'; import { sendMedia } from './utilities/send_media'; -import { clickOnTestIdWithText } from './utilities/utils'; +import { clickOn, clickOnWithText } from './utilities/utils'; test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => { await joinCommunity(aliceWindow1); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.scrollToBottomButton.selector, + Conversation.scrollToBottomButton, ); await sendMessage(aliceWindow1, 'Hello, community!'); // Check linked device for community - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, testCommunityName, ); }); @@ -35,17 +35,17 @@ test_Alice_1W_Bob_1W( // ]); await Promise.all( [aliceWindow1, bobWindow1].map((window) => - clickOnTestIdWithText( + clickOn( window, - Conversation.scrollToBottomButton.selector, + Conversation.scrollToBottomButton, ), ), ); await sendMessage(aliceWindow1, testMessage); // Check linked device for community - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, testCommunityName, ); await sendMedia( diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index aedb23f..e49c5c0 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -3,7 +3,7 @@ import { Global, LeftPane, Settings } from './locators'; import { newUser } from './setup/new_user'; import { sessionTestOneWindow } from './setup/sessionTest'; import { - clickOnTestIdWithText, + clickOn, waitForTestIdWithText, } from './utilities/utils'; @@ -11,7 +11,7 @@ sessionTestOneWindow('Create User', async ([window]) => { // Create User const userA = await newUser(window, 'Alice', false); // Open profile tab - await clickOnTestIdWithText(window, LeftPane.profileButton.selector); + await clickOn(window, LeftPane.profileButton); await sleepFor(100, true); // check username matches await waitForTestIdWithText( @@ -26,13 +26,13 @@ sessionTestOneWindow('Create User', async ([window]) => { userA.accountid, ); // exit profile modal - await clickOnTestIdWithText(window, Global.modalCloseButton.selector); + await clickOn(window, Global.modalCloseButton); // go to settings section - await clickOnTestIdWithText(window, LeftPane.settingsButton.selector); + await clickOn(window, LeftPane.settingsButton); // check recovery phrase matches - await clickOnTestIdWithText( + await clickOn( window, - Settings.recoveryPasswordMenuItem.selector, + Settings.recoveryPasswordMenuItem, ); await waitForTestIdWithText( window, diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 77080fc..e84893b 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -11,9 +11,10 @@ import { sessionTestTwoWindows } from './setup/sessionTest'; import { createContact } from './utilities/create_contact'; import { sendNewMessage } from './utilities/send_message'; import { + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, hasElementBeenDeleted, typeIntoInput, waitForElement, @@ -38,17 +39,17 @@ sessionTestTwoWindows( ]); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, LeftPane.settingsButton.selector); + await clickOn(windowA, LeftPane.settingsButton); // Click on clear all data - await clickOnTestIdWithText( + await clickOnWithText( windowA, - Settings.clearDataMenuItem.selector, + Settings.clearDataMenuItem, englishStrippedStr('sessionClearData').toString(), ); // Select entire account - await clickOnTestIdWithText( + await clickOnWithText( windowA, - Settings.clearDeviceAndNetworkRadial.selector, + Settings.clearDeviceAndNetworkRadial, englishStrippedStr('clearDeviceAndNetwork').toString(), ); // Confirm deletion by clicking Clear, twice @@ -68,9 +69,9 @@ sessionTestTwoWindows( restoringWindows = await openApp(1); // not using sessionTest here as we need to close and reopen one of the window const [restoringWindow] = restoringWindows; // Sign in with deleted account and check that nothing restores - await clickOnTestIdWithText( + await clickOn( restoringWindow, - Onboarding.iHaveAnAccountButton.selector, + Onboarding.iHaveAnAccountButton, ); // Fill in recovery phrase await typeIntoInput( @@ -79,9 +80,9 @@ sessionTestTwoWindows( userA.recoveryPassword, ); // Enter display name - await clickOnTestIdWithText( + await clickOn( restoringWindow, - Global.continueButton.selector, + Global.continueButton, ); await waitForLoadingAnimationToFinish( restoringWindow, @@ -94,9 +95,9 @@ sessionTestTwoWindows( userA.userName, ); // Click continue - await clickOnTestIdWithText( + await clickOn( restoringWindow, - Global.continueButton.selector, + Global.continueButton, ); await sleepFor(5000, true); // just to allow any messages from our swarm to show up @@ -108,9 +109,9 @@ sessionTestTwoWindows( HomeScreen.conversationItemName.selector, ); - await clickOnTestIdWithText( + await clickOn( restoringWindow, - HomeScreen.plusButton.selector, + HomeScreen.plusButton, ); // Expect contacts list to be empty await hasElementBeenDeleted( @@ -140,11 +141,11 @@ sessionTestTwoWindows( await createContact(windowA, windowB, userA, userB); // Delete all data from device // Click on settings tab - await clickOnTestIdWithText(windowA, LeftPane.settingsButton.selector); + await clickOn(windowA, LeftPane.settingsButton); // Click on clear all data - await clickOnTestIdWithText( + await clickOnWithText( windowA, - Settings.clearDataMenuItem.selector, + Settings.clearDataMenuItem, englishStrippedStr('sessionClearData').toString(), ); // Keep 'Clear Device only' selection diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index 90b5a34..4982e63 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -25,8 +25,9 @@ import { } from './utilities/send_media'; import { setDisappearingMessages } from './utilities/set_disappearing_messages'; import { + clickOn, clickOnElement, - clickOnTestIdWithText, + clickOnWithText, formatTimeOption, hasElementBeenDeleted, hasTextMessageBeenDeleted, @@ -242,34 +243,34 @@ test_Alice_1W_Bob_1W( await joinCommunity(aliceWindow1); // To stop the layout shift await sleepFor(500); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - ConversationSettings.inviteContactsOption.selector, + ConversationSettings.inviteContactsOption, ); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.contactItem.selector, + Global.contactItem, bob.userName, ); - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // For lack of a unique ID we use native Playwright methods await aliceWindow1 .getByTestId('invite-contacts-dialog') .getByTestId('modal-close-button') .click(); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Global.modalCloseButton); + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); await Promise.all([ diff --git a/tests/automation/disappearing_messages.spec.ts b/tests/automation/disappearing_messages.spec.ts index 6f80c5c..4679944 100644 --- a/tests/automation/disappearing_messages.spec.ts +++ b/tests/automation/disappearing_messages.spec.ts @@ -1,6 +1,7 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; import { sleepFor } from '../promise_utils'; import { defaultDisappearingOptions } from './constants/variables'; +import { Conversation, HomeScreen } from './locators'; import { test_Alice_2W, test_Alice_2W_Bob_1W, @@ -11,9 +12,10 @@ import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; import { setDisappearingMessages } from './utilities/set_disappearing_messages'; import { + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, doesTextIncludeString, formatTimeOption, hasElementBeenDeleted, @@ -42,9 +44,9 @@ test_Alice_2W_Bob_1W( // Create Contact await createContact(aliceWindow1, bobWindow1, alice, bob); // Click on conversation in linked device - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, ); @@ -106,9 +108,9 @@ test_Alice_2W_Bob_1W( await createContact(aliceWindow1, bobWindow1, alice, bob); // Click on conversation in linked device - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, ); await setDisappearingMessages( @@ -160,9 +162,9 @@ test_group_Alice_2W_Bob_1W_Charlie_1W( .toString(); const testMessage = 'Testing disappearing messages in groups'; - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await setDisappearingMessages(aliceWindow1, [ @@ -213,9 +215,9 @@ test_Alice_2W( // Open Note to self conversation await sendNewMessage(aliceWindow1, alice.accountid, testMessage); // Check messages are syncing across linked devices - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, englishStrippedStr('noteToSelf').toString(), ); await waitForTextMessage(aliceWindow2, testMessage); @@ -250,9 +252,9 @@ test_Alice_2W_Bob_1W( const formattedTime = formatTimeOption(timeOption); await createContact(aliceWindow1, bobWindow1, alice, bob); // Click on conversation on linked device - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, ); // Set disappearing messages to on @@ -301,12 +303,10 @@ test_Alice_2W_Bob_1W( waitForTextMessage(bobWindow1, testMessage), waitForTextMessage(aliceWindow2, testMessage), ]); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - 'conversation-options-avatar', - undefined, - undefined, - 1000, + Conversation.conversationSettingsIcon, + {maxWait: 1_000}, ); await clickOnElement({ window: aliceWindow1, diff --git a/tests/automation/group_testing.spec.ts b/tests/automation/group_testing.spec.ts index be3a50d..d1736b9 100644 --- a/tests/automation/group_testing.spec.ts +++ b/tests/automation/group_testing.spec.ts @@ -17,9 +17,10 @@ import { createContact } from './utilities/create_contact'; import { leaveGroup } from './utilities/leave_group'; import { renameGroup } from './utilities/rename_group'; import { + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, grabTextFromElement, typeIntoInput, waitForMatchingText, @@ -61,9 +62,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W_Dracula_1W( groupCreated, }) => { await createContact(aliceWindow1, draculaWindow1, alice, dracula); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); await clickOnElement({ @@ -97,10 +98,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W_Dracula_1W( }, [aliceWindow1, bobWindow1, charlieWindow1], ); - await clickOnTestIdWithText(draculaWindow1, Global.backButton.selector); - await clickOnTestIdWithText( + await clickOn(draculaWindow1, Global.backButton); + await clickOnWithText( draculaWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); }, @@ -133,17 +134,17 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Click on conversation options // Check to see that you can't change group name to empty string // Click on edit group name - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - ConversationSettings.editGroupButton.selector, + ConversationSettings.editGroupButton, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - ConversationSettings.clearGroupNameButton.selector, + ConversationSettings.clearGroupNameButton, ); await waitForTestIdWithText(aliceWindow1, Global.errorMessage.selector); const actualError = await grabTextFromElement( @@ -160,7 +161,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( aliceWindow1, englishStrippedStr('cancel').toString(), ); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); }, ); @@ -177,9 +178,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( }) => { // in windowA we should be able to mentions bob and userC - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await typeIntoInput(aliceWindow1, 'message-input-text-area', '@'); @@ -196,17 +197,17 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( charlie.userName, ); // ALice tags Bob - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'mentions-popup-row', + Conversation.mentionsPopup, bob.userName, ); await waitForMatchingText(bobWindow1, 'You'); // in windowB we should be able to mentions alice and charlie - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await typeIntoInput(bobWindow1, 'message-input-text-area', '@'); @@ -223,17 +224,17 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( charlie.userName, ); // Bob tags Charlie - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'mentions-popup-row', + Conversation.mentionsPopup, charlie.userName, ); await waitForMatchingText(charlieWindow1, 'You'); // in charlieWindow1 we should be able to mentions alice and userB - await clickOnTestIdWithText( + await clickOnWithText( charlieWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await typeIntoInput(charlieWindow1, 'message-input-text-area', '@'); @@ -250,9 +251,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( bob.userName, ); // Charlie tags Alice - await clickOnTestIdWithText( + await clickOnWithText( charlieWindow1, - 'mentions-popup-row', + Conversation.mentionsPopup, alice.userName, ); await waitForMatchingText(aliceWindow1, 'You'); diff --git a/tests/automation/input_validations.spec.ts b/tests/automation/input_validations.spec.ts index e0cddc2..d6d4c69 100644 --- a/tests/automation/input_validations.spec.ts +++ b/tests/automation/input_validations.spec.ts @@ -3,7 +3,6 @@ import { Global, Onboarding } from './locators'; import { sessionTestOneWindow } from './setup/sessionTest'; import { clickOn, - clickOnTestIdWithText, grabTextFromElement, typeIntoInput, waitForTestIdWithText, @@ -73,12 +72,12 @@ import { sessionTestOneWindow( `Display name validation: "${testName}"`, async ([window]) => { - await clickOnTestIdWithText( + await clickOn( window, - Onboarding.createAccountButton.selector, + Onboarding.createAccountButton, ); await typeIntoInput(window, 'display-name-input', displayName); - await clickOnTestIdWithText(window, Global.continueButton.selector); + await clickOn(window, Global.continueButton); await waitForTestIdWithText(window, Global.errorMessage.selector); const actualError = await grabTextFromElement( window, diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 322c17c..57949bd 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -18,8 +18,9 @@ import { import { leaveGroup } from './utilities/leave_group'; import { checkModalStrings, + clickOn, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, waitForTestIdWithText, } from './utilities/utils'; @@ -44,9 +45,9 @@ test_group_Alice_2W_Bob_1W_Charlie_1W( // Check for user A for control message that userC left group // await sleepFor(1000); // Click on group - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await waitForTestIdWithText( @@ -59,9 +60,9 @@ test_group_Alice_2W_Bob_1W_Charlie_1W( .toString(), ); // Check for linked device (userA) - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, groupCreated.userName, ); await waitForTestIdWithText( @@ -100,9 +101,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check group for members, conversation name and messages - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); // Check header name @@ -112,15 +113,15 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); // Check right panel has correct name await waitForTestIdWithText(aliceWindow2, 'group-name'); - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - ConversationSettings.manageMembersOption.selector, + ConversationSettings.manageMembersOption, ); await waitForTestIdWithText( aliceWindow2, @@ -149,11 +150,11 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ); async function clearDataOnWindow(window: Page) { - await clickOnTestIdWithText(window, LeftPane.settingsButton.selector); + await clickOn(window, LeftPane.settingsButton); // Click on clear data option on left pane - await clickOnTestIdWithText( + await clickOnWithText( window, - Settings.clearDataMenuItem.selector, + Settings.clearDataMenuItem, englishStrippedStr('sessionClearData').toString(), ); await checkModalStrings( @@ -162,9 +163,9 @@ async function clearDataOnWindow(window: Page) { englishStrippedStr('clearDataAllDescription').toString(), 'deleteAccountModal', ); - await clickOnTestIdWithText( + await clickOnWithText( window, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('clear').toString(), ); await checkModalStrings( @@ -191,9 +192,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check group for members, conversation name and messages - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); // Check header name @@ -203,13 +204,13 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - ConversationSettings.manageMembersOption.selector, + ConversationSettings.manageMembersOption, ); // Check for You, Bob and Charlie await Promise.all([ @@ -229,8 +230,8 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( charlie.userName, ), ]); - await clickOnTestIdWithText(aliceWindow2, Global.cancelButton.selector); - await clickOnTestIdWithText(aliceWindow2, Global.modalCloseButton.selector); + await clickOn(aliceWindow2, Global.cancelButton); + await clickOn(aliceWindow2, Global.modalCloseButton); // Delete device data on alicewindow2 await clearDataOnWindow(aliceWindow2); const [restoredWindow] = await openApp(1); @@ -242,9 +243,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check group for members, conversation name and messages - await clickOnTestIdWithText( + await clickOnWithText( restoredWindow, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); // Check header name @@ -254,13 +255,13 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText( + await clickOn( restoredWindow, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( restoredWindow, - ConversationSettings.manageMembersOption.selector, + ConversationSettings.manageMembersOption, ); // Check for You, Bob and Charlie await Promise.all([ @@ -281,10 +282,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ), ]); // Do it all again - await clickOnTestIdWithText(restoredWindow, Global.cancelButton.selector); - await clickOnTestIdWithText( + await clickOn(restoredWindow, Global.cancelButton); + await clickOn( restoredWindow, - Global.modalCloseButton.selector, + Global.modalCloseButton, ); // Delete device data on restoredWindow await clearDataOnWindow(restoredWindow); @@ -297,9 +298,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check group for members, conversation name and messages - await clickOnTestIdWithText( + await clickOnWithText( restoredWindow2, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, groupCreated.userName, ); // Check header name @@ -309,13 +310,13 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOnTestIdWithText( + await clickOn( restoredWindow2, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( restoredWindow2, - ConversationSettings.manageMembersOption.selector, + ConversationSettings.manageMembersOption, ); // Check for You, Bob and Charlie await Promise.all([ diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index d33f53d..29c7422 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -12,7 +12,8 @@ import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; import { checkModalStrings, - clickOnTestIdWithText, + clickOn, + clickOnWithText, waitForMatchingText, waitForTestIdWithText, waitForTextMessage, @@ -25,22 +26,22 @@ test_Alice_2W_Bob_1W( const testReply = `${alice.userName} accepting message request from ${bob.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Accept request in aliceWindow1 - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.acceptMessageRequestButton.selector, + Conversation.acceptMessageRequestButton, ); await waitForTestIdWithText( aliceWindow1, @@ -61,10 +62,10 @@ test_Alice_2W_Bob_1W( ); await sendMessage(aliceWindow1, testReply); await waitForTextMessage(bobWindow1, testReply); - await clickOnTestIdWithText(aliceWindow2, Global.backButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow2, Global.backButton); + await clickOn( aliceWindow2, - HomeScreen.plusButton.selector, + HomeScreen.plusButton, ); await waitForTestIdWithText( aliceWindow2, @@ -80,18 +81,18 @@ test_Alice_2W_Bob_1W( const testMessage = `${bob.userName} sending message request to ${alice.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Decline request in aliceWindow1 - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); await waitForTestIdWithText( aliceWindow2, @@ -99,14 +100,14 @@ test_Alice_2W_Bob_1W( bob.userName, ); await sleepFor(1000); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Conversation.deleteMessageRequestButton.selector, + Conversation.deleteMessageRequestButton, englishStrippedStr('delete').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('delete').toString(), ); await waitForMatchingText( @@ -127,20 +128,20 @@ test_Alice_2W_Bob_1W( // send a message to Bob to Alice await sendNewMessage(bobWindow1, alice.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); // Select message request from Bob - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); // Block Bob - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.blockMessageRequestButton.selector, + Conversation.blockMessageRequestButton, ); // Check modal strings await checkModalStrings( @@ -151,18 +152,18 @@ test_Alice_2W_Bob_1W( .toString(), ); // Confirm block - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // Need to wait for the blocked status to sync await sleepFor(2000); // Check blocked status in blocked contacts list - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, LeftPane.settingsButton); + await clickOn( aliceWindow1, - Settings.conversationsMenuItem.selector, + Settings.conversationsMenuItem, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.blockedContactsButton.selector, + Settings.blockedContactsButton, ); await waitForTestIdWithText( aliceWindow1, @@ -172,14 +173,14 @@ test_Alice_2W_Bob_1W( // Check that the blocked contacts is on alicewindow2 // Check blocked status in blocked contacts list await sleepFor(5000); - await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow2, LeftPane.settingsButton); + await clickOn( aliceWindow2, - Settings.conversationsMenuItem.selector, + Settings.conversationsMenuItem, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - Settings.blockedContactsButton.selector, + Settings.blockedContactsButton, ); await waitForTestIdWithText( aliceWindow2, diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index f6dda8e..35db7c4 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -22,10 +22,11 @@ import { linkedDevice } from './utilities/linked_device'; import { sendMessage } from './utilities/message'; import { checkModalStrings, + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, clickOnTextMessage, + clickOnWithText, doWhileWithMax, hasElementBeenDeleted, hasTextMessageBeenDeleted, @@ -42,7 +43,7 @@ sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { try { const userA = await newUser(aliceWindow1, 'Alice'); aliceWindow2 = await linkedDevice(userA.recoveryPassword); // not using fixture here as we want to check the behavior finely - await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); + await clickOn(aliceWindow1, LeftPane.profileButton); // Verify Username await waitForTestIdWithText( aliceWindow1, @@ -56,7 +57,7 @@ sessionTestOneWindow('Link a device', async ([aliceWindow1]) => { userA.accountid, ); // exit profile modal - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); // You're almost finished isn't displayed const errorDesc = 'Should not be found'; try { @@ -86,9 +87,9 @@ test_Alice_2W( 'Changed username syncs', async ({ aliceWindow1, aliceWindow2 }) => { const newUsername = 'Tiny bubble'; - await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); + await clickOn(aliceWindow1, LeftPane.profileButton); // Click on pencil icon - await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); + await clickOn(aliceWindow1, Settings.displayName); // Replace old username with new username await typeIntoInput( aliceWindow1, @@ -109,9 +110,9 @@ test_Alice_2W( 500, 'waiting for updated username in profile dialog', async () => { - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - LeftPane.profileButton.selector, + LeftPane.profileButton, ); // Verify username has changed to new username try { @@ -140,29 +141,29 @@ test_Alice_2W( test_Alice_2W( 'Profile picture syncs', async ({ aliceWindow1, aliceWindow2 }, testinfo) => { - await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); + await clickOn(aliceWindow1, LeftPane.profileButton); // Click on current profile picture - await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Settings.displayName); + await clickOn( aliceWindow1, - Settings.imageUploadSection.selector, + Settings.imageUploadSection, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.imageUploadClick.selector, + Settings.imageUploadClick, ); // allow for the image to be resized before we try to save it await sleepFor(500); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.saveProfileUpdateButton.selector, + Settings.saveProfileUpdateButton, ); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); await clickOnMatchingText( aliceWindow1, englishStrippedStr('save').toString(), ); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); if (testinfo.config.updateSnapshots === 'all') { await sleepFor(15000, true); // long time to be sure a poll happened when we want to update the snapshot @@ -226,9 +227,9 @@ test_Alice_2W_Bob_1W( await createContact(aliceWindow1, bobWindow1, alice, bob); await sendMessage(aliceWindow1, messageToDelete); // Navigate to conversation on linked device and for message from user A to user B - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, ); await Promise.all([ @@ -240,9 +241,9 @@ test_Alice_2W_Bob_1W( aliceWindow1, englishStrippedStr('delete').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('delete').toString(), ); await waitForTestIdWithText( @@ -269,9 +270,9 @@ test_Alice_2W_Bob_1W( await createContact(aliceWindow1, bobWindow1, alice, bob); await sendMessage(aliceWindow1, unsentMessage); // Navigate to conversation on linked device and for message from user A to user B - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, ); await Promise.all([ @@ -317,16 +318,16 @@ test_Alice_2W_Bob_1W( await createContact(aliceWindow1, bobWindow1, alice, bob); await sendMessage(aliceWindow1, testMessage); // Navigate to conversation on linked device and check for message from user A to user B - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, - true, + {rightButton: true}, ); // Select block - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - Global.contextMenuItem.selector, + Global.contextMenuItem, englishStrippedStr('block').toString(), ); // Check modal strings @@ -337,9 +338,9 @@ test_Alice_2W_Bob_1W( .withArgs({ name: bob.userName }) .toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow2, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('block').toString(), ); // Verify the user was moved to the blocked contact list @@ -350,18 +351,16 @@ test_Alice_2W_Bob_1W( ); // Check linked device for blocked contact in settings screen // Click on settings tab - await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow2, LeftPane.settingsButton); + await clickOn( aliceWindow2, - Settings.conversationsMenuItem.selector, + Settings.conversationsMenuItem, ); // a conf sync job can take 30s (if the last one failed) + 10s polling to show a change on a linked device. - await clickOnTestIdWithText( + await clickOn( aliceWindow2, - Settings.blockedContactsButton.selector, - undefined, - undefined, - 50000, + Settings.blockedContactsButton, + {maxWait: 50_000}, ); // Check if user B is in blocked contact list await waitForTestIdWithText( @@ -377,7 +376,7 @@ test_Alice_2W_Bob_1W( async ({ alice, aliceWindow1, aliceWindow2, bob, bobWindow1 }) => { // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); - await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); + await clickOn(bobWindow1, Global.backButton); await Promise.all( [aliceWindow1, aliceWindow2, bobWindow1].map((w) => clickOnElement({ @@ -406,19 +405,19 @@ test_Alice_2W_Bob_1W( ]); await Promise.all( [aliceWindow1, aliceWindow2, bobWindow1].map((w) => - clickOnTestIdWithText(w, Global.backButton.selector), + clickOn(w, Global.backButton), ), ); // Delete contact - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, - true, + {rightButton: true}, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.contextMenuItem.selector, + Global.contextMenuItem, englishStrippedStr('conversationsDelete').toString(), ); await checkModalStrings( @@ -428,9 +427,9 @@ test_Alice_2W_Bob_1W( .withArgs({ name: bob.userName }) .toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('delete').toString(), ); // Check if conversation is deleted @@ -452,22 +451,22 @@ test_Alice_2W_Bob_1W( test_Alice_2W( 'Hide note to self syncs', async ({ alice, aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.plusButton.selector, + HomeScreen.plusButton, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.newMessageOption.selector, + HomeScreen.newMessageOption, ); await typeIntoInput( aliceWindow1, HomeScreen.newMessageAccountIDInput.selector, alice.accountid, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - HomeScreen.newMessageNextButton.selector, + HomeScreen.newMessageNextButton, ); await waitForTestIdWithText( aliceWindow1, @@ -482,15 +481,15 @@ test_Alice_2W( HomeScreen.conversationItemName.selector, englishStrippedStr('noteToSelf').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, englishStrippedStr('noteToSelf').toString(), - true, + {rightButton: true}, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.contextMenuItem.selector, + Global.contextMenuItem, englishStrippedStr('noteToSelfHide').toString(), ); await checkModalStrings( @@ -498,9 +497,9 @@ test_Alice_2W( englishStrippedStr('noteToSelfHide').toString(), englishStrippedStr('noteToSelfHideDescription').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('hide').toString(), ); // Check linked device for hidden note to self diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index d475ecc..d62ed98 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -78,7 +78,6 @@ export class HomeScreen extends Locator { } export class Conversation extends Locator { - static readonly messageContent = this.testId('message-content') static readonly acceptMessageRequestButton = this.testId( 'accept-message-request', ); @@ -96,13 +95,15 @@ export class Conversation extends Locator { static readonly disappearingControlMessage = this.testId( 'disappear-control-message', ); + static readonly endCallButton = this.testId('end-call') static readonly endVoiceMessageButton = this.testId('end-voice-message'); + static readonly mentionsPopup = this.testId('mentions-popup-row') + static readonly messageContent = this.testId('message-content') static readonly messageInput = this.testId('message-input-text-area'); static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', ); - static readonly endCallButton = this.testId('end-call') static readonly microphoneButton = this.testId('microphone-button'); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); } @@ -143,6 +144,7 @@ export class Settings extends Locator { static readonly conversationsMenuItem = this.testId( 'conversations-settings-menu-item', ); + static readonly messageRequestsMenuItem = this.testId('message-requests-settings-menu-item') static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); static readonly recoveryPasswordMenuItem = this.testId( 'recovery-password-settings-menu-item', diff --git a/tests/automation/message_checks.spec.ts b/tests/automation/message_checks.spec.ts index 558fb77..d691794 100644 --- a/tests/automation/message_checks.spec.ts +++ b/tests/automation/message_checks.spec.ts @@ -24,10 +24,11 @@ import { trustUser, } from './utilities/send_media'; import { + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, clickOnTextMessage, + clickOnWithText, hasTextMessageBeenDeleted, measureSendingTime, typeIntoInput, @@ -127,35 +128,35 @@ test_Alice_1W_Bob_1W( async ({ alice, aliceWindow1, bob, bobWindow1 }) => { await createContact(aliceWindow1, bobWindow1, alice, bob); await joinCommunity(aliceWindow1); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Conversation.conversationSettingsIcon.selector, + Conversation.conversationSettingsIcon, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - ConversationSettings.inviteContactsOption.selector, + ConversationSettings.inviteContactsOption, ); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.contactItem.selector, + Global.contactItem, bob.userName, ); - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // For lack of a unique ID we use native Playwright methods await aliceWindow1 .getByTestId('invite-contacts-dialog') .getByTestId(Global.modalCloseButton.selector) .click(); // Close UCS modal - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Global.modalCloseButton); + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); await Promise.all([ diff --git a/tests/automation/message_requests.spec.ts b/tests/automation/message_requests.spec.ts index 73e1acf..8da7336 100644 --- a/tests/automation/message_requests.spec.ts +++ b/tests/automation/message_requests.spec.ts @@ -1,12 +1,13 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { Conversation, HomeScreen, LeftPane } from './locators'; +import { Conversation, Global, HomeScreen, LeftPane, Settings } from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; import { checkModalStrings, + clickOn, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, waitForMatchingText, waitForTestIdWithText, } from './utilities/utils'; @@ -19,20 +20,20 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText( + await clickOn( bobWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); // Select message request from User A - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, alice.userName, ); // Check that using the accept button has intended use - await clickOnTestIdWithText( + await clickOn( bobWindow1, - Conversation.acceptMessageRequestButton.selector, + Conversation.acceptMessageRequestButton, ); // Check config message of message request acceptance await waitForTestIdWithText( @@ -59,14 +60,14 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText( + await clickOn( bobWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); // Select message request from User A - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, alice.userName, ); await sendMessage(bobWindow1, testReply); @@ -95,20 +96,20 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText( + await clickOn( bobWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); // Select message request from User A - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, alice.userName, ); - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'delete-message-request', + Conversation.deleteMessageRequestButton, englishStrippedStr('delete').toString(), ); // Confirm decline @@ -117,9 +118,9 @@ test_Alice_1W_Bob_1W( englishStrippedStr('delete').toString(), englishStrippedStr('messageRequestsDelete').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('delete').toString(), ); // Check config message of message request acceptance @@ -137,9 +138,9 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOnTestIdWithText( + await clickOn( bobWindow1, - HomeScreen.messageRequestBanner.selector, + HomeScreen.messageRequestBanner, ); // Select 'Clear All' button await clickOnMatchingText( @@ -152,17 +153,17 @@ test_Alice_1W_Bob_1W( englishStrippedStr('clearAll').toString(), englishStrippedStr('messageRequestsClearAllExplanation').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('clear').toString(), ); // Navigate back to message request folder to check - await clickOnTestIdWithText(bobWindow1, LeftPane.settingsButton.selector); + await clickOn(bobWindow1, LeftPane.settingsButton); - await clickOnTestIdWithText( + await clickOnWithText( bobWindow1, - 'message-requests-settings-menu-item', + Settings.messageRequestsMenuItem, englishStrippedStr('sessionMessageRequests').toString(), ); // Check config message of message request acceptance diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 957bcdc..57816d8 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -5,8 +5,8 @@ import { sleepFor } from '../promise_utils'; import { Global, LeftPane, Settings } from './locators'; import { test_Alice_1W_no_network } from './setup/sessionTest'; import { + clickOn, clickOnMatchingText, - clickOnTestIdWithText, hasElementPoppedUpThatShouldnt, typeIntoInput, waitForTestIdWithText, @@ -29,13 +29,13 @@ async function expectRecoveryPhraseToBeVisible( test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOn(aliceWindow1, LeftPane.settingsButton); // Click on privacy - await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); + await clickOn(aliceWindow1, Settings.privacyMenuItem); // Click set password - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.setPasswordSettingsButton.selector, + Settings.setPasswordSettingsButton, ); // Enter password await typeIntoInput( @@ -49,9 +49,9 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { Settings.confirmPasswordInput.selector, testPassword, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.setPasswordButton.selector, + Settings.setPasswordButton, ); // Check toast notification await waitForTestIdWithText( @@ -61,11 +61,11 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { ); // Click on settings tab await sleepFor(300, true); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Global.modalCloseButton); + await clickOn(aliceWindow1, LeftPane.settingsButton); + await clickOn( aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, + Settings.recoveryPasswordMenuItem, ); await sleepFor(300, true); @@ -83,13 +83,13 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // check that the seed is visible now await expectRecoveryPhraseToBeVisible(aliceWindow1, alice.recoveryPassword); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText(aliceWindow1, Settings.privacyMenuItem.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); + await clickOn(aliceWindow1, LeftPane.settingsButton); + await clickOn(aliceWindow1, Settings.privacyMenuItem); // Change password - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.changePasswordSettingsButton.selector, + Settings.changePasswordSettingsButton, ); // Enter old password @@ -125,16 +125,16 @@ test_Alice_1W_no_network( async ({ alice: { recoveryPassword }, aliceWindow1 }) => { // Check if incorrect password works // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOn(aliceWindow1, LeftPane.settingsButton); // Click on privacy - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.privacyMenuItem.selector, + Settings.privacyMenuItem, ); // Click set password - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.setPasswordSettingsButton.selector, + Settings.setPasswordSettingsButton, ); // Enter password await typeIntoInput( @@ -148,16 +148,16 @@ test_Alice_1W_no_network( Settings.confirmPasswordInput.selector, testPassword, ); - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.setPasswordButton.selector, + Settings.setPasswordButton, ); // Click on recovery phrase tab await sleepFor(5000); - await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Global.modalBackButton); + await clickOn( aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, + Settings.recoveryPasswordMenuItem, ); // Type password into input field await typeIntoInput( @@ -166,16 +166,16 @@ test_Alice_1W_no_network( testPassword, ); // Confirm the password - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // this should print the recovery phrase await expectRecoveryPhraseToBeVisible(aliceWindow1, recoveryPassword); - await clickOnTestIdWithText(aliceWindow1, Global.modalBackButton.selector); + await clickOn(aliceWindow1, Global.modalBackButton); await sleepFor(500); // Click on recovery phrase tab - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, + Settings.recoveryPasswordMenuItem, ); // Try with incorrect password await typeIntoInput( @@ -184,7 +184,7 @@ test_Alice_1W_no_network( newTestPassword, ); // Confirm the password - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // this should NOT print the recovery phrase await hasElementPoppedUpThatShouldnt( @@ -200,15 +200,15 @@ test_Alice_1W_no_network( Global.errorMessage.selector, englishStrippedStr('passwordIncorrect').toString(), ); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); await sleepFor(100); // Click on recovery phrase tab - await clickOnTestIdWithText( + await clickOn( aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, + Settings.recoveryPasswordMenuItem, ); // No password entered - await clickOnTestIdWithText(aliceWindow1, Global.confirmButton.selector); + await clickOn(aliceWindow1, Global.confirmButton); // Banner should ask for password to be entered await waitForTestIdWithText( aliceWindow1, diff --git a/tests/automation/switching_theme.spec.ts b/tests/automation/switching_theme.spec.ts index cc5a7ec..67e0701 100644 --- a/tests/automation/switching_theme.spec.ts +++ b/tests/automation/switching_theme.spec.ts @@ -2,7 +2,7 @@ import { expect } from '@playwright/test'; import { LeftPane } from './locators'; import { test_Alice_1W_no_network } from './setup/sessionTest'; -import { clickOnTestIdWithText } from './utilities/utils'; +import { clickOn } from './utilities/utils'; test_Alice_1W_no_network('Switch themes', async ({ aliceWindow1 }) => { // Create @@ -11,7 +11,7 @@ test_Alice_1W_no_network('Switch themes', async ({ aliceWindow1 }) => { await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)'); // Click theme button and change to dark theme - await clickOnTestIdWithText(aliceWindow1, LeftPane.themeButton.selector); + await clickOn(aliceWindow1, LeftPane.themeButton); // Check background colour of background to verify dark theme const lightThemeColor = aliceWindow1.locator('.inbox.index'); await expect(lightThemeColor).toHaveCSS( @@ -20,7 +20,7 @@ test_Alice_1W_no_network('Switch themes', async ({ aliceWindow1 }) => { ); // Toggle back to light theme - await clickOnTestIdWithText(aliceWindow1, LeftPane.themeButton.selector); + await clickOn(aliceWindow1, LeftPane.themeButton); // Check background colour again await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)'); }); diff --git a/tests/automation/test.spec.ts b/tests/automation/test.spec.ts index afd0258..9017713 100644 --- a/tests/automation/test.spec.ts +++ b/tests/automation/test.spec.ts @@ -1,7 +1,7 @@ import { Onboarding } from './locators'; import { sessionTestOneWindow } from './setup/sessionTest'; -import { clickOnTestIdWithText } from './utilities/utils'; +import { clickOn } from './utilities/utils'; sessionTestOneWindow('Tiny test', async ([windowA]) => { - await clickOnTestIdWithText(windowA, Onboarding.createAccountButton.selector); + await clickOn(windowA, Onboarding.createAccountButton); }); From 8e8ec22a67177bb4268b9304d905219fe1b9e1f2 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 16:25:52 +1000 Subject: [PATCH 20/32] wip: linting --- tests/automation/community_tests.spec.ts | 10 +- tests/automation/create_user.spec.ts | 10 +- tests/automation/delete_account.spec.ts | 20 +- .../disappearing_message_checks.spec.ts | 16 +- .../automation/disappearing_messages.spec.ts | 8 +- tests/automation/group_testing.spec.ts | 15 +- tests/automation/input_validations.spec.ts | 5 +- tests/automation/linked_device_group.spec.ts | 45 +--- .../automation/linked_device_requests.spec.ts | 60 +---- tests/automation/linked_device_user.spec.ts | 54 ++--- tests/automation/locators/index.ts | 17 +- tests/automation/message_checks.spec.ts | 16 +- tests/automation/message_requests.spec.ts | 33 +-- tests/automation/password.spec.ts | 50 +--- tests/automation/setup/create_group.ts | 5 +- tests/automation/user_actions.spec.ts | 218 +++++++----------- tests/automation/utilities/join_community.ts | 5 +- tests/automation/utilities/send_media.ts | 7 +- tests/automation/utilities/voice_call.ts | 5 +- 19 files changed, 178 insertions(+), 421 deletions(-) diff --git a/tests/automation/community_tests.spec.ts b/tests/automation/community_tests.spec.ts index 4a73eed..694ca49 100644 --- a/tests/automation/community_tests.spec.ts +++ b/tests/automation/community_tests.spec.ts @@ -9,10 +9,7 @@ import { clickOn, clickOnWithText } from './utilities/utils'; test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => { await joinCommunity(aliceWindow1); - await clickOn( - aliceWindow1, - Conversation.scrollToBottomButton, - ); + await clickOn(aliceWindow1, Conversation.scrollToBottomButton); await sendMessage(aliceWindow1, 'Hello, community!'); // Check linked device for community await clickOnWithText( @@ -35,10 +32,7 @@ test_Alice_1W_Bob_1W( // ]); await Promise.all( [aliceWindow1, bobWindow1].map((window) => - clickOn( - window, - Conversation.scrollToBottomButton, - ), + clickOn(window, Conversation.scrollToBottomButton), ), ); await sendMessage(aliceWindow1, testMessage); diff --git a/tests/automation/create_user.spec.ts b/tests/automation/create_user.spec.ts index e49c5c0..e093043 100644 --- a/tests/automation/create_user.spec.ts +++ b/tests/automation/create_user.spec.ts @@ -2,10 +2,7 @@ import { sleepFor } from '../promise_utils'; import { Global, LeftPane, Settings } from './locators'; import { newUser } from './setup/new_user'; import { sessionTestOneWindow } from './setup/sessionTest'; -import { - clickOn, - waitForTestIdWithText, -} from './utilities/utils'; +import { clickOn, waitForTestIdWithText } from './utilities/utils'; sessionTestOneWindow('Create User', async ([window]) => { // Create User @@ -30,10 +27,7 @@ sessionTestOneWindow('Create User', async ([window]) => { // go to settings section await clickOn(window, LeftPane.settingsButton); // check recovery phrase matches - await clickOn( - window, - Settings.recoveryPasswordMenuItem, - ); + await clickOn(window, Settings.recoveryPasswordMenuItem); await waitForTestIdWithText( window, Settings.recoveryPasswordContainer.selector, diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index e84893b..93e67ea 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -69,10 +69,7 @@ sessionTestTwoWindows( restoringWindows = await openApp(1); // not using sessionTest here as we need to close and reopen one of the window const [restoringWindow] = restoringWindows; // Sign in with deleted account and check that nothing restores - await clickOn( - restoringWindow, - Onboarding.iHaveAnAccountButton, - ); + await clickOn(restoringWindow, Onboarding.iHaveAnAccountButton); // Fill in recovery phrase await typeIntoInput( restoringWindow, @@ -80,10 +77,7 @@ sessionTestTwoWindows( userA.recoveryPassword, ); // Enter display name - await clickOn( - restoringWindow, - Global.continueButton, - ); + await clickOn(restoringWindow, Global.continueButton); await waitForLoadingAnimationToFinish( restoringWindow, 'loading-animation', @@ -95,10 +89,7 @@ sessionTestTwoWindows( userA.userName, ); // Click continue - await clickOn( - restoringWindow, - Global.continueButton, - ); + await clickOn(restoringWindow, Global.continueButton); await sleepFor(5000, true); // just to allow any messages from our swarm to show up // Need to verify that no conversation is found at all @@ -109,10 +100,7 @@ sessionTestTwoWindows( HomeScreen.conversationItemName.selector, ); - await clickOn( - restoringWindow, - HomeScreen.plusButton, - ); // Expect contacts list to be empty + await clickOn(restoringWindow, HomeScreen.plusButton); // Expect contacts list to be empty await hasElementBeenDeleted( restoringWindow, diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index 4982e63..e7741e0 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -243,24 +243,14 @@ test_Alice_1W_Bob_1W( await joinCommunity(aliceWindow1); // To stop the layout shift await sleepFor(500); - await clickOn( - aliceWindow1, - Conversation.conversationSettingsIcon, - ); - await clickOn( - aliceWindow1, - ConversationSettings.inviteContactsOption, - ); + await clickOn(aliceWindow1, Conversation.conversationSettingsIcon); + await clickOn(aliceWindow1, ConversationSettings.inviteContactsOption); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnWithText( - aliceWindow1, - Global.contactItem, - bob.userName, - ); + await clickOnWithText(aliceWindow1, Global.contactItem, bob.userName); await clickOn(aliceWindow1, Global.confirmButton); // For lack of a unique ID we use native Playwright methods await aliceWindow1 diff --git a/tests/automation/disappearing_messages.spec.ts b/tests/automation/disappearing_messages.spec.ts index 4679944..11699ad 100644 --- a/tests/automation/disappearing_messages.spec.ts +++ b/tests/automation/disappearing_messages.spec.ts @@ -303,11 +303,9 @@ test_Alice_2W_Bob_1W( waitForTextMessage(bobWindow1, testMessage), waitForTextMessage(aliceWindow2, testMessage), ]); - await clickOn( - aliceWindow1, - Conversation.conversationSettingsIcon, - {maxWait: 1_000}, - ); + await clickOn(aliceWindow1, Conversation.conversationSettingsIcon, { + maxWait: 1_000, + }); await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', diff --git a/tests/automation/group_testing.spec.ts b/tests/automation/group_testing.spec.ts index d1736b9..54b171e 100644 --- a/tests/automation/group_testing.spec.ts +++ b/tests/automation/group_testing.spec.ts @@ -134,18 +134,9 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( // Click on conversation options // Check to see that you can't change group name to empty string // Click on edit group name - await clickOn( - aliceWindow1, - Conversation.conversationSettingsIcon, - ); - await clickOn( - aliceWindow1, - ConversationSettings.editGroupButton, - ); - await clickOn( - aliceWindow1, - ConversationSettings.clearGroupNameButton, - ); + await clickOn(aliceWindow1, Conversation.conversationSettingsIcon); + await clickOn(aliceWindow1, ConversationSettings.editGroupButton); + await clickOn(aliceWindow1, ConversationSettings.clearGroupNameButton); await waitForTestIdWithText(aliceWindow1, Global.errorMessage.selector); const actualError = await grabTextFromElement( aliceWindow1, diff --git a/tests/automation/input_validations.spec.ts b/tests/automation/input_validations.spec.ts index d6d4c69..d8f7fd4 100644 --- a/tests/automation/input_validations.spec.ts +++ b/tests/automation/input_validations.spec.ts @@ -72,10 +72,7 @@ import { sessionTestOneWindow( `Display name validation: "${testName}"`, async ([window]) => { - await clickOn( - window, - Onboarding.createAccountButton, - ); + await clickOn(window, Onboarding.createAccountButton); await typeIntoInput(window, 'display-name-input', displayName); await clickOn(window, Global.continueButton); await waitForTestIdWithText(window, Global.errorMessage.selector); diff --git a/tests/automation/linked_device_group.spec.ts b/tests/automation/linked_device_group.spec.ts index 57949bd..73587ce 100644 --- a/tests/automation/linked_device_group.spec.ts +++ b/tests/automation/linked_device_group.spec.ts @@ -113,16 +113,10 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOn( - aliceWindow2, - Conversation.conversationSettingsIcon, - ); + await clickOn(aliceWindow2, Conversation.conversationSettingsIcon); // Check right panel has correct name await waitForTestIdWithText(aliceWindow2, 'group-name'); - await clickOn( - aliceWindow2, - ConversationSettings.manageMembersOption, - ); + await clickOn(aliceWindow2, ConversationSettings.manageMembersOption); await waitForTestIdWithText( aliceWindow2, 'modal-heading', @@ -204,14 +198,8 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOn( - aliceWindow2, - Conversation.conversationSettingsIcon, - ); - await clickOn( - aliceWindow2, - ConversationSettings.manageMembersOption, - ); + await clickOn(aliceWindow2, Conversation.conversationSettingsIcon); + await clickOn(aliceWindow2, ConversationSettings.manageMembersOption); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( @@ -255,14 +243,8 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOn( - restoredWindow, - Conversation.conversationSettingsIcon, - ); - await clickOn( - restoredWindow, - ConversationSettings.manageMembersOption, - ); + await clickOn(restoredWindow, Conversation.conversationSettingsIcon); + await clickOn(restoredWindow, ConversationSettings.manageMembersOption); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( @@ -283,10 +265,7 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( ]); // Do it all again await clickOn(restoredWindow, Global.cancelButton); - await clickOn( - restoredWindow, - Global.modalCloseButton, - ); + await clickOn(restoredWindow, Global.modalCloseButton); // Delete device data on restoredWindow await clearDataOnWindow(restoredWindow); const [restoredWindow2] = await openApp(1); @@ -310,14 +289,8 @@ test_group_Alice_1W_Bob_1W_Charlie_1W( groupCreated.userName, ); // Check for group members - await clickOn( - restoredWindow2, - Conversation.conversationSettingsIcon, - ); - await clickOn( - restoredWindow2, - ConversationSettings.manageMembersOption, - ); + await clickOn(restoredWindow2, Conversation.conversationSettingsIcon); + await clickOn(restoredWindow2, ConversationSettings.manageMembersOption); // Check for You, Bob and Charlie await Promise.all([ waitForTestIdWithText( diff --git a/tests/automation/linked_device_requests.spec.ts b/tests/automation/linked_device_requests.spec.ts index 29c7422..6284459 100644 --- a/tests/automation/linked_device_requests.spec.ts +++ b/tests/automation/linked_device_requests.spec.ts @@ -26,23 +26,14 @@ test_Alice_2W_Bob_1W( const testReply = `${alice.userName} accepting message request from ${bob.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Accept request in aliceWindow1 - await clickOn( - aliceWindow1, - HomeScreen.messageRequestBanner, - ); - await clickOn( - aliceWindow2, - HomeScreen.messageRequestBanner, - ); + await clickOn(aliceWindow1, HomeScreen.messageRequestBanner); + await clickOn(aliceWindow2, HomeScreen.messageRequestBanner); await clickOnWithText( aliceWindow1, HomeScreen.conversationItemName, bob.userName, ); - await clickOn( - aliceWindow1, - Conversation.acceptMessageRequestButton, - ); + await clickOn(aliceWindow1, Conversation.acceptMessageRequestButton); await waitForTestIdWithText( aliceWindow1, Conversation.messageRequestAcceptControlMessage.selector, @@ -63,10 +54,7 @@ test_Alice_2W_Bob_1W( await sendMessage(aliceWindow1, testReply); await waitForTextMessage(bobWindow1, testReply); await clickOn(aliceWindow2, Global.backButton); - await clickOn( - aliceWindow2, - HomeScreen.plusButton, - ); + await clickOn(aliceWindow2, HomeScreen.plusButton); await waitForTestIdWithText( aliceWindow2, Global.contactItem.selector, @@ -81,19 +69,13 @@ test_Alice_2W_Bob_1W( const testMessage = `${bob.userName} sending message request to ${alice.userName}`; await sendNewMessage(bobWindow1, alice.accountid, testMessage); // Decline request in aliceWindow1 - await clickOn( - aliceWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(aliceWindow1, HomeScreen.messageRequestBanner); await clickOnWithText( aliceWindow1, HomeScreen.conversationItemName, bob.userName, ); - await clickOn( - aliceWindow2, - HomeScreen.messageRequestBanner, - ); + await clickOn(aliceWindow2, HomeScreen.messageRequestBanner); await waitForTestIdWithText( aliceWindow2, HomeScreen.conversationItemName.selector, @@ -128,10 +110,7 @@ test_Alice_2W_Bob_1W( // send a message to Bob to Alice await sendNewMessage(bobWindow1, alice.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOn( - aliceWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(aliceWindow1, HomeScreen.messageRequestBanner); // Select message request from Bob await clickOnWithText( aliceWindow1, @@ -139,10 +118,7 @@ test_Alice_2W_Bob_1W( bob.userName, ); // Block Bob - await clickOn( - aliceWindow1, - Conversation.blockMessageRequestButton, - ); + await clickOn(aliceWindow1, Conversation.blockMessageRequestButton); // Check modal strings await checkModalStrings( aliceWindow1, @@ -157,14 +133,8 @@ test_Alice_2W_Bob_1W( await sleepFor(2000); // Check blocked status in blocked contacts list await clickOn(aliceWindow1, LeftPane.settingsButton); - await clickOn( - aliceWindow1, - Settings.conversationsMenuItem, - ); - await clickOn( - aliceWindow1, - Settings.blockedContactsButton, - ); + await clickOn(aliceWindow1, Settings.conversationsMenuItem); + await clickOn(aliceWindow1, Settings.blockedContactsButton); await waitForTestIdWithText( aliceWindow1, Global.contactItem.selector, @@ -174,14 +144,8 @@ test_Alice_2W_Bob_1W( // Check blocked status in blocked contacts list await sleepFor(5000); await clickOn(aliceWindow2, LeftPane.settingsButton); - await clickOn( - aliceWindow2, - Settings.conversationsMenuItem, - ); - await clickOn( - aliceWindow2, - Settings.blockedContactsButton, - ); + await clickOn(aliceWindow2, Settings.conversationsMenuItem); + await clickOn(aliceWindow2, Settings.blockedContactsButton); await waitForTestIdWithText( aliceWindow2, Global.contactItem.selector, diff --git a/tests/automation/linked_device_user.spec.ts b/tests/automation/linked_device_user.spec.ts index 35db7c4..7714017 100644 --- a/tests/automation/linked_device_user.spec.ts +++ b/tests/automation/linked_device_user.spec.ts @@ -110,10 +110,7 @@ test_Alice_2W( 500, 'waiting for updated username in profile dialog', async () => { - await clickOn( - aliceWindow2, - LeftPane.profileButton, - ); + await clickOn(aliceWindow2, LeftPane.profileButton); // Verify username has changed to new username try { await waitForTestIdWithText( @@ -144,20 +141,11 @@ test_Alice_2W( await clickOn(aliceWindow1, LeftPane.profileButton); // Click on current profile picture await clickOn(aliceWindow1, Settings.displayName); - await clickOn( - aliceWindow1, - Settings.imageUploadSection, - ); - await clickOn( - aliceWindow1, - Settings.imageUploadClick, - ); + await clickOn(aliceWindow1, Settings.imageUploadSection); + await clickOn(aliceWindow1, Settings.imageUploadClick); // allow for the image to be resized before we try to save it await sleepFor(500); - await clickOn( - aliceWindow1, - Settings.saveProfileUpdateButton, - ); + await clickOn(aliceWindow1, Settings.saveProfileUpdateButton); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); await clickOnMatchingText( aliceWindow1, @@ -322,7 +310,7 @@ test_Alice_2W_Bob_1W( aliceWindow2, HomeScreen.conversationItemName, bob.userName, - {rightButton: true}, + { rightButton: true }, ); // Select block await clickOnWithText( @@ -352,16 +340,11 @@ test_Alice_2W_Bob_1W( // Check linked device for blocked contact in settings screen // Click on settings tab await clickOn(aliceWindow2, LeftPane.settingsButton); - await clickOn( - aliceWindow2, - Settings.conversationsMenuItem, - ); + await clickOn(aliceWindow2, Settings.conversationsMenuItem); // a conf sync job can take 30s (if the last one failed) + 10s polling to show a change on a linked device. - await clickOn( - aliceWindow2, - Settings.blockedContactsButton, - {maxWait: 50_000}, - ); + await clickOn(aliceWindow2, Settings.blockedContactsButton, { + maxWait: 50_000, + }); // Check if user B is in blocked contact list await waitForTestIdWithText( aliceWindow2, @@ -413,7 +396,7 @@ test_Alice_2W_Bob_1W( aliceWindow1, HomeScreen.conversationItemName, bob.userName, - {rightButton: true}, + { rightButton: true }, ); await clickOnWithText( aliceWindow1, @@ -451,23 +434,14 @@ test_Alice_2W_Bob_1W( test_Alice_2W( 'Hide note to self syncs', async ({ alice, aliceWindow1, aliceWindow2 }) => { - await clickOn( - aliceWindow1, - HomeScreen.plusButton, - ); - await clickOn( - aliceWindow1, - HomeScreen.newMessageOption, - ); + await clickOn(aliceWindow1, HomeScreen.plusButton); + await clickOn(aliceWindow1, HomeScreen.newMessageOption); await typeIntoInput( aliceWindow1, HomeScreen.newMessageAccountIDInput.selector, alice.accountid, ); - await clickOn( - aliceWindow1, - HomeScreen.newMessageNextButton, - ); + await clickOn(aliceWindow1, HomeScreen.newMessageNextButton); await waitForTestIdWithText( aliceWindow1, 'header-conversation-name', @@ -485,7 +459,7 @@ test_Alice_2W( aliceWindow1, HomeScreen.conversationItemName, englishStrippedStr('noteToSelf').toString(), - {rightButton: true}, + { rightButton: true }, ); await clickOnWithText( aliceWindow1, diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index d62ed98..45b41a1 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -69,12 +69,13 @@ export class HomeScreen extends Locator { 'module-conversation__user__profile-name', ); static readonly messageRequestBanner = this.testId('message-request-banner'); - static readonly plusButton = this.testId( - 'new-conversation-button', - ); + static readonly plusButton = this.testId('new-conversation-button'); static readonly revealRecoveryPhraseButton = this.testId( 'reveal-recovery-phrase', ); + static readonly setNicknameButton = this.testId( + 'set-nickname-confirm-button', + ); } export class Conversation extends Locator { @@ -95,11 +96,11 @@ export class Conversation extends Locator { static readonly disappearingControlMessage = this.testId( 'disappear-control-message', ); - static readonly endCallButton = this.testId('end-call') + static readonly endCallButton = this.testId('end-call'); static readonly endVoiceMessageButton = this.testId('end-voice-message'); - static readonly mentionsPopup = this.testId('mentions-popup-row') + static readonly mentionsPopup = this.testId('mentions-popup-row'); - static readonly messageContent = this.testId('message-content') + static readonly messageContent = this.testId('message-content'); static readonly messageInput = this.testId('message-input-text-area'); static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', @@ -144,7 +145,9 @@ export class Settings extends Locator { static readonly conversationsMenuItem = this.testId( 'conversations-settings-menu-item', ); - static readonly messageRequestsMenuItem = this.testId('message-requests-settings-menu-item') + static readonly messageRequestsMenuItem = this.testId( + 'message-requests-settings-menu-item', + ); static readonly privacyMenuItem = this.testId('privacy-settings-menu-item'); static readonly recoveryPasswordMenuItem = this.testId( 'recovery-password-settings-menu-item', diff --git a/tests/automation/message_checks.spec.ts b/tests/automation/message_checks.spec.ts index d691794..bb31894 100644 --- a/tests/automation/message_checks.spec.ts +++ b/tests/automation/message_checks.spec.ts @@ -128,24 +128,14 @@ test_Alice_1W_Bob_1W( async ({ alice, aliceWindow1, bob, bobWindow1 }) => { await createContact(aliceWindow1, bobWindow1, alice, bob); await joinCommunity(aliceWindow1); - await clickOn( - aliceWindow1, - Conversation.conversationSettingsIcon, - ); - await clickOn( - aliceWindow1, - ConversationSettings.inviteContactsOption, - ); + await clickOn(aliceWindow1, Conversation.conversationSettingsIcon); + await clickOn(aliceWindow1, ConversationSettings.inviteContactsOption); await waitForTestIdWithText( aliceWindow1, 'modal-heading', englishStrippedStr('membersInvite').toString(), ); - await clickOnWithText( - aliceWindow1, - Global.contactItem, - bob.userName, - ); + await clickOnWithText(aliceWindow1, Global.contactItem, bob.userName); await clickOn(aliceWindow1, Global.confirmButton); // For lack of a unique ID we use native Playwright methods await aliceWindow1 diff --git a/tests/automation/message_requests.spec.ts b/tests/automation/message_requests.spec.ts index 8da7336..21d22f2 100644 --- a/tests/automation/message_requests.spec.ts +++ b/tests/automation/message_requests.spec.ts @@ -1,5 +1,11 @@ import { englishStrippedStr } from '../localization/englishStrippedStr'; -import { Conversation, Global, HomeScreen, LeftPane, Settings } from './locators'; +import { + Conversation, + Global, + HomeScreen, + LeftPane, + Settings, +} from './locators'; import { test_Alice_1W_Bob_1W } from './setup/sessionTest'; import { sendMessage } from './utilities/message'; import { sendNewMessage } from './utilities/send_message'; @@ -20,10 +26,7 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOn( - bobWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(bobWindow1, HomeScreen.messageRequestBanner); // Select message request from User A await clickOnWithText( bobWindow1, @@ -31,10 +34,7 @@ test_Alice_1W_Bob_1W( alice.userName, ); // Check that using the accept button has intended use - await clickOn( - bobWindow1, - Conversation.acceptMessageRequestButton, - ); + await clickOn(bobWindow1, Conversation.acceptMessageRequestButton); // Check config message of message request acceptance await waitForTestIdWithText( bobWindow1, @@ -60,10 +60,7 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOn( - bobWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(bobWindow1, HomeScreen.messageRequestBanner); // Select message request from User A await clickOnWithText( bobWindow1, @@ -96,10 +93,7 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOn( - bobWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(bobWindow1, HomeScreen.messageRequestBanner); // Select message request from User A await clickOnWithText( bobWindow1, @@ -138,10 +132,7 @@ test_Alice_1W_Bob_1W( // send a message to User B from User A await sendNewMessage(aliceWindow1, bob.accountid, `${testMessage}`); // Check the message request banner appears and click on it - await clickOn( - bobWindow1, - HomeScreen.messageRequestBanner, - ); + await clickOn(bobWindow1, HomeScreen.messageRequestBanner); // Select 'Clear All' button await clickOnMatchingText( bobWindow1, diff --git a/tests/automation/password.spec.ts b/tests/automation/password.spec.ts index 57816d8..125326b 100644 --- a/tests/automation/password.spec.ts +++ b/tests/automation/password.spec.ts @@ -33,10 +33,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { // Click on privacy await clickOn(aliceWindow1, Settings.privacyMenuItem); // Click set password - await clickOn( - aliceWindow1, - Settings.setPasswordSettingsButton, - ); + await clickOn(aliceWindow1, Settings.setPasswordSettingsButton); // Enter password await typeIntoInput( aliceWindow1, @@ -49,10 +46,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { Settings.confirmPasswordInput.selector, testPassword, ); - await clickOn( - aliceWindow1, - Settings.setPasswordButton, - ); + await clickOn(aliceWindow1, Settings.setPasswordButton); // Check toast notification await waitForTestIdWithText( aliceWindow1, @@ -63,10 +57,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { await sleepFor(300, true); await clickOn(aliceWindow1, Global.modalCloseButton); await clickOn(aliceWindow1, LeftPane.settingsButton); - await clickOn( - aliceWindow1, - Settings.recoveryPasswordMenuItem, - ); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); await sleepFor(300, true); // Type password into input field and validate it @@ -87,10 +78,7 @@ test_Alice_1W_no_network('Set Password', async ({ alice, aliceWindow1 }) => { await clickOn(aliceWindow1, LeftPane.settingsButton); await clickOn(aliceWindow1, Settings.privacyMenuItem); // Change password - await clickOn( - aliceWindow1, - Settings.changePasswordSettingsButton, - ); + await clickOn(aliceWindow1, Settings.changePasswordSettingsButton); // Enter old password await typeIntoInput( @@ -127,15 +115,9 @@ test_Alice_1W_no_network( // Click on settings tab await clickOn(aliceWindow1, LeftPane.settingsButton); // Click on privacy - await clickOn( - aliceWindow1, - Settings.privacyMenuItem, - ); + await clickOn(aliceWindow1, Settings.privacyMenuItem); // Click set password - await clickOn( - aliceWindow1, - Settings.setPasswordSettingsButton, - ); + await clickOn(aliceWindow1, Settings.setPasswordSettingsButton); // Enter password await typeIntoInput( aliceWindow1, @@ -148,17 +130,11 @@ test_Alice_1W_no_network( Settings.confirmPasswordInput.selector, testPassword, ); - await clickOn( - aliceWindow1, - Settings.setPasswordButton, - ); + await clickOn(aliceWindow1, Settings.setPasswordButton); // Click on recovery phrase tab await sleepFor(5000); await clickOn(aliceWindow1, Global.modalBackButton); - await clickOn( - aliceWindow1, - Settings.recoveryPasswordMenuItem, - ); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); // Type password into input field await typeIntoInput( aliceWindow1, @@ -173,10 +149,7 @@ test_Alice_1W_no_network( await clickOn(aliceWindow1, Global.modalBackButton); await sleepFor(500); // Click on recovery phrase tab - await clickOn( - aliceWindow1, - Settings.recoveryPasswordMenuItem, - ); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); // Try with incorrect password await typeIntoInput( aliceWindow1, @@ -203,10 +176,7 @@ test_Alice_1W_no_network( await clickOn(aliceWindow1, Global.modalCloseButton); await sleepFor(100); // Click on recovery phrase tab - await clickOn( - aliceWindow1, - Settings.recoveryPasswordMenuItem, - ); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); // No password entered await clickOn(aliceWindow1, Global.confirmButton); // Banner should ask for password to be entered diff --git a/tests/automation/setup/create_group.ts b/tests/automation/setup/create_group.ts index 343b0a4..a24a63c 100644 --- a/tests/automation/setup/create_group.ts +++ b/tests/automation/setup/create_group.ts @@ -53,10 +53,7 @@ export const createGroup = async ( `${messageCA} Time: ${Date.now()}`, ); // Click new closed group tab - await clickOnTestIdWithText( - windowA, - HomeScreen.plusButton.selector, - ); + await clickOnTestIdWithText(windowA, HomeScreen.plusButton.selector); await clickOnTestIdWithText(windowA, HomeScreen.createGroupOption.selector); // Enter group name await typeIntoInput( diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index 7737439..b379283 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -20,9 +20,10 @@ import { createContact } from './utilities/create_contact'; import { sendMessage, waitForReadTick } from './utilities/message'; import { checkModalStrings, + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, doesElementExist, hasElementBeenDeleted, typeIntoInput, @@ -49,7 +50,7 @@ sessionTestTwoWindows('Create contact', async ([windowA, windowB]) => { }) .toString(), ); - await clickOnTestIdWithText(windowB, Global.backButton.selector); + await clickOn(windowB, Global.backButton); await Promise.all([ clickOnElement({ window: windowA, @@ -74,28 +75,25 @@ test_Alice_1W_Bob_1W( // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); // Check to see if User B is a contact - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.plusButton.selector, - ); + await clickOn(aliceWindow1, HomeScreen.plusButton); await waitForTestIdWithText( aliceWindow1, Global.contactItem.selector, bob.userName, ); // he is a contact, close the new conversation button tab as there is no right click allowed on it - await clickOnTestIdWithText(aliceWindow1, Global.backButton.selector); + await clickOn(aliceWindow1, Global.backButton); // then right click on the contact conversation list item to show the menu - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, - true, + { rightButton: true }, ); // Select block - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'context-menu-item', + Global.contextMenuItem, englishStrippedStr('block').toString(), ); // Check modal strings @@ -106,32 +104,22 @@ test_Alice_1W_Bob_1W( .withArgs({ name: bob.userName }) .toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('block').toString(), ); // Verify the user was moved to the blocked contact list // Click on settings tab - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); + await clickOn(aliceWindow1, LeftPane.settingsButton); // click on settings section 'conversation' - await clickOnTestIdWithText( - aliceWindow1, - Settings.conversationsMenuItem.selector, - ); + await clickOn(aliceWindow1, Settings.conversationsMenuItem); // Navigate to blocked users tab' - await clickOnTestIdWithText( - aliceWindow1, - Settings.blockedContactsButton.selector, - ); + await clickOn(aliceWindow1, Settings.blockedContactsButton); // select the contact to unblock by clicking on it by name - await clickOnTestIdWithText( - aliceWindow1, - Global.contactItem.selector, - bob.userName, - ); + await clickOnWithText(aliceWindow1, Global.contactItem, bob.userName); // Unblock user by clicking on unblock - await clickOnTestIdWithText(aliceWindow1, Settings.unblockButton.selector); + await clickOn(aliceWindow1, Settings.unblockButton); // make sure the confirm dialogs shows up await checkModalStrings( aliceWindow1, @@ -142,9 +130,9 @@ test_Alice_1W_Bob_1W( 'blockOrUnblockModal', ); // click on the unblock button - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('blockUnblock').toString(), ); // make sure no blocked contacts are listed @@ -158,9 +146,9 @@ test_Alice_1W_Bob_1W( test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { const newUsername = 'Tiny bubble'; // Open Profile - await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); + await clickOn(aliceWindow1, LeftPane.profileButton); // Click on current username to open edit field - await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); + await clickOn(aliceWindow1, Settings.displayName); // Type in new username await typeIntoInput( aliceWindow1, @@ -179,7 +167,7 @@ test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { ), ).toBe(newUsername); // Exit profile modal - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); }); // TODO: Normalize screenshot dimensions before comparison to handle different pixel densities (e.g. with sharp) @@ -192,30 +180,21 @@ test_Alice_1W_no_network( 'Change avatar', async ({ aliceWindow1 }, testInfo) => { // Open profile - await clickOnTestIdWithText(aliceWindow1, LeftPane.profileButton.selector); + await clickOn(aliceWindow1, LeftPane.profileButton); // Click on current profile picture - await clickOnTestIdWithText(aliceWindow1, Settings.displayName.selector); + await clickOn(aliceWindow1, Settings.displayName); - await clickOnTestIdWithText( - aliceWindow1, - Settings.imageUploadSection.selector, - ); - await clickOnTestIdWithText( - aliceWindow1, - Settings.imageUploadClick.selector, - ); + await clickOn(aliceWindow1, Settings.imageUploadSection); + await clickOn(aliceWindow1, Settings.imageUploadClick); // allow for the image to be resized before we try to save it await sleepFor(500); - await clickOnTestIdWithText( - aliceWindow1, - Settings.saveProfileUpdateButton.selector, - ); + await clickOn(aliceWindow1, Settings.saveProfileUpdateButton); await waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'); await clickOnMatchingText( aliceWindow1, englishStrippedStr('save').toString(), ); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); + await clickOn(aliceWindow1, Global.modalCloseButton); // if we were asked to update the snapshots, make sure we wait for the change to be received before taking a screenshot. if (testInfo.config.updateSnapshots === 'all') { await sleepFor(15000); @@ -265,11 +244,11 @@ test_Alice_1W_Bob_1W( const nickname = 'new nickname for Bob'; await createContact(aliceWindow1, bobWindow1, alice, bob); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, bob.userName, - true, + { rightButton: true }, ); await clickOnMatchingText( aliceWindow1, @@ -279,9 +258,9 @@ test_Alice_1W_Bob_1W( await typeIntoInput(aliceWindow1, 'nickname-input', nickname); await sleepFor(100); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'set-nickname-confirm-button', + HomeScreen.setNicknameButton, englishStrippedStr('save').toString(), ); await sleepFor(1000); @@ -314,19 +293,16 @@ test_Alice_1W_Bob_1W( strategy: 'data-testid', selector: LeftPane.settingsButton.selector, }); - await clickOnTestIdWithText( - aliceWindow1, - Settings.privacyMenuItem.selector, - ); + await clickOn(aliceWindow1, Settings.privacyMenuItem); await clickOnElement({ window: aliceWindow1, strategy: 'data-testid', selector: Settings.enableReadReceipts.selector, }); - await clickOnTestIdWithText(aliceWindow1, Global.modalCloseButton.selector); - await clickOnTestIdWithText( + await clickOn(aliceWindow1, Global.modalCloseButton); + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, ); await clickOnElement({ @@ -334,19 +310,19 @@ test_Alice_1W_Bob_1W( strategy: 'data-testid', selector: LeftPane.settingsButton.selector, }); - await clickOnTestIdWithText(bobWindow1, Settings.privacyMenuItem.selector); + await clickOn(bobWindow1, Settings.privacyMenuItem); await clickOnElement({ window: bobWindow1, strategy: 'data-testid', selector: Settings.enableReadReceipts.selector, }); - await clickOnTestIdWithText(bobWindow1, Global.modalCloseButton.selector); + await clickOn(bobWindow1, Global.modalCloseButton); await sendMessage(aliceWindow1, 'Testing read receipts'); - await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); - await clickOnTestIdWithText( + await clickOn(bobWindow1, Global.backButton); + await clickOnWithText( bobWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, alice.userName, ); await waitForReadTick(aliceWindow1, 'Testing read receipts'); @@ -358,7 +334,7 @@ test_Alice_1W_Bob_1W( async ({ aliceWindow1, bobWindow1, alice, bob }) => { // Create contact and send new message await createContact(aliceWindow1, bobWindow1, alice, bob); - await clickOnTestIdWithText(bobWindow1, Global.backButton.selector); + await clickOn(bobWindow1, Global.backButton); await Promise.all( [aliceWindow1, bobWindow1].map((w) => clickOnElement({ @@ -381,20 +357,18 @@ test_Alice_1W_Bob_1W( ), ]); await Promise.all( - [aliceWindow1, bobWindow1].map((w) => - clickOnTestIdWithText(w, Global.backButton.selector), - ), + [aliceWindow1, bobWindow1].map((w) => clickOn(w, Global.backButton)), ); // Delete contact - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - HomeScreen.conversationItemName.selector, + HomeScreen.conversationItemName, bob.userName, - true, + { rightButton: true }, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.contextMenuItem.selector, + Global.contextMenuItem, englishStrippedStr('conversationsDelete').toString(), ); await checkModalStrings( @@ -404,9 +378,9 @@ test_Alice_1W_Bob_1W( .withArgs({ name: bob.userName }) .toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('delete').toString(), ); // Check if conversation is deleted @@ -423,15 +397,9 @@ test_Alice_1W_Bob_1W( test_Alice_2W( 'Hide recovery password', async ({ aliceWindow1, aliceWindow2 }) => { - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( - aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, - ); - await clickOnTestIdWithText( - aliceWindow1, - Settings.hideRecoveryPasswordButton.selector, - ); + await clickOn(aliceWindow1, LeftPane.settingsButton); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); + await clickOn(aliceWindow1, Settings.hideRecoveryPasswordButton); // Check first modal await checkModalStrings( aliceWindow1, @@ -441,9 +409,9 @@ test_Alice_2W( ).toString(), 'hideRecoveryPasswordModal', ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('theContinue').toString(), ); await checkModalStrings( @@ -455,9 +423,9 @@ test_Alice_2W( 'hideRecoveryPasswordModal', ); // Click yes - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('yes').toString(), ); await doesElementExist( @@ -466,7 +434,7 @@ test_Alice_2W( Settings.recoveryPasswordMenuItem.selector, ); // Check linked device if Recovery Password is still visible (it should be) - await clickOnTestIdWithText(aliceWindow2, LeftPane.settingsButton.selector); + await clickOn(aliceWindow2, LeftPane.settingsButton); await waitForTestIdWithText( aliceWindow2, Settings.recoveryPasswordMenuItem.selector, @@ -475,19 +443,10 @@ test_Alice_2W( ); test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.plusButton.selector, - ); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.inviteAFriendOption.selector, - ); + await clickOn(aliceWindow1, HomeScreen.plusButton); + await clickOn(aliceWindow1, HomeScreen.inviteAFriendOption); await waitForTestIdWithText(aliceWindow1, 'your-account-id', alice.accountid); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.inviteAFriendCopyButton.selector, - ); + await clickOn(aliceWindow1, HomeScreen.inviteAFriendCopyButton); // Toast await waitForTestIdWithText( aliceWindow1, @@ -505,22 +464,13 @@ test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { englishStrippedStr('shareAccountIdDescriptionCopied').toString(), ); // To exit invite a friend - await clickOnTestIdWithText(aliceWindow1, Global.backButton.selector); + await clickOn(aliceWindow1, Global.backButton); // New message - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.newMessageOption.selector, - ); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.newMessageAccountIDInput.selector, - ); + await clickOn(aliceWindow1, HomeScreen.newMessageOption); + await clickOn(aliceWindow1, HomeScreen.newMessageAccountIDInput); const isMac = process.platform === 'darwin'; await aliceWindow1.keyboard.press(`${isMac ? 'Meta' : 'Control'}+V`); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.newMessageNextButton.selector, - ); + await clickOn(aliceWindow1, HomeScreen.newMessageNextButton); // Did the copied text create note to self? await waitForTestIdWithText( aliceWindow1, @@ -532,37 +482,28 @@ test_Alice_1W_no_network('Invite a friend', async ({ aliceWindow1, alice }) => { test_Alice_1W_no_network( 'Hide note to self', async ({ aliceWindow1, alice }) => { - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.plusButton.selector, - ); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.newMessageOption.selector, - ); + await clickOn(aliceWindow1, HomeScreen.plusButton); + await clickOn(aliceWindow1, HomeScreen.newMessageOption); await typeIntoInput( aliceWindow1, 'new-session-conversation', alice.accountid, ); - await clickOnTestIdWithText( - aliceWindow1, - HomeScreen.newMessageNextButton.selector, - ); + await clickOn(aliceWindow1, HomeScreen.newMessageNextButton); await waitForTestIdWithText( aliceWindow1, Conversation.conversationHeader.selector, englishStrippedStr('noteToSelf').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, englishStrippedStr('noteToSelf').toString(), - true, + { rightButton: true }, ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'context-menu-item', + Global.contextMenuItem, englishStrippedStr('noteToSelfHide').toString(), ); await checkModalStrings( @@ -570,9 +511,9 @@ test_Alice_1W_no_network( englishStrippedStr('noteToSelfHide').toString(), englishStrippedStr('noteToSelfHideDescription').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( aliceWindow1, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('hide').toString(), ); await hasElementBeenDeleted( @@ -586,11 +527,8 @@ test_Alice_1W_no_network( ); test_Alice_1W_no_network('Toggle password', async ({ aliceWindow1 }) => { - await clickOnTestIdWithText(aliceWindow1, LeftPane.settingsButton.selector); - await clickOnTestIdWithText( - aliceWindow1, - Settings.recoveryPasswordMenuItem.selector, - ); + await clickOn(aliceWindow1, LeftPane.settingsButton); + await clickOn(aliceWindow1, Settings.recoveryPasswordMenuItem); await waitForTestIdWithText( aliceWindow1, Settings.recoveryPasswordContainer.selector, diff --git a/tests/automation/utilities/join_community.ts b/tests/automation/utilities/join_community.ts index 7596019..dc3da9b 100644 --- a/tests/automation/utilities/join_community.ts +++ b/tests/automation/utilities/join_community.ts @@ -9,10 +9,7 @@ import { } from './utils'; export const joinCommunity = async (window: Page) => { - await clickOnTestIdWithText( - window, - HomeScreen.plusButton.selector, - ); + await clickOnTestIdWithText(window, HomeScreen.plusButton.selector); await clickOnTestIdWithText(window, HomeScreen.joinCommunityOption.selector); // The follow two test tags are pending implementation await typeIntoInput( diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index 82bd153..fbaae37 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -61,7 +61,12 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { strategy: 'data-testid', selector: 'send-message-button', }); - await clickOnTestIdWithText(window, Conversation.messageContent.selector, testLink, true); + await clickOnTestIdWithText( + window, + Conversation.messageContent.selector, + testLink, + true, + ); // Need to copy link to clipboard, as the enable link preview modal // doesn't pop up if manually typing link (needs to be pasted) // Need to have a nth(0) here to account for Copy Account ID, Appium was getting confused diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index c102533..4fbdcec 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -41,5 +41,8 @@ export const makeVoiceCall = async ( ); await clickOnTestIdWithText(receiverWindow, Global.modalCloseButton.selector); await sleepFor(5000); - await clickOnTestIdWithText(callerWindow, Conversation.endCallButton.selector); + await clickOnTestIdWithText( + callerWindow, + Conversation.endCallButton.selector, + ); }; From af12d09e4ff1cd9110636ddd4bdf8642dc0f00dc Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 17:13:05 +1000 Subject: [PATCH 21/32] refactor: eliminate clickOnTestIdWithText --- tests/automation/setup/create_group.ts | 27 +++++-------- tests/automation/setup/new_user.ts | 17 ++++---- tests/automation/setup/recovery_using_seed.ts | 6 +-- tests/automation/utilities/create_contact.ts | 7 ++-- tests/automation/utilities/join_community.ts | 8 ++-- tests/automation/utilities/leave_group.ts | 12 +++--- tests/automation/utilities/rename_group.ts | 14 ++----- tests/automation/utilities/send_media.ts | 39 ++++++++----------- tests/automation/utilities/send_message.ts | 8 ++-- .../utilities/set_disappearing_messages.ts | 12 ++---- tests/automation/utilities/utils.ts | 33 ++++++++-------- tests/automation/utilities/voice_call.ts | 31 ++++++--------- 12 files changed, 89 insertions(+), 125 deletions(-) diff --git a/tests/automation/setup/create_group.ts b/tests/automation/setup/create_group.ts index a24a63c..898a991 100644 --- a/tests/automation/setup/create_group.ts +++ b/tests/automation/setup/create_group.ts @@ -7,8 +7,9 @@ import { Group, User } from '../types/testing'; import { sendMessage } from '../utilities/message'; import { sendNewMessage } from '../utilities/send_message'; import { + clickOn, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, typeIntoInput, waitForTestIdWithText, waitForTextMessages, @@ -53,8 +54,8 @@ export const createGroup = async ( `${messageCA} Time: ${Date.now()}`, ); // Click new closed group tab - await clickOnTestIdWithText(windowA, HomeScreen.plusButton.selector); - await clickOnTestIdWithText(windowA, HomeScreen.createGroupOption.selector); + await clickOn(windowA, HomeScreen.plusButton); + await clickOn(windowA, HomeScreen.createGroupOption); // Enter group name await typeIntoInput( windowA, @@ -66,10 +67,7 @@ export const createGroup = async ( // Select user C await clickOnMatchingText(windowA, userThree.userName); // Click Next - await clickOnTestIdWithText( - windowA, - HomeScreen.createGroupCreateButton.selector, - ); + await clickOn(windowA, HomeScreen.createGroupCreateButton); // Check group was successfully created await clickOnMatchingText(windowB, group.userName); await waitForTestIdWithText( @@ -89,18 +87,11 @@ export const createGroup = async ( .toString(), ); // Click on test group - await Promise.all([ - clickOnTestIdWithText( - windowB, - 'module-conversation__user__profile-name', - group.userName, + await Promise.all( + [windowB, windowC].map((w) => + clickOnWithText(w, HomeScreen.conversationItemName, group.userName), ), - clickOnTestIdWithText( - windowC, - 'module-conversation__user__profile-name', - group.userName, - ), - ]); + ); // Make sure the empty state is in windowB & windowC await Promise.all([ waitForTestIdWithText( diff --git a/tests/automation/setup/new_user.ts b/tests/automation/setup/new_user.ts index 11c4c44..c59bec5 100644 --- a/tests/automation/setup/new_user.ts +++ b/tests/automation/setup/new_user.ts @@ -11,7 +11,7 @@ import { import { User } from '../types/testing'; import { checkPathLight, - clickOnTestIdWithText, + clickOn, grabTextFromElement, typeIntoInput, waitForTestIdWithText, @@ -23,15 +23,12 @@ export const newUser = async ( awaitOnionPath = true, ): Promise => { // Create User - await clickOnTestIdWithText(window, Onboarding.createAccountButton.selector); + await clickOn(window, Onboarding.createAccountButton); // Input username = testuser await typeIntoInput(window, Onboarding.displayNameInput.selector, userName); - await clickOnTestIdWithText(window, Global.continueButton.selector); + await clickOn(window, Global.continueButton); // save recovery phrase - await clickOnTestIdWithText( - window, - HomeScreen.revealRecoveryPhraseButton.selector, - ); + await clickOn(window, HomeScreen.revealRecoveryPhraseButton); await waitForTestIdWithText( window, Settings.recoveryPasswordContainer.selector, @@ -44,8 +41,8 @@ export const newUser = async ( // const recoveryPhrase = await window.innerText( // '[data-testid=recovery-password-seed-modal]', // ); - await clickOnTestIdWithText(window, Global.modalCloseButton.selector); - await clickOnTestIdWithText(window, LeftPane.profileButton.selector); + await clickOn(window, Global.modalCloseButton); + await clickOn(window, LeftPane.profileButton); // Save Account ID to a variable let accountid = await window.innerText( @@ -58,7 +55,7 @@ export const newUser = async ( accountid, )}" and Recovery password: "${chalk.green(recoveryPassword)}"`, ); - await clickOnTestIdWithText(window, Global.modalCloseButton.selector); + await clickOn(window, Global.modalCloseButton); if (awaitOnionPath) { await checkPathLight(window); } diff --git a/tests/automation/setup/recovery_using_seed.ts b/tests/automation/setup/recovery_using_seed.ts index 1a31039..de3f0a0 100644 --- a/tests/automation/setup/recovery_using_seed.ts +++ b/tests/automation/setup/recovery_using_seed.ts @@ -2,16 +2,16 @@ import { Page } from '@playwright/test'; import { Global, Onboarding } from '../locators'; import { - clickOnTestIdWithText, + clickOn, doesElementExist, typeIntoInput, waitForLoadingAnimationToFinish, } from '../utilities/utils'; export async function recoverFromSeed(window: Page, recoveryPhrase: string) { - await clickOnTestIdWithText(window, Onboarding.iHaveAnAccountButton.selector); + await clickOn(window, Onboarding.iHaveAnAccountButton); await typeIntoInput(window, 'recovery-phrase-input', recoveryPhrase); - await clickOnTestIdWithText(window, Global.continueButton.selector); + await clickOn(window, Global.continueButton); await waitForLoadingAnimationToFinish(window, 'loading-animation'); const displayName = await doesElementExist( window, diff --git a/tests/automation/utilities/create_contact.ts b/tests/automation/utilities/create_contact.ts index 46b6651..4b69332 100644 --- a/tests/automation/utilities/create_contact.ts +++ b/tests/automation/utilities/create_contact.ts @@ -1,9 +1,10 @@ import { Page } from '@playwright/test'; +import { HomeScreen } from '../locators'; import { User } from '../types/testing'; import { replyTo } from './reply_message'; import { sendNewMessage } from './send_message'; -import { clickOnElement, clickOnTestIdWithText } from './utils'; +import { clickOnElement, clickOnWithText } from './utils'; export const createContact = async ( windowA: Page, @@ -20,9 +21,9 @@ export const createContact = async ( strategy: 'data-testid', selector: 'message-request-banner', }); - await clickOnTestIdWithText( + await clickOnWithText( windowB, - 'module-conversation__user__profile-name', + HomeScreen.conversationItemName, userA.userName, ); await clickOnElement({ diff --git a/tests/automation/utilities/join_community.ts b/tests/automation/utilities/join_community.ts index dc3da9b..d6dd074 100644 --- a/tests/automation/utilities/join_community.ts +++ b/tests/automation/utilities/join_community.ts @@ -3,20 +3,20 @@ import { Page } from '@playwright/test'; import { testCommunityLink } from '../constants/community'; import { HomeScreen } from '../locators'; import { - clickOnTestIdWithText, + clickOn, typeIntoInput, waitForLoadingAnimationToFinish, } from './utils'; export const joinCommunity = async (window: Page) => { - await clickOnTestIdWithText(window, HomeScreen.plusButton.selector); - await clickOnTestIdWithText(window, HomeScreen.joinCommunityOption.selector); + await clickOn(window, HomeScreen.plusButton); + await clickOn(window, HomeScreen.joinCommunityOption); // The follow two test tags are pending implementation await typeIntoInput( window, HomeScreen.joinCommunityInput.selector, testCommunityLink, ); - await clickOnTestIdWithText(window, HomeScreen.joinCommunityButton.selector); + await clickOn(window, HomeScreen.joinCommunityButton); await waitForLoadingAnimationToFinish(window, 'loading-spinner'); }; diff --git a/tests/automation/utilities/leave_group.ts b/tests/automation/utilities/leave_group.ts index 466cb3c..4cd2750 100644 --- a/tests/automation/utilities/leave_group.ts +++ b/tests/automation/utilities/leave_group.ts @@ -4,26 +4,24 @@ import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { Conversation, Global } from '../locators'; import { Group } from '../types/testing'; import { + clickOn, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, hasElementBeenDeleted, } from './utils'; export const leaveGroup = async (window: Page, group: Group) => { // go to three dots menu - await clickOnTestIdWithText( - window, - Conversation.conversationSettingsIcon.selector, - ); + await clickOn(window, Conversation.conversationSettingsIcon); // Select Leave Group await clickOnMatchingText( window, englishStrippedStr('groupLeave').toString(), ); // Confirm leave group - await clickOnTestIdWithText( + await clickOnWithText( window, - Global.confirmButton.selector, + Global.confirmButton, englishStrippedStr('leave').toString(), ); // check config message diff --git a/tests/automation/utilities/rename_group.ts b/tests/automation/utilities/rename_group.ts index 758b43e..8aca644 100644 --- a/tests/automation/utilities/rename_group.ts +++ b/tests/automation/utilities/rename_group.ts @@ -3,8 +3,8 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { Conversation, ConversationSettings, Global } from '../locators'; import { + clickOn, clickOnMatchingText, - clickOnTestIdWithText, typeIntoInput, waitForMatchingText, waitForTestIdWithText, @@ -16,19 +16,13 @@ export const renameGroup = async ( newGroupName: string, ) => { await clickOnMatchingText(window, oldGroupName); - await clickOnTestIdWithText( - window, - Conversation.conversationSettingsIcon.selector, - ); - await clickOnTestIdWithText( - window, - ConversationSettings.editGroupButton.selector, - ); + await clickOn(window, Conversation.conversationSettingsIcon); + await clickOn(window, ConversationSettings.editGroupButton); await typeIntoInput(window, 'update-group-info-name-input', newGroupName); await window.keyboard.press('Enter'); await clickOnMatchingText(window, englishStrippedStr('save').toString()); await waitForTestIdWithText(window, 'group-name', newGroupName); - await clickOnTestIdWithText(window, Global.modalCloseButton.selector); + await clickOn(window, Global.modalCloseButton); // Check config message await waitForMatchingText( window, diff --git a/tests/automation/utilities/send_media.ts b/tests/automation/utilities/send_media.ts index fbaae37..a9ce17f 100644 --- a/tests/automation/utilities/send_media.ts +++ b/tests/automation/utilities/send_media.ts @@ -7,9 +7,10 @@ import { MediaType } from '../types/testing'; import { waitForSentTick } from './message'; import { checkModalStrings, + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, + clickOnWithText, typeIntoInput, waitForLoadingAnimationToFinish, waitForTestIdWithText, @@ -32,16 +33,13 @@ export const sendMedia = async ( }; export const sendVoiceMessage = async (window: Page) => { - await clickOnTestIdWithText(window, Conversation.microphoneButton.selector); - await clickOnTestIdWithText(window, Global.toast.selector); - await clickOnTestIdWithText(window, Settings.enableMicrophone.selector); - await clickOnTestIdWithText(window, Global.modalCloseButton.selector); - await clickOnTestIdWithText(window, Conversation.microphoneButton.selector); + await clickOn(window, Conversation.microphoneButton); + await clickOn(window, Global.toast); + await clickOn(window, Settings.enableMicrophone); + await clickOn(window, Global.modalCloseButton); + await clickOn(window, Conversation.microphoneButton); await sleepFor(5000); - await clickOnTestIdWithText( - window, - Conversation.endVoiceMessageButton.selector, - ); + await clickOn(window, Conversation.endVoiceMessageButton); await sleepFor(4000); await clickOnElement({ window, @@ -61,12 +59,9 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { strategy: 'data-testid', selector: 'send-message-button', }); - await clickOnTestIdWithText( - window, - Conversation.messageContent.selector, - testLink, - true, - ); + await clickOnWithText(window, Conversation.messageContent, testLink, { + rightButton: true, + }); // Need to copy link to clipboard, as the enable link preview modal // doesn't pop up if manually typing link (needs to be pasted) // Need to have a nth(0) here to account for Copy Account ID, Appium was getting confused @@ -83,9 +78,9 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { englishStrippedStr('copied').toString(), ); // click on the toast and wait for it to be closed to avoid the layout shift - await clickOnTestIdWithText(window, Global.toast.selector); + await clickOn(window, Global.toast); await sleepFor(1000); - await clickOnTestIdWithText(window, Conversation.messageInput.selector); + await clickOn(window, Conversation.messageInput); const isMac = process.platform === 'darwin'; await window.keyboard.press(`${isMac ? 'Meta' : 'Control'}+V`); await checkModalStrings( @@ -93,9 +88,9 @@ export const sendLinkPreview = async (window: Page, testLink: string) => { englishStrippedStr('linkPreviewsEnable').toString(), englishStrippedStr('linkPreviewsFirstDescription').toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( window, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('enable').toString(), ); await waitForLoadingAnimationToFinish(window, 'loading-spinner'); @@ -136,9 +131,9 @@ export const trustUser = async ( }) .toString(), ); - await clickOnTestIdWithText( + await clickOnWithText( window, - 'session-confirm-ok-button', + Global.confirmButton, englishStrippedStr('yes').toString(), ); }; diff --git a/tests/automation/utilities/send_message.ts b/tests/automation/utilities/send_message.ts index d9ef8e6..a3769b2 100644 --- a/tests/automation/utilities/send_message.ts +++ b/tests/automation/utilities/send_message.ts @@ -2,18 +2,18 @@ import { Page } from '@playwright/test'; import { HomeScreen } from '../locators'; import { sendMessage } from './message'; -import { clickOnTestIdWithText, typeIntoInput } from './utils'; +import { clickOn, typeIntoInput } from './utils'; export const sendNewMessage = async ( window: Page, sessionid: string, message: string, ) => { - await clickOnTestIdWithText(window, HomeScreen.plusButton.selector); - await clickOnTestIdWithText(window, HomeScreen.newMessageOption.selector); + await clickOn(window, HomeScreen.plusButton); + await clickOn(window, HomeScreen.newMessageOption); // Enter session ID of USER B await typeIntoInput(window, 'new-session-conversation', sessionid); // click next - await clickOnTestIdWithText(window, HomeScreen.newMessageNextButton.selector); + await clickOn(window, HomeScreen.newMessageNextButton); await sendMessage(window, message); }; diff --git a/tests/automation/utilities/set_disappearing_messages.ts b/tests/automation/utilities/set_disappearing_messages.ts index ee1f0d1..7f5b184 100644 --- a/tests/automation/utilities/set_disappearing_messages.ts +++ b/tests/automation/utilities/set_disappearing_messages.ts @@ -10,9 +10,9 @@ import { import { isChecked } from './checked'; import { checkModalStrings, + clickOn, clickOnElement, clickOnMatchingText, - clickOnTestIdWithText, formatTimeOption, waitForElement, waitForTestIdWithText, @@ -29,13 +29,9 @@ export const setDisappearingMessages = async ( windowB?: Page, ) => { const enforcedType: ConversationType = conversationType; - await clickOnTestIdWithText( - windowA, - Conversation.conversationSettingsIcon.selector, - undefined, - undefined, - 5_000, - ); + await clickOn(windowA, Conversation.conversationSettingsIcon, { + maxWait: 5_000, + }); await clickOnElement({ window: windowA, strategy: 'data-testid', diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index 2fb98e6..ae35be0 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -250,6 +250,12 @@ export async function checkPathLight(window: Page, maxWait?: number) { // ACTIONS +/** + * Clicks on an element using a locator object + * @param window - Playwright page instance + * @param locator - Element locator with strategy and selector + * @param options - Optional element interaction configuration + */ export async function clickOn( window: Page, locator: StrategyExtractionObj, @@ -270,6 +276,13 @@ export async function clickOn( ); } +/** + * Clicks on an element that contains specific text + * @param window - Playwright page instance + * @param locator - Element locator with strategy and selector + * @param text - Text content to match within the element + * @param options - Optional element interaction configuration + */ export async function clickOnWithText( window: Page, locator: StrategyExtractionObj, @@ -339,22 +352,6 @@ export async function clickOnMatchingText( ); } -// Legacy wrapper for backwards compatibility -export async function clickOnTestIdWithText( - window: Page, - dataTestId: DataTestId, - text?: string, - rightButton?: boolean, - maxWait?: number, -) { - const locator = { strategy: 'data-testid' as const, selector: dataTestId }; - - if (text) { - return clickOnWithText(window, locator, text, { rightButton, maxWait }); - } - return clickOn(window, locator, { rightButton, maxWait }); -} - export async function clickOnTextMessage( window: Page, text: string, @@ -382,7 +379,9 @@ export async function typeIntoInput( console.info(`typeIntoInput testId: ${dataTestId} : "${text}"`); const builtSelector = `css=[data-testid=${dataTestId}]`; // the new input made with onboarding element needs a click to reveal the input in the DOM - await clickOnTestIdWithText(window, dataTestId); + // Convert DataTestId to locator object for clickOn + const locator = { strategy: 'data-testid' as const, selector: dataTestId }; + await clickOn(window, locator); // reset the content to be empty before typing into the input await window.fill(builtSelector, ''); return window.type(builtSelector, text); diff --git a/tests/automation/utilities/voice_call.ts b/tests/automation/utilities/voice_call.ts index 4fbdcec..af23ed4 100644 --- a/tests/automation/utilities/voice_call.ts +++ b/tests/automation/utilities/voice_call.ts @@ -3,46 +3,39 @@ import { Page } from '@playwright/test'; import { englishStrippedStr } from '../../localization/englishStrippedStr'; import { sleepFor } from '../../promise_utils'; import { Conversation, Global, Settings } from '../locators'; -import { - checkModalStrings, - clickOnMatchingText, - clickOnTestIdWithText, -} from './utils'; +import { checkModalStrings, clickOn, clickOnMatchingText } from './utils'; export const makeVoiceCall = async ( callerWindow: Page, receiverWindow: Page, ) => { - await clickOnTestIdWithText(callerWindow, Conversation.callButton.selector); - await clickOnTestIdWithText(callerWindow, Global.toast.selector); - await clickOnTestIdWithText(callerWindow, Settings.enableCalls.selector); + await clickOn(callerWindow, Conversation.callButton); + await clickOn(callerWindow, Global.toast); + await clickOn(callerWindow, Settings.enableCalls); await checkModalStrings( callerWindow, englishStrippedStr('callsVoiceAndVideoBeta').toString(), englishStrippedStr('callsVoiceAndVideoModalDescription').toString(), 'confirmModal', ); - await clickOnTestIdWithText(callerWindow, Global.confirmButton.selector); - await clickOnTestIdWithText(callerWindow, Global.modalCloseButton.selector); - await clickOnTestIdWithText(callerWindow, Conversation.callButton.selector); + await clickOn(callerWindow, Global.confirmButton); + await clickOn(callerWindow, Global.modalCloseButton); + await clickOn(callerWindow, Conversation.callButton); // Enable calls in window B - await clickOnTestIdWithText(receiverWindow, Global.toast.selector); - await clickOnTestIdWithText(receiverWindow, Settings.enableCalls.selector); + await clickOn(receiverWindow, Global.toast); + await clickOn(receiverWindow, Settings.enableCalls); await checkModalStrings( receiverWindow, englishStrippedStr('callsVoiceAndVideoBeta').toString(), englishStrippedStr('callsVoiceAndVideoModalDescription').toString(), 'confirmModal', ); - await clickOnTestIdWithText(receiverWindow, Global.confirmButton.selector); + await clickOn(receiverWindow, Global.confirmButton); await clickOnMatchingText( receiverWindow, englishStrippedStr('accept').toString(), ); - await clickOnTestIdWithText(receiverWindow, Global.modalCloseButton.selector); + await clickOn(receiverWindow, Global.modalCloseButton); await sleepFor(5000); - await clickOnTestIdWithText( - callerWindow, - Conversation.endCallButton.selector, - ); + await clickOn(callerWindow, Conversation.endCallButton); }; From e7d301f9ea7a3ce98fd9238367fa78df100a5b33 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Thu, 4 Sep 2025 17:21:58 +1000 Subject: [PATCH 22/32] chore: begin refactoring clickOnElement --- tests/automation/delete_account.spec.ts | 7 +------ tests/automation/disappearing_message_checks.spec.ts | 7 +------ tests/automation/disappearing_messages.spec.ts | 6 +----- tests/automation/locators/index.ts | 3 ++- tests/automation/utilities/utils.ts | 3 +++ 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 93e67ea..6a6ceb0 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -12,7 +12,6 @@ import { createContact } from './utilities/create_contact'; import { sendNewMessage } from './utilities/send_message'; import { clickOn, - clickOnElement, clickOnMatchingText, clickOnWithText, hasElementBeenDeleted, @@ -163,11 +162,7 @@ sessionTestTwoWindows( userB.userName, ); // Check if contact is available in contacts section - await clickOnElement({ - window: restoringWindow, - strategy: 'data-testid', - selector: HomeScreen.plusButton.selector, - }); + await clickOn(restoringWindow, HomeScreen.plusButton); await waitForElement( restoringWindow, 'data-testid', diff --git a/tests/automation/disappearing_message_checks.spec.ts b/tests/automation/disappearing_message_checks.spec.ts index e7741e0..fec8a6b 100644 --- a/tests/automation/disappearing_message_checks.spec.ts +++ b/tests/automation/disappearing_message_checks.spec.ts @@ -26,7 +26,6 @@ import { import { setDisappearingMessages } from './utilities/set_disappearing_messages'; import { clickOn, - clickOnElement, clickOnWithText, formatTimeOption, hasElementBeenDeleted, @@ -139,11 +138,7 @@ test_Alice_1W_Bob_1W( ]); await typeIntoInput(aliceWindow1, 'message-input-text-area', longText); await sleepFor(100); - await clickOnElement({ - window: aliceWindow1, - strategy: 'data-testid', - selector: 'send-message-button', - }); + await clickOn(aliceWindow1, Conversation.sendMessageButton); await waitForSentTick(aliceWindow1, longText); await waitForTextMessage(bobWindow1, longText); // Wait 30 seconds for long text to disappear diff --git a/tests/automation/disappearing_messages.spec.ts b/tests/automation/disappearing_messages.spec.ts index 11699ad..9828d71 100644 --- a/tests/automation/disappearing_messages.spec.ts +++ b/tests/automation/disappearing_messages.spec.ts @@ -78,11 +78,7 @@ test_Alice_2W_Bob_1W( const message = 'Forcing window to front'; await typeIntoInput(bobWindow1, 'message-input-text-area', message); // click up arrow (send) - await clickOnElement({ - window: bobWindow1, - strategy: 'data-testid', - selector: 'send-message-button', - }); + await clickOn(bobWindow1, Conversation.sendMessageButton); await sleepFor(10000); await hasTextMessageBeenDeleted(bobWindow1, testMessage); }, diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index 45b41a1..de23eb4 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -99,14 +99,15 @@ export class Conversation extends Locator { static readonly endCallButton = this.testId('end-call'); static readonly endVoiceMessageButton = this.testId('end-voice-message'); static readonly mentionsPopup = this.testId('mentions-popup-row'); - static readonly messageContent = this.testId('message-content'); + static readonly messageInput = this.testId('message-input-text-area'); static readonly messageRequestAcceptControlMessage = this.testId( 'message-request-response-message', ); static readonly microphoneButton = this.testId('microphone-button'); static readonly scrollToBottomButton = this.testId('scroll-to-bottom-button'); + static readonly sendMessageButton = this.testId('send-message-button'); } export class ConversationSettings extends Locator { diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index ae35be0..33241f9 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -28,6 +28,9 @@ type ElementOptions = { rightButton?: boolean; }; +// TODO Unify element interaction functions to use locator objects the way clickOn and clickOnWithText do +// Remaining functions to migrate: waitForElement, typeIntoInput, grabTextFromElement etc. + // WAIT FOR FUNCTIONS export async function waitForTestIdWithText( From 3d70de399db816e465a553b1b6762f6f9a2599cf Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Mon, 8 Sep 2025 13:36:06 +1000 Subject: [PATCH 23/32] feat: normalize pixel density for macos consistency --- screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg | 4 ++-- .../Profile-picture-syncs/avatar-updated-blue-darwin.jpeg | 4 ++-- tests/automation/setup/open.ts | 1 + tests/automation/user_actions.spec.ts | 6 ------ 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg b/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg index b3548a9..cba87b7 100644 --- a/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg +++ b/screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfda79de8430bec68485159710f2832b4959056e3a464fa342047b65529f9c29 -size 1851 +oid sha256:e9069447a34a67f2695f041f31e4902b72651c4162d733086635ea689fb7492b +size 1262 diff --git a/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg b/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg index b3548a9..cba87b7 100644 --- a/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg +++ b/screenshots/Profile-picture-syncs/avatar-updated-blue-darwin.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfda79de8430bec68485159710f2832b4959056e3a464fa342047b65529f9c29 -size 1851 +oid sha256:e9069447a34a67f2695f041f31e4902b72651c4162d733086635ea689fb7492b +size 1262 diff --git a/tests/automation/setup/open.ts b/tests/automation/setup/open.ts index bb05590..4f98ba4 100644 --- a/tests/automation/setup/open.ts +++ b/tests/automation/setup/open.ts @@ -37,6 +37,7 @@ const openElectronAppOnly = async (multi: string) => { args: [ join(getAppRootPath(), 'ts', 'mains', 'main_node.js'), '--disable-gpu', + '--force-device-scale-factor=1', // Normalizes Retina and non-Retina mac screens ], }); return electronApp; diff --git a/tests/automation/user_actions.spec.ts b/tests/automation/user_actions.spec.ts index b379283..4347e34 100644 --- a/tests/automation/user_actions.spec.ts +++ b/tests/automation/user_actions.spec.ts @@ -170,12 +170,6 @@ test_Alice_1W_no_network('Change username', async ({ aliceWindow1 }) => { await clickOn(aliceWindow1, Global.modalCloseButton); }); -// TODO: Normalize screenshot dimensions before comparison to handle different pixel densities (e.g. with sharp) -// This would fix MacBook Retina (2x) vs M4 Mac Mini (1x) pixel density differences (56x56 vs 28x28) -// Alternatives: -// - Try to set deviceScaleFactor: 1 in Playwright context to force consistent scaling -// - Record pixel density dependent screenshots - test_Alice_1W_no_network( 'Change avatar', async ({ aliceWindow1 }, testInfo) => { From f6401fd291309ee74653c2a9b5a8b67513fc5ceb Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Mon, 8 Sep 2025 13:36:30 +1000 Subject: [PATCH 24/32] chore: fix more tests --- tests/automation/disappearing_messages.spec.ts | 4 ++-- tests/automation/locators/index.ts | 2 +- tests/automation/types/testing.ts | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/automation/disappearing_messages.spec.ts b/tests/automation/disappearing_messages.spec.ts index 9828d71..a173ac2 100644 --- a/tests/automation/disappearing_messages.spec.ts +++ b/tests/automation/disappearing_messages.spec.ts @@ -233,8 +233,8 @@ test_Alice_2W( await sendMessage(aliceWindow1, testMessageDisappear); await waitForTextMessage(aliceWindow2, testMessageDisappear); await Promise.all([ - hasTextMessageBeenDeleted(aliceWindow1, testMessageDisappear), - hasTextMessageBeenDeleted(aliceWindow2, testMessageDisappear), + hasTextMessageBeenDeleted(aliceWindow1, testMessageDisappear, 10_000), + hasTextMessageBeenDeleted(aliceWindow2, testMessageDisappear, 10_000), ]); }, ); diff --git a/tests/automation/locators/index.ts b/tests/automation/locators/index.ts index de23eb4..7db611a 100644 --- a/tests/automation/locators/index.ts +++ b/tests/automation/locators/index.ts @@ -180,7 +180,7 @@ export class Settings extends Locator { static readonly unblockButton = this.testId('unblock-button-settings-screen'); // Recovery Password static readonly hideRecoveryPasswordButton = this.testId( - 'hide-recovery-password-button', + 'hide-recovery-password-settings-button', ); static readonly recoveryPasswordContainer = this.testId( 'recovery-password-seed-modal', diff --git a/tests/automation/types/testing.ts b/tests/automation/types/testing.ts index f215d60..c7c2d33 100644 --- a/tests/automation/types/testing.ts +++ b/tests/automation/types/testing.ts @@ -76,8 +76,6 @@ export type LoaderType = 'loading-animation' | 'loading-spinner'; export type MediaType = 'audio' | 'file' | 'image' | 'video'; export type Strategy = ':has-text' | 'class' | 'data-testid'; -// Would be good to find a way to sort those with prettier -// TODO sort with eslint plugin perfectionist export type DataTestId = | DMTimeOption | 'accept-message-request' @@ -131,7 +129,7 @@ export type DataTestId = | 'group-name' | 'group-update-message' | 'header-conversation-name' - | 'hide-recovery-password-button' + | 'hide-recovery-password-settings-button' | 'image-upload-click' | 'image-upload-section' | 'invite-contacts-menu-option' From aec13ee5b8a57ed37393b86b741d7fedf19b1e3c Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Mon, 8 Sep 2025 14:21:25 +1000 Subject: [PATCH 25/32] chore: also upload lower density landing page states --- screenshots/landing-page-states/new-account-darwin.png | 4 ++-- screenshots/landing-page-states/restored-account-darwin.png | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/screenshots/landing-page-states/new-account-darwin.png b/screenshots/landing-page-states/new-account-darwin.png index b1843cc..4e4c139 100644 --- a/screenshots/landing-page-states/new-account-darwin.png +++ b/screenshots/landing-page-states/new-account-darwin.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d0da82b7711b507b623243fa6fc43de1272a2efe402228fd4f899dbb37d2bbd -size 95444 +oid sha256:b907914d0bef573eca81c81fd299d963364e13d2fd585dda81c7c44a26f83ea7 +size 40751 diff --git a/screenshots/landing-page-states/restored-account-darwin.png b/screenshots/landing-page-states/restored-account-darwin.png index b522c91..5fcffea 100644 --- a/screenshots/landing-page-states/restored-account-darwin.png +++ b/screenshots/landing-page-states/restored-account-darwin.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5af2a09db18e7161950f986d6f9aad001d3098dae95d4e5d2f703bad39712d69 -size 52581 +oid sha256:50a2585b25ef5e8d1d1cdcd81feac1104c6379cdd17f9d2172db5bfa3d292887 +size 23124 From ca02866e88e8f2def42273b73e79170a2ffce946 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Mon, 8 Sep 2025 15:26:01 +1000 Subject: [PATCH 26/32] fix: window closes too quickly --- tests/automation/delete_account.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/automation/delete_account.spec.ts b/tests/automation/delete_account.spec.ts index 6a6ceb0..fa0a372 100644 --- a/tests/automation/delete_account.spec.ts +++ b/tests/automation/delete_account.spec.ts @@ -145,9 +145,6 @@ sessionTestTwoWindows( windowA, englishStrippedStr('clear').toString(), ); - await waitForLoadingAnimationToFinish(windowA, 'loading-spinner'); - // Wait for window to close and reopen - // await windowA.close(); restoringWindows = await openApp(1); const [restoringWindow] = restoringWindows; // Sign in with deleted account and check that nothing restores From 9f91d55787417f00370d0b3b5222c8faa9ddb635 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 24 Sep 2025 10:31:35 +0200 Subject: [PATCH 27/32] fix: tests for linux avatar screenshots --- screenshots/Change-avatar/avatar-updated-blue-linux.jpeg | 4 ++-- .../Profile-picture-syncs/avatar-updated-blue-linux.jpeg | 4 ++-- tests/automation/group_disappearing_messages.spec.ts | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/screenshots/Change-avatar/avatar-updated-blue-linux.jpeg b/screenshots/Change-avatar/avatar-updated-blue-linux.jpeg index ca272e6..3f21393 100644 --- a/screenshots/Change-avatar/avatar-updated-blue-linux.jpeg +++ b/screenshots/Change-avatar/avatar-updated-blue-linux.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22c4440e25da54a94ee286bcf20916d2a9e11e5db4236b46d76d84eb4b8c2f10 -size 882 +oid sha256:cd339a84c915a8d2fb312166f96ce4c833ee36206b552b5d83430da53355d0bb +size 1255 diff --git a/screenshots/Profile-picture-syncs/avatar-updated-blue-linux.jpeg b/screenshots/Profile-picture-syncs/avatar-updated-blue-linux.jpeg index 581a066..3f21393 100644 --- a/screenshots/Profile-picture-syncs/avatar-updated-blue-linux.jpeg +++ b/screenshots/Profile-picture-syncs/avatar-updated-blue-linux.jpeg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afd7a7acb7fcd504f311c3258d64c0940bc5f0f429b59c5e613df291f91dfd58 -size 964 +oid sha256:cd339a84c915a8d2fb312166f96ce4c833ee36206b552b5d83430da53355d0bb +size 1255 diff --git a/tests/automation/group_disappearing_messages.spec.ts b/tests/automation/group_disappearing_messages.spec.ts index 4fed712..7ebe98f 100644 --- a/tests/automation/group_disappearing_messages.spec.ts +++ b/tests/automation/group_disappearing_messages.spec.ts @@ -56,7 +56,7 @@ mediaArray.forEach(({ mediaType, path }) => { waitForTestIdWithText(bobWindow1, 'audio-player'), waitForTestIdWithText(charlieWindow1, 'audio-player'), ]); - await sleepFor(30000); + await sleepFor(10000); await Promise.all([ hasElementBeenDeleted(bobWindow1, 'data-testid', 'audio-player'), hasElementBeenDeleted(charlieWindow1, 'data-testid', 'audio-player'), @@ -68,8 +68,8 @@ mediaArray.forEach(({ mediaType, path }) => { waitForTextMessage(bobWindow1, testMessage), waitForTextMessage(charlieWindow1, testMessage), ]); - // Wait 30 seconds for image to disappear - await sleepFor(30000); + // Wait 10 seconds for image to disappear + await sleepFor(10000); await Promise.all([ hasTextMessageBeenDeleted(bobWindow1, testMessage), hasTextMessageBeenDeleted(charlieWindow1, testMessage), From 65076768ee3180f9dbc6ee2c2d4a7b037dd696db Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 24 Sep 2025 11:27:40 +0200 Subject: [PATCH 28/32] fix: update linux screenshot and resize before comparing --- .gitignore | 2 + package.json | 8 +- .../landing-page-states/new-account-linux.png | 4 +- .../restored-account-linux.png | 4 +- tests/automation/utilities/utils.ts | 55 ++++- yarn.lock | 212 +++++++++++++++++- 6 files changed, 271 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 19ff287..80bf8e8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ output/ dist/ .eslintcache *-difference.png +*-current*.png +*-diff*.png diff --git a/package.json b/package.json index 69022bc..5f63d20 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "@playwright/test": "^1.51", "@types/fs-extra": "^11.0.1", "@types/lodash": "^4.14.196", + "@types/pixelmatch": "^5.2.6", + "@types/pngjs": "^6.0.5", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.2.1", "@typescript-eslint/parser": "^6.0.0", @@ -26,7 +28,9 @@ "eslint-plugin-perfectionist": "^4.15.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", + "pngjs": "^7.0.0", "prettier": "^3.0.1", + "sharp": "^0.34.4", "typescript": "^5.1.6", "uuid": "^9.0.1" }, @@ -40,5 +44,7 @@ "allure-create": "allure generate ./allure-results", "allure-open": "allure open ./allure-report" }, - "dependencies": {} + "dependencies": { + "pixelmatch": "^7.1.0" + } } diff --git a/screenshots/landing-page-states/new-account-linux.png b/screenshots/landing-page-states/new-account-linux.png index 6e22594..0b36c24 100644 --- a/screenshots/landing-page-states/new-account-linux.png +++ b/screenshots/landing-page-states/new-account-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f73c838496f090bc81d5d958febb45c8da18db5a99647147735d61b22731e9d3 -size 53875 +oid sha256:04f22791d5f6b9c6ab15ef13b92d5af23a58110b62da01c265fdbc25e8788143 +size 38781 diff --git a/screenshots/landing-page-states/restored-account-linux.png b/screenshots/landing-page-states/restored-account-linux.png index 69e3e88..ac29a5b 100644 --- a/screenshots/landing-page-states/restored-account-linux.png +++ b/screenshots/landing-page-states/restored-account-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1ecac5cd73fa59eb7baa3e30313b15edfffb5f14b76145fce00ecbccbd69fd6 -size 29276 +oid sha256:30ae560be76baa99193e8e502d7f90166a11d6fae7ae5ebcf8199d470878c539 +size 21659 diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index 33241f9..f656ef9 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -5,6 +5,7 @@ import { ElementHandle, Page } from '@playwright/test'; import fs from 'fs'; import path from 'path'; +import sharp from 'sharp'; import type { ElementState } from '../types/landing_page_states'; @@ -608,6 +609,9 @@ export async function compareScreenshot( elementState: ElementState, os: string, ) { + const { default: pixelmatch } = await import('pixelmatch'); + const { PNG } = await import('pngjs'); + const formattedTitle = testTitle.toLowerCase().replace(/\s+/g, '-'); await deleteDifferenceFile(formattedTitle, elementState, os); @@ -628,18 +632,53 @@ export async function compareScreenshot( } // If screenshot does exist, compare it to previous screenshot in the folder const previousScreenshot = fs.readFileSync(previousScreenshotFilePath); - const diffFilePath = path.join( + const currentFilePath = path.join( folderPath, - `${elementState}-${os}-difference.png`, + `${elementState}-${os}-current.png`, ); + + const sharpCurrent = sharp(elementScreenshot); + const sharpPrevious = sharp(previousScreenshot); + + const [metaCurrent, metaPrevious] = await Promise.all([ + sharpCurrent.metadata(), + sharpPrevious.metadata(), + ]); + const width = Math.min(metaCurrent.width!, metaPrevious.width!); + const height = Math.min(metaCurrent.height!, metaPrevious.height!); + console.info('Comparing screenshots with min dimensions:', width, height); + const bufferA = await sharpCurrent.resize(width, height).png().toBuffer(); + const bufferB = await sharpPrevious.resize(width, height).png().toBuffer(); + fs.writeFileSync(currentFilePath, elementScreenshot as any); + const diffFilePath = path.join(folderPath, `${elementState}-${os}-diff.png`); // If screenshots are different, then create a difference screenshot - if ( - Buffer.compare(elementScreenshot as any, previousScreenshot as any) !== 0 - ) { - // If elements do not match, then take the elementScreenshot and save it to same folder but with a new name of 'difference.png' - fs.writeFileSync(diffFilePath, elementScreenshot as any); + // If elements do not match, then take the elementScreenshot and save it to same folder but with a new name of 'difference.png' + try { + const pngA = PNG.sync.read(bufferA); + const pngB = PNG.sync.read(bufferB); + + const diff = new PNG({ width, height }); + + const mismatches = pixelmatch( + pngA.data, + pngB.data, + diff.data, + width, + height, + { threshold: 0.1 }, + ); + + if (mismatches !== 0) { + const diffBuffer = PNG.sync.write(diff); + + fs.writeFileSync(diffFilePath, diffBuffer as any); + + console.warn('Mismatches:', mismatches); + throw new Error('Screenshots do not match'); + } + } catch (e) { throw new Error( - `Screenshots do not match, see ${screenshotFolder} > ${testTitle} folder > \n\t\t diff: ${diffFilePath}\n\t\t previous: ${previousScreenshotFilePath}`, + `Screenshots do not match, see ${screenshotFolder} > ${testTitle} folder > \n\t\t current: ${currentFilePath}\n\t\t previous: ${previousScreenshotFilePath}\n\t\t diff: ${diffFilePath}`, ); } } diff --git a/yarn.lock b/yarn.lock index 692d8cd..0214e25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,6 +22,13 @@ optionalDependencies: global-agent "^3.0.0" +"@emnapi/runtime@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.5.0.tgz#9aebfcb9b17195dce3ab53c86787a6b7d058db73" + integrity sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ== + dependencies: + tslib "^2.4.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -80,6 +87,141 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@img/colour@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311" + integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== + +"@img/sharp-darwin-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz#8a0dcac9e621ff533fbf2e830f6a977b38d67a0c" + integrity sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.3" + +"@img/sharp-darwin-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz#0ba2bd9dbf07f7300fab73305b787e66156f7752" + integrity sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.3" + +"@img/sharp-libvips-darwin-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz#f43c9aa3b74fd307e4318da63ebbe0ed4c34e744" + integrity sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw== + +"@img/sharp-libvips-darwin-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz#c42ff786d4a1f42ef8929dba4a989dd5df6417f0" + integrity sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA== + +"@img/sharp-libvips-linux-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz#c9073e5c4b629ee417f777db21c552910d84ed77" + integrity sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ== + +"@img/sharp-libvips-linux-arm@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz#3cbc333fd6b8f224a14d69b03a1dd11df897c799" + integrity sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA== + +"@img/sharp-libvips-linux-ppc64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz#68e0e0076299f43d838468675674fabcc7161d16" + integrity sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg== + +"@img/sharp-libvips-linux-s390x@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz#7da9ab11a50c0ca905979f0aae14a4ccffab27b2" + integrity sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w== + +"@img/sharp-libvips-linux-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz#3b162d6b190cf77926819040e09fb15eec42135e" + integrity sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz#ac99576630dd8e33cb598d7c4586f6e0655912ea" + integrity sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz#93e9495af7bf6c4e0d41dd71d0196c35c3753a1c" + integrity sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g== + +"@img/sharp-linux-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz#0570ff1a4fa6e1d6779456fca8b5e8c18a6a9cf2" + integrity sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.3" + +"@img/sharp-linux-arm@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz#5f020d933f54f3fc49203d32c3b7dd0ec11ffcdb" + integrity sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.3" + +"@img/sharp-linux-ppc64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz#8d5775f6dc7e30ea3a1efa43798b7690bb5cb344" + integrity sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.3" + +"@img/sharp-linux-s390x@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz#740aa5b369188ee2c1913b1015e7f830f4dfdb50" + integrity sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.3" + +"@img/sharp-linux-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz#573ce4196b2d0771bba32acc13a37b7adc9b6212" + integrity sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.3" + +"@img/sharp-linuxmusl-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz#3c91bc8348cc3b42b43c6fca14f9dbb5cb47bd0d" + integrity sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" + +"@img/sharp-linuxmusl-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz#33de7d476ac9e2db7ef654331b54cc679b806bda" + integrity sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.3" + +"@img/sharp-wasm32@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz#d617f7b3f851f899802298f360667c20605c0198" + integrity sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA== + dependencies: + "@emnapi/runtime" "^1.5.0" + +"@img/sharp-win32-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz#38e2c8a88826eac647f7c3f99efefb39897a8f5c" + integrity sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA== + +"@img/sharp-win32-ia32@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz#003a7eb0fdaba600790c3007cfd756e41a9cf749" + integrity sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw== + +"@img/sharp-win32-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz#b19f1f88ace8bfc20784a0ad31767f3438e025d1" + integrity sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -184,6 +326,20 @@ dependencies: undici-types "~6.19.2" +"@types/pixelmatch@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.6.tgz#fba6de304ac958495f27d85989f5c6bb7499a686" + integrity sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg== + dependencies: + "@types/node" "*" + +"@types/pngjs@^6.0.5": + version "6.0.5" + resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-6.0.5.tgz#6dec2f7eb8284543ca4e423f3c09b119fa939ea3" + integrity sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ== + dependencies: + "@types/node" "*" + "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" @@ -644,6 +800,11 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +detect-libc@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.0.tgz#3ca811f60a7b504b0480e5008adacc660b0b8c4f" + integrity sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -1795,6 +1956,13 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pixelmatch@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-7.1.0.tgz#9d59bddc8c779340e791106c0f245ac33ae4d113" + integrity sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng== + dependencies: + pngjs "^7.0.0" + playwright-core@1.51.1: version "1.51.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.51.1.tgz#d57f0393e02416f32a47cf82b27533656a8acce1" @@ -1809,6 +1977,11 @@ playwright@1.51.1: optionalDependencies: fsevents "2.3.2" +pngjs@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" + integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -1959,7 +2132,7 @@ semver@^7.3.2, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -semver@^7.6.0: +semver@^7.6.0, semver@^7.7.2: version "7.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== @@ -1971,6 +2144,38 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" +sharp@^0.34.4: + version "0.34.4" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.4.tgz#73c2c5a425e98250b8b927e5537f711da8966e38" + integrity sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.0" + semver "^7.7.2" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.4" + "@img/sharp-darwin-x64" "0.34.4" + "@img/sharp-libvips-darwin-arm64" "1.2.3" + "@img/sharp-libvips-darwin-x64" "1.2.3" + "@img/sharp-libvips-linux-arm" "1.2.3" + "@img/sharp-libvips-linux-arm64" "1.2.3" + "@img/sharp-libvips-linux-ppc64" "1.2.3" + "@img/sharp-libvips-linux-s390x" "1.2.3" + "@img/sharp-libvips-linux-x64" "1.2.3" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" + "@img/sharp-libvips-linuxmusl-x64" "1.2.3" + "@img/sharp-linux-arm" "0.34.4" + "@img/sharp-linux-arm64" "0.34.4" + "@img/sharp-linux-ppc64" "0.34.4" + "@img/sharp-linux-s390x" "0.34.4" + "@img/sharp-linux-x64" "0.34.4" + "@img/sharp-linuxmusl-arm64" "0.34.4" + "@img/sharp-linuxmusl-x64" "0.34.4" + "@img/sharp-wasm32" "0.34.4" + "@img/sharp-win32-arm64" "0.34.4" + "@img/sharp-win32-ia32" "0.34.4" + "@img/sharp-win32-x64" "0.34.4" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -2097,6 +2302,11 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@^2.4.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" From cdb09739f25062d983cf83ec1009388cfbdf3c42 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Sep 2025 07:11:30 +0200 Subject: [PATCH 29/32] fix: remove screenshot comparison for empty states instead, look for correct strings to be displayed --- package.json | 7 +- .../new-account-darwin.png | 3 - .../landing-page-states/new-account-linux.png | 3 - .../restored-account-darwin.png | 3 - .../restored-account-linux.png | 3 - tests/automation/landing_page.spec.ts | 71 +++++++++--- tests/automation/types/landing_page_states.ts | 1 - tests/automation/utilities/utils.ts | 106 ------------------ yarn.lock | 26 ----- 9 files changed, 59 insertions(+), 164 deletions(-) delete mode 100644 screenshots/landing-page-states/new-account-darwin.png delete mode 100644 screenshots/landing-page-states/new-account-linux.png delete mode 100644 screenshots/landing-page-states/restored-account-darwin.png delete mode 100644 screenshots/landing-page-states/restored-account-linux.png delete mode 100644 tests/automation/types/landing_page_states.ts diff --git a/package.json b/package.json index 5f63d20..de87f80 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,6 @@ "@playwright/test": "^1.51", "@types/fs-extra": "^11.0.1", "@types/lodash": "^4.14.196", - "@types/pixelmatch": "^5.2.6", - "@types/pngjs": "^6.0.5", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.2.1", "@typescript-eslint/parser": "^6.0.0", @@ -28,7 +26,6 @@ "eslint-plugin-perfectionist": "^4.15.0", "fs-extra": "^11.1.1", "lodash": "^4.17.21", - "pngjs": "^7.0.0", "prettier": "^3.0.1", "sharp": "^0.34.4", "typescript": "^5.1.6", @@ -44,7 +41,5 @@ "allure-create": "allure generate ./allure-results", "allure-open": "allure open ./allure-report" }, - "dependencies": { - "pixelmatch": "^7.1.0" - } + "dependencies": {} } diff --git a/screenshots/landing-page-states/new-account-darwin.png b/screenshots/landing-page-states/new-account-darwin.png deleted file mode 100644 index 4e4c139..0000000 --- a/screenshots/landing-page-states/new-account-darwin.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b907914d0bef573eca81c81fd299d963364e13d2fd585dda81c7c44a26f83ea7 -size 40751 diff --git a/screenshots/landing-page-states/new-account-linux.png b/screenshots/landing-page-states/new-account-linux.png deleted file mode 100644 index 0b36c24..0000000 --- a/screenshots/landing-page-states/new-account-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04f22791d5f6b9c6ab15ef13b92d5af23a58110b62da01c265fdbc25e8788143 -size 38781 diff --git a/screenshots/landing-page-states/restored-account-darwin.png b/screenshots/landing-page-states/restored-account-darwin.png deleted file mode 100644 index 5fcffea..0000000 --- a/screenshots/landing-page-states/restored-account-darwin.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:50a2585b25ef5e8d1d1cdcd81feac1104c6379cdd17f9d2172db5bfa3d292887 -size 23124 diff --git a/screenshots/landing-page-states/restored-account-linux.png b/screenshots/landing-page-states/restored-account-linux.png deleted file mode 100644 index ac29a5b..0000000 --- a/screenshots/landing-page-states/restored-account-linux.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:30ae560be76baa99193e8e502d7f90166a11d6fae7ae5ebcf8199d470878c539 -size 21659 diff --git a/tests/automation/landing_page.spec.ts b/tests/automation/landing_page.spec.ts index 7b071df..4503f30 100644 --- a/tests/automation/landing_page.spec.ts +++ b/tests/automation/landing_page.spec.ts @@ -1,5 +1,9 @@ +import { englishStrippedStr } from '../localization/englishStrippedStr'; import { test_Alice_2W } from './setup/sessionTest'; -import { compareScreenshot, waitForElement } from './utilities/utils'; +import { + hasElementPoppedUpThatShouldnt, + waitForElement, +} from './utilities/utils'; // TODO: Normalize screenshot dimensions before comparison to handle different pixel densities (e.g. with sharp) // This would fix MacBook Retina (2x) vs M4 Mac Mini (1x) pixel density differences (1000x1584 vs 500x792) @@ -9,25 +13,66 @@ import { compareScreenshot, waitForElement } from './utilities/utils'; test_Alice_2W( `Landing page states`, - async ({ aliceWindow1, aliceWindow2 }, testInfo) => { + async ({ aliceWindow1, aliceWindow2 }, _testInfo) => { const os = process.platform; console.log('OS:', os); - const [landingPage, restoredPage] = await Promise.all([ + await Promise.all([ waitForElement(aliceWindow1, 'class', 'session-conversation'), waitForElement(aliceWindow2, 'class', 'session-conversation'), ]); - await compareScreenshot( - landingPage, - `${testInfo.title}`, - 'new-account', - os, + // Check that the account created has all the required strings displayed + await Promise.all( + [ + englishStrippedStr('onboardingAccountCreated'), + englishStrippedStr('onboardingBubbleWelcomeToSession').withArgs({ + emoji: '👋', + }), + englishStrippedStr('conversationsNone'), + englishStrippedStr('onboardingHitThePlusButton'), + ].map(async (builder) => + waitForElement( + aliceWindow1, + 'data-testid', + 'empty-msg-view-account-created', + 1000, + builder.toString(), + ), + ), ); - await compareScreenshot( - restoredPage, - `${testInfo.title}`, - 'restored-account', - os, + + // Check that the account restored has all the required strings displayed + await Promise.all( + [ + englishStrippedStr('conversationsNone'), + englishStrippedStr('onboardingHitThePlusButton'), + ].map(async (builder) => + waitForElement( + aliceWindow2, + 'data-testid', + 'empty-msg-view-welcome', + 1000, + builder.toString(), + ), + ), + ); + + // Make sure the "account created" part is not visible on the restored window + await Promise.all( + [ + englishStrippedStr('onboardingAccountCreated'), + englishStrippedStr('onboardingBubbleWelcomeToSession').withArgs({ + emoji: '👋', + }), + ].map(async (builder) => + hasElementPoppedUpThatShouldnt( + aliceWindow2, + 'data-testid', + 'empty-msg-view-account-created', + + builder.toString(), + ), + ), ); }, ); diff --git a/tests/automation/types/landing_page_states.ts b/tests/automation/types/landing_page_states.ts deleted file mode 100644 index e7166d0..0000000 --- a/tests/automation/types/landing_page_states.ts +++ /dev/null @@ -1 +0,0 @@ -export type ElementState = 'new-account' | 'restored-account'; diff --git a/tests/automation/utilities/utils.ts b/tests/automation/utilities/utils.ts index f656ef9..ed7428f 100644 --- a/tests/automation/utilities/utils.ts +++ b/tests/automation/utilities/utils.ts @@ -3,14 +3,8 @@ /* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable no-await-in-loop */ import { ElementHandle, Page } from '@playwright/test'; -import fs from 'fs'; -import path from 'path'; -import sharp from 'sharp'; - -import type { ElementState } from '../types/landing_page_states'; import { sleepFor } from '../../promise_utils'; -import { screenshotFolder } from '../constants/variables'; import { DataTestId, DMTimeOption, @@ -582,103 +576,3 @@ export function formatTimeOption(option: DMTimeOption) { const formattedTime = timePart.replace(/-/g, ' '); return formattedTime; } - -async function deleteDifferenceFile( - fileFolder: string, - fileName: string, - os: string, -) { - const filePath = path.join( - screenshotFolder, - fileFolder, - `${fileName}-${os}-difference.png`, - ); - - if (fs.existsSync(filePath)) { - // Delete the file if it exists - fs.unlinkSync(filePath); - console.log(`Deleted difference file at: ${filePath}`); - } else { - console.log(`No difference file found at: ${filePath}, proceeding...`); - } -} - -export async function compareScreenshot( - element: ElementHandle, - testTitle: string, - elementState: ElementState, - os: string, -) { - const { default: pixelmatch } = await import('pixelmatch'); - const { PNG } = await import('pngjs'); - - const formattedTitle = testTitle.toLowerCase().replace(/\s+/g, '-'); - await deleteDifferenceFile(formattedTitle, elementState, os); - - const elementScreenshot = await element.screenshot(); - const folderPath = path.join(screenshotFolder, `${formattedTitle}`); - - // If folder doesn't exist, create folder - if (!fs.existsSync(folderPath)) { - fs.mkdirSync(folderPath, { recursive: true }); - } - const previousScreenshotFilePath = path.join( - folderPath, - `${elementState}-${os}.png`, - ); - // If screenshot does not exist, save it to the folder - if (!fs.existsSync(previousScreenshotFilePath)) { - fs.writeFileSync(previousScreenshotFilePath, elementScreenshot as any); // TS really hates this unless its cast as any - } - // If screenshot does exist, compare it to previous screenshot in the folder - const previousScreenshot = fs.readFileSync(previousScreenshotFilePath); - const currentFilePath = path.join( - folderPath, - `${elementState}-${os}-current.png`, - ); - - const sharpCurrent = sharp(elementScreenshot); - const sharpPrevious = sharp(previousScreenshot); - - const [metaCurrent, metaPrevious] = await Promise.all([ - sharpCurrent.metadata(), - sharpPrevious.metadata(), - ]); - const width = Math.min(metaCurrent.width!, metaPrevious.width!); - const height = Math.min(metaCurrent.height!, metaPrevious.height!); - console.info('Comparing screenshots with min dimensions:', width, height); - const bufferA = await sharpCurrent.resize(width, height).png().toBuffer(); - const bufferB = await sharpPrevious.resize(width, height).png().toBuffer(); - fs.writeFileSync(currentFilePath, elementScreenshot as any); - const diffFilePath = path.join(folderPath, `${elementState}-${os}-diff.png`); - // If screenshots are different, then create a difference screenshot - // If elements do not match, then take the elementScreenshot and save it to same folder but with a new name of 'difference.png' - try { - const pngA = PNG.sync.read(bufferA); - const pngB = PNG.sync.read(bufferB); - - const diff = new PNG({ width, height }); - - const mismatches = pixelmatch( - pngA.data, - pngB.data, - diff.data, - width, - height, - { threshold: 0.1 }, - ); - - if (mismatches !== 0) { - const diffBuffer = PNG.sync.write(diff); - - fs.writeFileSync(diffFilePath, diffBuffer as any); - - console.warn('Mismatches:', mismatches); - throw new Error('Screenshots do not match'); - } - } catch (e) { - throw new Error( - `Screenshots do not match, see ${screenshotFolder} > ${testTitle} folder > \n\t\t current: ${currentFilePath}\n\t\t previous: ${previousScreenshotFilePath}\n\t\t diff: ${diffFilePath}`, - ); - } -} diff --git a/yarn.lock b/yarn.lock index 0214e25..f43a2ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -326,20 +326,6 @@ dependencies: undici-types "~6.19.2" -"@types/pixelmatch@^5.2.6": - version "5.2.6" - resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.6.tgz#fba6de304ac958495f27d85989f5c6bb7499a686" - integrity sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg== - dependencies: - "@types/node" "*" - -"@types/pngjs@^6.0.5": - version "6.0.5" - resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-6.0.5.tgz#6dec2f7eb8284543ca4e423f3c09b119fa939ea3" - integrity sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ== - dependencies: - "@types/node" "*" - "@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" @@ -1956,13 +1942,6 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pixelmatch@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-7.1.0.tgz#9d59bddc8c779340e791106c0f245ac33ae4d113" - integrity sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng== - dependencies: - pngjs "^7.0.0" - playwright-core@1.51.1: version "1.51.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.51.1.tgz#d57f0393e02416f32a47cf82b27533656a8acce1" @@ -1977,11 +1956,6 @@ playwright@1.51.1: optionalDependencies: fsevents "2.3.2" -pngjs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" - integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" From 52b89ca7380df4099b02aa84b7571ef33a4db0d4 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Sep 2025 07:13:00 +0200 Subject: [PATCH 30/32] chore: remove uneeded sharp dep --- package.json | 1 - tests/automation/landing_page.spec.ts | 6 - yarn.lock | 186 +------------------------- 3 files changed, 1 insertion(+), 192 deletions(-) diff --git a/package.json b/package.json index de87f80..69022bc 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "fs-extra": "^11.1.1", "lodash": "^4.17.21", "prettier": "^3.0.1", - "sharp": "^0.34.4", "typescript": "^5.1.6", "uuid": "^9.0.1" }, diff --git a/tests/automation/landing_page.spec.ts b/tests/automation/landing_page.spec.ts index 4503f30..29bf530 100644 --- a/tests/automation/landing_page.spec.ts +++ b/tests/automation/landing_page.spec.ts @@ -5,12 +5,6 @@ import { waitForElement, } from './utilities/utils'; -// TODO: Normalize screenshot dimensions before comparison to handle different pixel densities (e.g. with sharp) -// This would fix MacBook Retina (2x) vs M4 Mac Mini (1x) pixel density differences (1000x1584 vs 500x792) -// Alternatives: -// - Try to set deviceScaleFactor: 1 in Playwright context to force consistent scaling -// - Record pixel density dependent screenshots - test_Alice_2W( `Landing page states`, async ({ aliceWindow1, aliceWindow2 }, _testInfo) => { diff --git a/yarn.lock b/yarn.lock index f43a2ec..692d8cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,13 +22,6 @@ optionalDependencies: global-agent "^3.0.0" -"@emnapi/runtime@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.5.0.tgz#9aebfcb9b17195dce3ab53c86787a6b7d058db73" - integrity sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ== - dependencies: - tslib "^2.4.0" - "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -87,141 +80,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@img/colour@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311" - integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== - -"@img/sharp-darwin-arm64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz#8a0dcac9e621ff533fbf2e830f6a977b38d67a0c" - integrity sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA== - optionalDependencies: - "@img/sharp-libvips-darwin-arm64" "1.2.3" - -"@img/sharp-darwin-x64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz#0ba2bd9dbf07f7300fab73305b787e66156f7752" - integrity sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg== - optionalDependencies: - "@img/sharp-libvips-darwin-x64" "1.2.3" - -"@img/sharp-libvips-darwin-arm64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz#f43c9aa3b74fd307e4318da63ebbe0ed4c34e744" - integrity sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw== - -"@img/sharp-libvips-darwin-x64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz#c42ff786d4a1f42ef8929dba4a989dd5df6417f0" - integrity sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA== - -"@img/sharp-libvips-linux-arm64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz#c9073e5c4b629ee417f777db21c552910d84ed77" - integrity sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ== - -"@img/sharp-libvips-linux-arm@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz#3cbc333fd6b8f224a14d69b03a1dd11df897c799" - integrity sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA== - -"@img/sharp-libvips-linux-ppc64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz#68e0e0076299f43d838468675674fabcc7161d16" - integrity sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg== - -"@img/sharp-libvips-linux-s390x@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz#7da9ab11a50c0ca905979f0aae14a4ccffab27b2" - integrity sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w== - -"@img/sharp-libvips-linux-x64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz#3b162d6b190cf77926819040e09fb15eec42135e" - integrity sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg== - -"@img/sharp-libvips-linuxmusl-arm64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz#ac99576630dd8e33cb598d7c4586f6e0655912ea" - integrity sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw== - -"@img/sharp-libvips-linuxmusl-x64@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz#93e9495af7bf6c4e0d41dd71d0196c35c3753a1c" - integrity sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g== - -"@img/sharp-linux-arm64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz#0570ff1a4fa6e1d6779456fca8b5e8c18a6a9cf2" - integrity sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ== - optionalDependencies: - "@img/sharp-libvips-linux-arm64" "1.2.3" - -"@img/sharp-linux-arm@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz#5f020d933f54f3fc49203d32c3b7dd0ec11ffcdb" - integrity sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA== - optionalDependencies: - "@img/sharp-libvips-linux-arm" "1.2.3" - -"@img/sharp-linux-ppc64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz#8d5775f6dc7e30ea3a1efa43798b7690bb5cb344" - integrity sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ== - optionalDependencies: - "@img/sharp-libvips-linux-ppc64" "1.2.3" - -"@img/sharp-linux-s390x@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz#740aa5b369188ee2c1913b1015e7f830f4dfdb50" - integrity sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw== - optionalDependencies: - "@img/sharp-libvips-linux-s390x" "1.2.3" - -"@img/sharp-linux-x64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz#573ce4196b2d0771bba32acc13a37b7adc9b6212" - integrity sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A== - optionalDependencies: - "@img/sharp-libvips-linux-x64" "1.2.3" - -"@img/sharp-linuxmusl-arm64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz#3c91bc8348cc3b42b43c6fca14f9dbb5cb47bd0d" - integrity sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" - -"@img/sharp-linuxmusl-x64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz#33de7d476ac9e2db7ef654331b54cc679b806bda" - integrity sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg== - optionalDependencies: - "@img/sharp-libvips-linuxmusl-x64" "1.2.3" - -"@img/sharp-wasm32@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz#d617f7b3f851f899802298f360667c20605c0198" - integrity sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA== - dependencies: - "@emnapi/runtime" "^1.5.0" - -"@img/sharp-win32-arm64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz#38e2c8a88826eac647f7c3f99efefb39897a8f5c" - integrity sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA== - -"@img/sharp-win32-ia32@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz#003a7eb0fdaba600790c3007cfd756e41a9cf749" - integrity sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw== - -"@img/sharp-win32-x64@0.34.4": - version "0.34.4" - resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz#b19f1f88ace8bfc20784a0ad31767f3438e025d1" - integrity sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -786,11 +644,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -detect-libc@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.0.tgz#3ca811f60a7b504b0480e5008adacc660b0b8c4f" - integrity sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg== - detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -2106,7 +1959,7 @@ semver@^7.3.2, semver@^7.5.4: dependencies: lru-cache "^6.0.0" -semver@^7.6.0, semver@^7.7.2: +semver@^7.6.0: version "7.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== @@ -2118,38 +1971,6 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" -sharp@^0.34.4: - version "0.34.4" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.4.tgz#73c2c5a425e98250b8b927e5537f711da8966e38" - integrity sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA== - dependencies: - "@img/colour" "^1.0.0" - detect-libc "^2.1.0" - semver "^7.7.2" - optionalDependencies: - "@img/sharp-darwin-arm64" "0.34.4" - "@img/sharp-darwin-x64" "0.34.4" - "@img/sharp-libvips-darwin-arm64" "1.2.3" - "@img/sharp-libvips-darwin-x64" "1.2.3" - "@img/sharp-libvips-linux-arm" "1.2.3" - "@img/sharp-libvips-linux-arm64" "1.2.3" - "@img/sharp-libvips-linux-ppc64" "1.2.3" - "@img/sharp-libvips-linux-s390x" "1.2.3" - "@img/sharp-libvips-linux-x64" "1.2.3" - "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" - "@img/sharp-libvips-linuxmusl-x64" "1.2.3" - "@img/sharp-linux-arm" "0.34.4" - "@img/sharp-linux-arm64" "0.34.4" - "@img/sharp-linux-ppc64" "0.34.4" - "@img/sharp-linux-s390x" "0.34.4" - "@img/sharp-linux-x64" "0.34.4" - "@img/sharp-linuxmusl-arm64" "0.34.4" - "@img/sharp-linuxmusl-x64" "0.34.4" - "@img/sharp-wasm32" "0.34.4" - "@img/sharp-win32-arm64" "0.34.4" - "@img/sharp-win32-ia32" "0.34.4" - "@img/sharp-win32-x64" "0.34.4" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -2276,11 +2097,6 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.4.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" From e61c9e33589c8c9a0ccbb55b668f2aa77fb5cdcc Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Sep 2025 07:38:44 +0200 Subject: [PATCH 31/32] chore: remove useless logs --- tests/automation/landing_page.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/automation/landing_page.spec.ts b/tests/automation/landing_page.spec.ts index 29bf530..9338ec4 100644 --- a/tests/automation/landing_page.spec.ts +++ b/tests/automation/landing_page.spec.ts @@ -8,8 +8,6 @@ import { test_Alice_2W( `Landing page states`, async ({ aliceWindow1, aliceWindow2 }, _testInfo) => { - const os = process.platform; - console.log('OS:', os); await Promise.all([ waitForElement(aliceWindow1, 'class', 'session-conversation'), waitForElement(aliceWindow2, 'class', 'session-conversation'), From 317bbfa65b06b59cf56f4f19f9c4357d2dc08204 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 25 Sep 2025 07:43:55 +0200 Subject: [PATCH 32/32] chore: add new strings verification --- tests/automation/enforce_localized_str.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/automation/enforce_localized_str.spec.ts b/tests/automation/enforce_localized_str.spec.ts index 1a5812b..ec9dc63 100644 --- a/tests/automation/enforce_localized_str.spec.ts +++ b/tests/automation/enforce_localized_str.spec.ts @@ -251,6 +251,15 @@ function getExpectedStringFromKey( return 'Are you sure you want to permanently hide your recovery password on this device? This cannot be undone.'; case 'enter': return 'Enter'; + case 'onboardingAccountCreated': + return 'Account Created'; + case 'onboardingBubbleWelcomeToSession': + return 'Welcome to Session {emoji}'; + case 'conversationsNone': + return "You don't have any conversations yet"; + case 'onboardingHitThePlusButton': + return 'Hit the plus button to start a chat, create a group, or join an official community!'; + default: // returning null means we don't have an expected string yet for this key. // This will make the test fail