Skip to content

test(e2e): Mattermost webapp interaction, channel UI, and downloads - #3857

Merged
yasserfaraazkhan merged 17 commits into
masterfrom
e2e/03-mattermost-shell
Jul 2, 2026
Merged

test(e2e): Mattermost webapp interaction, channel UI, and downloads#3857
yasserfaraazkhan merged 17 commits into
masterfrom
e2e/03-mattermost-shell

Conversation

@yasserfaraazkhan

@yasserfaraazkhan yasserfaraazkhan commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary:

  • New shared helpers (mattermostShell, team, channelMenu, downloads, downloadsDropdown) — these are the interaction layer for anything that touches the loaded Mattermost webapp or file downloads.

  • mattermostShell / team — login recovery, shell readiness, team sidebar after API fallback. Bookmarks and custom groups specs exercise the trickiest paths (session/API, sidebar state).

  • Downloads — local HTTP server in downloads.ts plus IPC to drive the downloads dropdown/manager. Teardown uses Promise.allSettled and fast app close

  • Specs are the contract — if a helper API feels awkward, check whether the spec reads clearly

Release Note

NONE

Change Impact: 🟡 Medium

Regression Risk: Shared E2E helpers were added/expanded across many Mattermost and downloads specs, including complex renderer DOM/editor interactions, shell/server-view readiness + reload recovery, and authenticated API flows (login, channel/team resolution, team creation). While scoped to the E2E harness (not production code), selector/IPC/browser-context assumptions and session/token handling could affect multiple test suites and introduce flakiness.

QA Recommendation: Prefer full CI execution of all affected Mattermost UI/specs (copy link/context menus/bookmarks/custom groups/alt-enter) and downloads E2E suites (open/cancel/clear/all/manager/dropdown items/video). Minimal manual QA only if needed: one quick smoke run locally for (1) composing/post editor insertion and (2) a basic download flow (open or cancel) to catch obvious selector/IPC issues.
Generated by CodeRabbitAI

Part 1 of splitting #3847 — core Playwright config, fixtures, electronApp
teardown, and GitHub Actions E2E workflow updates. No new specs yet.
Exposes __e2eTestRefs, message-box stub, tray/deep-link hooks (NODE_ENV=test
only) plus directLaunch, testRefs, and shared helper updates.
@mm-cloud-bot

Copy link
Copy Markdown

@yasserfaraazkhan: Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

I understand the commands that are listed here

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

This PR adds shared E2E helpers for Mattermost, downloads, and GitHub status handling, then updates Mattermost and downloads Playwright specs to use them. It also changes E2E workflow cancellation and final-status logic for PR-triggered runs and overrides.

Changes

E2E Helper, Spec, and Workflow Updates

Layer / File(s) Summary
Server API helpers and team setup
e2e/helpers/server_api/*.ts, e2e/helpers/team.ts
Adds shared login, request, channel, credential, and team API helpers, and rewrites team setup to use the shared API flow.
Shell, menu, and bookmark helpers
e2e/helpers/mattermostShell.ts, e2e/helpers/channelMenu.ts, e2e/helpers/badServer.ts
Adds server-shell readiness, textbox, menu, bookmark, and bad-server error helpers for Mattermost UI flows.
Download helpers
e2e/helpers/downloads.ts, e2e/helpers/downloadsDropdown.ts
Adds download server, app launch, dropdown, state polling, file polling, teardown, and dropdown-close helpers.
Workflow status and cancellation updates
.github/actions/cancel-e2e-runs/action.yml, .github/workflows/e2e-functional*.yml, .github/workflows/e2e-pr-trigger.yml, e2e/utils/*.js
Updates flaky-test analysis, commit-status handling, cancellation helpers, and E2E workflow triggers and actions.
Mattermost specs
e2e/specs/mattermost/*.test.ts
Adds and updates Mattermost specs for bookmarks, copy link, context menus, custom groups, Alt+Enter, external links, notification navigation, bad servers, drag-and-drop recovery, and window close behavior.
Downloads specs
e2e/specs/downloads/*.test.ts
Adds download cancel, clear-all, open, completion, dropdown-items, manager, menubar, and video download tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • mattermost/desktop#3858: Shares the Mattermost E2E helper and server-view readiness work used by several updated specs here.
  • mattermost/desktop#3859: Overlaps with the downloads helpers and download-spec changes included in this PR.

Suggested reviewers: devinbinnie, NARSimoes, saturninoabril

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main scope: Mattermost E2E webapp interactions, channel UI, and downloads.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch e2e/03-mattermost-shell

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

@yasserfaraazkhan yasserfaraazkhan changed the title E2E: Mattermost shell helpers — bookmarks, custom groups (3/10) E2E: Mattermost shell helpers — bookmarks, custom groups Jun 19, 2026
Base automatically changed from e2e/02-main-hooks to e2e/01-harness-ci June 19, 2026 11:21
Base automatically changed from e2e/01-harness-ci to master June 30, 2026 23:13
Resolve conflicts by keeping merged harness/hook fixes from #3855
and retaining PR 3 Mattermost shell helpers and specs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added the E2E/Run Run Desktop E2E Tests label Jun 30, 2026
@mm-cloud-bot

Copy link
Copy Markdown

❌ E2E Test Setup Failed

Failed to create E2E test instances: installation wait cancelled: context canceled

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (3)
e2e/specs/mattermost/custom_groups.test.ts (2)

56-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate menu-item lookup logic.

The hasGroupsMenuItem check (lines 56-64) and the groupsClicked evaluate (lines 74-87) repeat the same selector and lowercase text-matching logic. Consider combining into a single evaluate() call that locates and clicks the item in one pass, returning whether it was found/clicked.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/specs/mattermost/custom_groups.test.ts` around lines 56 - 87, The product
switcher lookup is duplicated in the custom_groups test, with the same selector
and text-matching logic used for both `hasGroupsMenuItem` and `groupsClicked`.
Refactor the `firstServer!.evaluate()` flow to locate and click the User Groups
item in one pass, returning whether it was found/clicked and using that result
to decide whether to `test.skip()`. Keep the logic centered around the existing
`hasGroupsMenuItem`/`groupsClicked` block in `custom_groups.test.ts`.

45-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use locator() for the product switcher query. locator() keeps Playwright’s auto-waiting and retry behavior for the click path, while $() returns a static ElementHandle.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/specs/mattermost/custom_groups.test.ts` at line 45, The product switcher
lookup in the custom groups test is using a static ElementHandle from $(), which
bypasses Playwright’s auto-waiting. Update the query in the test around the
product switcher selection to use locator() on firstServer instead, and keep the
subsequent click path working off that locator so retries and waiting are
preserved.
e2e/specs/mattermost/bookmarks.test.ts (1)

45-48: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Move shared login/channel setup to beforeAll() for this serial suite.

The suite is serial, but each test calls loginToOffTopicChannel(). Share the login/channel setup once and reuse the prepared ServerView.

As per coding guidelines, “Use shared login in beforeAll() for serial test suites instead of beforeEach() to avoid repeating expensive login operations.”

Also applies to: 73-73, 99-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/specs/mattermost/bookmarks.test.ts` around lines 45 - 48, The serial
`mattermost/bookmarks` suite is repeating expensive setup by calling
`loginToOffTopicChannel()` in each test instead of sharing it once. Move the
shared login/channel preparation into `beforeAll()` in this suite, store the
resulting `ServerView`, and have the tests reuse that prepared state rather than
logging in again. Update the affected tests that currently call
`loginToOffTopicChannel()` so they consume the shared setup instead.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e/helpers/mattermostShell.ts`:
- Around line 8-13: The fallback in POST_TEXTBOX_SELECTOR is too broad because
bare [role="textbox"] can match non-composer inputs; scope this selector so it
only targets the post composer area and not search or modal fields. Update the
selector constant in mattermostShell and review the keyboard-typing flow that
relies on it in the referenced helper methods so the active element path always
resolves to the composer textbox before typing.
- Around line 231-237: The textarea branch in mattermostShell’s caret/marker
coordinate calculation is using the marker’s left edge for x, unlike the
contenteditable path which targets the word center. Update the x value returned
from the textarea-related logic to use the midpoint of the marker rectangle,
while keeping the existing y calculation unchanged, so the click lands on the
textarea word center and reduces spell-check menu misses.
- Around line 113-116: The textarea/input branch in mattermostShell helper is
setting value directly, which can make the helper report success before the app
has actually processed the input event. Update the typing path in the relevant
helper to use the native value setter pattern used by
serverView::__mmSetElementValue instead of assigning root.value directly, then
keep dispatching the input event and verifying the updated value so the keyboard
fallback still runs when needed.

In `@e2e/helpers/team.ts`:
- Around line 135-158: The fallback path in ensure teams handling can return
before the sidebar is ready when ensureMultipleTeamsViaApi(app, serverUrl,
username, password) succeeds with created=false. Update the ensure flow in
team.ts so the readiness waits for `#sidebarItem_town-square` and
`#teamSidebarWrapper` run after the API fallback as well, not only inside the
created branch, while keeping the existing renderer execution and reload logic
in app.evaluate/webContents.

In `@e2e/specs/mattermost/bookmarks.test.ts`:
- Around line 116-203: Move the bookmark cleanup into the existing try/finally
flow so it always runs even when assertions fail. Keep the external-bookmark
test logic in the try block, and call deleteAllBookmarksInBar(firstServer!) from
the finally section (alongside shell.openExternal restoration) so the created
bookmark is removed regardless of test outcome.
- Around line 6-13: The helper import block in bookmarks.test.ts is out of order
within the sibling/parent group. Reorder the imports in the test file to match
the repository’s ESLint import order, keeping groups separated by blank lines
and alphabetized within the group; use the existing symbols like
openChannelHeaderMenu, enableBookmarksBar, closeOverlayWindowsIfOpen,
loginToMattermost, prepareMattermostServerView, and waitForMattermostShell as
the location to update.
- Around line 164-184: The bookmark URL check in the server view inspection uses
substring matching, which can falsely match app/server URLs hosted on the same
domain. Update the assertion around serverViewURLs to compare parsed URL
components instead of using includes('mattermost.com'), and reuse the same
origin/path matching approach used for the actual external bookmark URL so the
test only flags real navigations to the bookmark target.

In `@e2e/specs/mattermost/custom_groups.test.ts`:
- Around line 25-36: The current custom_groups.test.ts beforeEach only skips
when MM_TEST_SERVER_URL is missing, but it still calls loginToMattermost even
when MM_TEST_USER_NAME or MM_TEST_PASSWORD are unset. Update the beforeEach
setup to validate the Mattermost login credentials before invoking
loginToMattermost, and skip the test suite gracefully when either credential is
missing, similar to the existing MM_TEST_SERVER_URL guard. Keep the check near
the existing serverMap/demoMattermostConfig login setup so the behavior is
handled consistently before firstServer is used.

---

Nitpick comments:
In `@e2e/specs/mattermost/bookmarks.test.ts`:
- Around line 45-48: The serial `mattermost/bookmarks` suite is repeating
expensive setup by calling `loginToOffTopicChannel()` in each test instead of
sharing it once. Move the shared login/channel preparation into `beforeAll()` in
this suite, store the resulting `ServerView`, and have the tests reuse that
prepared state rather than logging in again. Update the affected tests that
currently call `loginToOffTopicChannel()` so they consume the shared setup
instead.

In `@e2e/specs/mattermost/custom_groups.test.ts`:
- Around line 56-87: The product switcher lookup is duplicated in the
custom_groups test, with the same selector and text-matching logic used for both
`hasGroupsMenuItem` and `groupsClicked`. Refactor the `firstServer!.evaluate()`
flow to locate and click the User Groups item in one pass, returning whether it
was found/clicked and using that result to decide whether to `test.skip()`. Keep
the logic centered around the existing `hasGroupsMenuItem`/`groupsClicked` block
in `custom_groups.test.ts`.
- Line 45: The product switcher lookup in the custom groups test is using a
static ElementHandle from $(), which bypasses Playwright’s auto-waiting. Update
the query in the test around the product switcher selection to use locator() on
firstServer instead, and keep the subsequent click path working off that locator
so retries and waiting are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d28cae97-6274-4d88-8b52-5d1d31bf03be

📥 Commits

Reviewing files that changed from the base of the PR and between 08129c4 and a2f373b.

📒 Files selected for processing (4)
  • e2e/helpers/mattermostShell.ts
  • e2e/helpers/team.ts
  • e2e/specs/mattermost/bookmarks.test.ts
  • e2e/specs/mattermost/custom_groups.test.ts

Comment thread e2e/helpers/mattermostShell.ts Outdated
Comment thread e2e/helpers/mattermostShell.ts
Comment thread e2e/helpers/mattermostShell.ts
Comment thread e2e/helpers/team.ts Outdated
Comment thread e2e/specs/mattermost/bookmarks.test.ts
Comment thread e2e/specs/mattermost/bookmarks.test.ts Outdated
Comment thread e2e/specs/mattermost/bookmarks.test.ts
Comment thread e2e/specs/mattermost/custom_groups.test.ts
Scope post textbox selectors, use native value setter for inputs,
center textarea spell-check coordinates, wait for team sidebar after
API fallback, and harden bookmarks/custom_groups test cleanup and skips.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Jun 30, 2026
@mm-cloud-bot

Copy link
Copy Markdown

❌ E2E Test Setup Failed

Failed to create E2E test instances: failed to create installation: failed with status code 409

@yasserfaraazkhan

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yasserfaraazkhan yasserfaraazkhan added E2E/Reset-Servers Destroy E2E server for a fresh Run. Add E2E/Run label to kick off an e2e run. and removed E2E/Run Run Desktop E2E Tests E2E/Reset-Servers Destroy E2E server for a fresh Run. Add E2E/Run label to kick off an e2e run. labels Jul 1, 2026
* E2E: channelMenu helper and Mattermost UI specs (4/10).

* Remove local-only files accidentally included in master merge

tray_menu.test.ts belongs in the tray/deeplink PR; split-e2e-prs.sh
is a local helper script, not part of the migration stack.

Fail bookmark cleanup after retry exhaustion and guard serverEntry
before prepareMattermostServerView in copy_link.test.ts.
@github-actions github-actions Bot added the E2E/Run Run Desktop E2E Tests label Jul 1, 2026
* E2E: Downloads helpers and specs (5/10).

* Address CodeRabbit review on downloads E2E helpers and specs

Handle download server bind errors, use closeElectronAppFast, close the
dropdown via IPC, guard teardown with allSettled, and store openPath
captures on __e2eTestRefs.
@github-actions github-actions Bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Jul 1, 2026
@github-actions github-actions Bot removed the E2E/Run Run Desktop E2E Tests label Jul 1, 2026
…res.

Extract shared ErrorView wait logic that accounts for retry timing and transient ERR_ABORTED during reloads, accept modern Chromium connection-reset errors for RC4 endpoints, and restore Mattermost shell readiness after drag-and-drop state resets.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added the E2E/Run Run Desktop E2E Tests label Jul 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/e2e-functional.yml (1)

118-130: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Script-injection risk: ${{ inputs.pr_number }} expanded directly into the JS template.

Interpolating ${{ inputs.pr_number }} straight into the script: string lets its raw value become literal JS source before execution — the classic GitHub Actions script-injection pattern (flagged by zizmor as template-injection). The remove-e2e-label job later in this same file already uses the safe pattern (env: PR_NUMBER: ... + process.env.PR_NUMBER); this new code should follow the same convention instead.

🔒️ Proposed fix: pass the input via env instead of template expansion
       - name: Update final status for all platforms
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
         with:
           github-token: ${{ github.token }}
+          env:
+            PR_NUMBER: ${{ inputs.pr_number }}
           script: |
             const { updateFinalStatus } = require('./e2e/utils/github-actions.js');
             const platforms = ${{ needs.prepare-matrix.outputs.platforms }};
             const outputs = ${{ toJSON(needs.e2e-tests.outputs) }};
-            const prNumber = parseInt('${{ inputs.pr_number }}', 10) || null;
+            const prNumber = parseInt(process.env.PR_NUMBER, 10) || null;
             await updateFinalStatus({

Flagging: zizmor static analysis reported error 122-122: code injection via template expansion (template-injection) for this line.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e-functional.yml around lines 118 - 130, The
`update-final-status` step is using unsafe template expansion for
`inputs.pr_number`, which can inject raw content into the JavaScript source.
Move the PR number into an environment variable in the workflow step and read it
from `process.env` inside the script, following the same safe pattern already
used by the `remove-e2e-label` job; keep the rest of the `updateFinalStatus`
call unchanged.

Source: Linters/SAST tools

♻️ Duplicate comments (1)
e2e/helpers/team.ts (1)

17-43: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Sidebar readiness wait is still skipped when no team was created.

This is the same class of issue flagged on a prior commit for this function (then addressed for the renderer+API-fallback version). The function has been rewritten to only use the API path, but the readiness wait (#sidebarItem_town-square / #teamSidebarWrapper) is still gated behind result.created. If the user already had ≥2 teams before this call, the function returns immediately with no wait, and a caller could proceed before the sidebar has actually rendered.

🩺 Proposed fix: always wait for sidebar readiness
     if (result.created) {
         await app.evaluate(async ({webContents}, id) => {
             const wc = webContents.fromId(id);
             if (!wc || wc.isDestroyed()) {
                 throw new Error(`webContents ${id} is not available`);
             }
             await wc.executeJavaScript('window.location.reload()', true);
         }, webContentsId);
-
-        await win.waitForSelector('`#sidebarItem_town-square`', {timeout: 30_000});
-        await win.waitForSelector('`#teamSidebarWrapper`', {state: 'visible', timeout: 30_000});
     }
+
+    await win.waitForSelector('`#sidebarItem_town-square`', {timeout: 30_000});
+    await win.waitForSelector('`#teamSidebarWrapper`', {state: 'visible', timeout: 30_000});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/team.ts` around lines 17 - 43, The sidebar readiness wait in
ensureMultipleTeams is still incorrectly tied to result.created, so callers can
continue before the UI is ready when no team was newly created. Update
ensureMultipleTeams to always perform the sidebar waits for
`#sidebarItem_town-square` and `#teamSidebarWrapper` after the API check, while
keeping the reload/webContents logic only for the created path. Use the existing
ensureMultipleTeams, app.evaluate, and win.waitForSelector flow so the readiness
check happens on every call.
🧹 Nitpick comments (6)
e2e/helpers/mattermostShell.ts (1)

74-96: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated post-textbox selector list risks drift from POST_TEXTBOX_SELECTOR.

This candidate list overlaps heavily with POST_TEXTBOX_SELECTOR (used by pressPostTextboxKey) but is maintained separately. If one is updated (e.g., to scope the composer more tightly, as done in a prior fix) without updating the other, getPostTextboxValue and keyboard-based interactions could target different elements.

Consider deriving both from a single shared array of selector strings, e.g.:

export const POST_TEXTBOX_CANDIDATES = [
    '[data-slate-editor="true"]',
    '`#post_textbox`[contenteditable="true"]',
    // ...
];
export const POST_TEXTBOX_SELECTOR = POST_TEXTBOX_CANDIDATES.join(', ');

Then use POST_TEXTBOX_CANDIDATES inside the renderer script for getPostTextboxValue.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/mattermostShell.ts` around lines 74 - 96, The post textbox
selector logic is duplicated between getPostTextboxValue and
POST_TEXTBOX_SELECTOR, which can drift and cause the value lookup and keyboard
helpers to target different elements. Refactor mattermostShell.ts so both
getPostTextboxValue and pressPostTextboxKey share a single source of truth,
ideally a reusable POST_TEXTBOX_CANDIDATES array or equivalent helper, and have
POST_TEXTBOX_SELECTOR derive from it while getPostTextboxValue uses the same
shared candidates inside the renderer script.
e2e/helpers/server_api/client.ts (1)

27-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Spreading init.headers silently drops headers when a Headers instance is passed.

RequestInit['headers'] can be a Headers object, plain record, or tuple array. Object spread only copies own enumerable properties, and Headers doesn't expose entries that way, so ...init.headers becomes a no-op for Headers instances — any caller-supplied headers would be silently lost. No current caller passes a Headers instance, but this is a shared low-level helper intended for reuse by later PRs in the stack.

♻️ Proposed fix to normalize headers before spreading
     const response = await fetch(`${baseUrl}${path}`, {
         ...init,
         headers: {
             Authorization: `Bearer ${token}`,
             'Content-Type': 'application/json',
-            ...init.headers,
+            ...Object.fromEntries(new Headers(init.headers ?? {})),
         },
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/server_api/client.ts` around lines 27 - 46, The apiRequest helper
merges headers by spreading init.headers, which breaks when callers pass a
Headers instance because its entries are not enumerable and get dropped. Update
apiRequest to normalize RequestInit['headers'] before merging in the fetch call,
so Authorization and Content-Type are combined with any caller-supplied headers
regardless of whether they are a Headers object, plain record, or tuple array.
e2e/utils/github-actions.js (1)

185-230: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

cancelActiveE2ERuns may miss active runs beyond the first page.

listWorkflowRuns is queried per status with per_page: 20 and no branch filter, then filtered client-side by runBelongsToPr. If more than 20 runs are active for a given status across the whole workflow (busy repo, many concurrent PRs), runs beyond the first page for this PR's branch are silently skipped and never cancelled. The API supports a branch query parameter to filter server-side, which would avoid this pagination gap entirely.

♻️ Proposed fix: filter server-side by branch
     for (const status of ACTIVE_RUN_STATUSES) {
         const {data: {workflow_runs: workflowRuns}} = await github.rest.actions.listWorkflowRuns({
             owner,
             repo,
             workflow_id: e2eWorkflow.id,
             status,
+            branch,
             per_page: 20,
         });

         for (const run of workflowRuns) {
-            if (!runBelongsToPr(run, branch)) {
-                console.log(`Skipping E2E run ${run.id} (branch ${run.head_branch ?? 'unknown'} != ${branch})`);
-                continue;
-            }
-
             try {

Based on GitHub's REST API documentation, the "List workflow runs for a workflow" endpoint accepts a branch parameter to narrow results server-side, which would eliminate this pagination risk.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/utils/github-actions.js` around lines 185 - 230, `cancelActiveE2ERuns`
can skip active runs because `listWorkflowRuns` only fetches the first 20
results per status and filters by branch in memory. Update the workflow-runs
lookup in `cancelActiveE2ERuns` to pass the resolved branch from
`resolvePrHeadBranch` as a server-side `branch` filter when calling
`github.rest.actions.listWorkflowRuns`, and keep the existing `runBelongsToPr`
guard as a safety check. This will ensure all matching runs for the PR branch
are considered before cancellation.
e2e/specs/server_management/bad_servers.test.ts (1)

293-295: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a Locator instead of the legacy page.$() handle.

mainWindow.$('.ErrorView') returns a one-shot ElementHandle with no auto-waiting/retrying, unlike mainWindow.locator('.ErrorView'). Purely stylistic here since the app is meant to be settled/trusted at this point.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/specs/server_management/bad_servers.test.ts` around lines 293 - 295, The
`bad_servers.test.ts` check is using the legacy one-shot `page.$()` handle for
`.ErrorView`; switch this lookup in `getMainWindow(app)` usage to a `Locator` so
it matches the newer Playwright pattern. Update the `errorView` assignment to
use `mainWindow.locator('.ErrorView')` and keep the rest of the test flow
unchanged.
e2e/helpers/badServer.ts (2)

69-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated terminal-failure detection logic.

waitForTerminalLoadFailure (lines 76-90) and waitForRendererReadyThenReload's inline hasTerminalFailure (lines 102-111) implement the identical isVisible('.ErrorView') + innerText('.ErrorView-techInfo') + ERR_ABORTED check. Extracting a shared helper avoids the two copies drifting apart.

♻️ Extract shared helper
+async function isTerminalFailure(mainWindow: Page, acceptedError: RegExp): Promise<{matched: boolean; errorInfo: string}> {
+    if (!(await mainWindow.isVisible('.ErrorView'))) {
+        return {matched: false, errorInfo: ''};
+    }
+    const errorInfo = await mainWindow.innerText('.ErrorView-techInfo');
+    if ((/ERR_ABORTED/).test(errorInfo) && !acceptedError.test(errorInfo)) {
+        return {matched: false, errorInfo};
+    }
+    return {matched: acceptedError.test(errorInfo), errorInfo};
+}

Then use it inside both waitForTerminalLoadFailure's poll callback and waitForRendererReadyThenReload's hasTerminalFailure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/badServer.ts` around lines 69 - 118, The terminal-failure
detection logic is duplicated between waitForTerminalLoadFailure and the inline
hasTerminalFailure check inside waitForRendererReadyThenReload, so extract the
shared isVisible('.ErrorView') plus innerText('.ErrorView-techInfo') with
ERR_ABORTED filtering into a helper in badServer.ts and reuse it in both places.
Keep the acceptedError RegExp handling and return shape the same, and have
waitForTerminalLoadFailure’s expect.poll and waitForRendererReadyThenReload’s
reload decision call that helper instead of maintaining separate copies.

29-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use ElectronApplication directly here. e2e/helpers/badServer.ts can replace the computed alias with Playwright’s exported type, matching the rest of the e2e helpers and keeping the signature simpler.

♻️ Simplify the type alias
-import {expect} from '`@playwright/test`';
-import type {Page} from 'playwright';
+import {expect} from '`@playwright/test`';
+import type {ElectronApplication, Page} from 'playwright';
...
-type ElectronApp = Awaited<ReturnType<typeof import('playwright')['_electron']['launch']>>;
+type ElectronApp = ElectronApplication;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/badServer.ts` around lines 29 - 35, The helper type alias in
getMainWindow is overcomplicated and should use Playwright’s exported
ElectronApplication type directly instead of computing it from
import('playwright')['_electron']['launch']. Update the ElectronApp alias to
match the rest of the e2e helpers, then keep getMainWindow’s signature the same
but backed by the simpler exported type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e-pr-trigger.yml:
- Around line 26-35: The workflow-level permissions are too broad and should be
narrowed to each job’s actual needs. Move the GitHub permissions from the
top-level block into the individual jobs in e2e-pr-trigger.yml, especially
around cancel-on-manual-unlabel and the other job that handles label changes, so
each job only gets the specific scopes it uses. Remove any unused pull-requests:
write grant and keep actions/statuses only where the composite action or API
calls actually require them.

In `@e2e/helpers/badServer.ts`:
- Around line 22-27: The INSECURE_CIPHER_ERROR fallback in badServer.ts is using
the wrong Chromium error prefix, so it won’t match ERR_NETWORK_* terminal
failures. Update the INSECURE_CIPHER_ERROR regex to cover NETWORK_ (or
explicitly list the relevant ERR_NETWORK_* codes such as ERR_NETWORK_CHANGED and
ERR_NETWORK_IO_SUSPENDED) while keeping the existing SSL and connection-reset
cases.

In `@e2e/helpers/server_api/channel.ts`:
- Around line 39-64: The 404 detection in resolveChannelByName is brittle
because it relies on message.includes('404') inside the team loop. Update
apiGetChannelByName handling to use a typed error or explicit status code check
instead of parsing the error message, and only continue on a real not-found
response. Keep resolveChannelByName and its catch block as the lookup flow, but
make the decision based on structured error data so non-404 failures are
rethrown immediately.

---

Outside diff comments:
In @.github/workflows/e2e-functional.yml:
- Around line 118-130: The `update-final-status` step is using unsafe template
expansion for `inputs.pr_number`, which can inject raw content into the
JavaScript source. Move the PR number into an environment variable in the
workflow step and read it from `process.env` inside the script, following the
same safe pattern already used by the `remove-e2e-label` job; keep the rest of
the `updateFinalStatus` call unchanged.

---

Duplicate comments:
In `@e2e/helpers/team.ts`:
- Around line 17-43: The sidebar readiness wait in ensureMultipleTeams is still
incorrectly tied to result.created, so callers can continue before the UI is
ready when no team was newly created. Update ensureMultipleTeams to always
perform the sidebar waits for `#sidebarItem_town-square` and `#teamSidebarWrapper`
after the API check, while keeping the reload/webContents logic only for the
created path. Use the existing ensureMultipleTeams, app.evaluate, and
win.waitForSelector flow so the readiness check happens on every call.

---

Nitpick comments:
In `@e2e/helpers/badServer.ts`:
- Around line 69-118: The terminal-failure detection logic is duplicated between
waitForTerminalLoadFailure and the inline hasTerminalFailure check inside
waitForRendererReadyThenReload, so extract the shared isVisible('.ErrorView')
plus innerText('.ErrorView-techInfo') with ERR_ABORTED filtering into a helper
in badServer.ts and reuse it in both places. Keep the acceptedError RegExp
handling and return shape the same, and have waitForTerminalLoadFailure’s
expect.poll and waitForRendererReadyThenReload’s reload decision call that
helper instead of maintaining separate copies.
- Around line 29-35: The helper type alias in getMainWindow is overcomplicated
and should use Playwright’s exported ElectronApplication type directly instead
of computing it from import('playwright')['_electron']['launch']. Update the
ElectronApp alias to match the rest of the e2e helpers, then keep
getMainWindow’s signature the same but backed by the simpler exported type.

In `@e2e/helpers/mattermostShell.ts`:
- Around line 74-96: The post textbox selector logic is duplicated between
getPostTextboxValue and POST_TEXTBOX_SELECTOR, which can drift and cause the
value lookup and keyboard helpers to target different elements. Refactor
mattermostShell.ts so both getPostTextboxValue and pressPostTextboxKey share a
single source of truth, ideally a reusable POST_TEXTBOX_CANDIDATES array or
equivalent helper, and have POST_TEXTBOX_SELECTOR derive from it while
getPostTextboxValue uses the same shared candidates inside the renderer script.

In `@e2e/helpers/server_api/client.ts`:
- Around line 27-46: The apiRequest helper merges headers by spreading
init.headers, which breaks when callers pass a Headers instance because its
entries are not enumerable and get dropped. Update apiRequest to normalize
RequestInit['headers'] before merging in the fetch call, so Authorization and
Content-Type are combined with any caller-supplied headers regardless of whether
they are a Headers object, plain record, or tuple array.

In `@e2e/specs/server_management/bad_servers.test.ts`:
- Around line 293-295: The `bad_servers.test.ts` check is using the legacy
one-shot `page.$()` handle for `.ErrorView`; switch this lookup in
`getMainWindow(app)` usage to a `Locator` so it matches the newer Playwright
pattern. Update the `errorView` assignment to use
`mainWindow.locator('.ErrorView')` and keep the rest of the test flow unchanged.

In `@e2e/utils/github-actions.js`:
- Around line 185-230: `cancelActiveE2ERuns` can skip active runs because
`listWorkflowRuns` only fetches the first 20 results per status and filters by
branch in memory. Update the workflow-runs lookup in `cancelActiveE2ERuns` to
pass the resolved branch from `resolvePrHeadBranch` as a server-side `branch`
filter when calling `github.rest.actions.listWorkflowRuns`, and keep the
existing `runBelongsToPr` guard as a safety check. This will ensure all matching
runs for the PR branch are considered before cancellation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a92ddf68-382b-41f5-a779-f1a4859fb236

📥 Commits

Reviewing files that changed from the base of the PR and between 0922144 and f7aa85b.

📒 Files selected for processing (24)
  • .github/actions/cancel-e2e-runs/action.yml
  • .github/workflows/e2e-functional-template.yml
  • .github/workflows/e2e-functional.yml
  • .github/workflows/e2e-pr-trigger.yml
  • e2e/helpers/badServer.ts
  • e2e/helpers/channelMenu.ts
  • e2e/helpers/downloads.ts
  • e2e/helpers/downloadsDropdown.ts
  • e2e/helpers/mattermostShell.ts
  • e2e/helpers/server_api/channel.ts
  • e2e/helpers/server_api/client.ts
  • e2e/helpers/server_api/credentials.ts
  • e2e/helpers/server_api/team.ts
  • e2e/helpers/team.ts
  • e2e/specs/downloads/download_clear_all.test.ts
  • e2e/specs/downloads/video_download.test.ts
  • e2e/specs/mattermost/alt_enter.test.ts
  • e2e/specs/mattermost/context_menu.test.ts
  • e2e/specs/mattermost/custom_groups.test.ts
  • e2e/specs/notification_trigger/notification_click.test.ts
  • e2e/specs/server_management/bad_servers.test.ts
  • e2e/specs/server_management/drag_and_drop.test.ts
  • e2e/utils/analyze-flaky-test.js
  • e2e/utils/github-actions.js
💤 Files with no reviewable changes (1)
  • e2e/specs/mattermost/custom_groups.test.ts
✅ Files skipped from review due to trivial changes (2)
  • e2e/helpers/server_api/credentials.ts
  • e2e/specs/downloads/download_clear_all.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • e2e/specs/mattermost/alt_enter.test.ts
  • e2e/helpers/downloadsDropdown.ts
  • e2e/specs/mattermost/context_menu.test.ts
  • e2e/helpers/downloads.ts
  • e2e/helpers/channelMenu.ts

Comment thread .github/workflows/e2e-pr-trigger.yml Outdated
Comment thread e2e/helpers/badServer.ts Outdated
Comment thread e2e/helpers/server_api/channel.ts
@github-actions github-actions Bot removed the E2E/Run Run Desktop E2E Tests label Jul 1, 2026
yasserfaraazkhan and others added 2 commits July 1, 2026 08:28
Label add/remove on PRs requires pull-requests:write in pull_request
workflows; issues:write alone returns 403 from the labels API.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added the E2E/Run Run Desktop E2E Tests label Jul 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/e2e-functional.yml (1)

116-132: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Template expansion of job outputs into inline script enables code injection.

platforms (Line 122) and outputs (Line 123) are still interpolated directly via ${{ }} into the script body rather than passed through env + process.env/JSON.parse, unlike PR_NUMBER which now correctly uses the safer pattern. If either job output contains characters that break out of the JS literal (e.g. backticks, quotes), an attacker-influenced value could inject arbitrary code that executes with github-token: ${{ github.token }}, which has statuses: write permission in this job.

🔒 Proposed fix: route platforms/outputs through env vars like PR_NUMBER
       - name: Update final status for all platforms
         uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
         env:
           PR_NUMBER: ${{ inputs.pr_number }}
+          PLATFORMS_JSON: ${{ needs.prepare-matrix.outputs.platforms }}
+          OUTPUTS_JSON: ${{ toJSON(needs.e2e-tests.outputs) }}
         with:
           github-token: ${{ github.token }}
           script: |
             const { updateFinalStatus } = require('./e2e/utils/github-actions.js');
-            const platforms = ${{ needs.prepare-matrix.outputs.platforms }};
-            const outputs = ${{ toJSON(needs.e2e-tests.outputs) }};
+            const platforms = JSON.parse(process.env.PLATFORMS_JSON);
+            const outputs = JSON.parse(process.env.OUTPUTS_JSON);
             const prNumber = parseInt(process.env.PR_NUMBER, 10) || null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e-functional.yml around lines 116 - 132, The inline
script in the e2e status update step still injects job outputs directly via
template expansion, which can lead to code injection. Update the
updateFinalStatus call site to pass platforms and outputs through env variables
and read them with process.env plus JSON.parse inside the script, following the
safer pattern already used for PR_NUMBER. Keep the logic in the same script
block and ensure the identifiers updateFinalStatus, platforms, outputs, and
PR_NUMBER are wired through environment values rather than direct `${{ }}`
interpolation.

Source: Linters/SAST tools

🧹 Nitpick comments (2)
e2e/helpers/server_api/client.ts (2)

33-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use ApiRequestError for consistency with apiRequest.

apiLogin throws a plain Error on failure, while apiRequest throws ApiRequestError with a status field. Downstream code (e.g. resolveChannelByName in e2e/helpers/server_api/channel.ts) relies on catching ApiRequestError and inspecting .status for retry logic. Any caller wrapping apiLogin in similar status-based handling won't work since it never gets a typed error.

♻️ Proposed fix
     if (!response.ok) {
-        throw new Error(`POST /api/v4/users/login failed: ${response.status} ${await response.text()}`);
+        throw new ApiRequestError('POST', '/api/v4/users/login', response.status, await response.text());
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/server_api/client.ts` around lines 33 - 35, apiLogin currently
throws a plain Error on failed login, unlike apiRequest which throws
ApiRequestError with a status field. Update apiLogin in client.ts to throw
ApiRequestError on non-ok responses, preserving the response status and response
body text so callers like resolveChannelByName can reliably branch on .status.
Keep the error shape consistent with apiRequest and use the same ApiRequestError
symbol for the failure path.

27-68: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No timeout on fetch calls.

Both apiLogin and apiRequest issue fetch without any timeout/AbortController. If the test server hangs or is unreachable, these calls block indefinitely, which can stall E2E CI runs rather than failing fast.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/helpers/server_api/client.ts` around lines 27 - 68, Both apiLogin and
apiRequest use fetch without any timeout handling, so hanging or unreachable
servers can block E2E runs indefinitely. Update these helpers to use an
AbortController with a configurable timeout, and ensure the controller is passed
into the fetch options in both functions. Handle timeout aborts by throwing a
clear error from apiLogin and ApiRequestError in apiRequest, and keep the logic
localized to these two symbols so the timeout behavior is easy to find and
maintain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/e2e-functional.yml:
- Around line 116-132: The inline script in the e2e status update step still
injects job outputs directly via template expansion, which can lead to code
injection. Update the updateFinalStatus call site to pass platforms and outputs
through env variables and read them with process.env plus JSON.parse inside the
script, following the safer pattern already used for PR_NUMBER. Keep the logic
in the same script block and ensure the identifiers updateFinalStatus,
platforms, outputs, and PR_NUMBER are wired through environment values rather
than direct `${{ }}` interpolation.

---

Nitpick comments:
In `@e2e/helpers/server_api/client.ts`:
- Around line 33-35: apiLogin currently throws a plain Error on failed login,
unlike apiRequest which throws ApiRequestError with a status field. Update
apiLogin in client.ts to throw ApiRequestError on non-ok responses, preserving
the response status and response body text so callers like resolveChannelByName
can reliably branch on .status. Keep the error shape consistent with apiRequest
and use the same ApiRequestError symbol for the failure path.
- Around line 27-68: Both apiLogin and apiRequest use fetch without any timeout
handling, so hanging or unreachable servers can block E2E runs indefinitely.
Update these helpers to use an AbortController with a configurable timeout, and
ensure the controller is passed into the fetch options in both functions. Handle
timeout aborts by throwing a clear error from apiLogin and ApiRequestError in
apiRequest, and keep the logic localized to these two symbols so the timeout
behavior is easy to find and maintain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0a08dbe7-82de-41ce-99c1-fb07333d4496

📥 Commits

Reviewing files that changed from the base of the PR and between f7aa85b and b64f379.

📒 Files selected for processing (9)
  • .github/workflows/e2e-functional.yml
  • .github/workflows/e2e-pr-trigger.yml
  • e2e/helpers/badServer.ts
  • e2e/helpers/mattermostShell.ts
  • e2e/helpers/server_api/channel.ts
  • e2e/helpers/server_api/client.ts
  • e2e/helpers/team.ts
  • e2e/specs/server_management/bad_servers.test.ts
  • e2e/utils/github-actions.js
🚧 Files skipped from review as they are similar to previous changes (7)
  • e2e/helpers/server_api/channel.ts
  • e2e/helpers/team.ts
  • .github/workflows/e2e-pr-trigger.yml
  • e2e/utils/github-actions.js
  • e2e/specs/server_management/bad_servers.test.ts
  • e2e/helpers/mattermostShell.ts
  • e2e/helpers/badServer.ts

@github-actions github-actions Bot removed the E2E/Run Run Desktop E2E Tests label Jul 1, 2026
@github-actions github-actions Bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Jul 1, 2026
@yasserfaraazkhan
yasserfaraazkhan enabled auto-merge (squash) July 1, 2026 05:28
@yasserfaraazkhan yasserfaraazkhan added E2E/Reset-Servers Destroy E2E server for a fresh Run. Add E2E/Run label to kick off an e2e run. and removed E2E/Reset-Servers Destroy E2E server for a fresh Run. Add E2E/Run label to kick off an e2e run. labels Jul 1, 2026
…helper

- Narrow INSECURE_CIPHER_ERROR to SSL handshake errors + the documented
  ERR_CONNECTION_RESET case; drop ERR_CONNECTION_CLOSED/ERR_NETWORK_* since
  those are generic and could let the RC4/TLS1.1 tests pass for the wrong
  reason (e.g. an unrelated CI network blip).
- Harden reloadServerViewsFromMainProcess to fail loudly if ServerManager/
  ViewManager/WebContentsManager are renamed, instead of silently reloading
  nothing and leaving the caller to time out with a generic message.
- ensureMultipleTeams now returns a cleanup() that deletes the team it
  created via the REST API, so context_menu.test.ts's MM-T1307_2 no longer
  leaves an "e2e-<random>" team on the shared test server on every run
  against an account with fewer than 2 teams.
- Remove helpers/downloadsDropdown.ts's closeDownloadsDropdownIfOpen: dead
  code (never imported), and overlayWindows.ts already covers closing
  dropdown-style overlay windows generically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added E2E/Run Run Desktop E2E Tests and removed E2E/Run Run Desktop E2E Tests labels Jul 1, 2026
yasserfaraazkhan added a commit that referenced this pull request Jul 1, 2026
…picks

MAIN FIX (the "10 did not run" tests): e2e/specs/menu_bar/window_menu.test.ts
imports closeDownloadsDropdownIfOpen from e2e/helpers/downloadsDropdown, but
that module wasn't on this branch — I deleted it in a fix commit on sibling
PR #3857 without checking whether the stacked PRs above it referenced it.
That broke this PR's build: Playwright couldn't load window_menu.test.ts, so
its ~10 tests never ran (showed up as "did not run" instead of "failed" or
"skipped", which is why it was easy to miss until the module-not-found
error was surfaced). Restored the helper on this branch verbatim from
git history so PR #3862 is self-contained regardless of sibling merge order.

CodeRabbit nitpicks addressed:
- methodSpy.ts: routed the dock/flash-frame spy install/restore through
  evaluateInMainProcess[WithArg] so they get the shared transient-context
  retry behavior used by the tray helpers — these spies wrap install/restore
  around notification triggers that navigate windows, exactly the case where
  transient evaluate failures happen.
- settingsWindow.ts: dropped the local try/catch retry loop around
  ipcMain.emit(SHOW_SETTINGS_WINDOW) in favor of evaluateInMainProcessWithArg,
  centralizing the "Execution context was destroyed" retry logic instead of
  duplicating it.
- notification_click.test.ts: replaced two inline duplicated MainWindow
  visibility polls with the existing isMainWindowVisible helper in tray.ts
  (identical predicate — pure dedup, no behavior change).
- notifications/index.ts findActiveMentionByChannelId: now iterates through
  ALL matches and returns the most-recently-inserted one, in case older
  Mention notifications for the same channel haven't dismissed yet — Map
  preserves insertion order, so scanning to the end reliably gives us the
  notification the test just displayed. All 66 existing notification unit
  tests still pass.

Skipped one CodeRabbit nitpick: the suggestion to extend evaluateInMainProcess
itself to expose SHOW_SETTINGS_WINDOW as a param — the current usage via
evaluateInMainProcessWithArg already achieves the goal with no helper change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@saturninoabril saturninoabril left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @yasserfaraazkhan, lots to digest but looks good to me. Left comment to understand the idea behind the runInRenderer (non-blocking).

webContentsId: number,
): Promise<void> {
await win.waitForSelector(TEAM_SIDEBAR_BUTTON, {timeout: 15_000});
const point = await win.runInRenderer(`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you explain why it needs to do win.runInRenderer? Just curious since they are customize and I wonder how it helps with the testing of the app.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@saturninoabril , win.runInRenderer is the Electron's webContents.executeJavaScript().
in the side bar we can right click to get the context menu. But they menu is not accessible through the playwright.

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