From dc05dba4e0323ef8078036c02c856223ba84f8e8 Mon Sep 17 00:00:00 2001 From: Miklos Mandoki Date: Wed, 19 Nov 2025 15:24:01 +1100 Subject: [PATCH] feat: alphabetize locator files --- eslint.config.mjs | 6 + run/test/specs/locators/browsers.ts | 35 +- run/test/specs/locators/conversation.ts | 494 +++++++++--------- .../specs/locators/disappearing_messages.ts | 82 +-- run/test/specs/locators/external.ts | 42 +- run/test/specs/locators/global.ts | 86 +-- run/test/specs/locators/global_search.ts | 16 +- run/test/specs/locators/groups.ts | 215 ++++---- run/test/specs/locators/home.ts | 100 ++-- run/test/specs/locators/index.ts | 336 ++++++------ run/test/specs/locators/network_page.ts | 96 ++-- run/test/specs/locators/onboarding.ts | 94 ++-- run/test/specs/locators/settings.ts | 216 ++++---- run/test/specs/locators/start_conversation.ts | 68 ++- 14 files changed, 932 insertions(+), 954 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index ef4b1204b..a708d9643 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -89,5 +89,11 @@ export default tseslint.config( 'perfectionist/sort-named-imports': 'off', 'perfectionist/sort-union-types': 'off', }, + }, + { + files: ['run/test/specs/locators/*'], + rules: { + 'perfectionist/sort-modules': 'error', + }, } ); diff --git a/run/test/specs/locators/browsers.ts b/run/test/specs/locators/browsers.ts index e73ed35e0..14039f64a 100644 --- a/run/test/specs/locators/browsers.ts +++ b/run/test/specs/locators/browsers.ts @@ -1,24 +1,19 @@ import { LocatorsInterface } from '.'; -// SHARED LOCATORS -export class URLInputField extends LocatorsInterface { +export class ChromeNotificationsNegativeButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'com.android.chrome:id/url_bar', + selector: 'com.android.chrome:id/negative_button', } as const; case 'ios': - return { - strategy: 'accessibility id', - selector: 'URL', - } as const; + throw new Error('Unsupported platform'); } } } -// ANDROID ONLY export class ChromeUseWithoutAnAccount extends LocatorsInterface { public build() { switch (this.platform) { @@ -34,22 +29,21 @@ export class ChromeUseWithoutAnAccount extends LocatorsInterface { } } -export class ChromeNotificationsNegativeButton extends LocatorsInterface { +export class SafariAddressBar extends LocatorsInterface { public build() { switch (this.platform) { case 'android': + throw new Error('Unsupported platform'); + case 'ios': return { - strategy: 'id', - selector: 'com.android.chrome:id/negative_button', + strategy: 'accessibility id', + selector: 'TabBarItemTitle', } as const; - case 'ios': - throw new Error('Unsupported platform'); } } } -// iOS ONLY -export class SafariAddressBar extends LocatorsInterface { +export class SafariShareButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': @@ -57,20 +51,23 @@ export class SafariAddressBar extends LocatorsInterface { case 'ios': return { strategy: 'accessibility id', - selector: 'TabBarItemTitle', + selector: 'ShareButton', } as const; } } } -export class SafariShareButton extends LocatorsInterface { +export class URLInputField extends LocatorsInterface { public build() { switch (this.platform) { case 'android': - throw new Error('Unsupported platform'); + return { + strategy: 'id', + selector: 'com.android.chrome:id/url_bar', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'ShareButton', + selector: 'URL', } as const; } } diff --git a/run/test/specs/locators/conversation.ts b/run/test/specs/locators/conversation.ts index 66cfce859..921c7aa68 100644 --- a/run/test/specs/locators/conversation.ts +++ b/run/test/specs/locators/conversation.ts @@ -6,308 +6,363 @@ import { StrategyExtractionObj } from '../../../types/testing'; import { getAppDisplayName } from '../utils/devnet'; import { LocatorsInterface } from './index'; -export class MessageInput extends LocatorsInterface { +export class AttachmentsButton extends LocatorsInterface { public build() { return { strategy: 'accessibility id', - selector: 'Message input box', + selector: 'Attachments button', } as const; } } -export class SendButton extends LocatorsInterface { - public build(): StrategyExtractionObj { - return { - strategy: 'accessibility id', - selector: 'Send message button', - }; +export class BlockedBanner extends LocatorsInterface { + public build() { + switch (this.platform) { + case 'android': + return { + strategy: 'accessibility id', + selector: 'blocked-banner', + } as const; + case 'ios': + return { + strategy: 'accessibility id', + selector: 'Blocked banner', + } as const; + } } } -export class NewVoiceMessageButton extends LocatorsInterface { +export class CallButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': + return { + strategy: 'accessibility id', + selector: 'Call button', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'New voice message', + selector: 'Call', } as const; } } } -export class MessageBody extends LocatorsInterface { - public text: string | undefined; - constructor(device: DeviceWrapper, text?: string) { - super(device); - this.text = text; - } - public build() { +export class CommunityInvitation extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': + return { + strategy: 'id', + selector: 'network.loki.messenger.qa:id/openGroupTitleTextView', + text: testCommunityName, + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Message body', - text: this.text, + selector: 'Community invitation', + text: testCommunityName, } as const; } } } -export class VoiceMessage extends LocatorsInterface { +export class CommunityInviteConfirmButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': + return { + strategy: 'id', + selector: 'invite-contacts-button', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Voice message', + selector: 'Invite contacts button', } as const; } } } -export class MediaMessage extends LocatorsInterface { - public build() { +export class CommunityMessageAuthor extends LocatorsInterface { + public text: string; + constructor(device: DeviceWrapper, text: string) { + super(device); + this.text = text; + } + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': + // Identify the profile picture of a message with a specific text + return { + strategy: 'xpath', + selector: `//android.view.ViewGroup[@resource-id='network.loki.messenger.qa:id/mainContainer'][.//android.widget.TextView[contains(@text,'${this.text}')]]//androidx.compose.ui.platform.ComposeView[@resource-id='network.loki.messenger.qa:id/profilePictureView']`, + } as const; case 'ios': + // Identify the display name of a blinded sender of a message with a specific text return { - strategy: 'accessibility id', - selector: 'Media message', + strategy: 'xpath', + selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@name='Message body' and contains(@label,'${this.text}')]]//XCUIElementTypeStaticText[contains(@value,'(15')]`, } as const; } } } -export class DocumentMessage extends LocatorsInterface { +export class ConversationHeaderName extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } public build() { switch (this.platform) { case 'android': + return { + strategy: '-android uiautomator', + selector: `new UiSelector().resourceId("Conversation header name").childSelector(new UiSelector().resourceId("pro-badge-text"))`, + text: this.text, + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Document', + selector: 'Conversation header name', + text: this.text, } as const; } } } -export class ScrollToBottomButton extends LocatorsInterface { +export class ConversationSettings extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/scrollToBottomButton', + selector: 'conversation-options-avatar', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Scroll button', + selector: 'More options', } as const; } } } -export class ConversationSettings extends LocatorsInterface { +export class DeleteContactConfirmButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'conversation-options-avatar', + selector: 'delete-contact-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'More options', + selector: 'Delete', } as const; } } } -export class DeletedMessage extends LocatorsInterface { +export class DeleteContactMenuItem extends LocatorsInterface { public build() { - return { - strategy: 'accessibility id', - selector: 'Deleted message', - } as const; + switch (this.platform) { + case 'android': + return { + strategy: 'id', + selector: 'delete-contact-menu-option', + } as const; + case 'ios': + return { + strategy: 'accessibility id', + selector: 'Delete Contact', + } as const; + } } } -// Empty conversation state -export class EmptyConversation extends LocatorsInterface { +export class DeleteConversationMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': + return { + strategy: 'id', + selector: 'delete-conversation-menu-option', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Empty list', + selector: 'Delete Conversation', } as const; } } } -export class Hide extends LocatorsInterface { +export class DeleteConversationModalConfirm extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'Clear', // I guess they changed the label to Hide but not the ax id + strategy: 'id', + selector: 'delete-conversation-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Hide', + selector: 'Delete', } as const; } } } -export class AttachmentsButton extends LocatorsInterface { +export class DeletedMessage extends LocatorsInterface { public build() { return { strategy: 'accessibility id', - selector: 'Attachments button', + selector: 'Deleted message', } as const; } } -// TODO tie this to the message whose status we want to check (similar to EmojiReactsPill) -export class OutgoingMessageStatusSent extends LocatorsInterface { +export class DocumentMessage extends LocatorsInterface { public build() { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: 'network.loki.messenger.qa:id/messageStatusTextView', - text: 'Sent', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: `Message sent status: Sent`, + selector: 'Document', } as const; } } } -export class CallButton extends LocatorsInterface { +export class EditNicknameButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'accessibility id', - selector: 'Call button', + selector: 'Edit', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Call', + selector: 'Username', } as const; } } } -export class ConversationHeaderName extends LocatorsInterface { - public text: string | undefined; - constructor(device: DeviceWrapper, text?: string) { +export class EmojiReactsCount extends LocatorsInterface { + constructor( + device: DeviceWrapper, + private messageText: string, + private expectedCount: string = '2' + ) { super(device); - this.text = text; } - public build() { + + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: '-android uiautomator', - selector: `new UiSelector().resourceId("Conversation header name").childSelector(new UiSelector().resourceId("pro-badge-text"))`, - text: this.text, + strategy: 'xpath', + selector: `//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/mainContainer"][.//android.widget.TextView[contains(@text,"${this.messageText}")]]//android.widget.TextView[@resource-id="network.loki.messenger.qa:id/reactions_pill_count"][@text="${this.expectedCount}"]`, } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Conversation header name', - text: this.text, + strategy: 'xpath', + selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@label="${this.messageText}"]]//XCUIElementTypeStaticText[@value="${this.expectedCount}"]`, } as const; } } } -export class NotificationsModalButton extends LocatorsInterface { - public build() { +// Find the reactions pill underneath a specific message +export class EmojiReactsPill extends LocatorsInterface { + constructor( + device: DeviceWrapper, + private messageText: string + ) { + super(device); + } + + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': + return { + strategy: 'xpath', + selector: `//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/mainContainer"][.//android.widget.TextView[contains(@text,"${this.messageText}")]]//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/layout_emoji_container"]`, + } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Notifications', + strategy: 'xpath', + selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@label="${this.messageText}"]]//XCUIElementTypeStaticText[@value="😂"]`, } as const; } } } -export class NotificationSwitch extends LocatorsInterface { +// Empty conversation state +export class EmptyConversation extends LocatorsInterface { public build() { switch (this.platform) { case 'android': + case 'ios': return { - strategy: 'id', - selector: 'com.android.settings:id/switch_text', - text: `All ${getAppDisplayName()} notifications`, + strategy: 'accessibility id', + selector: 'Empty list', } as const; - case 'ios': - throw new Error('Platform not supported'); } } } -export class BlockedBanner extends LocatorsInterface { +export class FirstEmojiReact extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'blocked-banner', + strategy: 'id', + selector: 'network.loki.messenger.qa:id/reaction_1', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Blocked banner', + selector: '😂', } as const; } } } -export class DeleteConversationMenuItem extends LocatorsInterface { +export class Hide extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'delete-conversation-menu-option', + strategy: 'accessibility id', + selector: 'Clear', // I guess they changed the label to Hide but not the ax id } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete Conversation', + selector: 'Hide', } as const; } } } -export class DeleteConversationModalConfirm extends LocatorsInterface { +export class HideNoteToSelfConfirmButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'delete-conversation-confirm-button', + selector: 'hide-nts-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete', + selector: 'Hide', } as const; } } @@ -330,171 +385,197 @@ export class HideNoteToSelfMenuOption extends LocatorsInterface { } } -export class HideNoteToSelfConfirmButton extends LocatorsInterface { +export class MediaMessage extends LocatorsInterface { public build() { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: 'hide-nts-confirm-button', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Hide', + selector: 'Media message', } as const; } } } -export class ShowNoteToSelfMenuOption extends LocatorsInterface { +export class MessageBody extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } public build() { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: 'hide-nts-menu-option', // Yes this has the 'hide' ID - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Show Note to Self', + selector: 'Message body', + text: this.text, } as const; } } } -export class ShowNoteToSelfConfirmButton extends LocatorsInterface { +export class MessageInput extends LocatorsInterface { public build() { + return { + strategy: 'accessibility id', + selector: 'Message input box', + } as const; + } +} +export class MessageLengthCountdown extends LocatorsInterface { + constructor( + device: DeviceWrapper, + private length?: string + ) { + super(device); + } + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'show-nts-confirm-button', + selector: 'network.loki.messenger.qa:id/characterLimitText', + text: this.length, } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Show', + strategy: 'xpath', + selector: `//XCUIElementTypeStaticText[@name="${this.length}"]`, + text: this.length, } as const; } } } -export class DeleteContactMenuItem extends LocatorsInterface { +export class MessageLengthOkayButton extends LocatorsInterface { + public build(): StrategyExtractionObj { + switch (this.platform) { + case 'android': + return { strategy: 'id', selector: 'Okay' } as const; + case 'ios': + return { strategy: 'xpath', selector: '//XCUIElementTypeButton[@name="Okay"]' } as const; + } + } +} + +export class MessageRequestAcceptDescription extends LocatorsInterface { public build() { + const messageRequestsAcceptDescription = englishStrippedStr( + 'messageRequestsAcceptDescription' + ).toString(); switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'delete-contact-menu-option', + selector: 'network.loki.messenger.qa:id/sendAcceptsTextView', + text: messageRequestsAcceptDescription, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete Contact', + selector: 'Control message', + text: messageRequestsAcceptDescription, } as const; } } } -export class DeleteContactConfirmButton extends LocatorsInterface { + +export class MessageRequestPendingDescription extends LocatorsInterface { public build() { + const messageRequestPendingDescription = englishStrippedStr( + 'messageRequestPendingDescription' + ).toString(); switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'delete-contact-confirm-button', + selector: 'network.loki.messenger.qa:id/textSendAfterApproval', + text: messageRequestPendingDescription, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete', + selector: 'Control message', + text: messageRequestPendingDescription, } as const; } } } -export class CommunityInviteConfirmButton extends LocatorsInterface { +export class NewVoiceMessageButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: 'invite-contacts-button', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Invite contacts button', + selector: 'New voice message', } as const; } } } -export class CommunityInvitation extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class NicknameInput extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/openGroupTitleTextView', - text: testCommunityName, + selector: 'nickname-input', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Community invitation', - text: testCommunityName, + selector: 'Username input', } as const; } } } -export class EditNicknameButton extends LocatorsInterface { +export class NotificationsModalButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': - return { - strategy: 'accessibility id', - selector: 'Edit', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Username', + selector: 'Notifications', } as const; } } } -export class NicknameInput extends LocatorsInterface { +export class NotificationSwitch extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'nickname-input', + selector: 'com.android.settings:id/switch_text', + text: `All ${getAppDisplayName()} notifications`, } as const; case 'ios': - return { - strategy: 'accessibility id', - selector: 'Username input', - } as const; + throw new Error('Platform not supported'); } } } -export class SaveNicknameButton extends LocatorsInterface { +// TODO tie this to the message whose status we want to check (similar to EmojiReactsPill) +export class OutgoingMessageStatusSent extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'set-nickname-confirm-button', + selector: 'network.loki.messenger.qa:id/messageStatusTextView', + text: 'Sent', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Save', + selector: `Message sent status: Sent`, } as const; } } @@ -524,128 +605,78 @@ export class PreferredDisplayName extends LocatorsInterface { } } -export class FirstEmojiReact extends LocatorsInterface { +export class SaveNicknameButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/reaction_1', + selector: 'set-nickname-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: '😂', + selector: 'Save', } as const; } } } -// Find the reactions pill underneath a specific message -export class EmojiReactsPill extends LocatorsInterface { - constructor( - device: DeviceWrapper, - private messageText: string - ) { - super(device); - } - - public build(): StrategyExtractionObj { +export class ScrollToBottomButton extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { - strategy: 'xpath', - selector: `//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/mainContainer"][.//android.widget.TextView[contains(@text,"${this.messageText}")]]//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/layout_emoji_container"]`, + strategy: 'id', + selector: 'network.loki.messenger.qa:id/scrollToBottomButton', } as const; case 'ios': return { - strategy: 'xpath', - selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@label="${this.messageText}"]]//XCUIElementTypeStaticText[@value="😂"]`, + strategy: 'accessibility id', + selector: 'Scroll button', } as const; } } } -export class EmojiReactsCount extends LocatorsInterface { - constructor( - device: DeviceWrapper, - private messageText: string, - private expectedCount: string = '2' - ) { - super(device); - } - +export class SendButton extends LocatorsInterface { public build(): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { - strategy: 'xpath', - selector: `//android.view.ViewGroup[@resource-id="network.loki.messenger.qa:id/mainContainer"][.//android.widget.TextView[contains(@text,"${this.messageText}")]]//android.widget.TextView[@resource-id="network.loki.messenger.qa:id/reactions_pill_count"][@text="${this.expectedCount}"]`, - } as const; - case 'ios': - return { - strategy: 'xpath', - selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@label="${this.messageText}"]]//XCUIElementTypeStaticText[@value="${this.expectedCount}"]`, - } as const; - } + return { + strategy: 'accessibility id', + selector: 'Send message button', + }; } } -export class MessageLengthCountdown extends LocatorsInterface { - constructor( - device: DeviceWrapper, - private length?: string - ) { - super(device); - } - public build(): StrategyExtractionObj { +export class ShowNoteToSelfConfirmButton extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/characterLimitText', - text: this.length, + selector: 'show-nts-confirm-button', } as const; case 'ios': return { - strategy: 'xpath', - selector: `//XCUIElementTypeStaticText[@name="${this.length}"]`, - text: this.length, + strategy: 'accessibility id', + selector: 'Show', } as const; } } } -export class MessageLengthOkayButton extends LocatorsInterface { - public build(): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { strategy: 'id', selector: 'Okay' } as const; - case 'ios': - return { strategy: 'xpath', selector: '//XCUIElementTypeButton[@name="Okay"]' } as const; - } - } -} - -export class CommunityMessageAuthor extends LocatorsInterface { - public text: string; - constructor(device: DeviceWrapper, text: string) { - super(device); - this.text = text; - } - public build(): StrategyExtractionObj { +export class ShowNoteToSelfMenuOption extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': - // Identify the profile picture of a message with a specific text return { - strategy: 'xpath', - selector: `//android.view.ViewGroup[@resource-id='network.loki.messenger.qa:id/mainContainer'][.//android.widget.TextView[contains(@text,'${this.text}')]]//androidx.compose.ui.platform.ComposeView[@resource-id='network.loki.messenger.qa:id/profilePictureView']`, + strategy: 'id', + selector: 'hide-nts-menu-option', // Yes this has the 'hide' ID } as const; case 'ios': - // Identify the display name of a blinded sender of a message with a specific text return { - strategy: 'xpath', - selector: `//XCUIElementTypeCell[.//XCUIElementTypeOther[@name='Message body' and contains(@label,'${this.text}')]]//XCUIElementTypeStaticText[contains(@value,'(15')]`, + strategy: 'accessibility id', + selector: 'Show Note to Self', } as const; } } @@ -668,45 +699,14 @@ export class UPMMessageButton extends LocatorsInterface { } } -export class MessageRequestPendingDescription extends LocatorsInterface { - public build() { - const messageRequestPendingDescription = englishStrippedStr( - 'messageRequestPendingDescription' - ).toString(); - switch (this.platform) { - case 'android': - return { - strategy: 'id', - selector: 'network.loki.messenger.qa:id/textSendAfterApproval', - text: messageRequestPendingDescription, - } as const; - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Control message', - text: messageRequestPendingDescription, - } as const; - } - } -} - -export class MessageRequestAcceptDescription extends LocatorsInterface { +export class VoiceMessage extends LocatorsInterface { public build() { - const messageRequestsAcceptDescription = englishStrippedStr( - 'messageRequestsAcceptDescription' - ).toString(); switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: 'network.loki.messenger.qa:id/sendAcceptsTextView', - text: messageRequestsAcceptDescription, - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Control message', - text: messageRequestsAcceptDescription, + selector: 'Voice message', } as const; } } diff --git a/run/test/specs/locators/disappearing_messages.ts b/run/test/specs/locators/disappearing_messages.ts index 48d0377e7..251b3fb77 100644 --- a/run/test/specs/locators/disappearing_messages.ts +++ b/run/test/specs/locators/disappearing_messages.ts @@ -6,81 +6,99 @@ import { StrategyExtractionObj, } from '../../../types/testing'; -export class DisappearingMessagesMenuOption extends LocatorsInterface { +export class DisableDisappearingMessages extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'disappearing-messages-menu-option', + selector: `Disable disappearing messages`, }; case 'ios': return { strategy: 'accessibility id', - selector: 'Disappearing Messages', + selector: 'Off', }; } } } -export class DisappearingMessagesSubtitle extends LocatorsInterface { +export class DisappearingMessageRadial extends LocatorsInterface { + private timer: DISAPPEARING_TIMES; + + // Receives a timer argument so that one locator can handle all DM durations + constructor(device: DeviceWrapper, timer: DISAPPEARING_TIMES) { + super(device); + this.timer = timer; + } public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Disappearing messages type and time', - }; + selector: this.timer, + } as const; case 'ios': return { strategy: 'accessibility id', - selector: `Disappearing messages type and time`, - }; + selector: `${this.timer} - Radio`, + } as const; } } } -export class DisableDisappearingMessages extends LocatorsInterface { +export class DisappearingMessagesMenuOption extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: `Disable disappearing messages`, + selector: 'disappearing-messages-menu-option', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Off', + selector: 'Disappearing Messages', }; } } } -export class SetDisappearMessagesButton extends LocatorsInterface { +export class DisappearingMessagesSubtitle extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Set button', - } as const; + selector: 'Disappearing messages type and time', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Set button', - } as const; + selector: `Disappearing messages type and time`, + }; } } } -export class SetModalButton extends LocatorsInterface { +export class DisappearingMessagesTimerType extends LocatorsInterface { + private timerType: DisappearingOptions; + + constructor(device: DeviceWrapper, timerType: DisappearingOptions) { + super(device); + this.timerType = timerType; + } + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': + return { + strategy: 'id', + selector: this.timerType, + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Set', + selector: this.timerType, } as const; } } @@ -98,49 +116,31 @@ export class FollowSettingsButton extends LocatorsInterface { } } } -export class DisappearingMessageRadial extends LocatorsInterface { - private timer: DISAPPEARING_TIMES; - - // Receives a timer argument so that one locator can handle all DM durations - constructor(device: DeviceWrapper, timer: DISAPPEARING_TIMES) { - super(device); - this.timer = timer; - } +export class SetDisappearMessagesButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: this.timer, + selector: 'Set button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: `${this.timer} - Radio`, + selector: 'Set button', } as const; } } } -export class DisappearingMessagesTimerType extends LocatorsInterface { - private timerType: DisappearingOptions; - - constructor(device: DeviceWrapper, timerType: DisappearingOptions) { - super(device); - this.timerType = timerType; - } - +export class SetModalButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: this.timerType, - } as const; case 'ios': return { strategy: 'accessibility id', - selector: this.timerType, + selector: 'Set', } as const; } } diff --git a/run/test/specs/locators/external.ts b/run/test/specs/locators/external.ts index a6b7252aa..1a7ef3855 100644 --- a/run/test/specs/locators/external.ts +++ b/run/test/specs/locators/external.ts @@ -1,14 +1,5 @@ import { LocatorsInterface } from '.'; -export class PhotoLibrary extends LocatorsInterface { - public build() { - return { - strategy: 'accessibility id', - selector: 'Photos', - } as const; - } -} - export class DisguisedApp extends LocatorsInterface { public build() { return { @@ -18,20 +9,22 @@ export class DisguisedApp extends LocatorsInterface { } as const; } } -export class IOSSaveToFiles extends LocatorsInterface { + +export class iOSPhotosContinuebutton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': throw new Error('Unsupported platform'); case 'ios': return { - strategy: 'accessibility id', - selector: 'Save to Files', + strategy: 'xpath', + selector: `//XCUIElementTypeButton[@name="Continue"]`, + maxWait: 5000, } as const; } } } -export class IOSSaveButton extends LocatorsInterface { +export class IOSReplaceButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': @@ -39,12 +32,12 @@ export class IOSSaveButton extends LocatorsInterface { case 'ios': return { strategy: 'accessibility id', - selector: 'Save', + selector: 'Replace', } as const; } } } -export class IOSReplaceButton extends LocatorsInterface { +export class IOSSaveButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': @@ -52,23 +45,30 @@ export class IOSReplaceButton extends LocatorsInterface { case 'ios': return { strategy: 'accessibility id', - selector: 'Replace', + selector: 'Save', } as const; } } } - -export class iOSPhotosContinuebutton extends LocatorsInterface { +export class IOSSaveToFiles extends LocatorsInterface { public build() { switch (this.platform) { case 'android': throw new Error('Unsupported platform'); case 'ios': return { - strategy: 'xpath', - selector: `//XCUIElementTypeButton[@name="Continue"]`, - maxWait: 5000, + strategy: 'accessibility id', + selector: 'Save to Files', } as const; } } } + +export class PhotoLibrary extends LocatorsInterface { + public build() { + return { + strategy: 'accessibility id', + selector: 'Photos', + } as const; + } +} diff --git a/run/test/specs/locators/global.ts b/run/test/specs/locators/global.ts index dc4b1e300..f9eb9c8e6 100644 --- a/run/test/specs/locators/global.ts +++ b/run/test/specs/locators/global.ts @@ -1,102 +1,100 @@ import { DeviceWrapper } from '../../../types/DeviceWrapper'; import { LocatorsInterface } from './index'; -export class ModalHeading extends LocatorsInterface { +export class AccountIDDisplay extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Modal heading', + selector: 'Account ID', + text: this.text, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Modal heading', + selector: 'Account ID', + text: this.text, } as const; } } } -export class ModalDescription extends LocatorsInterface { +export class AllowPermissionLocator extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Modal description', + selector: 'com.android.permissioncontroller:id/permission_allow_button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Modal description', + selector: 'Allow', } as const; } } } -export class ContinueButton extends LocatorsInterface { +export class Contact extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Continue', + selector: 'pro-badge-text', + text: this.text, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Continue', + selector: 'Contact', + text: this.text, } as const; } } } -export class EnableLinkPreviewsModalButton extends LocatorsInterface { - public build() { - return { - strategy: 'accessibility id', - selector: 'Enable', - } as const; - } -} - -export class Contact extends LocatorsInterface { - public text: string | undefined; - constructor(device: DeviceWrapper, text?: string) { - super(device); - this.text = text; - } +export class ContinueButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'pro-badge-text', - text: this.text, + selector: 'Continue', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Contact', - text: this.text, + selector: 'Continue', } as const; } } } -export class AllowPermissionLocator extends LocatorsInterface { +export class CopyURLButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'com.android.permissioncontroller:id/permission_allow_button', + selector: 'Copy URL', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Allow', + selector: 'Copy URL', } as const; } } @@ -119,42 +117,44 @@ export class DenyPermissionLocator extends LocatorsInterface { } } -export class AccountIDDisplay extends LocatorsInterface { - public text: string | undefined; - constructor(device: DeviceWrapper, text?: string) { - super(device); - this.text = text; +export class EnableLinkPreviewsModalButton extends LocatorsInterface { + public build() { + return { + strategy: 'accessibility id', + selector: 'Enable', + } as const; } +} + +export class ModalDescription extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Account ID', - text: this.text, + selector: 'Modal description', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Account ID', - text: this.text, + selector: 'Modal description', } as const; } } } -export class CopyURLButton extends LocatorsInterface { +export class ModalHeading extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Copy URL', + selector: 'Modal heading', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Copy URL', + selector: 'Modal heading', } as const; } } diff --git a/run/test/specs/locators/global_search.ts b/run/test/specs/locators/global_search.ts index 3230131fc..7d8962164 100644 --- a/run/test/specs/locators/global_search.ts +++ b/run/test/specs/locators/global_search.ts @@ -1,37 +1,37 @@ import { StrategyExtractionObj } from '../../../types/testing'; import { LocatorsInterface } from './index'; -export class NoteToSelfOption extends LocatorsInterface { +export class CancelSearchButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'pro-badge-text', - text: 'Note to Self', + selector: 'network.loki.messenger.qa:id/search_cancel', + text: 'Cancel', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Note to Self', + selector: 'Cancel', }; } } } -export class CancelSearchButton extends LocatorsInterface { +export class NoteToSelfOption extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/search_cancel', - text: 'Cancel', + selector: 'pro-badge-text', + text: 'Note to Self', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Cancel', + selector: 'Note to Self', }; } } diff --git a/run/test/specs/locators/groups.ts b/run/test/specs/locators/groups.ts index 89f1439f9..220dc9c84 100644 --- a/run/test/specs/locators/groups.ts +++ b/run/test/specs/locators/groups.ts @@ -6,18 +6,18 @@ import { DeviceWrapper } from '../../../types/DeviceWrapper'; import { StrategyExtractionObj } from '../../../types/testing'; import { GROUPNAME } from '../../../types/testing'; -export class GroupNameInput extends LocatorsInterface { +export class ConfirmRemovalButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Group name input', + selector: 'Remove', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Group name input', + selector: 'Remove', } as const; } } @@ -40,49 +40,70 @@ export class CreateGroupButton extends LocatorsInterface { } } -export class InviteContactConfirm extends LocatorsInterface { +export class DeleteGroupConfirm extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'invite-contacts-button', + selector: 'delete-group-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Confirm invite button', + selector: 'Delete', } as const; } } } -export class UpdateGroupInformation extends LocatorsInterface { - private groupName?: GROUPNAME; - - // Receives a group name argument so that one locator can handle all possible group names - constructor(device: DeviceWrapper, groupName?: GROUPNAME) { - super(device); - this.groupName = groupName; +export class DeleteGroupMenuItem extends LocatorsInterface { + public build(): StrategyExtractionObj { + switch (this.platform) { + case 'android': + return { + strategy: 'id', + selector: 'delete-group-menu-option', + } as const; + case 'ios': + return { + strategy: 'accessibility id', + selector: 'Leave group', // yep this is leave even for the delete option + } as const; + } } +} +export class EditGroupDescriptionInput extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': + return { + strategy: 'id', + selector: 'update-group-info-description-input', + } as const; + case 'ios': return { strategy: 'accessibility id', - selector: 'Edit', - }; - case 'ios': { - const groupName = this.groupName; - if (!groupName) { - throw new Error('groupName must be provided for iOS'); - } + selector: 'Group description text field', + } as const; + } + } +} + +export class EditGroupNameInput extends LocatorsInterface { + public build(): StrategyExtractionObj { + switch (this.platform) { + case 'android': + return { + strategy: 'id', + selector: 'update-group-info-name-input', + } as const; + case 'ios': return { strategy: 'accessibility id', - selector: groupName, - }; - } + selector: 'Group name text field', + } as const; } } } @@ -113,69 +134,73 @@ export class GroupDescription extends LocatorsInterface { } } -export class EditGroupNameInput extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class GroupMember extends LocatorsInterface { + public build(username?: UserNameType): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'update-group-info-name-input', + selector: 'pro-badge-text', + text: `${username}`, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Group name text field', + selector: 'Contact', + text: `${username}`, } as const; } } } -export class EditGroupDescriptionInput extends LocatorsInterface { +export class GroupNameInput extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'update-group-info-description-input', + selector: 'Group name input', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Group description text field', + selector: 'Group name input', } as const; } } } - -export class SaveGroupNameChangeButton extends LocatorsInterface { +export class InviteContactConfirm extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'update-group-info-confirm-button', + selector: 'invite-contacts-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Save', + selector: 'Confirm invite button', } as const; } } } - -export class LeaveGroupMenuItem extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class LatestReleaseBanner extends LocatorsInterface { + public build() { switch (this.platform) { + // On Android, the text of the banner is exposed to Appium + // so it's possible to verify that the banner is visible and it has the correct text case 'android': return { strategy: 'id', - selector: 'leave-group-menu-option', + selector: 'Version warning banner', + text: englishStrippedStr('groupInviteVersion').toString(), } as const; case 'ios': + // On iOS, the text is currently not exposed to Appium return { strategy: 'accessibility id', - selector: 'Leave group', + selector: 'Version warning banner', } as const; } } @@ -196,58 +221,58 @@ export class LeaveGroupConfirm extends LocatorsInterface { } } } -export class DeleteGroupMenuItem extends LocatorsInterface { +export class LeaveGroupMenuItem extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'delete-group-menu-option', + selector: 'leave-group-menu-option', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Leave group', // yep this is leave even for the delete option + selector: 'Leave group', } as const; } } } -export class DeleteGroupConfirm extends LocatorsInterface { +export class ManageMembersMenuItem extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'delete-group-confirm-button', - } as const; + selector: 'manage-members-menu-option', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete', - } as const; + selector: 'Manage Members', + }; } } } -export class LatestReleaseBanner extends LocatorsInterface { - public build() { + +export class MemberStatus extends LocatorsInterface { + public build(text?: string): StrategyExtractionObj { switch (this.platform) { - // On Android, the text of the banner is exposed to Appium - // so it's possible to verify that the banner is visible and it has the correct text case 'android': return { strategy: 'id', - selector: 'Version warning banner', - text: englishStrippedStr('groupInviteVersion').toString(), + selector: 'Contact status', + text, } as const; case 'ios': - // On iOS, the text is currently not exposed to Appium return { strategy: 'accessibility id', - selector: 'Version warning banner', + selector: 'Contact status', + text, } as const; } } } + export class RecreateGroupBannerAdmin extends LocatorsInterface { public build(): StrategyExtractionObj { return { @@ -268,42 +293,6 @@ export class RecreateGroupBannerMember extends LocatorsInterface { } } -export class RecreateGroupButton extends LocatorsInterface { - public build(): StrategyExtractionObj { - switch (this.platform) { - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Legacy Groups Recreate Button', - } as const; - case 'android': - return { - strategy: 'accessibility id', - selector: 'Accept message request', - } as const; - } - } -} - -export class GroupMember extends LocatorsInterface { - public build(username?: UserNameType): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { - strategy: 'id', - selector: 'pro-badge-text', - text: `${username}`, - } as const; - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Contact', - text: `${username}`, - } as const; - } - } -} - export class RemoveMemberButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { @@ -321,54 +310,48 @@ export class RemoveMemberButton extends LocatorsInterface { } } -export class ConfirmRemovalButton extends LocatorsInterface { +export class SaveGroupNameChangeButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Remove', + selector: 'update-group-info-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Remove', + selector: 'Save', } as const; } } } +export class UpdateGroupInformation extends LocatorsInterface { + private groupName?: GROUPNAME; -export class MemberStatus extends LocatorsInterface { - public build(text?: string): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { - strategy: 'id', - selector: 'Contact status', - text, - } as const; - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Contact status', - text, - } as const; - } + // Receives a group name argument so that one locator can handle all possible group names + constructor(device: DeviceWrapper, groupName?: GROUPNAME) { + super(device); + this.groupName = groupName; } -} -export class ManageMembersMenuItem extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'manage-members-menu-option', + strategy: 'accessibility id', + selector: 'Edit', }; - case 'ios': + case 'ios': { + const groupName = this.groupName; + if (!groupName) { + throw new Error('groupName must be provided for iOS'); + } return { strategy: 'accessibility id', - selector: 'Manage Members', + selector: groupName, }; + } } } } diff --git a/run/test/specs/locators/home.ts b/run/test/specs/locators/home.ts index df2c090c3..c152fe3ff 100644 --- a/run/test/specs/locators/home.ts +++ b/run/test/specs/locators/home.ts @@ -3,6 +3,25 @@ import type { DeviceWrapper } from '../../../types/DeviceWrapper'; import { StrategyExtractionObj } from '../../../types/testing'; import { LocatorsInterface } from './index'; +export class ConversationItem extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } + public build() { + switch (this.platform) { + case 'android': + case 'ios': + return { + strategy: 'accessibility id', + selector: 'Conversation list item', + text: this.text, + } as const; + } + } +} + export class EmptyLandingPage extends LocatorsInterface { public build() { switch (this.platform) { @@ -20,21 +39,22 @@ export class EmptyLandingPage extends LocatorsInterface { } } -export class MessageRequestsBanner extends LocatorsInterface { - public build() { +export class LongPressBlockOption extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': - case 'ios': return { strategy: 'accessibility id', - selector: 'Message requests banner', - } as const; + selector: 'Block', + }; + case 'ios': + throw new Error('Not implemented'); } } } -export class ConversationItem extends LocatorsInterface { - public text: string | undefined; +export class MessageRequestItem extends LocatorsInterface { + public text?: string | undefined; constructor(device: DeviceWrapper, text?: string) { super(device); this.text = text; @@ -45,27 +65,21 @@ export class ConversationItem extends LocatorsInterface { case 'ios': return { strategy: 'accessibility id', - selector: 'Conversation list item', + selector: 'Message request', text: this.text, } as const; } } } -export class MessageRequestItem extends LocatorsInterface { - public text?: string | undefined; - constructor(device: DeviceWrapper, text?: string) { - super(device); - this.text = text; - } +export class MessageRequestsBanner extends LocatorsInterface { public build() { switch (this.platform) { case 'android': case 'ios': return { strategy: 'accessibility id', - selector: 'Message request', - text: this.text, + selector: 'Message requests banner', } as const; } } @@ -107,117 +121,103 @@ export class PlusButton extends LocatorsInterface { } as const; } } - -export class SearchButton extends LocatorsInterface { +export class ReviewPromptItsGreatButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: `Search icon`, + strategy: 'id', + selector: 'enjoy-session-positive-button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Search button', - }; - } - } -} -export class LongPressBlockOption extends LocatorsInterface { - public build(): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { - strategy: 'accessibility id', - selector: 'Block', + selector: 'enjoy-session-positive-button', }; - case 'ios': - throw new Error('Not implemented'); } } } -export class ReviewPromptItsGreatButton extends LocatorsInterface { +export class ReviewPromptNeedsWorkButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'enjoy-session-positive-button', + selector: 'enjoy-session-negative-button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'enjoy-session-positive-button', + selector: 'enjoy-session-negative-button', }; } } } -export class ReviewPromptNeedsWorkButton extends LocatorsInterface { +export class ReviewPromptNotNowButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'enjoy-session-negative-button', + selector: 'not-now-button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'enjoy-session-negative-button', + selector: 'not-now-button', }; } } } -export class ReviewPromptRateAppButton extends LocatorsInterface { +export class ReviewPromptOpenSurveyButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'rate-app-button', + selector: 'open-survey-button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'rate-app-button', + selector: 'open-survey-button', }; } } } -export class ReviewPromptNotNowButton extends LocatorsInterface { +export class ReviewPromptRateAppButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'not-now-button', + selector: 'rate-app-button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'not-now-button', + selector: 'rate-app-button', }; } } } -export class ReviewPromptOpenSurveyButton extends LocatorsInterface { +export class SearchButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'open-survey-button', + strategy: 'accessibility id', + selector: `Search icon`, }; case 'ios': return { strategy: 'accessibility id', - selector: 'open-survey-button', + selector: 'Search button', }; } } diff --git a/run/test/specs/locators/index.ts b/run/test/specs/locators/index.ts index 955f7c001..021d6528b 100644 --- a/run/test/specs/locators/index.ts +++ b/run/test/specs/locators/index.ts @@ -29,21 +29,6 @@ export abstract class LocatorsInterface { } } -export function describeLocator(locator: StrategyExtractionObj & { text?: string }): string { - const { strategy, selector, text } = locator; - - // Trim selector if its too long, show beginning and end - const maxSelectorLength = 80; - const halfLength = Math.floor(maxSelectorLength / 2); - const trimmedSelector = - selector.length > maxSelectorLength - ? `${selector.substring(0, halfLength)}…${selector.substring(selector.length - halfLength)}` - : selector; - - const base = `${strategy} "${trimmedSelector}"`; - return text ? `${base} and text "${text}"` : base; -} - export class ApplyChanges extends LocatorsInterface { public build() { switch (this.platform) { @@ -61,391 +46,393 @@ export class ApplyChanges extends LocatorsInterface { } } -export class ReadReceiptsButton extends LocatorsInterface { - public build() { +export class BlockedContactsSettings extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'android:id/summary', - text: 'Show read receipts for all messages you send and receive.', - } as const; + strategy: 'accessibility id', + selector: 'qa-blocked-contacts-settings-item', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Read Receipts - Switch', - } as const; + selector: 'Block contacts - Navigation', + }; } } } -export class CloseSettings extends LocatorsInterface { - public build() { +export class BlockUser extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { - case 'android': - return { - strategy: 'accessibility id', - selector: 'Close', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Close button', - } as const; + selector: 'Block', + }; + case 'android': + return { + strategy: 'id', + selector: 'block-user-menu-option', + }; } } } -export class UsernameDisplay extends LocatorsInterface { - public text: string | undefined; - constructor(device: DeviceWrapper, text?: string) { - super(device); - this.text = text; - } - public build() { +export class BlockUserConfirmationModal extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Display name', - text: this.text, + selector: 'block-user-confirm-button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Username', - text: this.text, + selector: 'Block', } as const; } } } -export class EditUsernameButton extends LocatorsInterface { - public build() { +export class ChangeProfilePictureButton extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'Edit', - } as const; + strategy: 'id', + selector: 'Image picker', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Username', - } as const; + selector: 'Upload', + }; } } } -export class UsernameInput extends LocatorsInterface { +export class ClearInputButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'class name', - selector: 'android.widget.EditText', + strategy: 'id', + selector: 'clear-input-button', } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Username input', + strategy: 'id', + selector: 'clear-input-button', } as const; } } } -export class ClearInputButton extends LocatorsInterface { +export class CloseSettings extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'clear-input-button', + strategy: 'accessibility id', + selector: 'Close', } as const; case 'ios': return { - strategy: 'id', - selector: 'clear-input-button', + strategy: 'accessibility id', + selector: 'Close button', } as const; } } } -export class FirstGif extends LocatorsInterface { +export class CommunityInput extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'xpath', - selector: ANDROID_XPATHS.FIRST_GIF, + strategy: 'id', + selector: 'Community input', }; case 'ios': return { - strategy: 'xpath', - selector: IOS_XPATHS.FIRST_GIF, + strategy: 'accessibility id', + selector: 'Enter Community URL', }; } } } -export class BlockUser extends LocatorsInterface { +export class DeclineMessageRequestButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { - case 'ios': + case 'android': return { strategy: 'accessibility id', - selector: 'Block', + selector: 'Delete message request', }; - case 'android': + case 'ios': return { - strategy: 'id', - selector: 'block-user-menu-option', + strategy: 'accessibility id', + selector: 'Delete message request', }; } } } -export class ChangeProfilePictureButton extends LocatorsInterface { +export class DeleteMessageConfirmationModal extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Image picker', + selector: 'Delete', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Upload', + selector: 'Delete', }; } } } -export class ImagePermissionsModalAllow extends LocatorsInterface { +export class DeleteMessageForEveryone extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'com.android.permissioncontroller:id/permission_allow_foreground_only_button', + selector: 'delete-for-everyone', }; case 'ios': - return { strategy: 'accessibility id', selector: 'Allow Full Access' }; + return { + strategy: 'accessibility id', + selector: 'Delete for everyone', + }; } } } -export class JoinCommunityButton extends LocatorsInterface { +export class DeleteMessageLocally extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Join community button', + selector: 'delete-only-on-this-device', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Join', + selector: 'Delete for me', }; } } } -export class CommunityInput extends LocatorsInterface { +export class DeleteMessageRequestButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Community input', + selector: `android:id/title`, + text: 'Delete', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Enter Community URL', + selector: 'Delete', }; } } } -export class InviteContactsButton extends LocatorsInterface { +export class DeleteMesssageRequestConfirmation extends LocatorsInterface { + public build(): StrategyExtractionObj { + return { + strategy: 'accessibility id', + selector: 'Delete', + }; + } +} + +export class DownloadMediaButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'Invite button', + strategy: 'accessibility id', + selector: 'Download', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Invite button', + selector: 'Download', }; } } } -export class InviteContactsMenuItem extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class EditUsernameButton extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'invite-contacts-menu-option', - }; + strategy: 'accessibility id', + selector: 'Edit', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Invite Contacts', - }; + selector: 'Username', + } as const; } } } -export class DeleteMessageLocally extends LocatorsInterface { +export class FirstGif extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'delete-only-on-this-device', + strategy: 'xpath', + selector: ANDROID_XPATHS.FIRST_GIF, }; case 'ios': return { - strategy: 'accessibility id', - selector: 'Delete for me', + strategy: 'xpath', + selector: IOS_XPATHS.FIRST_GIF, }; } } } -export class DeleteMessageForEveryone extends LocatorsInterface { +export class ImageName extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { + // Dates can wildly differ between emulators but it will begin with "Photo taken on" on Android case 'android': return { - strategy: 'id', - selector: 'delete-for-everyone', + strategy: 'xpath', + selector: `//*[starts-with(@content-desc, "Photo taken on")]`, }; case 'ios': - return { - strategy: 'accessibility id', - selector: 'Delete for everyone', - }; + throw new Error(`No such element on iOS`); } } } -export class DeleteMessageConfirmationModal extends LocatorsInterface { +export class ImagePermissionsModalAllow extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Delete', + selector: 'com.android.permissioncontroller:id/permission_allow_foreground_only_button', }; case 'ios': - return { - strategy: 'accessibility id', - selector: 'Delete', - }; + return { strategy: 'accessibility id', selector: 'Allow Full Access' }; } } } -export class BlockUserConfirmationModal extends LocatorsInterface { +export class InviteContactsButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'block-user-confirm-button', - } as const; + selector: 'Invite button', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Block', - } as const; + selector: 'Invite button', + }; } } } -export class BlockedContactsSettings extends LocatorsInterface { +export class InviteContactsMenuItem extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'qa-blocked-contacts-settings-item', + strategy: 'id', + selector: 'invite-contacts-menu-option', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Block contacts - Navigation', + selector: 'Invite Contacts', }; } } } -export class DeclineMessageRequestButton extends LocatorsInterface { +export class JoinCommunityButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'Delete message request', + strategy: 'id', + selector: 'Join community button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'Delete message request', + selector: 'Join', }; } } } -export class DeleteMessageRequestButton extends LocatorsInterface { +export class LinkPreview extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': - return { - strategy: 'id', - selector: `android:id/title`, - text: 'Delete', - }; + throw new Error(`No such element on Android`); case 'ios': return { strategy: 'accessibility id', - selector: 'Delete', - }; + selector: 'Session | Send Messages, Not Metadata. | Private Messenger', + } as const; } } } -export class DeleteMesssageRequestConfirmation extends LocatorsInterface { +export class LinkPreviewMessage extends LocatorsInterface { public build(): StrategyExtractionObj { - return { - strategy: 'accessibility id', - selector: 'Delete', - }; + switch (this.platform) { + case 'android': + return { + strategy: 'id', + selector: 'network.loki.messenger.qa:id/linkPreviewView', + }; + case 'ios': + throw new Error(`No such element on iOS`); + } } } -export class DownloadMediaButton extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class ReadReceiptsButton extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'Download', - }; + strategy: 'id', + selector: 'android:id/summary', + text: 'Show read receipts for all messages you send and receive.', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Download', - }; + selector: 'Read Receipts - Switch', + } as const; } } } @@ -466,45 +453,58 @@ export class ShareExtensionIcon extends LocatorsInterface { } } } -export class LinkPreview extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class UsernameDisplay extends LocatorsInterface { + public text: string | undefined; + constructor(device: DeviceWrapper, text?: string) { + super(device); + this.text = text; + } + public build() { switch (this.platform) { case 'android': - throw new Error(`No such element on Android`); + return { + strategy: 'id', + selector: 'Display name', + text: this.text, + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Session | Send Messages, Not Metadata. | Private Messenger', + selector: 'Username', + text: this.text, } as const; } } } -export class LinkPreviewMessage extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class UsernameInput extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'network.loki.messenger.qa:id/linkPreviewView', - }; + strategy: 'class name', + selector: 'android.widget.EditText', + } as const; case 'ios': - throw new Error(`No such element on iOS`); + return { + strategy: 'accessibility id', + selector: 'Username input', + } as const; } } } -export class ImageName extends LocatorsInterface { - public build(): StrategyExtractionObj { - switch (this.platform) { - // Dates can wildly differ between emulators but it will begin with "Photo taken on" on Android - case 'android': - return { - strategy: 'xpath', - selector: `//*[starts-with(@content-desc, "Photo taken on")]`, - }; - case 'ios': - throw new Error(`No such element on iOS`); - } - } +export function describeLocator(locator: StrategyExtractionObj & { text?: string }): string { + const { strategy, selector, text } = locator; + + // Trim selector if its too long, show beginning and end + const maxSelectorLength = 80; + const halfLength = Math.floor(maxSelectorLength / 2); + const trimmedSelector = + selector.length > maxSelectorLength + ? `${selector.substring(0, halfLength)}…${selector.substring(selector.length - halfLength)}` + : selector; + + const base = `${strategy} "${trimmedSelector}"`; + return text ? `${base} and text "${text}"` : base; } diff --git a/run/test/specs/locators/network_page.ts b/run/test/specs/locators/network_page.ts index 6b577f89e..b5673aa2a 100644 --- a/run/test/specs/locators/network_page.ts +++ b/run/test/specs/locators/network_page.ts @@ -2,159 +2,159 @@ import { LocatorsInterface } from '.'; import { englishStrippedStr } from '../../../localizer/englishStrippedStr'; import { DeviceWrapper } from '../../../types/DeviceWrapper'; -export class SessionNetworkMenuItem extends LocatorsInterface { +export class LastUpdatedTimeStamp extends LocatorsInterface { + private expectedText: string; + + constructor(device: DeviceWrapper, relative_time: string) { + super(device); + this.expectedText = englishStrippedStr('updated').withArgs({ relative_time }).toString(); + } public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'session-network-menu-item', + selector: 'Last updated timestamp', + text: this.expectedText, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Session Network', + selector: 'Last updated timestamp', + text: this.expectedText, } as const; } } } -export class SessionNetworkLearnMoreNetwork extends LocatorsInterface { +export class MarketCapAmount extends LocatorsInterface { + private expectedText: string; + + constructor(device: DeviceWrapper, amount: number) { + super(device); + // Round to whole number, then format with commas and USD suffix + const rounded = Math.round(amount); + this.expectedText = `$${rounded.toLocaleString('en-US')} USD`; + } + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Learn more link', + selector: 'Market cap amount', + text: this.expectedText, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Learn more link', + selector: 'Market cap amount', + text: this.expectedText, } as const; } } } -export class SessionNetworkLearnMoreStaking extends LocatorsInterface { +export class OpenLinkButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Learn about staking link', + selector: 'Open', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Learn about staking link', + selector: 'Open', } as const; } } } -export class LastUpdatedTimeStamp extends LocatorsInterface { +export class SESHPrice extends LocatorsInterface { private expectedText: string; - constructor(device: DeviceWrapper, relative_time: string) { + constructor(device: DeviceWrapper, priceValue: number) { super(device); - this.expectedText = englishStrippedStr('updated').withArgs({ relative_time }).toString(); + this.expectedText = `$${priceValue.toFixed(2)} USD`; } + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Last updated timestamp', + selector: 'SESH price', text: this.expectedText, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Last updated timestamp', + selector: 'SENT price', text: this.expectedText, } as const; } } } -export class OpenLinkButton extends LocatorsInterface { +export class SessionNetworkLearnMoreNetwork extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Open', + selector: 'Learn more link', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Open', + selector: 'Learn more link', } as const; } } } -export class SESHPrice extends LocatorsInterface { - private expectedText: string; - - constructor(device: DeviceWrapper, priceValue: number) { - super(device); - this.expectedText = `$${priceValue.toFixed(2)} USD`; - } - +export class SessionNetworkLearnMoreStaking extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'SESH price', - text: this.expectedText, + selector: 'Learn about staking link', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'SENT price', - text: this.expectedText, + selector: 'Learn about staking link', } as const; } } } -export class StakingRewardPoolAmount extends LocatorsInterface { - private expectedText: string; - - constructor(device: DeviceWrapper, amount: number) { - super(device); - // Format with commas and SESH suffix - this.expectedText = `${amount.toLocaleString('en-US')} SESH`; - } - +export class SessionNetworkMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Staking reward pool amount', - text: this.expectedText, + selector: 'session-network-menu-item', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Staking reward pool amount', - text: this.expectedText, + selector: 'Session Network', } as const; } } } -export class MarketCapAmount extends LocatorsInterface { +export class StakingRewardPoolAmount extends LocatorsInterface { private expectedText: string; constructor(device: DeviceWrapper, amount: number) { super(device); - // Round to whole number, then format with commas and USD suffix - const rounded = Math.round(amount); - this.expectedText = `$${rounded.toLocaleString('en-US')} USD`; + // Format with commas and SESH suffix + this.expectedText = `${amount.toLocaleString('en-US')} SESH`; } public build() { @@ -162,13 +162,13 @@ export class MarketCapAmount extends LocatorsInterface { case 'android': return { strategy: 'id', - selector: 'Market cap amount', + selector: 'Staking reward pool amount', text: this.expectedText, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Market cap amount', + selector: 'Staking reward pool amount', text: this.expectedText, } as const; } diff --git a/run/test/specs/locators/onboarding.ts b/run/test/specs/locators/onboarding.ts index 869e16c8b..54153dc49 100644 --- a/run/test/specs/locators/onboarding.ts +++ b/run/test/specs/locators/onboarding.ts @@ -3,20 +3,18 @@ import { LocatorsInterface } from './index'; // SHARED LOCATORS -export class ErrorMessage extends LocatorsInterface { +export class AccountRestoreButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'error-message', - maxWait: 5000, + selector: 'Restore your session button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Error message', - maxWait: 5000, + selector: 'Restore your session button', } as const; } } @@ -39,15 +37,6 @@ export class BackButton extends LocatorsInterface { } } -export class WarningModalQuitButton extends LocatorsInterface { - public build(): StrategyExtractionObj { - return { - strategy: 'id', - selector: 'Quit', - } as const; - } -} - // SPLASH SCREEN export class CreateAccountButton extends LocatorsInterface { public build() { @@ -66,56 +55,58 @@ export class CreateAccountButton extends LocatorsInterface { } } -export class AccountRestoreButton extends LocatorsInterface { +export class DisplayNameInput extends LocatorsInterface { public build() { switch (this.platform) { - case 'android': - return { - strategy: 'id', - selector: 'Restore your session button', - } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Restore your session button', + selector: 'Enter display name', + } as const; + case 'android': + return { + strategy: 'id', + selector: 'Enter display name', } as const; } } } -export class SplashScreenLinks extends LocatorsInterface { +export class ErrorMessage extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Open URL', + selector: 'error-message', + maxWait: 5000, } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Open URL', + selector: 'Error message', + maxWait: 5000, } as const; } } } -export class TermsOfServiceButton extends LocatorsInterface { + +export class LoadingAnimation extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Terms of Service', // will be Terms of service *button* past 1.29.0 + selector: 'Loading animation', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Terms of Service', + selector: 'Loading animation', } as const; } } } - export class PrivacyPolicyButton extends LocatorsInterface { public build() { switch (this.platform) { @@ -133,76 +124,79 @@ export class PrivacyPolicyButton extends LocatorsInterface { } } -// CREATE ACCOUNT FLOW - -export class DisplayNameInput extends LocatorsInterface { +export class SeedPhraseInput extends LocatorsInterface { public build() { switch (this.platform) { - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Enter display name', - } as const; case 'android': return { strategy: 'id', - selector: 'Enter display name', + selector: 'Recovery phrase input', + } as const; + case 'ios': + return { + strategy: 'accessibility id', + selector: 'Recovery password input', } as const; } } } -// LOAD ACCOUNT FLOW - -export class SeedPhraseInput extends LocatorsInterface { +export class SlowModeRadio extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Recovery phrase input', + selector: 'Slow mode notifications button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Recovery password input', + selector: 'Slow mode notifications button', } as const; } } } -// MESSAGE NOTIFICATIONS - -export class SlowModeRadio extends LocatorsInterface { +export class SplashScreenLinks extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Slow mode notifications button', + selector: 'Open URL', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Slow mode notifications button', + selector: 'Open URL', } as const; } } } -export class LoadingAnimation extends LocatorsInterface { +export class TermsOfServiceButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Loading animation', + selector: 'Terms of Service', // will be Terms of service *button* past 1.29.0 } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Loading animation', + selector: 'Terms of Service', } as const; } } } + +export class WarningModalQuitButton extends LocatorsInterface { + public build(): StrategyExtractionObj { + return { + strategy: 'id', + selector: 'Quit', + } as const; + } +} diff --git a/run/test/specs/locators/settings.ts b/run/test/specs/locators/settings.ts index 02ae1349b..7e747d102 100644 --- a/run/test/specs/locators/settings.ts +++ b/run/test/specs/locators/settings.ts @@ -1,363 +1,363 @@ import { StrategyExtractionObj } from '../../../types/testing'; import { LocatorsInterface } from './index'; -export class HideRecoveryPasswordButton extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class AppDisguiseMeetingIcon extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Hide recovery password button', + selector: 'MeetingSE option', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Hide recovery password button', + selector: 'Meetings option', } as const; } } } -export class YesButton extends LocatorsInterface { +export class AppDisguisePage extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'Yes', + strategy: 'class name', + selector: 'android.widget.ScrollView', } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Yes', + strategy: 'class name', + selector: 'XCUIElementTypeTable', } as const; } } } -export class UserSettings extends LocatorsInterface { - public build() { - return { - strategy: 'accessibility id', - selector: 'User settings', - } as const; - } -} - -export class UserAvatar extends LocatorsInterface { +export class AppearanceMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'User settings', + strategy: '-android uiautomator', + selector: + 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("Appearance"))', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'User settings', + selector: 'Appearance', } as const; } } } -export class RecoveryPasswordMenuItem extends LocatorsInterface { +export class ClassicLightThemeOption extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Recovery password menu item', + selector: 'network.loki.messenger.qa:id/theme_option_classic_light', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Recovery password menu item', + selector: 'Classic Light', } as const; } } } -export class RevealRecoveryPhraseButton extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class CloseAppButton extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'Reveal recovery phrase button', - }; + strategy: 'class name', + selector: 'android.widget.TextView', + text: 'Close App', + } as const; case 'ios': - return { - strategy: 'accessibility id', - selector: 'Continue', - }; + throw new Error('Modal not implemented for iOS'); } } } -export class RecoveryPhraseContainer extends LocatorsInterface { +export class CommunityMessageRequestSwitch extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'id', - selector: 'Recovery password container', + strategy: '-android uiautomator', + selector: 'new UiSelector().text("Community Message Requests")', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Recovery password container', + selector: 'Community Message Requests', } as const; } } } -export class CommunityMessageRequestSwitch extends LocatorsInterface { +export class ConversationsMenuItem extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: '-android uiautomator', - selector: 'new UiSelector().text("Community Message Requests")', + selector: + 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("Conversations"))', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Community Message Requests', + selector: 'Conversations', } as const; } } } -export class SaveProfilePictureButton extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class DonationsMenuItem extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Save', + selector: 'donate-menu-item', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Save', + selector: 'Donate', } as const; } } } -export class SaveNameChangeButton extends LocatorsInterface { + +export class HideRecoveryPasswordButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'update-username-confirm-button', + selector: 'Hide recovery password button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Save', + selector: 'Hide recovery password button', } as const; } } } - -export class PrivacyMenuItem extends LocatorsInterface { +export class NotificationsMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Privacy', + selector: 'Notifications', } as const; case 'ios': - return { strategy: 'id', selector: 'Privacy' } as const; + return { + strategy: 'accessibility id', + selector: 'Notifications', + } as const; } } } -export class ConversationsMenuItem extends LocatorsInterface { +export class PathMenuItem extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: '-android uiautomator', selector: - 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("Conversations"))', + 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("path-menu-item"))', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Conversations', + selector: 'Path', } as const; } } } -export class NotificationsMenuItem extends LocatorsInterface { +export class PrivacyMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Notifications', + selector: 'Privacy', } as const; case 'ios': - return { - strategy: 'accessibility id', - selector: 'Notifications', - } as const; + return { strategy: 'id', selector: 'Privacy' } as const; } } } -export class AppearanceMenuItem extends LocatorsInterface { +export class RecoveryPasswordMenuItem extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: '-android uiautomator', - selector: - 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("Appearance"))', + strategy: 'id', + selector: 'Recovery password menu item', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Appearance', + selector: 'Recovery password menu item', } as const; } } } -export class ClassicLightThemeOption extends LocatorsInterface { - public build() { +export class RecoveryPhraseContainer extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'network.loki.messenger.qa:id/theme_option_classic_light', + selector: 'Recovery password container', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Classic Light', + selector: 'Recovery password container', } as const; } } } -export class SelectAppIcon extends LocatorsInterface { - public build() { +export class RevealRecoveryPhraseButton extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: '-android uiautomator', - selector: - 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("Select app icon"))', - } as const; + strategy: 'id', + selector: 'Reveal recovery phrase button', + }; case 'ios': return { strategy: 'accessibility id', - selector: 'Select alternate app icon', - } as const; + selector: 'Continue', + }; } } } -export class AppDisguisePage extends LocatorsInterface { - public build() { + +export class SaveNameChangeButton extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'class name', - selector: 'android.widget.ScrollView', + strategy: 'id', + selector: 'update-username-confirm-button', } as const; case 'ios': return { - strategy: 'class name', - selector: 'XCUIElementTypeTable', + strategy: 'accessibility id', + selector: 'Save', } as const; } } } -export class AppDisguiseMeetingIcon extends LocatorsInterface { - public build() { +export class SaveProfilePictureButton extends LocatorsInterface { + public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'MeetingSE option', + selector: 'Save', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Meetings option', + selector: 'Save', } as const; } } } - -export class CloseAppButton extends LocatorsInterface { +export class SelectAppIcon extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: 'class name', - selector: 'android.widget.TextView', - text: 'Close App', + strategy: '-android uiautomator', + selector: + 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("Select app icon"))', } as const; case 'ios': - throw new Error('Modal not implemented for iOS'); + return { + strategy: 'accessibility id', + selector: 'Select alternate app icon', + } as const; } } } -export class DonationsMenuItem extends LocatorsInterface { + +export class UserAvatar extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'donate-menu-item', + selector: 'User settings', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Donate', + selector: 'User settings', } as const; } } } +export class UserSettings extends LocatorsInterface { + public build() { + return { + strategy: 'accessibility id', + selector: 'User settings', + } as const; + } +} -export class PathMenuItem extends LocatorsInterface { - public build(): StrategyExtractionObj { +export class VersionNumber extends LocatorsInterface { + public build() { switch (this.platform) { case 'android': return { strategy: '-android uiautomator', selector: - 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId("path-menu-item"))', + 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().textStartsWith("Version"))', } as const; case 'ios': return { - strategy: 'accessibility id', - selector: 'Path', + strategy: 'xpath', + selector: `//XCUIElementTypeStaticText[contains(@name, "Version")]`, } as const; } } } -export class VersionNumber extends LocatorsInterface { +export class YesButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { - strategy: '-android uiautomator', - selector: - 'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().textStartsWith("Version"))', + strategy: 'id', + selector: 'Yes', } as const; case 'ios': return { - strategy: 'xpath', - selector: `//XCUIElementTypeStaticText[contains(@name, "Version")]`, + strategy: 'accessibility id', + selector: 'Yes', } as const; } } diff --git a/run/test/specs/locators/start_conversation.ts b/run/test/specs/locators/start_conversation.ts index 92042db94..b61c9b7ab 100644 --- a/run/test/specs/locators/start_conversation.ts +++ b/run/test/specs/locators/start_conversation.ts @@ -1,18 +1,35 @@ import { StrategyExtractionObj } from '../../../types/testing'; import { LocatorsInterface } from './index'; -export class NewMessageOption extends LocatorsInterface { +export class CloseButton extends LocatorsInterface { + public build(): StrategyExtractionObj { + switch (this.platform) { + case 'android': + return { + strategy: 'accessibility id', + selector: 'Close', + }; + case 'ios': + return { + strategy: 'accessibility id', + selector: 'X', + }; + } + } +} + +export class CopyButton extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'New direct message', + selector: 'Copy button', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'New direct message', + selector: 'Copy button', } as const; } } @@ -35,19 +52,20 @@ export class CreateGroupOption extends LocatorsInterface { } } -export class JoinCommunityOption extends LocatorsInterface { +// NEW MESSAGE SECTION +export class EnterAccountID extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Join community button', - }; + selector: 'Session id input box', + } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Join Community', - }; + selector: 'Session id input box', + } as const; } } } @@ -69,40 +87,39 @@ export class InviteAFriendOption extends LocatorsInterface { } } -export class CloseButton extends LocatorsInterface { +export class JoinCommunityOption extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { case 'android': return { - strategy: 'accessibility id', - selector: 'Close', + strategy: 'id', + selector: 'Join community button', }; case 'ios': return { strategy: 'accessibility id', - selector: 'X', + selector: 'Join Community', }; } } } -export class CopyButton extends LocatorsInterface { +export class NewMessageOption extends LocatorsInterface { public build() { switch (this.platform) { case 'android': return { strategy: 'id', - selector: 'Copy button', + selector: 'New direct message', } as const; case 'ios': return { strategy: 'accessibility id', - selector: 'Copy button', + selector: 'New direct message', } as const; } } } - export class NextButton extends LocatorsInterface { public build(): StrategyExtractionObj { switch (this.platform) { @@ -119,25 +136,6 @@ export class NextButton extends LocatorsInterface { } } } -// NEW MESSAGE SECTION -export class EnterAccountID extends LocatorsInterface { - public build(): StrategyExtractionObj { - switch (this.platform) { - case 'android': - return { - strategy: 'id', - selector: 'Session id input box', - } as const; - case 'ios': - return { - strategy: 'accessibility id', - selector: 'Session id input box', - } as const; - } - } -} - -// INVITE A FRIEND SECTION export class ShareButton extends LocatorsInterface { public build() {