Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0ce23e7
fix: tests do not fail immediately
Miki-Session Aug 28, 2025
b71e6b6
fix: only keep hex when getting accountid
Miki-Session Aug 28, 2025
d3d87d3
feat: begin adding locator classes
Miki-Session Aug 28, 2025
afde637
chore: continue using locator classes
Miki-Session Aug 29, 2025
12baf5a
fix: remove message-section from create group util
Miki-Session Aug 29, 2025
abe3d6f
fix: settings is called settings-section again
Miki-Session Sep 3, 2025
20d86c5
fix: password tests have correct ids now
Miki-Session Sep 3, 2025
e3ade7f
refactor: add locators to linked device requests file
Miki-Session Sep 3, 2025
8dc26af
feat: target specific modals in checkModalStrings
Miki-Session Sep 3, 2025
3d6dd5e
refactor: update more tests to use locators
Miki-Session Sep 3, 2025
d171c2d
feat: add perfectionist, enforce sorting
Miki-Session Sep 3, 2025
41492e0
chore: update strings
Miki-Session Sep 3, 2025
7ae3649
refactor: keep fixing them tests
Miki-Session Sep 3, 2025
00eb0b7
chore: more refactoring tests
Miki-Session Sep 4, 2025
af6e4d3
feat: add perfectionist/sort-classes rule
Miki-Session Sep 4, 2025
cba535b
refactor: keep fixing them tests
Miki-Session Sep 4, 2025
9c287e4
chore: keep on keeping on
Miki-Session Sep 4, 2025
8faa8ba
chore: replace all clickOnTestIdWithText instances with locators
Miki-Session Sep 4, 2025
23b799f
wip: replace all clickOnTestIdWithText with explicit functions
Miki-Session Sep 4, 2025
8e8ec22
wip: linting
Miki-Session Sep 4, 2025
af12d09
refactor: eliminate clickOnTestIdWithText
Miki-Session Sep 4, 2025
e7d301f
chore: begin refactoring clickOnElement
Miki-Session Sep 4, 2025
3d70de3
feat: normalize pixel density for macos consistency
Miki-Session Sep 8, 2025
f6401fd
chore: fix more tests
Miki-Session Sep 8, 2025
aec13ee
chore: also upload lower density landing page states
Miki-Session Sep 8, 2025
ca02866
fix: window closes too quickly
Miki-Session Sep 8, 2025
9f91d55
fix: tests for linux avatar screenshots
Bilb Sep 24, 2025
6507676
fix: update linux screenshot and resize before comparing
Bilb Sep 24, 2025
cdb0973
fix: remove screenshot comparison for empty states
Bilb Sep 25, 2025
52b89ca
chore: remove uneeded sharp dep
Bilb Sep 25, 2025
e61c9e3
chore: remove useless logs
Bilb Sep 25, 2025
317bbfa
chore: add new strings verification
Bilb Sep 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {

extends: ['airbnb-base', 'airbnb-typescript/base', 'prettier', 'plugin:@typescript-eslint/recommended'],

plugins: ['mocha', 'more', '@typescript-eslint'],
plugins: ['mocha', 'more', '@typescript-eslint', 'perfectionist'],
parser: '@typescript-eslint/parser',
parserOptions: { project: ['./tsconfig.json'] },

Expand Down Expand Up @@ -54,6 +54,36 @@ module.exports = {
'import/order': 'off',
'no-useless-catch': 'off',

'perfectionist/sort-imports': 'error',
'perfectionist/sort-named-imports': 'error',
'perfectionist/sort-classes': [
'error',
{
partitionByComment: true,
},
],
'perfectionist/sort-union-types': [
'error',
{
// This ensures null/undefined come after other types for better readability
groups: [
'named',
'keyword',
'operator',
'literal',
'function',
'import',
'conditional',
'object',
'tuple',
'intersection',
'union',
'nullish',
],
}
],


quotes: [
'error',
'single',
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ output/
dist/
.eslintcache
*-difference.png
*-current*.png
*-diff*.png
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import tseslint from '@typescript-eslint/eslint-plugin';
import globals from 'globals';

export default tseslint.config(
Expand Down
3 changes: 2 additions & 1 deletion global.setup.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { readdirSync, rm } from 'fs-extra';
import { isEmpty } from 'lodash';
import { homedir } from 'os';
import { join } from 'path';

import { MULTI_PREFIX, NODE_ENV } from './tests/automation/setup/open';
import { isLinux, isMacOS } from './tests/os_utils';
import { isEmpty } from 'lodash';

const getDirectoriesOfSessionDataPath = (source: string) =>
readdirSync(source, { withFileTypes: true })
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-mocha": "^10.1.0",
"eslint-plugin-more": "^1.0.5",
"eslint-plugin-perfectionist": "^4.15.0",
"fs-extra": "^11.1.1",
"lodash": "^4.17.21",
"prettier": "^3.0.1",
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';
import { toNumber } from 'lodash';

import dotenv from 'dotenv';
import { screenshotFolder } from './tests/automation/constants/variables';

dotenv.config();
Expand Down
4 changes: 2 additions & 2 deletions screenshots/Change-avatar/avatar-updated-blue-darwin.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions screenshots/Change-avatar/avatar-updated-blue-linux.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 0 additions & 3 deletions screenshots/landing-page-states/new-account-darwin.png

This file was deleted.

3 changes: 0 additions & 3 deletions screenshots/landing-page-states/new-account-linux.png

This file was deleted.

3 changes: 0 additions & 3 deletions screenshots/landing-page-states/restored-account-darwin.png

This file was deleted.

3 changes: 0 additions & 3 deletions screenshots/landing-page-states/restored-account-linux.png

This file was deleted.

107 changes: 54 additions & 53 deletions sessionReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
TestError,
TestResult,
} from '@playwright/test/reporter';

import chalk from 'chalk';
import { Dictionary, groupBy, isString, mean, sortBy } from 'lodash';

Expand Down Expand Up @@ -74,14 +75,14 @@ function printFailedTestLogs() {
}

class SessionReporter implements Reporter {
private startTime = 0;
private allResults: Array<TestAndResult> = [];

private allTestsCount = 0;

private allResults: Array<TestAndResult> = [];

private countWorkers = 1;

private startTime = 0;

onBegin(config: FullConfig, suite: Suite) {
this.allTestsCount = suite.allTests().length;
this.countWorkers = config.workers;
Expand All @@ -92,6 +93,56 @@ class SessionReporter implements Reporter {
this.startTime = Date.now();
}

onEnd(result: FullResult) {
console.log(
chalk.bgWhiteBright.black(
`\n\n\n\t\tFinished the run: ${result.status}, count of tests run: ${
this.allResults.length
}, took ${Math.floor(
(Date.now() - this.startTime) / (60 * 1000),
)} minute(s)`,
),
);
const { allFailedSoFar, allPassedSoFar, partiallyPassed } =
this.groupResultsByTestName();

sortByTitle(allPassedSoFar).forEach((m) => formatGroupedByResults(m));
sortByTitle(partiallyPassed).forEach((m) => formatGroupedByResults(m));
sortByTitle(allFailedSoFar).forEach((m) => formatGroupedByResults(m));
}

onError?(error: TestError) {
console.info('global error:', error);
}

onStdErr?(
chunk: Buffer | string,
test: TestCase | void,
_result: TestResult | void,
) {
if (printOngoingTestLogs()) {
process.stdout.write(
`"${test ? `${chalk.cyanBright(test.title)}` : ''}":err: ${
isString(chunk) ? chunk : chunk.toString('utf-8')
}`,
);
}
}

onStdOut?(
chunk: Buffer | string,
test: TestCase | void,
_result: TestResult | void,
) {
if (printOngoingTestLogs()) {
process.stdout.write(
`"${test ? `${chalk.cyanBright(test.title)}` : ''}": ${
isString(chunk) ? chunk : chunk.toString('utf-8')
}`,
);
}
}

onTestBegin(test: TestCase, result: TestResult) {
console.log(
chalk.magenta(
Expand Down Expand Up @@ -200,56 +251,6 @@ class SessionReporter implements Reporter {
),
};
}

onEnd(result: FullResult) {
console.log(
chalk.bgWhiteBright.black(
`\n\n\n\t\tFinished the run: ${result.status}, count of tests run: ${
this.allResults.length
}, took ${Math.floor(
(Date.now() - this.startTime) / (60 * 1000),
)} minute(s)`,
),
);
const { allFailedSoFar, allPassedSoFar, partiallyPassed } =
this.groupResultsByTestName();

sortByTitle(allPassedSoFar).forEach((m) => formatGroupedByResults(m));
sortByTitle(partiallyPassed).forEach((m) => formatGroupedByResults(m));
sortByTitle(allFailedSoFar).forEach((m) => formatGroupedByResults(m));
}

onStdOut?(
chunk: string | Buffer,
test: void | TestCase,
_result: void | TestResult,
) {
if (printOngoingTestLogs()) {
process.stdout.write(
`"${test ? `${chalk.cyanBright(test.title)}` : ''}": ${
isString(chunk) ? chunk : chunk.toString('utf-8')
}`,
);
}
}

onStdErr?(
chunk: string | Buffer,
test: void | TestCase,
_result: void | TestResult,
) {
if (printOngoingTestLogs()) {
process.stdout.write(
`"${test ? `${chalk.cyanBright(test.title)}` : ''}":err: ${
isString(chunk) ? chunk : chunk.toString('utf-8')
}`,
);
}
}

onError?(error: TestError) {
console.info('global error:', error);
}
}

export default SessionReporter;
2 changes: 1 addition & 1 deletion tests/automation/call_checks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test_Alice_1W_Bob_1W(
'Voice calls',
async ({ alice, aliceWindow1, bob, bobWindow1 }) => {
await createContact(aliceWindow1, bobWindow1, alice, bob);
await makeVoiceCall(aliceWindow1, bobWindow1, alice, bob);
await makeVoiceCall(aliceWindow1, bobWindow1);
// In the receivers window, the message is 'Call in progress'
await waitForTestIdWithText(
bobWindow1,
Expand Down
22 changes: 12 additions & 10 deletions tests/automation/community_tests.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { testCommunityName } from './constants/community';
import { Conversation, HomeScreen } from './locators';
import { test_Alice_1W_Bob_1W, test_Alice_2W } from './setup/sessionTest';
import { joinCommunity } from './utilities/join_community';
import { sendMessage } from './utilities/message';
import { replyTo } from './utilities/reply_message';
import { sendMedia } from './utilities/send_media';
import { clickOnTestIdWithText } from './utilities/utils';
import { clickOn, clickOnWithText } from './utilities/utils';

test_Alice_2W('Join community', async ({ aliceWindow1, aliceWindow2 }) => {
await joinCommunity(aliceWindow1);
await clickOnTestIdWithText(aliceWindow1, 'scroll-to-bottom-button');
await clickOn(aliceWindow1, Conversation.scrollToBottomButton);
await sendMessage(aliceWindow1, 'Hello, community!');
// Check linked device for community
await clickOnTestIdWithText(
await clickOnWithText(
aliceWindow2,
'module-conversation__user__profile-name',
HomeScreen.conversationItemName,
testCommunityName,
);
});
Expand All @@ -29,15 +30,16 @@ test_Alice_1W_Bob_1W(
// waitForLoadingAnimationToFinish(aliceWindow1, 'loading-spinner'),
// waitForLoadingAnimationToFinish(bobWindow1, 'loading-spinner'),
// ]);
await Promise.all([
clickOnTestIdWithText(aliceWindow1, 'scroll-to-bottom-button'),
clickOnTestIdWithText(bobWindow1, 'scroll-to-bottom-button'),
]);
await Promise.all(
[aliceWindow1, bobWindow1].map((window) =>
clickOn(window, Conversation.scrollToBottomButton),
),
);
await sendMessage(aliceWindow1, testMessage);
// Check linked device for community
await clickOnTestIdWithText(
await clickOnWithText(
aliceWindow1,
'module-conversation__user__profile-name',
HomeScreen.conversationItemName,
testCommunityName,
);
await sendMedia(
Expand Down
4 changes: 2 additions & 2 deletions tests/automation/constants/variables.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
DMTimeOption,
DisappearActions,
DisappearGroupType,
DisappearType,
DMTimeOption,
MediaType,
} from '../types/testing';

Expand Down Expand Up @@ -42,7 +42,7 @@ export const mediaArray = [

type DisappearingOption = {
timeOption: DMTimeOption;
disappearingMessagesType: DisappearType | DisappearGroupType;
disappearingMessagesType: DisappearGroupType | DisappearType;
disappearAction: DisappearActions;
};

Expand Down
28 changes: 17 additions & 11 deletions tests/automation/create_user.spec.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { sleepFor } from '../promise_utils';
import { Global, LeftPane, Settings } from './locators';
import { newUser } from './setup/new_user';
import { sessionTestOneWindow } from './setup/sessionTest';
import {
clickOnTestIdWithText,
waitForTestIdWithText,
} from './utilities/utils';
import { clickOn, waitForTestIdWithText } from './utilities/utils';

sessionTestOneWindow('Create User', async ([window]) => {
// Create User
const userA = await newUser(window, 'Alice', false);
// Open profile tab
await clickOnTestIdWithText(window, 'leftpane-primary-avatar');
await clickOn(window, LeftPane.profileButton);
await sleepFor(100, true);
// check username matches
await waitForTestIdWithText(window, 'your-profile-name', userA.userName);
await waitForTestIdWithText(
window,
Settings.displayName.selector,
userA.userName,
);
// check Account ID matches
await waitForTestIdWithText(window, 'your-account-id', userA.accountid);
await waitForTestIdWithText(
window,
Settings.accountId.selector,
userA.accountid,
);
// exit profile modal
await clickOnTestIdWithText(window, 'modal-close-button');
await clickOn(window, Global.modalCloseButton);
// go to settings section
await clickOnTestIdWithText(window, 'settings-section');
await clickOn(window, LeftPane.settingsButton);
// check recovery phrase matches
await clickOnTestIdWithText(window, 'recovery-password-settings-menu-item');
await clickOn(window, Settings.recoveryPasswordMenuItem);
await waitForTestIdWithText(
window,
'recovery-password-seed-modal',
Settings.recoveryPasswordContainer.selector,
userA.recoveryPassword,
);
});
Loading
Loading