Skip to content

Commit af0725c

Browse files
e2e(ci): bootstrap public links and flaky-test reporting for Playwright CI (#3885)
1 parent 9e5328f commit af0725c

16 files changed

Lines changed: 1008 additions & 56 deletions

File tree

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@
9494
{
9595
"files": [
9696
"e2e/**/*",
97-
"src/**/*.test.js"
97+
"src/**/*.test.js",
98+
"src/**/*.test.ts"
9899
],
99100
"env": {
100101
"jest": true

.github/workflows/e2e-functional-template.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ jobs:
287287
npm ci
288288
cd e2e && npm ci
289289
290+
- name: e2e/enable-public-links
291+
if: env.MM_TEST_SERVER_URL != ''
292+
run: cd e2e && npm run enable-public-links
293+
290294
- name: e2e/suppress-macos-dialogs
291295
if: runner.os == 'macOS'
292296
run: |

e2e/helpers/badge.ts

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import {expect} from '@playwright/test';
55
import type {ElectronApplication} from 'playwright';
66

7+
import type {BadgeTestState} from 'src/main/e2e/badgeState';
8+
import type {E2eGlobalRefs} from 'src/main/e2e/hooks';
9+
710
import {evaluateInMainProcess, evaluateInMainProcessWithArg} from './testRefs';
811

912
export type OsBadgeState = {
@@ -15,7 +18,8 @@ export type OsBadgeState = {
1518
export async function waitForBadgeInfrastructure(app: ElectronApplication): Promise<void> {
1619
await expect.poll(
1720
async () => app.evaluate(() => {
18-
const refs = (global as any).__e2eTestRefs;
21+
const e2eTestRefsKey = '__e2eTestRefs';
22+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
1923
return Boolean(refs?.AppState && refs?.ServerManager);
2024
}),
2125
{timeout: 30_000, message: 'AppState and ServerManager must be exposed on __e2eTestRefs'},
@@ -24,7 +28,8 @@ export async function waitForBadgeInfrastructure(app: ElectronApplication): Prom
2428

2529
export async function setUnreadBadgeSetting(app: ElectronApplication, enabled: boolean): Promise<void> {
2630
await evaluateInMainProcessWithArg(app, (_electron, showUnreadBadge) => {
27-
const refs = (global as any).__e2eTestRefs;
31+
const e2eTestRefsKey = '__e2eTestRefs';
32+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
2833
if (!refs?.setUnreadBadgeSetting) {
2934
throw new Error('setUnreadBadgeSetting missing from __e2eTestRefs');
3035
}
@@ -40,7 +45,8 @@ export async function updateServerBadgeViaAppState(
4045
unreads: boolean,
4146
): Promise<void> {
4247
await evaluateInMainProcessWithArg(app, (_electron, {serverName: name, mentions: mentionCount, unreads: hasUnreads}) => {
43-
const refs = (global as any).__e2eTestRefs;
48+
const e2eTestRefsKey = '__e2eTestRefs';
49+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
4450
const AppState = refs?.AppState;
4551
const ServerManager = refs?.ServerManager;
4652
if (!AppState || !ServerManager) {
@@ -60,7 +66,8 @@ export async function setServerExpiredViaAppState(
6066
expired: boolean,
6167
): Promise<void> {
6268
await evaluateInMainProcessWithArg(app, (_electron, {serverName: name, expired: isExpired}) => {
63-
const refs = (global as any).__e2eTestRefs;
69+
const e2eTestRefsKey = '__e2eTestRefs';
70+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
6471
const AppState = refs?.AppState;
6572
const ServerManager = refs?.ServerManager;
6673
if (!AppState || !ServerManager) {
@@ -76,7 +83,8 @@ export async function setServerExpiredViaAppState(
7683

7784
export async function clearAllBadgesViaAppState(app: ElectronApplication): Promise<void> {
7885
await evaluateInMainProcess(app, () => {
79-
const refs = (global as any).__e2eTestRefs;
86+
const e2eTestRefsKey = '__e2eTestRefs';
87+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
8088
const AppState = refs?.AppState;
8189
const ServerManager = refs?.ServerManager;
8290
if (!AppState || !ServerManager) {
@@ -91,9 +99,54 @@ export async function clearAllBadgesViaAppState(app: ElectronApplication): Promi
9199
});
92100
}
93101

102+
/**
103+
* Clear all servers and set one server's badge state in a single main-process
104+
* turn so external AppState updates cannot land between separate clear/set IPC calls.
105+
*/
106+
export async function prepareServerBadgeViaAppState(
107+
app: ElectronApplication,
108+
serverName: string,
109+
mentions: number,
110+
unreads: boolean,
111+
options: {enableUnreadBadge?: boolean} = {},
112+
): Promise<void> {
113+
const {enableUnreadBadge = false} = options;
114+
await evaluateInMainProcessWithArg(app, (_, payload) => {
115+
const e2eTestRefsKey = '__e2eTestRefs';
116+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
117+
const AppState = refs?.AppState;
118+
const ServerManager = refs?.ServerManager;
119+
if (!AppState || !ServerManager) {
120+
throw new Error('AppState or ServerManager missing from __e2eTestRefs');
121+
}
122+
123+
for (const server of ServerManager.getAllServers()) {
124+
AppState.updateUnreadsAndMentionsPerServer(server.id, 0, false);
125+
AppState.updateExpired(server.id, false);
126+
}
127+
refs.Config?.set?.('showUnreadBadge', payload.enableUnreadBadge);
128+
refs.setUnreadBadgeSetting?.(payload.enableUnreadBadge);
129+
130+
const server = ServerManager.getAllServers().find((s: {name: string}) => s.name === payload.serverName);
131+
if (!server) {
132+
throw new Error(`Server not found: ${payload.serverName}`);
133+
}
134+
AppState.updateUnreadsAndMentionsPerServer(server.id, payload.mentions, payload.unreads);
135+
}, {serverName, mentions, unreads, enableUnreadBadge});
136+
}
137+
138+
export async function refreshBadgeStateForTest(app: ElectronApplication): Promise<void> {
139+
await evaluateInMainProcess(app, () => {
140+
const e2eTestRefsKey = '__e2eTestRefs';
141+
const refs = (global as Record<string, unknown>)[e2eTestRefsKey] as E2eGlobalRefs | undefined;
142+
refs?.AppState?.emitStatus();
143+
});
144+
}
145+
94146
export async function readOsBadge(electronApp: ElectronApplication): Promise<OsBadgeState> {
95147
return evaluateInMainProcess(electronApp, ({app}) => {
96-
const testState = (global as any).__testBadgeState;
148+
const testBadgeStateKey = '__testBadgeState';
149+
const testState = (global as Record<string, unknown>)[testBadgeStateKey] as BadgeTestState | undefined;
97150

98151
if (process.platform === 'darwin') {
99152
const badge = app.dock?.getBadge() ?? '';

0 commit comments

Comments
 (0)