Skip to content

feat(e2e): Migrate Desktop E2E to Playwright and add merged cross-OS reporting#3728

Open
yasserfaraazkhan wants to merge 85 commits intomasterfrom
add-notification-tests
Open

feat(e2e): Migrate Desktop E2E to Playwright and add merged cross-OS reporting#3728
yasserfaraazkhan wants to merge 85 commits intomasterfrom
add-notification-tests

Conversation

@yasserfaraazkhan
Copy link
Contributor

@yasserfaraazkhan yasserfaraazkhan commented Mar 15, 2026

This PR completes the Mattermost Desktop E2E migration away from the legacy Electron test stack and standardizes on Playwright.

It does three main things:

  • Migrates and stabilizes the Electron E2E suite around Playwright fixtures, shared readiness helpers, isolated userDataDirs, and embedded WebContentsView discovery for Mattermost server tabs.
  • Cleans up legacy E2E infrastructure by removing the active electron-mocha/robotjs path and modernizing CI/reporting around Playwright artifacts.
  • Improves test correctness and infra reliability by switching menu tests back to native Electron menu/edit actions and replacing shell-based orphan cleanup with PID-based teardown.

Highlights

  • Playwright is now the active E2E runner.
  • CI now publishes one merged cross-OS Playwright HTML report while keeping 3 OS-specific PR checks.
  • Menu-bar coverage is stronger:
    • view_menu uses real View menu items
    • edit_menu uses native Electron edit commands instead of a page-local shim
  • Test teardown is more robust:
    • test-mode Electron main processes register their PIDs
    • global teardown kills only registered test PIDs
  • Downloads, startup, popup, server-management, and several menu-bar specs were stabilized and verified.

Why this is better

  • More deterministic than the old OS-input-driven approach
  • Better artifacts for debugging failures: Playwright HTML report, trace, video, screenshot behavior
  • Better CI ergonomics with merged reporting across macOS, Linux, and Windows
  • Less fragile cleanup and fewer orphaned Electron processes
  • Better support for testing embedded Mattermost views that Playwright cannot see as normal windows
NONE

yasserfaraazkhan and others added 16 commits March 16, 2026 02:43
Badge E2E tests (e2e/specs/notification_trigger/):
- Add 20 Windows + 5 Linux test scenarios covering badge type priority,
  unread setting toggle, badge clearing, state transitions, and edge cases
- Add test trigger hooks to badge.ts (__testTriggerBadge, __testBadgeState,
  __testTriggerSetUnreadBadgeSetting)

Notification unit tests (src/main/notifications/):
- index.test.ts: add 23 tests covering missing view/server guards,
  String(false) sound semantics, failed events, 10s timeout, click routing
  (NOTIFICATION_CLICKED), Linux DND, Windows Priority-Only, download
  DND/show/close/failed, and displayUpgrade/displayRestartToUpgrade flows
- Mention.test.ts: 9 tests covering sound selection, icon stripping, Win7
  fallback, uId uniqueness, channelId/teamId storage
- Download.test.ts: 8 tests covering platform title/body, icon stripping,
  uId uniqueness
- Upgrade.test.ts: 6 tests covering icon stripping and localization keys

E2E test maintenance:
- Remove stale known_flaky_tests.json allowlist (all entries were dead)
- Fix deeplink.test.js and full_screen.test.js for deterministic assertions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers 45 new test scenarios across index.test.ts additions and three
new class-level test files (Mention, Download, Upgrade).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NM-11: add isPriority to windows-focus-assist mock requirement
- DD-01: specify process.platform='darwin' is required for DND path
- NM-05/06: replace contradictory 'fire after await' approach with
  correct nested describe + prototype.show override pattern

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
prototype.show override doesn't work because show is an own instance
property; replace with blockShow flag pattern consistent with NM-07.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 unit tests (PM-U01–U07) filling gaps in Calls widget routing,
external fullscreen dialog, no-mainWindow crash guard, Windows IPC
URLs, and Linux/macOS media access guards. 3 E2E IPC registration
tests (E2E-P01–P03) proving ipcMain handler wiring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plan covers PM-U01–U07 unit tests and E2E-P01–P03 IPC registration
tests for src/main/security/permissionsManager.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds and expands end-to-end and unit tests for badge, notification, and permissions behavior across platforms; exposes test-only badge hooks; replaces fullscreen sleeps with deterministic waits; increases several test timeouts; and removes the flaky-test analyzer and its known list.

Changes

Cohort / File(s) Summary
E2E Timeouts & Fullscreen
e2e/specs/deep_linking/deeplink.test.js, e2e/specs/menu_bar/full_screen.test.js
Increased Mocha timeouts to 120s; fullscreen test now waits for window.isFullScreen() via waitForFunction instead of fixed sleeps.
Notification Badge E2E
e2e/specs/notification_trigger/notification_badge_windows_linux.test.js
Adds comprehensive Windows overlay-icon and Linux setBadgeCount E2E tests, platform gating, helpers (triggerBadge, getBadgeState, resetBadgeState), and many badge scenario cases.
Permissions IPC E2E
e2e/specs/permissions/permissions_ipc.test.js
Adds IPC tests for media access status and Windows-only tests that assert ms-settings: camera/microphone URLs are opened via mocked shell.openExternal.
Removed Flaky-test Utilities
e2e/utils/analyze-flaky-test.js, e2e/utils/known_flaky_tests.json
Deletes the flaky-test analyzer and the known flaky tests JSON file (removes analyzeFlakyTests() and known lists).
Badge Test Hooks
src/app/system/badge.ts
Adds TestGlobal type; in NODE_ENV === 'test' computes resolvedType, stores {sessionExpired, mentionCount, showUnreadBadge, resolvedType} on global.__testBadgeState, and exposes global.__testTriggerBadge and global.__testTriggerSetUnreadBadgeSetting.
Notification Unit Tests
src/main/notifications/Download.test.ts, src/main/notifications/Mention.test.ts, src/main/notifications/Upgrade.test.ts
Adds unit tests covering platform-specific notification behavior (icons, localization, sound selection, UID uniqueness) with mocks for Electron, OS, UUID, i18n, and util version checks.
Notification Integration Tests Expanded
src/main/notifications/index.test.ts
Large additions covering DND/priority logic, click/close/timeout handling, active-notification lifecycle, displayDownload/Upgrade/Restart scenarios, mock controls (e.g., mockBlockShow, mockNotificationConstruct), and download-related fixtures (dlMainWindow).
Permissions Manager Tests
src/main/security/permissionsManager.test.js
Adds tests for Windows navigation to privacy settings via shell.openExternal, media permission checks, Calls widget flows, and platform-specific behavior; tests reference openWindowsCameraPreferences() and openWindowsMicrophonePreferences() usage.
Misc. Test Flow Adjustments
e2e/..., src/...
Various timeout increases and deterministic wait replacements across E2E tests; many new test files increasing test coverage and surface area.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • wiggin77
  • edgarbellot
  • esarafianou
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title mentions Playwright migration and cross-OS reporting, but the actual changeset focuses on adding E2E and unit tests for permissions, notifications, and badge behavior. Update the title to reflect the actual changes: 'test: add E2E and unit test coverage for permissions, notifications, and badge behavior' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-notification-tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Add eslint-disable-next-line no-new comments for constructor side-effect
  tests in Download, Mention, and Upgrade notification test files
- Apply auto-fix linter changes (brace style, dot notation, blank line)
- Remove superpowers design/plan docs that are no longer needed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/security/permissionsManager.test.js (1)

74-112: ⚠️ Potential issue | 🟠 Major

setForServer tests are order-dependent without mock resets.

systemPreferences mock call history persists across tests in this describe, so PM-U06/PM-U07 can fail due to previous tests rather than current behavior.

🧪 Suggested isolation fix
 describe('main/PermissionsManager', () => {
     describe('setForServer', () => {
+        beforeEach(() => {
+            systemPreferences.getMediaAccessStatus.mockReset();
+            systemPreferences.askForMediaAccess.mockReset();
+        });
+
         if (process.platform !== 'linux') {
             it('should ask for media permission when is not granted but the user explicitly granted it', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/security/permissionsManager.test.js` around lines 74 - 112, The
tests under describe('setForServer') share persisted mock call history on
systemPreferences which makes PM-U06/PM-U07 order-dependent; add a beforeEach
inside that describe to clear/reset the mocks (e.g., jest.clearAllMocks() or
specifically systemPreferences.getMediaAccessStatus.mockClear() and
systemPreferences.askForMediaAccess.mockClear()) so each test invoking
PermissionsManager.setForServer runs with a fresh mock state and does not rely
on previous test calls.
🧹 Nitpick comments (2)
e2e/utils/analyze-flaky-test.js (1)

12-21: LGTM – simplification by removing stale flaky-test allowlist.

The change correctly removes the per-OS filtering against a known flaky tests list, which aligns with the PR objective of removing the stale allowlist after fixing the flaky tests.

Minor pre-existing issue in adjacent code: The error path at line 20 returns {}, but the consuming workflow (.github/workflows/e2e-functional-template.yml) destructures newFailedTests and accesses .length. If an error occurs (e.g., report file missing), this will throw a TypeError. Consider returning a consistent shape:

♻️ Suggested fix for error handling consistency
     } catch (error) {
         console.error('Error analyzing failures:', error);
-        return {};
+        return {newFailedTests: [], os: process.platform};
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/utils/analyze-flaky-test.js` around lines 12 - 21, analyzeFlakyTests
currently returns {} on errors which breaks callers that destructure
newFailedTests and call .length; update the error path in analyzeFlakyTests to
return the same shape as the success path (e.g., { newFailedTests: [], os }) so
callers always receive newFailedTests as an array; locate and modify the catch
block in the analyzeFlakyTests function (references: readJsonFromFile,
generateShortSummary, failedFullTitles, MOCHAWESOME_REPORT_DIR) to log the error
and return the consistent object.
docs/superpowers/specs/2026-03-16-notification-unit-tests-design.md (1)

17-24: Add a language specifier to the fenced code block.

The static analysis tool flagged this code block for missing a language. Adding a language specifier (e.g., text or plaintext) improves rendering consistency and accessibility.

-```
+```text
 src/main/notifications/
   index.test.ts          ← existing file — add NM-01…NM-11, DD-01…DD-05, UV-07…UV-13
   Mention.test.ts        ← NEW (construction logic only)
   Download.test.ts       ← NEW (construction logic only)
   Upgrade.test.ts        ← NEW (NewVersionNotification + UpgradeNotification construction only)
   dnd-windows.test.js    ← existing, untouched

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/superpowers/specs/2026-03-16-notification-unit-tests-design.md around
lines 17 - 24, The fenced code block listing notification test files is missing
a language specifier; update the opening fence from to a language such astext or ```plaintext so the block containing "index.test.ts",
"Mention.test.ts", "Download.test.ts", "Upgrade.test.ts", and
"dnd-windows.test.js" is rendered with the specified language for consistent
formatting and accessibility.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @docs/superpowers/plans/2026-03-16-permissions-manager-tests.md:

  • Around line 55-57: Replace the machine-specific cd command and absolute path
    with a repo-relative instruction: remove "cd
    /Users/yasserkhan/Documents/mattermost/desktop" and instruct readers to run the
    test from the repository root using the existing npm script (e.g., "npm run
    test:unit -- --testPathPattern=permissionsManager"); alternatively suggest
    adding a package.json script like "test:permissions" that runs "npm run
    test:unit -- --testPathPattern=permissionsManager" so contributors can run a
    single, portable command.

In @src/app/system/badge.ts:

  • Around line 130-132: The test-only global __testBadgeState currently stores
    the raw inputs (sessionExpired, mentionCount, showUnreadBadge) which can hide
    bugs in the actual badge resolution; modify the test branch so it records the
    resolved badge outcome (e.g., resolvedType or resolvedBadge) from the real badge
    resolution logic instead of just inputs—locate where the badge resolution is
    computed (the variable/symbol that holds the final badge decision such as
    resolvedType/resolvedBadge in badge.ts) and include that resolved value in
    __testBadgeState along with any minimal metadata needed for E2E checks, keeping
    this change limited to the process.env.NODE_ENV === 'test' branch.

Outside diff comments:
In @src/main/security/permissionsManager.test.js:

  • Around line 74-112: The tests under describe('setForServer') share persisted
    mock call history on systemPreferences which makes PM-U06/PM-U07
    order-dependent; add a beforeEach inside that describe to clear/reset the mocks
    (e.g., jest.clearAllMocks() or specifically
    systemPreferences.getMediaAccessStatus.mockClear() and
    systemPreferences.askForMediaAccess.mockClear()) so each test invoking
    PermissionsManager.setForServer runs with a fresh mock state and does not rely
    on previous test calls.

Nitpick comments:
In @docs/superpowers/specs/2026-03-16-notification-unit-tests-design.md:

  • Around line 17-24: The fenced code block listing notification test files is
    missing a language specifier; update the opening fence from to a language such astext or ```plaintext so the block containing "index.test.ts",
    "Mention.test.ts", "Download.test.ts", "Upgrade.test.ts", and
    "dnd-windows.test.js" is rendered with the specified language for consistent
    formatting and accessibility.

In @e2e/utils/analyze-flaky-test.js:

  • Around line 12-21: analyzeFlakyTests currently returns {} on errors which
    breaks callers that destructure newFailedTests and call .length; update the
    error path in analyzeFlakyTests to return the same shape as the success path
    (e.g., { newFailedTests: [], os }) so callers always receive newFailedTests as
    an array; locate and modify the catch block in the analyzeFlakyTests function
    (references: readJsonFromFile, generateShortSummary, failedFullTitles,
    MOCHAWESOME_REPORT_DIR) to log the error and return the consistent object.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Repository UI

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `ef381e77-dfda-4922-902f-c3b08d65ee85`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3357df5215b25d9448549a9fb4dd4289051a60f4 and 4b6c60fd9d5c26f5871df234a93cf05585984f5b.

</details>

<details>
<summary>📒 Files selected for processing (15)</summary>

* `docs/superpowers/plans/2026-03-16-permissions-manager-tests.md`
* `docs/superpowers/specs/2026-03-16-notification-unit-tests-design.md`
* `docs/superpowers/specs/2026-03-16-permissions-manager-tests-design.md`
* `e2e/specs/deep_linking/deeplink.test.js`
* `e2e/specs/menu_bar/full_screen.test.js`
* `e2e/specs/notification_trigger/notification_badge_windows_linux.test.js`
* `e2e/specs/permissions/permissions_ipc.test.js`
* `e2e/utils/analyze-flaky-test.js`
* `e2e/utils/known_flaky_tests.json`
* `src/app/system/badge.ts`
* `src/main/notifications/Download.test.ts`
* `src/main/notifications/Mention.test.ts`
* `src/main/notifications/Upgrade.test.ts`
* `src/main/notifications/index.test.ts`
* `src/main/security/permissionsManager.test.js`

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* e2e/utils/known_flaky_tests.json

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

yasserfaraazkhan and others added 3 commits March 16, 2026 04:57
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add beforeEach in setForServer describe to clear systemPreferences mock
  call history, preventing PM-U06's not.toHaveBeenCalled() from testing
  against cumulative calls from prior tests
- Add resolvedType field to __testBadgeState computed from real branch
  logic, so priority/toggle E2E tests verify actual resolution not just
  raw inputs
- Assert resolvedType in W-06/07/08/09/10 and L-04 badge tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/notifications/index.test.ts`:
- Line 673: The tests currently assert on the mock-only static
Notification.didConstruct which doesn't exist on Electron's Notification type
and causes TypeScript errors; replace these with a standalone Jest mock function
(e.g., notificationConstructMock) that you call from your Notification test
double/constructor replacement and assert on that mock instead of
Notification.didConstruct; update all occurrences referenced (around the
Notification constructor checks at the previous didConstruct assertions) to
call/expect notificationConstructMock (ensure the mock is created at top of the
test file and invoked inside the mocked Notification implementation used by
tests).
- Around line 489-490: Tests are returning null from mocks but the Map.get()
usages are typed to return undefined; update the mock return values to use
undefined instead of null for
WebContentsManager.getViewByWebContentsId.mockReturnValue and
WebContentsManager.getServerByWebContentsId.mockReturnValue so they match the
expected types (MattermostWebContentsView | undefined and MattermostServer |
undefined) referenced when calling NotificationManager.displayMention; locate
those mocks and replace null with undefined to satisfy TypeScript.
- Around line 573-581: The test uses the unavailable jest.runAllTimersAsync API;
replace it with the synchronous timers API (e.g., jest.runAllTimers() or
jest.advanceTimersByTime(10000)) so the pending 10s timeout in the
NotificationManager.displayMention test is executed in Jest 29.4.1; update the
test that invokes NotificationManager.displayMention (the "NM-07" it block) to
call the synchronous jest timer helper after creating the promise and before
awaiting it.

In `@src/main/notifications/Upgrade.test.ts`:
- Around line 6-7: The test currently imports the i18nManager default as
notMockedLocalizeMessage which is incorrect for TypeScript: change the import to
use the named export localizeMessage instead of the default export (the default
is the i18nManager instance without a localizeMessage property); update the
import line to import { localizeMessage } (or rename as needed) and update any
references to notMockedLocalizeMessage to use the named localizeMessage to
restore proper typing and runtime behavior for the localizeMessage function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 69b48067-7ab0-4f40-b0c5-3ed23a064fe9

📥 Commits

Reviewing files that changed from the base of the PR and between 4b6c60f and 5e4cefc.

📒 Files selected for processing (7)
  • e2e/specs/permissions/permissions_ipc.test.js
  • e2e/utils/analyze-flaky-test.js
  • src/main/notifications/Download.test.ts
  • src/main/notifications/Mention.test.ts
  • src/main/notifications/Upgrade.test.ts
  • src/main/notifications/index.test.ts
  • src/main/security/permissionsManager.test.js
💤 Files with no reviewable changes (1)
  • e2e/utils/analyze-flaky-test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/notifications/Mention.test.ts
  • e2e/specs/permissions/permissions_ipc.test.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/security/permissionsManager.test.js (1)

119-126: Prefer testing Windows settings navigation through a public flow, not private methods.

At Lines 121 and 124, the test directly invokes internal helpers, which makes it brittle to internal refactors. Consider asserting the same behavior via the public permission-handling path that triggers these helpers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/security/permissionsManager.test.js` around lines 119 - 126, The
test calls internal helpers openWindowsCameraPreferences and
openWindowsMicrophonePreferences directly; instead exercise the public
permission-handling flow on PermissionsManager that triggers those helpers
(e.g., call the public method that requests or handles a 'camera' and
'microphone' permission), keep shell.openExternal mocked/spied, and assert that
shell.openExternal was called with 'ms-settings:privacy-webcam' and
'ms-settings:privacy-microphone'; replace direct calls to
openWindowsCameraPreferences/openWindowsMicrophonePreferences with calls to the
public permission request/handler method so the spec remains stable against
internal refactors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/system/badge.ts`:
- Around line 130-136: The nested ternary expressions used to set resolvedType
inside the process.env.NODE_ENV === 'test' block (within the process.platform
=== 'linux' and else branches) violate the lint rule; replace those ternaries
with equivalent if/else logic to preserve behavior: for the linux branch set
resolvedType to 'mention' if mentionCount > 0, else to 'expired' if
sessionExpired, else 'none'; for the non-linux branch set resolvedType to
'mention' if mentionCount > 0, else to 'unread' if both showUnreadBadge and
showUnreadBadgeSetting are true, else to 'expired' if sessionExpired, else
'none'. Ensure you update the same resolvedType variable (declared as 'let
resolvedType: ...') and keep the surrounding process.env.NODE_ENV and
process.platform checks intact.

---

Nitpick comments:
In `@src/main/security/permissionsManager.test.js`:
- Around line 119-126: The test calls internal helpers
openWindowsCameraPreferences and openWindowsMicrophonePreferences directly;
instead exercise the public permission-handling flow on PermissionsManager that
triggers those helpers (e.g., call the public method that requests or handles a
'camera' and 'microphone' permission), keep shell.openExternal mocked/spied, and
assert that shell.openExternal was called with 'ms-settings:privacy-webcam' and
'ms-settings:privacy-microphone'; replace direct calls to
openWindowsCameraPreferences/openWindowsMicrophonePreferences with calls to the
public permission request/handler method so the spec remains stable against
internal refactors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c11c1186-4559-4440-a044-b0b430e59d4a

📥 Commits

Reviewing files that changed from the base of the PR and between 5e4cefc and c5b39eb.

📒 Files selected for processing (3)
  • e2e/specs/notification_trigger/notification_badge_windows_linux.test.js
  • src/app/system/badge.ts
  • src/main/security/permissionsManager.test.js

yasserfaraazkhan and others added 5 commits March 16, 2026 05:17
- Replace static Notification.didConstruct with module-level
  mockNotificationConstruct so assertions don't rely on a property that
  doesn't exist on Electron's Notification type
- Change mockReturnValue(null) to undefined for getViewByWebContentsId
  and getServer mocks (Map.get return type is T | undefined, not null)
- Replace non-existent jest.runAllTimersAsync() with
  jest.advanceTimersByTime(10000); configure fake timers to not fake
  setImmediate so await new Promise(setImmediate) can flush displayMention's
  async chain before advancing the clock
- Fix Upgrade.test.ts to import localizeMessage as named export instead
  of accessing it via the default import (mock has no default export)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change 6 nested describe callbacks from function() to arrow functions
  in notification_badge_windows_linux.test.js so this.app is accessible
  from the outer Mocha suite context in all test callbacks
- Fix Download.test.ts to use named import for localizeMessage instead
  of default import, matching the actual export shape of i18nManager

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Design spec for migrating the Mattermost Desktop E2E test suite from
electron-mocha to @playwright/test, covering fixture architecture,
app readiness signalling, platform parallelism constraints, and
three-phase migration plan with P0/P1 new test coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detailed step-by-step plan for migrating from electron-mocha to
@playwright/test across 3 phases: foundation infrastructure, 8 new
P0/P1 tests, and complete migration of all 36 legacy test files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- webpack: fix double-dot SVG filenames ([name].[ext] → [name][ext])
- deeplink: replace waitForEvent('window') with polling for WebContentsView navigation
- focus: use cancelModal() IPC instead of page.close() to restore focus
- linux_dark_mode: use direct menu invocation instead of keyboard nav
- copy_link: increase sidebar selector timeout from 5s to 30s
- edit_menu: unify clickEditMenuItem to use direct wc API on all platforms
- file_menu: use correct menu ID (app on macOS, file elsewhere)
- full_screen: use direct menu invocation instead of three-dot + keyboard
- menu: use direct menu invocation instead of Alt + keyboard nav
- view_menu: use clickApplicationMenuItem for Find (sends Ctrl+Shift+F)
- window_menu: fix createExtraTabs() to wait for DOM and WebContentsManager
- notification_badge: reset showUnreadBadgeSetting after WIN_02 test
- drag_and_drop: poll getCurrentActiveTabView until view is registered
- tab_management: poll buildServerMap until 2 entries exist after tab create
- startup/app: add Linux platform guard for MM-T4985

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yasserfaraazkhan yasserfaraazkhan added the E2E/Run Run Desktop E2E Tests label Mar 19, 2026
yasserfaraazkhan and others added 3 commits March 19, 2026 09:37
…ns Linux guard, search focus, server view race

- linux_dark_mode: .topBar never gets darkMode class; fix selector to body.darkMode
  since setupDarkMode() adds/removes the class on document.body, not on .topBar
- permissions E2E-P01: systemPreferences.getMediaAccessStatus is not a function on
  Linux; skip the test on Linux where the API doesn't exist
- view_menu MM-T813: revert darwin to keyboard.press('Meta+f') which was passing;
  clickApplicationMenuItem → openFind() → Cmd+Shift+F does not focus search-bar on macOS CI
- focus.test.ts: buildServerMap returns when any server is found, but beforeAll needs
  both 'example' and 'community' registered; poll until both are present (up to 30s)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- deeplink.test.ts: extract inline try/catch arrow fn to named helper to
  satisfy brace-style and max-statements-per-line rules
- full_screen.test.ts: remove unused mainWindow destructure from test params

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… fallback

The remove-e2e-label job only ran when pr_number was explicitly passed as
input. The e2e-label-cleanup.yml fallback uses workflow_run which only fires
from workflows on the default branch, so it never triggered on this branch.

Fix: remove the pr_number guard (if: always() without the != '' check) and
add an inline branch-name lookup when pr_number is not provided, matching
the same logic used in removeE2ELabel(). No file checkout needed — pure
GitHub API calls via github-script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yasserfaraazkhan yasserfaraazkhan added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Mar 19, 2026
yasserfaraazkhan and others added 2 commits March 19, 2026 10:44
- Use cross-env in run:policy script so RUN_POLICY_E2E=true works on
  Windows cmd.exe (inline KEY=val syntax is bash-only)
- Switch CI reporter from dot to line for readable per-test output in
  GitHub Actions logs instead of cryptic symbols

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The remove-e2e-label job was getting HTTP 403 despite declaring
issues:write. The GitHub API response showed pull_requests=write is
also accepted for label operations on PRs. The Mattermost org appears
to restrict GITHUB_TOKEN issues scope for workflow_dispatch on
non-default branches, but pull-requests scope works.

Add pull-requests:write to both e2e-functional.yml and
e2e-label-cleanup.yml so the token has the necessary access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yasserfaraazkhan yasserfaraazkhan added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Mar 19, 2026
@github-actions github-actions bot removed the E2E/Run Run Desktop E2E Tests label Mar 19, 2026
yasserfaraazkhan and others added 4 commits March 19, 2026 11:50
PowerShell Remove-Item -ErrorAction SilentlyContinue still exits with
non-zero on Windows 2025 GitHub runners, causing execFileSync to throw.
Replace with if (Test-Path ...) { Remove-Item ... } which always exits 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- deeplink: guard afterAll against undefined userDataDir when beforeAll skips on non-Windows
- focus: add focusMainWindow() helper and call it in beforeEach to ensure OS-level window focus in CI
- copy_link: increase timeout to 15s and handle both 'Copy Link' / 'Copy link' capitalizations
- view_menu: wait for search-bar focus via waitForFunction after Cmd+F to avoid timing race
- window_menu: fall back to getAllWindows() when getFocusedWindow() returns null in headless CI
- notification_badge_in_dock: gracefully skip when CustomizeYourExperienceTour element is absent
- popout_windows: fall back to getAllWindows() when getFocusedWindow() returns null in headless CI
- bad_servers: add waitForRendererThenReload() to fix race where SSL failure fires before onLoadFailed listener registers
- drag_and_drop: replace getCurrentActiveTabView() with buildServerMap polling to fix IPC ordering race

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e state isolation

- focus.test.ts: increase waitForFunction timeout from 5s to 15s for Windows focus delivery
- view_menu.test.ts: increase waitForFunction timeout from 5s to 15s for async search bar
- drag_and_drop.test.ts: use toContainText with timeout instead of reading innerText immediately
- window_menu.test.ts: use toContainText for active tab assertion; add 15s timeout to all
  expect.poll(getActiveTabTitle) calls to accommodate Windows IPC timing
- notification_badge_windows_linux.test.ts: add top-level beforeEach to reset
  showUnreadBadgeSetting to false and clear __testBadgeState before each test, preventing
  state bleed when MM-T_BADGE_WIN_08 fails before its inline reset runs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, policy, tab_management, deeplink

- file_menu MM-T805/MM-T804: replace three-dot-menu keyboard navigation with direct
  electronApp.evaluate() menu invocation — keyboard events miss popup menus in headless CI
- full_screen MM-T816: use __e2eTestRefs.MainWindow.get() instead of getAllWindows()[0]
  when polling for fullscreen state, so we track the correct BrowserWindow
- policy MM-T_GPO_1: wait for .ServerDropdownButton to render before reading its text
- tab_management MM-TXXXX_1: add 15s timeout to waitForSelector calls for
  #sidebarItem_off-topic and .serverTabItem__close, which render slowly on Windows CI
- deeplink MM-T1304/MM-T1306: replace 2s fixed delay + single retry with expect.poll
  (15s timeout) to reliably wait for the github server view to register in buildServerMap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yasserfaraazkhan yasserfaraazkhan added the E2E/Run Run Desktop E2E Tests label Mar 19, 2026
@github-actions github-actions bot removed the E2E/Run Run Desktop E2E Tests label Mar 19, 2026
…nd artifact warning

- focus.test.ts: rewrite focusMainWindow to use __e2eTestRefs.MainWindow.get()
  and call show() before focus() so isFocused() returns true on headless Linux
- window_menu.test.ts: prefer __e2eTestRefs.MainWindow.get() over
  getAllWindows().find() as menu click target to avoid targeting wrong window
- popout_windows.test.ts: same fix for clickFileMenuItem's target window
- e2e-functional.yml: remove if-no-files-found from actions/download-artifact
  step (not a valid input for that action, only valid for upload-artifact)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yasserfaraazkhan yasserfaraazkhan added the E2E/Run Run Desktop E2E Tests label Mar 19, 2026
Adds a new workflow (e2e-pr-trigger.yml) that fires on pull_request
events (opened, reopened, ready_for_review, synchronize) against master
and automatically adds the E2E/Run label when the PR is not in draft
status.

The label is removed-then-re-added on every event so the labeled webhook
always fires — even when tests are already running for a previous commit.
This ensures Matterwick provisions servers and triggers e2e-functional.yml
for every qualifying commit without manual intervention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Mar 19, 2026
- Cancel all in_progress/queued/waiting Electron Playwright Tests runs
  before re-adding the E2E/Run label on synchronize events.
  Matterwick dispatches e2e-functional.yml via workflow_dispatch with
  the default branch as ref (head_branch=master for all runs), making
  PR-specific filtering unreliable — so all non-terminal runs are
  cancelled, which is correct since only one labelled PR triggers tests
  at a time.
- Add concurrency group (e2e-pr-trigger-{PR}) with cancel-in-progress so
  rapid successive pushes collapse into a single label operation.
- Add actions: write permission for the cancel API call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Mar 19, 2026
- focus.test.ts: skip Focus textbox tests on Linux and in CI environments
  where BrowserWindow.isFocused() is unreliable (headless Xvfb on Linux,
  GitHub Actions macOS runners); MattermostWebContentsView.focus() silently
  no-ops when isFocused() returns false so these tests require a real
  interactive desktop session
- window_menu.test.ts: retry clickWindowMenuItem on 'not found' errors so
  the 15 s deadline absorbs the async menu rebuild MenuManager does after
  TAB_ADDED fires (CmdOrCtrl+2 accelerator may not exist yet immediately
  after createExtraTabs)
- popout_windows.test.ts: drop URL predicate from waitForEvent('window');
  Playwright fires the event at BrowserWindow creation before PopoutManager
  calls loadURL, so the URL is still blank when the predicate runs; now
  catch any new window then waitForURL('**/popout.html')
- drag_and_drop.test.ts: increase sidebar selector timeouts 15 s → 30 s
  and toContainText timeouts 10 s → 15 s for newly created tab views that
  take longer to render the channel list on slow CI runners
- tab_management.test.ts: same sidebar selector timeout increase 15 s → 30 s
- helpers/menu.ts: add __e2eTestRefs.MainWindow.get() fallback in
  clickApplicationMenuItem; BrowserWindow.getFocusedWindow() returns null
  on headless CI so getAllWindows()[0] previously returned the wrong window
  (dropdown/modal), causing DevTools to open on the wrong target (MM-T820)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants