Adds data-testid to loading-animation, microphone recording button, recording permissions button, stop recording button, consolidates tests into user actions test, adds media to fixtures folder, updates linked device tests with avatar change, username change and group tests. Adds tests for messaging, sending image, video, document, gif and link with preview. Also updates reply message functionality to wait for loading animation

pull/2786/head
Emily 2 years ago
parent d64dbc163f
commit eeb6cfb435

@ -65,6 +65,8 @@
"format-full": "prettier --list-different --write \"*.{css,js,json,scss,ts,tsx}\" \"./**/*.{css,js,json,scss,ts,tsx}\"", "format-full": "prettier --list-different --write \"*.{css,js,json,scss,ts,tsx}\" \"./**/*.{css,js,json,scss,ts,tsx}\"",
"integration-test": "npx playwright test", "integration-test": "npx playwright test",
"start-prod-test": "cross-env NODE_ENV=production NODE_APP_INSTANCE=$MULTI electron .",
"integration-test-snapshots": "npx playwright test -g 'profile picture' --update-snapshots", "integration-test-snapshots": "npx playwright test -g 'profile picture' --update-snapshots",
"test": "mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"", "test": "mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"",
"coverage": "nyc --reporter=html mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"", "coverage": "nyc --reporter=html mocha -r jsdom-global/register --recursive --exit --timeout 10000 \"./ts/test/**/*_test.js\"",

@ -46,6 +46,7 @@ type Props = {
active: boolean; active: boolean;
onClick: () => void; onClick: () => void;
confirmationDialogParams?: any | undefined; confirmationDialogParams?: any | undefined;
dataTestId?: string;
}; };
export const SessionToggle = (props: Props) => { export const SessionToggle = (props: Props) => {
@ -84,7 +85,12 @@ export const SessionToggle = (props: Props) => {
}; };
return ( return (
<StyledSessionToggle role="button" onClick={clickHandler} active={props.active}> <StyledSessionToggle
role="button"
onClick={clickHandler}
active={props.active}
data-testid={props.dataTestId}
>
<StyledKnob active={props.active} /> <StyledKnob active={props.active} />
</StyledSessionToggle> </StyledSessionToggle>
); );

@ -4,6 +4,7 @@ import styled from 'styled-components';
type Props = { type Props = {
size: 'small' | 'normal'; size: 'small' | 'normal';
direction?: string; direction?: string;
dataTestId?: string;
}; };
// Module: Spinner // Module: Spinner
@ -69,7 +70,7 @@ export const Spinner = (props: Props) => {
if (size === 'small') { if (size === 'small') {
return ( return (
<SpinnerContainerSmall> <SpinnerContainerSmall data-testid="loading-animation">
<SpinnerArcSmall> <SpinnerArcSmall>
<path d={spinner24Path} /> <path d={spinner24Path} />
</SpinnerArcSmall> </SpinnerArcSmall>
@ -78,7 +79,7 @@ export const Spinner = (props: Props) => {
} }
return ( return (
<SpinnerContainer> <SpinnerContainer data-testid="loading-animation">
<SpinnerArc> <SpinnerArc>
<path d={spinner56Path} /> <path d={spinner56Path} />
</SpinnerArc> </SpinnerArc>

@ -129,6 +129,7 @@ export class SessionRecording extends React.Component<Props, State> {
iconSize="medium" iconSize="medium"
iconColor={'var(--danger-color)'} iconColor={'var(--danger-color)'}
onClick={actionPauseFn} onClick={actionPauseFn}
dataTestId="end-voice-message"
/> />
)} )}
{actionPauseAudio && ( {actionPauseAudio && (
@ -175,6 +176,7 @@ export class SessionRecording extends React.Component<Props, State> {
iconRotation={90} iconRotation={90}
onClick={this.onSendVoiceMessage} onClick={this.onSendVoiceMessage}
margin={'var(--margins-sm)'} margin={'var(--margins-sm)'}
dataTestId="send-message-button"
/> />
</div> </div>
)} )}

@ -25,6 +25,7 @@ export const AddStagedAttachmentButton = (props: { onClick: () => void }) => {
borderRadius="300px" borderRadius="300px"
iconPadding="8px" iconPadding="8px"
onClick={props.onClick} onClick={props.onClick}
dataTestId="attachments-button"
/> />
</StyledChatButtonContainer> </StyledChatButtonContainer>
); );
@ -41,6 +42,7 @@ export const StartRecordingButton = (props: { onClick: () => void }) => {
borderRadius="300px" borderRadius="300px"
iconPadding="6px" iconPadding="6px"
onClick={props.onClick} onClick={props.onClick}
dataTestId="microphone-button"
/> />
</StyledChatButtonContainer> </StyledChatButtonContainer>
); );
@ -59,6 +61,7 @@ export const ToggleEmojiButton = React.forwardRef<HTMLDivElement, { onClick: ()
borderRadius="300px" borderRadius="300px"
iconPadding="6px" iconPadding="6px"
onClick={props.onClick} onClick={props.onClick}
dataTestId="emoji-button"
/> />
</StyledChatButtonContainer> </StyledChatButtonContainer>
); );

@ -128,6 +128,7 @@ export const SessionToggleWithDescription = (props: {
onClickToggle: () => void; onClickToggle: () => void;
confirmationDialogParams?: SessionConfirmDialogProps; confirmationDialogParams?: SessionConfirmDialogProps;
childrenDescription?: React.ReactNode; // if set, those elements will be appended next to description field (only used for typing message settings as of now) childrenDescription?: React.ReactNode; // if set, those elements will be appended next to description field (only used for typing message settings as of now)
dataTestId?: string;
}) => { }) => {
const { const {
title, title,
@ -136,6 +137,7 @@ export const SessionToggleWithDescription = (props: {
onClickToggle, onClickToggle,
confirmationDialogParams, confirmationDialogParams,
childrenDescription, childrenDescription,
dataTestId,
} = props; } = props;
return ( return (
@ -149,6 +151,7 @@ export const SessionToggleWithDescription = (props: {
active={active} active={active}
onClick={onClickToggle} onClick={onClickToggle}
confirmationDialogParams={confirmationDialogParams} confirmationDialogParams={confirmationDialogParams}
dataTestId={dataTestId}
/> />
</SessionSettingsItemWrapper> </SessionSettingsItemWrapper>
); );

@ -64,6 +64,7 @@ export const SettingsCategoryPermissions = (props: { hasPassword: boolean | null
title={window.i18n('mediaPermissionsTitle')} title={window.i18n('mediaPermissionsTitle')}
description={window.i18n('mediaPermissionsDescription')} description={window.i18n('mediaPermissionsDescription')}
active={Boolean(window.getSettingValue('media-permissions'))} active={Boolean(window.getSettingValue('media-permissions'))}
dataTestId="enable-microphone"
/> />
<SessionToggleWithDescription <SessionToggleWithDescription
onClickToggle={async () => { onClickToggle={async () => {
@ -73,6 +74,7 @@ export const SettingsCategoryPermissions = (props: { hasPassword: boolean | null
title={window.i18n('callMediaPermissionsTitle')} title={window.i18n('callMediaPermissionsTitle')}
description={window.i18n('callMediaPermissionsDescription')} description={window.i18n('callMediaPermissionsDescription')}
active={Boolean(window.getCallMediaPermissions())} active={Boolean(window.getCallMediaPermissions())}
data-dataTestId="enable-calls"
/> />
<SessionToggleWithDescription <SessionToggleWithDescription
onClickToggle={async () => { onClickToggle={async () => {

@ -84,7 +84,7 @@ import { installPermissionsHandler } from '../node/permissions'; // checked - on
let appStartInitialSpellcheckSetting = true; let appStartInitialSpellcheckSetting = true;
const enableTestIntegrationWiderWindow = true; const enableTestIntegrationWiderWindow = false;
const isTestIntegration = const isTestIntegration =
enableTestIntegrationWiderWindow && enableTestIntegrationWiderWindow &&
Boolean( Boolean(

@ -1,43 +0,0 @@
import { _electron, expect, Page, test } from '@playwright/test';
import { openAppAndWait } from './setup/open';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { newUser } from './setup/new_user';
import { clickOnTestIdWithText, waitForTestIdWithText } from './utilities/utils';
import { sleepFor } from '../../session/utils/Promise';
let window: Page | undefined;
test.beforeEach(beforeAllClean);
test.afterEach(async () => {
if (window) {
await forceCloseAllWindows([window]);
}
});
test('Change profile picture/avatar', async () => {
window = await openAppAndWait('1');
await newUser(window, 'userA');
// Open profile
await clickOnTestIdWithText(window, 'leftpane-primary-avatar');
// Click on current profile picture
await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy');
await clickOnTestIdWithText(window, 'image-upload-section');
await clickOnTestIdWithText(window, 'save-button-profile-update');
await waitForTestIdWithText(window, 'loading-spinner');
await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy');
await clickOnTestIdWithText(window, 'modal-close-button');
await sleepFor(500);
const leftpaneAvatarContainer = await waitForTestIdWithText(window, 'leftpane-primary-avatar');
await sleepFor(500);
const screenshot = await leftpaneAvatarContainer.screenshot({
type: 'jpeg',
// path: 'avatar-updated-blue',
});
expect(screenshot).toMatchSnapshot({ name: 'avatar-updated-blue.jpeg' });
});

@ -1,36 +0,0 @@
import { _electron, expect, Page, test } from '@playwright/test';
import { newUser } from './setup/new_user';
import { openAppAndWait } from './setup/open';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { clickOnTestIdWithText, typeIntoInput } from './utilities/utils';
let window: Page | undefined;
test.beforeEach(beforeAllClean);
test.afterEach(async () => {
if (window) {
await forceCloseAllWindows([window]);
}
});
test('Change username', async () => {
// Open App
window = await openAppAndWait('1');
// Create user
await newUser(window, 'userA');
// Open Profile
await clickOnTestIdWithText(window, 'leftpane-primary-avatar');
// Click on current username to open edit field
await clickOnTestIdWithText(window, 'edit-profile-icon');
// Type in new username
await typeIntoInput(window, 'profile-name-input', 'new username');
// await window.fill('.profile-name-input', 'new username');
// Press enter to confirm username input
await window.keyboard.press('Enter');
// Wait for Copy button to appear to verify username change
await window.isVisible("'Copy'");
// verify name change
expect(await window.innerText('[data-testid=your-profile-name]')).toBe('new username');
// Exit profile module
await window.click('.session-icon-button.small');
});

@ -1,8 +1,8 @@
import { _electron, Page, test } from '@playwright/test'; import { Page, test } from '@playwright/test';
import { sleepFor } from '../../session/utils/Promise';
import { beforeAllClean } from './setup/beforeEach';
import { newUser } from './setup/new_user'; import { newUser } from './setup/new_user';
import { openAppAndWait } from './setup/open'; import { openAppAndWait } from './setup/open';
import { sleepFor } from '../../session/utils/Promise';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { import {
clickOnMatchingText, clickOnMatchingText,
clickOnTestIdWithText, clickOnTestIdWithText,

@ -1,23 +1,19 @@
import { _electron, Page, test } from '@playwright/test'; import { _electron, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { openAppsAndNewUsers, openAppsNoNewUsers } from './setup/new_user'; import { newUser } from './setup/new_user';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { clickOnMatchingText, clickOnTestIdWithText, typeIntoInput } from './utilities/utils'; import { clickOnMatchingText, clickOnTestIdWithText, typeIntoInput } from './utilities/utils';
import { sleepFor } from '../../session/utils/Promise'; import { sleepFor } from '../../session/utils/Promise';
import { openApp } from './setup/open';
// tslint:disable: no-console // tslint:disable: no-console
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows));
test('Delete account from swarm', async () => { test('Delete account from swarm', async () => {
const testMessage = `A -> B: ${Date.now()}`; const [windowA, windowB] = await openApp(2);
const testReply = `B -> A: ${Date.now()}`; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const windowLoggedIn = await openAppsAndNewUsers(2); const testMessage = `${userA.userName} to ${userB.userName}`;
windows = windowLoggedIn.windows; const testReply = `${userB.userName} to ${userA.userName}`;
const [windowA, windowB] = windows;
const [userA, userB] = windowLoggedIn.users;
// Create contact and send new message // Create contact and send new message
await Promise.all([ await Promise.all([
sendNewMessage(windowA, userB.sessionid, testMessage), sendNewMessage(windowA, userB.sessionid, testMessage),
@ -37,7 +33,7 @@ test('Delete account from swarm', async () => {
// Wait for window to close and reopen // Wait for window to close and reopen
await sleepFor(10000, true); await sleepFor(10000, true);
// await windowA.close(); // await windowA.close();
const restoringWindows = await openAppsNoNewUsers(1); const restoringWindows = await openApp(1);
const [restoringWindow] = restoringWindows; const [restoringWindow] = restoringWindows;
// Sign in with deleted account and check that nothing restores // Sign in with deleted account and check that nothing restores
await clickOnTestIdWithText(restoringWindow, 'restore-using-recovery', 'Restore your account'); await clickOnTestIdWithText(restoringWindow, 'restore-using-recovery', 'Restore your account');

@ -1,21 +1,21 @@
import { _electron, Page, test } from '@playwright/test'; import { test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { sleepFor } from '../../session/utils/Promise';
import { messageSent } from './utilities/message'; import { beforeAllClean } from './setup/beforeEach';
import { openAppsAndNewUsers } from './setup/new_user'; import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { sendMessage } from './utilities/message';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { import {
clickOnMatchingText, clickOnMatchingText,
clickOnTestIdWithText, clickOnTestIdWithText,
waitForControlMessageWithText,
waitForMatchingText, waitForMatchingText,
waitForReadableMessageWithText,
waitForTestIdWithText, waitForTestIdWithText,
} from './utilities/utils'; } from './utilities/utils';
import { sleepFor } from '../../session/utils/Promise';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows)); // test.afterEach(() => forceCloseAllWindows(windows));
// tslint:disable: no-console // tslint:disable: no-console
const testMessage = 'Test-Message- (A -> B) '; const testMessage = 'Test-Message- (A -> B) ';
@ -23,18 +23,15 @@ const testReply = 'Reply-Test-Message- (B -> A)';
const sentMessage = `${testMessage}${Date.now()}`; const sentMessage = `${testMessage}${Date.now()}`;
const sentReplyMessage = `${testReply} :${Date.now()}`; const sentReplyMessage = `${testReply} :${Date.now()}`;
test('Disappearing Messages', async () => { test('Disappearing messages', async () => {
// Open App // Open App
// Create User // Create User
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users;
const [windowA, windowB] = windows;
const [userA, userB] = users;
// Create Contact // Create Contact
await sendNewMessage(windowA, userB.sessionid, sentMessage); await sendNewMessage(windowA, userB.sessionid, sentMessage);
await sendNewMessage(windowB, userA.sessionid, sentReplyMessage); await sendNewMessage(windowB, userA.sessionid, sentReplyMessage);
await waitForReadableMessageWithText(windowA, 'Your message request has been accepted'); await waitForControlMessageWithText(windowA, 'Your message request has been accepted');
// await waitForMatchingText(windowA, `You have accepted ${userA.userName}'s message request`); // await waitForMatchingText(windowA, `You have accepted ${userA.userName}'s message request`);
// await waitForMatchingText(windowB, 'Your message request has been accepted'); // await waitForMatchingText(windowB, 'Your message request has been accepted');
// Click on user's avatar to open conversation options // Click on user's avatar to open conversation options
@ -48,7 +45,7 @@ test('Disappearing Messages', async () => {
// Check config message // Check config message
await waitForTestIdWithText( await waitForTestIdWithText(
windowA, windowA,
'readable-message', 'control-message',
'You set the disappearing message timer to 5 seconds' 'You set the disappearing message timer to 5 seconds'
); );
await sleepFor(2000); await sleepFor(2000);
@ -57,7 +54,7 @@ test('Disappearing Messages', async () => {
await waitForTestIdWithText(windowA, 'disappearing-messages-indicator', '5 seconds'); await waitForTestIdWithText(windowA, 'disappearing-messages-indicator', '5 seconds');
// Send message // Send message
// Wait for tick of confirmation // Wait for tick of confirmation
await messageSent(windowA, sentMessage); await sendMessage(windowA, sentMessage);
// Check timer is functioning // Check timer is functioning
// Verify message is deleted // Verify message is deleted
@ -82,7 +79,7 @@ test('Disappearing Messages', async () => {
// Click chevron to close menu // Click chevron to close menu
await clickOnTestIdWithText(windowA, 'back-button-conversation-options'); await clickOnTestIdWithText(windowA, 'back-button-conversation-options');
// Check config message // Check config message
await waitForTestIdWithText(windowA, 'readable-message', 'You disabled disappearing messages.'); await waitForTestIdWithText(windowA, 'control-message', 'You disabled disappearing messages.');
// Verify message is deleted in windowB for receiver user // Verify message is deleted in windowB for receiver user
// Check config message in windowB // Check config message in windowB
await waitForMatchingText( await waitForMatchingText(

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

@ -1,75 +0,0 @@
import { _electron, Page, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { messageSent } from './utilities/message';
import { openAppsAndNewUsers } from './setup/new_user';
import { sendNewMessage } from './utilities/send_message';
import {
clickOnMatchingText,
clickOnTestIdWithText,
typeIntoInput,
waitForReadableMessageWithText,
waitForTestIdWithText,
} from './utilities/utils';
const testGroupName = 'Test Group Name';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows));
test('Create group', async () => {
const windowLoggedIn = await openAppsAndNewUsers(3);
windows = windowLoggedIn.windows;
const users = windowLoggedIn.users;
const [windowA, windowB, windowC] = windows;
const [userA, userB, userC] = users;
// Add contacts
await sendNewMessage(windowA, userC.sessionid, `A -> C: ${Date.now()}`);
await Promise.all([
sendNewMessage(windowA, userB.sessionid, `A -> B: ${Date.now()}`),
sendNewMessage(windowB, userA.sessionid, `B -> A: ${Date.now()}`),
sendNewMessage(windowC, userA.sessionid, `C -> A: ${Date.now()}`),
]);
// Click new closed group tab
await clickOnTestIdWithText(windowA, 'new-conversation-button');
await clickOnTestIdWithText(windowA, 'chooser-new-group'); // Enter group name
await typeIntoInput(windowA, 'new-closed-group-name', testGroupName);
// Select user B
await clickOnMatchingText(windowA, userB.userName);
// Select user C
await clickOnMatchingText(windowA, userC.userName);
// Click Done
await clickOnTestIdWithText(windowA, 'next-button');
// Check group was successfully created
await clickOnMatchingText(windowB, testGroupName);
await waitForTestIdWithText(windowB, 'header-conversation-name', testGroupName);
// Send message in group chat from user A
const msgAToGroup = 'A -> Group';
await messageSent(windowA, msgAToGroup);
// Verify it was received by other two accounts
// Navigate to group in window B
await clickOnTestIdWithText(windowB, 'message-section');
// Click on test group
await clickOnMatchingText(windowB, testGroupName);
// wait for selector 'test message' in chat window
await waitForReadableMessageWithText(windowB, msgAToGroup);
// Send reply message
const msgBToGroup = 'B -> Group';
await messageSent(windowB, msgBToGroup);
// Navigate to group in window C
await clickOnTestIdWithText(windowC, 'message-section');
// Click on test group
await clickOnMatchingText(windowC, testGroupName);
// windowC must see the message from A
await waitForReadableMessageWithText(windowC, msgAToGroup);
// windowC must see the message from B
await waitForReadableMessageWithText(windowC, msgBToGroup);
// Send message from C to the group
const msgCToGroup = 'C -> Group';
await messageSent(windowC, msgCToGroup);
// windowA should see the message from B and the message from C
await waitForReadableMessageWithText(windowA, msgBToGroup);
await waitForReadableMessageWithText(windowA, msgCToGroup);
});

@ -3,13 +3,18 @@ import { beforeAllClean } from './setup/beforeEach';
import { import {
clickOnMatchingText, clickOnMatchingText,
clickOnTestIdWithText, clickOnTestIdWithText,
typeIntoInput,
waitForControlMessageWithText, waitForControlMessageWithText,
waitForMatchingText, waitForMatchingText,
waitForTestIdWithText,
} from './utilities/utils'; } from './utilities/utils';
import { renameGroup } from './utilities/rename_group'; import { renameGroup } from './utilities/rename_group';
import { createGroup } from './setup/create_group'; import { createGroup } from './setup/create_group';
// import { leaveGroup } from './utilities/leave_group'; // import { leaveGroup } from './utilities/leave_group';
import { newUser, openApp } from './setup/new_user'; import { newUser } from './setup/new_user';
import { leaveGroup } from './utilities/leave_group';
import { openApp } from './setup/open';
import { sleepFor } from '../../session/utils/Promise';
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
@ -26,18 +31,22 @@ test('Create group', async () => {
const testGroupName = 'Tiny Bubble Gang'; const testGroupName = 'Tiny Bubble Gang';
await createGroup(testGroupName, userA, windowA, userB, windowB, userC, windowC); await createGroup(testGroupName, userA, windowA, userB, windowB, userC, windowC);
// Check config messages in all windows // Check config messages in all windows
await waitForControlMessageWithText( await sleepFor(1000);
windowA, // await waitForTestIdWithText(windowA, 'control-message');
`"${userC.userName}", "${userB.userName}", You joined the group.` await Promise.all([
); waitForControlMessageWithText(
await waitForControlMessageWithText( windowA,
windowB, `"${userB.userName}", "${userC.userName}", You joined the group.`
`"${userC.userName}", "${userA.userName}", You joined the group.` ),
); waitForControlMessageWithText(
await waitForControlMessageWithText( windowB,
windowC, `You, "${userC.userName}", "${userA.userName}" joined the group.`
`"${userB.userName}", "${userA.userName}", You joined the group.` ),
); waitForControlMessageWithText(
windowC,
`"${userB.userName}", You, "${userA.userName}" joined the group.`
),
]);
}); });
test('Change group name', async () => { test('Change group name', async () => {
@ -56,7 +65,7 @@ test('Change group name', async () => {
await renameGroup(windowA, group.userName, newGroupName); await renameGroup(windowA, group.userName, newGroupName);
// Check config message in window B for group name change // Check config message in window B for group name change
await clickOnMatchingText(windowB, newGroupName); await clickOnMatchingText(windowB, newGroupName);
await waitForMatchingText(windowB, `Group name is now ${newGroupName}.`); await waitForMatchingText(windowB, `Group name is now '${newGroupName}'.`);
// Click on conversation options // Click on conversation options
// Check to see that you can't change group name to empty string // Check to see that you can't change group name to empty string
// Click on edit group name // Click on edit group name
@ -68,3 +77,52 @@ test('Change group name', async () => {
await clickOnMatchingText(windowA, 'Cancel'); await clickOnMatchingText(windowA, 'Cancel');
await clickOnTestIdWithText(windowA, 'back-button-conversation-options'); await clickOnTestIdWithText(windowA, 'back-button-conversation-options');
}); });
test('Test mentions', async () => {
const [windowA, windowB, windowC] = await openApp(3);
const [userA, userB, userC] = await Promise.all([
newUser(windowA, 'Alice'),
newUser(windowB, 'Bob'),
newUser(windowC, 'Chloe'),
]);
const testGroupName = 'Tiny Bubble Gang';
const group = await createGroup(testGroupName, userA, windowA, userB, windowB, userC, windowC);
// in windowA we should be able to mentions userB and userC
await clickOnTestIdWithText(windowA, 'module-conversation__user__profile-name', group.userName);
await typeIntoInput(windowA, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowA, 'mentions-popup-row');
await waitForTestIdWithText(windowA, 'mentions-popup-row', userB.userName);
await waitForTestIdWithText(windowA, 'mentions-popup-row', userC.userName);
// in windowB we should be able to mentions userA and userC
await clickOnTestIdWithText(windowB, 'module-conversation__user__profile-name', group.userName);
await typeIntoInput(windowB, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowB, 'mentions-popup-row');
await waitForTestIdWithText(windowB, 'mentions-popup-row', userA.userName);
await waitForTestIdWithText(windowB, 'mentions-popup-row', userC.userName);
// in windowC we should be able to mentions userA and userB
await clickOnTestIdWithText(windowC, 'module-conversation__user__profile-name', group.userName);
await typeIntoInput(windowC, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowC, 'mentions-popup-row');
await waitForTestIdWithText(windowC, 'mentions-popup-row', userA.userName);
await waitForTestIdWithText(windowC, 'mentions-popup-row', userB.userName);
});
test('Leave group', async () => {
const [windowA, windowB, windowC] = await openApp(3);
const [userA, userB, userC] = await Promise.all([
newUser(windowA, 'Alice'),
newUser(windowB, 'Bob'),
newUser(windowC, 'Chloe'),
]);
const testGroupName = 'Tiny Bubble Gang';
await createGroup(testGroupName, userA, windowA, userB, windowB, userC, windowC);
await leaveGroup(windowC);
});

@ -1,16 +1,15 @@
import { _electron, Page, test } from '@playwright/test'; import { _electron, test } from '@playwright/test';
import { beforeAllClean } from './setup/beforeEach'; import { beforeAllClean } from './setup/beforeEach';
import { openApp } from './setup/new_user';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { logIn } from './setup/log_in'; import { logIn } from './setup/log_in';
import { userA, userB, userC, userD, userE } from './setup/test_user'; import { userA, userB, userC, userD, userE } from './setup/test_user';
import { openApp } from './setup/open';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.skip('Group upkeep', async () => { test.skip('Group upkeep', async () => {
const [windowA, windowB, windowC, windowD, windowE] = await openApp(5); const [windowA, windowB, windowC, windowD, windowE] = await openApp(5);
windows = [windowA, windowB, windowC, windowD, windowE];
await Promise.all([ await Promise.all([
logIn(windowA, userA.recoveryPhrase), logIn(windowA, userA.recoveryPhrase),
logIn(windowB, userB.recoveryPhrase), logIn(windowB, userB.recoveryPhrase),

@ -1,5 +1,7 @@
import { _electron, Page, test } from '@playwright/test'; import { _electron, Page, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { linkedDevice } from './utilities/linked_device'; import { linkedDevice } from './utilities/linked_device';
import { clickOnTestIdWithText, typeIntoInput, waitForTestIdWithText } from './utilities/utils'; import { clickOnTestIdWithText, typeIntoInput, waitForTestIdWithText } from './utilities/utils';
@ -9,21 +11,22 @@ test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows)); test.afterEach(() => forceCloseAllWindows(windows));
// tslint:disable: no-console // tslint:disable: no-console
test('linking device', async () => { test('Link a device', async () => {
const { windowA1, windowA2, userA } = await linkedDevice(); const [windowA] = await openApp(1);
windows.push(windowA1, windowA2); const userA = await newUser(windowA, 'Alice');
const [windowB] = await linkedDevice(userA.recoveryPhrase);
await clickOnTestIdWithText(windowA1, 'leftpane-primary-avatar'); const newUsername = 'Tiny bubble';
await clickOnTestIdWithText(windowA, 'leftpane-primary-avatar');
// Verify Username // Verify Username
await waitForTestIdWithText(windowA1, 'your-profile-name', userA.userName); await waitForTestIdWithText(windowA, 'your-profile-name', userA.userName);
// Verify Session ID // Verify Session ID
await waitForTestIdWithText(windowA1, 'your-session-id', userA.sessionid); await waitForTestIdWithText(windowA, 'your-session-id', userA.sessionid);
// exit profile module // exit profile module
await clickOnTestIdWithText(windowA1, 'modal-close-button'); await clickOnTestIdWithText(windowA, 'modal-close-button');
// You're almost finished isn't displayed // You're almost finished isn't displayed
const errorDesc = 'Should not be found'; const errorDesc = 'Should not be found';
try { try {
const elemShouldNotBeFound = windowA2.locator('[data-testid=reveal-recovery-phrase]'); const elemShouldNotBeFound = windowB.locator('[data-testid=reveal-recovery-phrase]');
if (elemShouldNotBeFound) { if (elemShouldNotBeFound) {
console.error('Element not found'); console.error('Element not found');
throw new Error(errorDesc); throw new Error(errorDesc);
@ -34,19 +37,18 @@ test('linking device', async () => {
throw e; throw e;
} }
} }
await clickOnTestIdWithText(windowA1, 'leftpane-primary-avatar'); await clickOnTestIdWithText(windowA, 'leftpane-primary-avatar');
// Click on pencil icon // Click on pencil icon
await clickOnTestIdWithText(windowA1, 'edit-profile-icon'); await clickOnTestIdWithText(windowA, 'edit-profile-icon');
// Replace old username with new username // Replace old username with new username
const newUsername = 'new-username'; await typeIntoInput(windowA, 'profile-name-input', newUsername);
await typeIntoInput(windowA1, 'profile-name-input', newUsername);
// Press enter to confirm change // Press enter to confirm change
await windowA1.keyboard.press('Enter'); await windowA.keyboard.press('Enter');
// Wait for loading animation // Wait for loading animation
// Check username change in window B2 // Check username change in window B2
// Click on profile settings in window B // Click on profile settings in window B
await clickOnTestIdWithText(windowA2, 'leftpane-primary-avatar'); await clickOnTestIdWithText(windowB, 'leftpane-primary-avatar');
// Verify username has changed to new username // Verify username has changed to new username
await waitForTestIdWithText(windowA2, 'your-profile-name', newUsername); await waitForTestIdWithText(windowB, 'your-profile-name', newUsername);
// Check message is deleting on both devices // Check message is deleting on both devices
}); });

@ -1,51 +0,0 @@
import { _electron, Page, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { clickOnTestIdWithText, typeIntoInput, waitForTestIdWithText } from './utilities/utils';
import { createGroup } from './setup/create_group';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows));
test('Mentions', async () => {
const { userA, userB, userC, windowA, windowB, windowC } = await createGroup('Test Group Name');
windows = [windowA, windowB, windowC];
// in windowA we should be able to mentions userB and userC
await clickOnTestIdWithText(
windowA,
'module-conversation__user__profile-name',
'Test Group Name'
);
await typeIntoInput(windowA, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowA, 'mentions-popup-row');
await waitForTestIdWithText(windowA, 'mentions-popup-row', userB.userName);
await waitForTestIdWithText(windowA, 'mentions-popup-row', userC.userName);
// in windowB we should be able to mentions userA and userC
await clickOnTestIdWithText(
windowB,
'module-conversation__user__profile-name',
'Test Group Name'
);
await typeIntoInput(windowB, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowB, 'mentions-popup-row');
await waitForTestIdWithText(windowB, 'mentions-popup-row', userA.userName);
await waitForTestIdWithText(windowB, 'mentions-popup-row', userC.userName);
// in windowC we should be able to mentions userA and userB
await clickOnTestIdWithText(
windowC,
'module-conversation__user__profile-name',
'Test Group Name'
);
await typeIntoInput(windowC, 'message-input-text-area', '@');
// does 'message-input-text-area' have aria-expanded: true when @ is typed into input
await waitForTestIdWithText(windowC, 'mentions-popup-row');
await waitForTestIdWithText(windowC, 'mentions-popup-row', userA.userName);
await waitForTestIdWithText(windowC, 'mentions-popup-row', userB.userName);
});

@ -0,0 +1,146 @@
import { test } from '@playwright/test';
import { sleepFor } from '../../session/utils/Promise';
import { beforeAllClean } from './setup/beforeEach';
import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { createContact } from './utilities/create_contact';
import { replyTo } from './utilities/reply_message';
import {
clickOnMatchingText,
clickOnTestIdWithText,
typeIntoInput,
waitForLoadingAnimationToFinish,
} from './utilities/utils';
test.beforeEach(beforeAllClean);
test('Send image and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = `${userA.userName} sending image to ${userB.userName}`;
const testReply = `${userB.userName} replying to image from ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await windowA.setInputFiles("input[type='file']", 'ts/test/automation/fixtures/test-image.png');
await typeIntoInput(windowA, 'message-input-text-area', testMessage);
await clickOnTestIdWithText(windowA, 'send-message-button');
// Click on untrusted attachment in window B
await sleepFor(1000);
await clickOnMatchingText(windowB, 'Click to download media');
await clickOnTestIdWithText(windowB, 'session-confirm-ok-button');
await waitForLoadingAnimationToFinish(windowB);
// Waiting for image to change from loading state to loaded (takes a second)
await sleepFor(1000);
await replyTo(windowB, testMessage, testReply);
});
test('Send video and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = `${userA.userName} sending video to ${userB.userName}`;
const testReply = `${userB.userName} replying to video from ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await windowA.setInputFiles("input[type='file']", 'ts/test/automation/fixtures/test-video.mp4');
await typeIntoInput(windowA, 'message-input-text-area', testMessage);
await sleepFor(100);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await clickOnMatchingText(windowB, 'Click to download media');
await clickOnTestIdWithText(windowB, 'session-confirm-ok-button');
await waitForLoadingAnimationToFinish(windowB);
// Waiting for videoto change from loading state to loaded (takes a second)
await sleepFor(1000);
await replyTo(windowB, testMessage, testReply);
});
test('Send document and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = `${userA.userName} sending document to ${userB.userName}`;
const testReply = `${userB.userName} replying to document from ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await windowA.setInputFiles("input[type='file']", 'ts/test/automation/fixtures/test-file.pdf');
await typeIntoInput(windowA, 'message-input-text-area', testMessage);
await sleepFor(100);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await clickOnMatchingText(windowB, 'Click to download media');
await clickOnTestIdWithText(windowB, 'session-confirm-ok-button');
await waitForLoadingAnimationToFinish(windowB);
// Waiting for videoto change from loading state to loaded (takes a second)
await sleepFor(1000);
await replyTo(windowB, testMessage, testReply);
});
test('Send voice message and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
// const testReply = `${userB.userName} to ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await clickOnTestIdWithText(windowA, 'microphone-button');
await clickOnTestIdWithText(windowA, 'session-toast');
await clickOnTestIdWithText(windowA, 'enable-microphone');
await clickOnTestIdWithText(windowA, 'message-section');
await clickOnTestIdWithText(windowA, 'microphone-button');
await sleepFor(5000);
await clickOnTestIdWithText(windowA, 'end-voice-message');
await sleepFor(4000);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await clickOnMatchingText(windowB, 'Click to download media');
await clickOnTestIdWithText(windowB, 'session-confirm-ok-button');
});
test('Send GIF and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
// const testReply = `${userB.userName} to ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await windowA.setInputFiles("input[type='file']", 'ts/test/automation/fixtures/test-gif.gif');
await sleepFor(100);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await clickOnMatchingText(windowB, 'Click to download media');
});
test('Send long text and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testReply = `${userB.userName} replying to long text message from ${userA.userName}`;
const longText =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis lacinia mi. Praesent fermentum vehicula rhoncus. Aliquam ac purus lobortis, convallis nisi quis, pulvinar elit. Nam commodo eros in molestie lobortis. Donec at mattis est. In tempor ex nec velit mattis, vitae feugiat augue maximus. Nullam risus libero, bibendum et enim et, viverra viverra est. Suspendisse potenti. Sed ut nibh in sem rhoncus suscipit. Etiam tristique leo sit amet ullamcorper dictum. Suspendisse sollicitudin, lectus et suscipit eleifend, libero dui ultricies neque, non elementum nulla orci bibendum lorem. Suspendisse potenti. Aenean a tellus imperdiet, iaculis metus quis, pretium diam. Nunc varius vitae enim vestibulum interdum. In hac habitasse platea dictumst. Donec auctor sem quis eleifend fermentum. Vestibulum neque nulla, maximus non arcu gravida, condimentum euismod turpis. Cras ac mattis orci. Quisque ac enim pharetra felis sodales eleifend. Aliquam erat volutpat. Donec sit amet mollis nibh, eget feugiat ipsum. Integer vestibulum purus ac suscipit egestas. Duis vitae aliquet ligula.';
await createContact(windowA, windowB, userA, userB);
await typeIntoInput(windowA, 'message-input-text-area', longText);
await sleepFor(100);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await replyTo(windowB, longText, testReply);
});
test('Send link and reply test', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = 'https://nerdlegame.com/';
const testReply = `${userB.userName} replying to link from ${userA.userName}`;
await createContact(windowA, windowB, userA, userB);
await typeIntoInput(windowA, 'message-input-text-area', testMessage);
await sleepFor(5000);
await clickOnTestIdWithText(windowA, 'send-message-button');
await sleepFor(1000);
await replyTo(windowB, testMessage, testReply);
});
// Send link
// Send long text
// Unsend
// Delete message

@ -1,29 +1,27 @@
import { _electron, Page, test } from '@playwright/test'; import { test } from '@playwright/test';
import { beforeAllClean } from './setup/beforeEach';
import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { sendMessage } from './utilities/message';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach';
import { openAppsAndNewUsers } from './setup/new_user';
import { import {
clickOnMatchingText,
clickOnTestIdWithText, clickOnTestIdWithText,
waitForMatchingText, waitForMatchingText,
waitForTestIdWithText, waitForTestIdWithText,
} from './utilities/utils'; } from './utilities/utils';
const testMessage = 'A -> B';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows)); // test.afterEach(() => forceCloseAllWindows(windows));
// Open two windows and log into 2 separate accounts // Open two windows and log into 2 separate accounts
test.describe('Message requests', () => { test.describe('Message requests', () => {
test('Message request acceptance', async () => { test('Message requests accept', async () => {
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users; const testMessage = `Sender: ${userA.userName} Receiver: ${userB.userName}`;
const [windowA, windowB] = windows;
const [userA, userB] = users;
// send a message to User B from User A // send a message to User B from User A
await sendNewMessage(windowA, userB.sessionid, `${testMessage}${Date.now()}`); await sendNewMessage(windowA, userB.sessionid, `${testMessage}`);
// Check the message request banner appears and click on it // Check the message request banner appears and click on it
await clickOnTestIdWithText(windowB, 'message-request-banner'); await clickOnTestIdWithText(windowB, 'message-request-banner');
// Select message request from User A // Select message request from User A
@ -33,19 +31,38 @@ test.describe('Message requests', () => {
// Check config message of message request acceptance // Check config message of message request acceptance
await waitForTestIdWithText( await waitForTestIdWithText(
windowB, windowB,
'readable-message', 'control-message',
`You have accepted ${userA.userName}'s message request` `You have accepted ${userA.userName}'s message request`
); );
await waitForMatchingText(windowB, 'No pending message requests'); await waitForMatchingText(windowB, 'No pending message requests');
}); });
test('Message request rejection', async () => { test('Message requests text reply', async () => {
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users; const testMessage = `Sender: ${userA.userName}, Receiver: ${userB.userName}`;
const [windowA, windowB] = windows; const testReply = `Sender: ${userB.userName}, Receiver: ${userA.userName}`;
const [userA, userB] = users;
// send a message to User B from User A // send a message to User B from User A
await sendNewMessage(windowA, userB.sessionid, `${testMessage}${Date.now()}`); await sendNewMessage(windowA, userB.sessionid, `${testMessage}`);
// Check the message request banner appears and click on it
await clickOnTestIdWithText(windowB, 'message-request-banner');
// Select message request from User A
await clickOnTestIdWithText(windowB, 'module-conversation__user__profile-name', userA.userName);
// Check that using the accept button has intended use
await sendMessage(windowB, testReply);
// Check config message of message request acceptance
await waitForTestIdWithText(
windowB,
'control-message',
`You have accepted ${userA.userName}'s message request`
);
await waitForMatchingText(windowB, 'No pending message requests');
});
test('Message requests decline', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = `Sender: ${userA.userName}, Receiver: ${userB.userName}`;
// send a message to User B from User A
await sendNewMessage(windowA, userB.sessionid, `${testMessage}`);
// Check the message request banner appears and click on it // Check the message request banner appears and click on it
await clickOnTestIdWithText(windowB, 'message-request-banner'); await clickOnTestIdWithText(windowB, 'message-request-banner');
// Select message request from User A // Select message request from User A
@ -58,4 +75,26 @@ test.describe('Message requests', () => {
await waitForTestIdWithText(windowB, 'session-toast', 'Blocked'); await waitForTestIdWithText(windowB, 'session-toast', 'Blocked');
await waitForMatchingText(windowB, 'No pending message requests'); await waitForMatchingText(windowB, 'No pending message requests');
}); });
test('Message requests clear all', async () => {
const [windowA, windowB] = await openApp(2);
const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const testMessage = `Sender: ${userA.userName}, Receiver: ${userB.userName}`;
// send a message to User B from User A
await sendNewMessage(windowA, userB.sessionid, `${testMessage}`);
// Check the message request banner appears and click on it
await clickOnTestIdWithText(windowB, 'message-request-banner');
// Select 'Clear All' button
await clickOnMatchingText(windowB, 'Clear All');
// Confirm decline
await clickOnTestIdWithText(windowB, 'session-confirm-ok-button', 'OK');
// Navigate back to message request folder to check
await clickOnTestIdWithText(windowB, 'settings-section');
// Check config message of message request acceptance
await waitForMatchingText(windowB, 'No pending message requests');
});
}); });
// Clear all requests
// Delete request (not a feature yet)
// Block request (not a feature yet)

@ -1,7 +1,8 @@
import { _electron, Page } from '@playwright/test'; import { Page } from '@playwright/test';
import { readdirSync, rmdirSync } from 'fs-extra'; import { readdirSync, rmdirSync } from 'fs-extra';
import { dirname, join } from 'path'; import { join } from 'path';
import { MULTI_PREFIX, NODE_ENV, openElectronAppOnly } from './open'; import { isMacOS } from '../../../OS';
import { MULTI_PREFIX, NODE_ENV } from './open';
// tslint:disable: no-console // tslint:disable: no-console
const getDirectoriesOfSessionDataPath = (source: string) => const getDirectoriesOfSessionDataPath = (source: string) =>
@ -12,33 +13,21 @@ const getDirectoriesOfSessionDataPath = (source: string) =>
}) })
.filter(n => n.includes(`${NODE_ENV}-${MULTI_PREFIX}`)); .filter(n => n.includes(`${NODE_ENV}-${MULTI_PREFIX}`));
let alreadyCleaned = false; const alreadyCleaned = false;
let alreadyCleanedWaiting = false; let alreadyCleanedWaiting = false;
const cleanUpOtherTest = async () => { function cleanUpOtherTest() {
if (alreadyCleaned || alreadyCleanedWaiting) { if (alreadyCleaned || alreadyCleanedWaiting) {
return; return;
} }
alreadyCleaned = true;
const electronApp = await openElectronAppOnly('start');
const appPath = await electronApp.evaluate(async ({ app }) => {
return app.getPath('userData');
});
const window = await electronApp.firstWindow();
await window.close();
if (alreadyCleaned && alreadyCleanedWaiting) {
return;
}
alreadyCleanedWaiting = true; alreadyCleanedWaiting = true;
if (!appPath.length) { const parentFolderOfAllDataPath = isMacOS() ? '~/Library/Application Support/' : null;
throw new Error('appDataPath unset'); if (!parentFolderOfAllDataPath) {
throw new Error('Only macOS is currrently supported ');
} }
const parentFolderOfAllDataPath = dirname(appPath);
if (!parentFolderOfAllDataPath || parentFolderOfAllDataPath.length < 20) { if (!parentFolderOfAllDataPath || parentFolderOfAllDataPath.length < 20) {
throw new Error('parentFolderOfAllDataPath not found or invalid'); throw new Error('parentFolderOfAllDataPath not found or invalid');
} }
@ -48,14 +37,11 @@ const cleanUpOtherTest = async () => {
console.info('allAppDataPath', allAppDataPath); console.info('allAppDataPath', allAppDataPath);
allAppDataPath.map(folder => { allAppDataPath.map(folder => {
if (!appPath) {
throw new Error('parentFolderOfAllDataPath unset');
}
const pathToRemove = join(parentFolderOfAllDataPath, folder); const pathToRemove = join(parentFolderOfAllDataPath, folder);
rmdirSync(pathToRemove, { recursive: true }); rmdirSync(pathToRemove, { recursive: true });
}); });
console.info('...done'); console.info('...done');
}; }
export const beforeAllClean = cleanUpOtherTest; export const beforeAllClean = cleanUpOtherTest;

@ -1,5 +1,5 @@
import { _electron, Page } from '@playwright/test'; import { _electron, Page } from '@playwright/test';
import { messageSent } from '../utilities/message'; import { sendMessage } from '../utilities/message';
import { sendNewMessage } from '../utilities/send_message'; import { sendNewMessage } from '../utilities/send_message';
import { import {
clickOnMatchingText, clickOnMatchingText,
@ -56,7 +56,7 @@ export const createGroup = async (
await clickOnMatchingText(windowB, group.userName); await clickOnMatchingText(windowB, group.userName);
await waitForTestIdWithText(windowB, 'header-conversation-name', group.userName); await waitForTestIdWithText(windowB, 'header-conversation-name', group.userName);
// Send message in group chat from user A // Send message in group chat from user A
await messageSent(windowA, msgAToGroup); await sendMessage(windowA, msgAToGroup);
// Focus screen // Focus screen
await clickOnMatchingText(windowA, msgAToGroup); await clickOnMatchingText(windowA, msgAToGroup);
// Verify it was received by other two accounts // Verify it was received by other two accounts
@ -67,7 +67,7 @@ export const createGroup = async (
// wait for selector 'test message' in chat window // wait for selector 'test message' in chat window
await waitForControlMessageWithText(windowB, msgAToGroup); await waitForControlMessageWithText(windowB, msgAToGroup);
// Send reply message // Send reply message
await messageSent(windowB, msgBToGroup); await sendMessage(windowB, msgBToGroup);
// Focus screen // Focus screen
// await clickOnTestIdWithText(windowB, 'scroll-to-bottom-button'); // await clickOnTestIdWithText(windowB, 'scroll-to-bottom-button');
await clickOnMatchingText(windowB, msgBToGroup); await clickOnMatchingText(windowB, msgBToGroup);
@ -79,7 +79,7 @@ export const createGroup = async (
await waitForControlMessageWithText(windowC, msgAToGroup); await waitForControlMessageWithText(windowC, msgAToGroup);
await waitForControlMessageWithText(windowC, msgBToGroup); await waitForControlMessageWithText(windowC, msgBToGroup);
// Send message from C to the group // Send message from C to the group
await messageSent(windowC, msgCToGroup); await sendMessage(windowC, msgCToGroup);
// windowA should see the message from B and the message from C // windowA should see the message from B and the message from C
await waitForControlMessageWithText(windowA, msgBToGroup); await waitForControlMessageWithText(windowA, msgBToGroup);
await waitForControlMessageWithText(windowA, msgCToGroup); await waitForControlMessageWithText(windowA, msgCToGroup);

@ -1,10 +1,7 @@
import { _electron, Page } from '@playwright/test'; import { Page } from '@playwright/test';
import _ from 'lodash';
import { User } from '../types/testing'; import { User } from '../types/testing';
import { clickOnMatchingText, typeIntoInput } from '../utilities/utils'; import { clickOnMatchingText, typeIntoInput } from '../utilities/utils';
import { openAppAndWait } from './open'; // tslint:disable: no-console
const multisAvailable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
export const newUser = async (window: Page, userName: string): Promise<User> => { export const newUser = async (window: Page, userName: string): Promise<User> => {
// Create User // Create User
await clickOnMatchingText(window, 'Create Session ID'); await clickOnMatchingText(window, 'Create Session ID');
@ -20,46 +17,34 @@ export const newUser = async (window: Page, userName: string): Promise<User> =>
await clickOnMatchingText(window, 'Reveal Recovery Phrase'); await clickOnMatchingText(window, 'Reveal Recovery Phrase');
const recoveryPhrase = await window.innerText('[data-testid=recovery-phrase-seed-modal]'); const recoveryPhrase = await window.innerText('[data-testid=recovery-phrase-seed-modal]');
console.info(`${userName}: Session ID: ${sessionid} and Recovery phrase: ${recoveryPhrase}`);
await window.click('.session-icon-button.small'); await window.click('.session-icon-button.small');
return { userName, sessionid, recoveryPhrase }; return { userName, sessionid, recoveryPhrase };
}; };
const openAppAndNewUser = async (multi: string): Promise<User & { window: Page }> => { // const openAppAndNewUser = async (multi: string): Promise<User & { window: Page }> => {
const window = await openAppAndWait(multi); // const window = await openAppAndWait(multi);
const userName = `${multi}-user`;
const loggedIn = await newUser(window, userName);
return { window, ...loggedIn };
};
export async function openAppsAndNewUsers(windowToCreate: number) { // const userName = `${multi}-user`;
if (windowToCreate >= multisAvailable.length) { // const loggedIn = await newUser(window, userName);
throw new Error(`Do you really need ${multisAvailable.length} windows?!`); // return { window, ...loggedIn };
} // };
// if windowToCreate = 3, this array will be ABC. If windowToCreate = 5, this array will be ABCDE
const multisToUse = multisAvailable.slice(0, windowToCreate);
const loggedInDetails = await Promise.all(
[...multisToUse].map(async m => {
return openAppAndNewUser(m);
})
);
const windows = loggedInDetails.map(w => w.window); // export async function openAppsAndNewUsers(windowToCreate: number) {
const users = loggedInDetails.map(w => { // if (windowToCreate >= multisAvailable.length) {
return _.pick(w, ['sessionid', 'recoveryPhrase', 'userName']); // throw new Error(`Do you really need ${multisAvailable.length} windows?!`);
}); // }
return { windows, users }; // // if windowToCreate = 3, this array will be ABC. If windowToCreate = 5, this array will be ABCDE
} // const multisToUse = multisAvailable.slice(0, windowToCreate);
// const loggedInDetails = await Promise.all(
// [...multisToUse].map(async m => {
// return openAppAndNewUser(m);
// })
// );
export async function openApp(windowsToCreate: number) { // const windows = loggedInDetails.map(w => w.window);
if (windowsToCreate >= multisAvailable.length) { // const users = loggedInDetails.map(w => {
throw new Error(`Do you really need ${multisAvailable.length} windows?!`); // return _.pick(w, ['sessionid', 'recoveryPhrase', 'userName']);
} // });
// if windowToCreate = 3, this array will be ABC. If windowToCreate = 5, this array will be ABCDE // return { windows, users };
const multisToUse = multisAvailable.slice(0, windowsToCreate); // }
return Promise.all(
[...multisToUse].map(async m => {
return openAppAndWait(`${m}`);
})
);
}

@ -4,8 +4,22 @@ import { getAppRootPath } from '../../../node/getRootPath';
export const NODE_ENV = 'production'; export const NODE_ENV = 'production';
export const MULTI_PREFIX = 'test-integration-testnet-'; export const MULTI_PREFIX = 'test-integration-testnet-';
const multisAvailable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// tslint:disable: no-console // tslint:disable: no-console
export async function openApp(windowsToCreate: number) {
if (windowsToCreate >= multisAvailable.length) {
throw new Error(`Do you really need ${multisAvailable.length} windows?!`);
}
// if windowToCreate = 3, this array will be ABC. If windowToCreate = 5, this array will be ABCDE
const multisToUse = multisAvailable.slice(0, windowsToCreate);
return Promise.all(
[...multisToUse].map(async m => {
return openAppAndWait(`${m}`);
})
);
}
export const openElectronAppOnly = async (multi: string) => { export const openElectronAppOnly = async (multi: string) => {
process.env.NODE_APP_INSTANCE = `${MULTI_PREFIX}-${Date.now()}-${multi}`; process.env.NODE_APP_INSTANCE = `${MULTI_PREFIX}-${Date.now()}-${multi}`;
process.env.NODE_ENV = NODE_ENV; process.env.NODE_ENV = NODE_ENV;

@ -1,19 +1,18 @@
import { _electron, expect, Page, test } from '@playwright/test'; import { expect, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { beforeAllClean } from './setup/beforeEach';
import { openAppsAndNewUsers } from './setup/new_user'; import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { clickOnTestIdWithText } from './utilities/utils'; import { clickOnTestIdWithText } from './utilities/utils';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows)); // test.afterEach(() => forceCloseAllWindows(windows));
test('Switch themes', async () => { test('Switch themes', async () => {
// Open App // Open App
const [windowA] = await openApp(1);
// Create User // Create User
const windowLoggedIn = await openAppsAndNewUsers(1); await newUser(windowA, 'Alice');
windows = windowLoggedIn.windows;
const [windowA] = windows;
// Check light theme colour is correct // Check light theme colour is correct
const darkThemeColor = windowA.locator('.inbox.index'); const darkThemeColor = windowA.locator('.inbox.index');
await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)'); await expect(darkThemeColor).toHaveCSS('background-color', 'rgb(27, 27, 27)');

@ -0,0 +1,11 @@
import { test } from '@playwright/test';
import { beforeAllClean } from './setup/beforeEach';
import { openApp } from './setup/open';
import { clickOnMatchingText } from './utilities/utils';
test.beforeEach(beforeAllClean);
test('Tiny test', async () => {
const [windowA] = await openApp(1);
await clickOnMatchingText(windowA, 'Create Session ID');
});

@ -10,3 +10,5 @@ export type Group = {
userTwo: User; userTwo: User;
userThree: User; userThree: User;
}; };
export type Strategy = 'data-testid' | 'class' | ':has-text';

@ -1,6 +1,7 @@
import { _electron, Page, test } from '@playwright/test'; import { test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { beforeAllClean } from './setup/beforeEach';
import { openAppsAndNewUsers } from './setup/new_user'; import { newUser } from './setup/new_user';
import { openApp } from './setup/open';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { import {
clickOnMatchingText, clickOnMatchingText,
@ -12,18 +13,14 @@ import {
const testMessage = 'A -> B: '; const testMessage = 'A -> B: ';
const testReply = 'B -> A: '; const testReply = 'B -> A: ';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
test.afterEach(() => forceCloseAllWindows(windows)); // test.afterEach(() => forceCloseAllWindows(windows));
test('Unsend message', async () => { test('Unsend message', async () => {
// Open App // Open App
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users;
const [windowA, windowB] = windows;
const [userA, userB] = users;
// Send message between two users // Send message between two users
await sendNewMessage(windowA, userB.sessionid, `${testMessage}${Date.now()}`); await sendNewMessage(windowA, userB.sessionid, `${testMessage}${Date.now()}`);
await sendNewMessage(windowB, userA.sessionid, `${testReply}${Date.now()}`); await sendNewMessage(windowB, userA.sessionid, `${testReply}${Date.now()}`);

@ -1,27 +1,25 @@
import { _electron, Page, test } from '@playwright/test'; import { expect, test } from '@playwright/test';
import { beforeAllClean, forceCloseAllWindows } from './setup/beforeEach'; import { beforeAllClean } from './setup/beforeEach';
import { sleepFor } from '../../session/utils/Promise';
import { newUser } from './setup/new_user';
import { sendNewMessage } from './utilities/send_message'; import { sendNewMessage } from './utilities/send_message';
import { openAppsAndNewUsers } from './setup/new_user';
import { import {
clickOnMatchingText, clickOnMatchingText,
clickOnTestIdWithText, clickOnTestIdWithText,
typeIntoInput,
waitForMatchingText, waitForMatchingText,
waitForTestIdWithText, waitForTestIdWithText,
} from './utilities/utils'; } from './utilities/utils';
import { openApp } from './setup/open';
let windows: Array<Page> = [];
test.beforeEach(beforeAllClean); test.beforeEach(beforeAllClean);
// test.afterEach(() => forceCloseAllWindows(windows)); // test.afterEach(() => forceCloseAllWindows(windows));
// Send message in one to one conversation with new contact // Send message in one to one conversation with new contact
test('Create contact', async () => { test('Create contact', async () => {
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users;
const [windowA, windowB] = windows;
const [userA, userB] = users;
const testMessage = `${userA.userName} to ${userB.userName}`; const testMessage = `${userA.userName} to ${userB.userName}`;
const testReply = `${userB.userName} to ${userA.userName}`; const testReply = `${userB.userName} to ${userA.userName}`;
@ -39,13 +37,11 @@ test('Create contact', async () => {
await clickOnTestIdWithText(windowA, 'new-conversation-button'); await clickOnTestIdWithText(windowA, 'new-conversation-button');
}); });
test('Block User', async () => { test('Block user in conversation options', async () => {
// Open app and create user // Open app and create user
const windowLoggedIn = await openAppsAndNewUsers(2); const [windowA, windowB] = await openApp(2);
windows = windowLoggedIn.windows; const [userA, userB] = await Promise.all([newUser(windowA, 'Alice'), newUser(windowB, 'Bob')]);
const users = windowLoggedIn.users;
const [windowA, windowB] = windows;
const [userA, userB] = users;
const testMessage = `${userA.userName} to ${userB.userName}`; const testMessage = `${userA.userName} to ${userB.userName}`;
const testReply = `${userB.userName} to ${userA.userName}`; const testReply = `${userB.userName} to ${userA.userName}`;
// Create contact and send new message // Create contact and send new message
@ -78,3 +74,51 @@ test('Block User', async () => {
await waitForTestIdWithText(windowA, 'session-toast', 'Unblocked'); await waitForTestIdWithText(windowA, 'session-toast', 'Unblocked');
await waitForMatchingText(windowA, 'No blocked contacts'); await waitForMatchingText(windowA, 'No blocked contacts');
}); });
test('Change username', async () => {
// Open App
const [window] = await openApp(1);
// Create user
const newUsername = 'Tiny bubble';
await newUser(window, 'Alice');
// Open Profile
await clickOnTestIdWithText(window, 'leftpane-primary-avatar');
// Click on current username to open edit field
await clickOnTestIdWithText(window, 'edit-profile-icon');
// Type in new username
await typeIntoInput(window, 'profile-name-input', newUsername);
// await window.fill('.profile-name-input', 'new username');
// Press enter to confirm username input
await window.keyboard.press('Enter');
// Wait for Copy button to appear to verify username change
await window.isVisible("'Copy'");
// verify name change
expect(await window.innerText('[data-testid=your-profile-name]')).toBe(newUsername);
// Exit profile module
await window.click('.session-icon-button.small');
});
test('Change avatar', async () => {
const [window] = await openApp(1);
await newUser(window, 'Alice');
// Open profile
await clickOnTestIdWithText(window, 'leftpane-primary-avatar');
// Click on current profile picture
await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy');
await clickOnTestIdWithText(window, 'image-upload-section');
await clickOnTestIdWithText(window, 'save-button-profile-update');
await waitForTestIdWithText(window, 'loading-spinner');
await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy');
await clickOnTestIdWithText(window, 'modal-close-button');
await sleepFor(500);
const leftpaneAvatarContainer = await waitForTestIdWithText(window, 'leftpane-primary-avatar');
await sleepFor(500);
const screenshot = await leftpaneAvatarContainer.screenshot({
type: 'jpeg',
// path: 'avatar-updated-blue',
});
expect(screenshot).toMatchSnapshot({ name: 'avatar-updated-blue.jpeg' });
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

@ -0,0 +1,20 @@
import { Page } from '@playwright/test';
import { User } from '../types/testing';
import { sendNewMessage } from './send_message';
import { clickOnTestIdWithText, waitForTestIdWithText } from './utils';
export const createContact = async (windowA: Page, windowB: Page, userA: User, userB: User) => {
const testMessage = `${userA.userName} to ${userB.userName}`;
const testReply = `${userB.userName} to ${userA.userName}`;
// User A sends message to User B
await sendNewMessage(windowA, userB.sessionid, `${testMessage}`);
// User B sends message to User B to USER A
await sendNewMessage(windowB, userA.sessionid, `${testReply}`);
await clickOnTestIdWithText(windowA, 'new-conversation-button');
await windowA.waitForTimeout(2000);
await waitForTestIdWithText(windowB, 'module-conversation__user__profile-name', userA.userName);
// Navigate to contacts tab in User A's window
await clickOnTestIdWithText(windowA, 'new-conversation-button');
};

@ -9,5 +9,5 @@ export const leaveGroup = async (window: Page) => {
// Confirm leave group // Confirm leave group
await clickOnTestIdWithText(window, 'session-confirm-ok-button', 'OK'); await clickOnTestIdWithText(window, 'session-confirm-ok-button', 'OK');
// check config message // check config message
await waitForTestIdWithText(window, 'readable-message', 'You have left the group.'); await waitForTestIdWithText(window, 'control-message', 'You have left the group.');
}; };

@ -1,15 +1,11 @@
import { _electron } from 'playwright-core'; import { _electron } from 'playwright-core';
import { openAppsAndNewUsers, openAppsNoNewUsers } from '../setup/new_user';
import { logIn } from '../setup/log_in'; import { logIn } from '../setup/log_in';
import { openApp } from '../setup/open';
export async function linkedDevice() { export async function linkedDevice(recoveryPhrase: string) {
const windowLoggedIn = await openAppsAndNewUsers(1); const [windowB] = await openApp(1);
const [windowA1] = windowLoggedIn.windows;
const users = windowLoggedIn.users;
const [userA] = users;
const [windowA2] = await openAppsNoNewUsers(1);
await logIn(windowA2, userA.recoveryPhrase); await logIn(windowB, recoveryPhrase);
return { windowA1, windowA2, userA }; return [windowB];
} }

@ -2,13 +2,13 @@ import { _electron, Page } from '@playwright/test';
import { clickOnTestIdWithText, typeIntoInput } from './utils'; import { clickOnTestIdWithText, typeIntoInput } from './utils';
// tslint:disable: no-console // tslint:disable: no-console
export const messageSent = async (window: Page, message: string) => { export const sendMessage = async (window: Page, message: string) => {
// type into message input box // type into message input box
await typeIntoInput(window, 'message-input-text-area', message); await typeIntoInput(window, 'message-input-text-area', message);
// click up arrow (send) // click up arrow (send)
await clickOnTestIdWithText(window, 'send-message-button'); await clickOnTestIdWithText(window, 'send-message-button');
// wait for confirmation tick to send reply message // wait for confirmation tick to send reply message
const selc = `css=[data-testid=readable-message]:has-text("${message}"):has([data-testid=msg-status-outgoing][data-testtype=sent])`; const selc = `css=[data-testid=control-message]:has-text("${message}"):has([data-testid=msg-status-outgoing][data-testtype=sent])`;
console.error('waiting for sent tick of message: ', message); console.error('waiting for sent tick of message: ', message);
const tickMessageSent = await window.waitForSelector(selc, { timeout: 30000 }); const tickMessageSent = await window.waitForSelector(selc, { timeout: 30000 });

@ -0,0 +1,11 @@
import { Page } from '@playwright/test';
import { sendMessage } from './message';
import { clickOnMatchingText, clickOnTestIdWithText, waitForTextMessage } from './utils';
export const replyTo = async (window: Page, textMessage: string, replyText: string) => {
await waitForTextMessage(window, textMessage);
await clickOnTestIdWithText(window, 'control-message', textMessage, true);
await clickOnMatchingText(window, 'Reply to message');
await sendMessage(window, replyText);
console.warn();
};

@ -1,5 +1,5 @@
import { _electron, Page } from '@playwright/test'; import { _electron, Page } from '@playwright/test';
import { messageSent } from './message'; import { sendMessage } from './message';
import { clickOnTestIdWithText, typeIntoInput } from './utils'; import { clickOnTestIdWithText, typeIntoInput } from './utils';
export const sendNewMessage = async (window: Page, sessionid: string, message: string) => { export const sendNewMessage = async (window: Page, sessionid: string, message: string) => {
@ -9,5 +9,5 @@ export const sendNewMessage = async (window: Page, sessionid: string, message: s
await typeIntoInput(window, 'new-session-conversation', sessionid); await typeIntoInput(window, 'new-session-conversation', sessionid);
// click next // click next
await clickOnTestIdWithText(window, 'next-new-conversation-button', 'Next'); await clickOnTestIdWithText(window, 'next-new-conversation-button', 'Next');
await messageSent(window, message); await sendMessage(window, message);
}; };

@ -1,19 +1,57 @@
import { ElementHandle } from '@playwright/test';
import { Page } from 'playwright-core'; import { Page } from 'playwright-core';
import { sleepFor } from '../../../session/utils/Promise';
import { Strategy } from '../types/testing';
// tslint:disable: no-console // tslint:disable: no-console
// WAIT FOR FUNCTIONS
export async function waitForTestIdWithText(window: Page, dataTestId: string, text?: string) { export async function waitForTestIdWithText(window: Page, dataTestId: string, text?: string) {
let builtSelector = `css=[data-testid=${dataTestId}]`; let builtSelector = `css=[data-testid=${dataTestId}]`;
if (text) { if (text) {
builtSelector += `:has-text("${text}")`; // " => \\\"
} /* prettier-ignore */
// tslint:disable-next-line: quotemark
const escapedText = text.replace(/"/g, '\\\"');
console.info('looking for selector', builtSelector); builtSelector += `:has-text("${escapedText}")`;
console.warn('builtSelector:', builtSelector);
// console.warn('Text is tiny bubble: ', escapedText);
}
// console.info('looking for selector', builtSelector);
const found = await window.waitForSelector(builtSelector, { timeout: 55000 }); const found = await window.waitForSelector(builtSelector, { timeout: 55000 });
console.info('found selector', builtSelector); // console.info('found selector', builtSelector);
return found; return found;
} }
export async function waitForElement(
window: Page,
strategy: Strategy,
selector: string,
maxWaitMs?: number
) {
const builtSelector = `css=[${strategy}=${selector}]`;
return window.waitForSelector(builtSelector, { timeout: maxWaitMs });
}
export async function waitForTextMessage(window: Page, text: string, maxWait?: number) {
let builtSelector = `:has-text("${text}")`;
if (text) {
// " => \\\"
/* prettier-ignore */
// tslint:disable-next-line: quotemark
const escapedText = text.replace(/"/g, '\\\"');
builtSelector += `:has-text("${escapedText}")`;
console.warn('builtSelector:', builtSelector);
// console.warn('Text is tiny bubble: ', escapedText);
}
const el = await window.waitForSelector(builtSelector, { timeout: maxWait });
return el;
}
export async function waitForControlMessageWithText(window: Page, text: string) { export async function waitForControlMessageWithText(window: Page, text: string) {
return waitForTestIdWithText(window, 'control-message', text); return waitForTestIdWithText(window, 'control-message', text);
} }
@ -27,12 +65,48 @@ export async function waitForMatchingText(window: Page, text: string) {
console.info(`got matchingText: ${text}`); console.info(`got matchingText: ${text}`);
} }
export async function waitForLoadingAnimationToFinish(window: Page) {
let loadingAnimation: ElementHandle<SVGElement | HTMLElement> | undefined;
await waitForElement(window, 'data-testid', 'loading-animation');
do {
try {
loadingAnimation = await waitForElement(window, 'data-testid', 'loading-animation', 100);
await sleepFor(100);
console.info('loading-animation was found, waiting for it to be gone');
} catch (e) {
loadingAnimation = undefined;
}
} while (loadingAnimation);
}
console.info('Loading animation has finished');
// ACTIONS
export async function clickOnElement(
window: Page,
strategy: Strategy,
selector: string,
maxWait?: number
) {
const builtSelector = `css=[${strategy}=${selector}]`;
await window.waitForSelector(builtSelector, { timeout: maxWait });
await window.click(builtSelector);
return;
}
export async function clickOnMatchingText(window: Page, text: string, rightButton = false) { export async function clickOnMatchingText(window: Page, text: string, rightButton = false) {
console.info(`clickOnMatchingText: "${text}"`); console.info(`clickOnMatchingText: "${text}"`);
return window.click(`"${text}"`, rightButton ? { button: 'right' } : undefined); return window.click(`"${text}"`, rightButton ? { button: 'right' } : undefined);
} }
export async function clickOnTestIdWithText(window: Page, dataTestId: string, text?: string) { export async function clickOnTestIdWithText(
window: Page,
dataTestId: string,
text?: string,
rightButton?: boolean
) {
console.info(`clickOnTestIdWithText with testId:${dataTestId} and text:${text ? text : 'none'}`); console.info(`clickOnTestIdWithText with testId:${dataTestId} and text:${text ? text : 'none'}`);
const builtSelector = !text const builtSelector = !text
@ -40,7 +114,7 @@ export async function clickOnTestIdWithText(window: Page, dataTestId: string, te
: `css=[data-testid=${dataTestId}]:has-text("${text}")`; : `css=[data-testid=${dataTestId}]:has-text("${text}")`;
await window.waitForSelector(builtSelector); await window.waitForSelector(builtSelector);
return window.click(builtSelector); return window.click(builtSelector, rightButton ? { button: 'right' } : undefined);
} }
export function getMessageTextContentNow() { export function getMessageTextContentNow() {
@ -50,5 +124,5 @@ export function getMessageTextContentNow() {
export async function typeIntoInput(window: Page, dataTestId: string, text: string) { export async function typeIntoInput(window: Page, dataTestId: string, text: string) {
console.info(`typeIntoInput testId: ${dataTestId} : "${text}"`); console.info(`typeIntoInput testId: ${dataTestId} : "${text}"`);
const builtSelector = `css=[data-testid=${dataTestId}]`; const builtSelector = `css=[data-testid=${dataTestId}]`;
return window.fill(builtSelector, text); return window.type(builtSelector, text);
} }

Loading…
Cancel
Save