Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tests/e2e/ext-specs/firefox-vpn.e2e.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ describe('Firefox VPN', function() {
it('plays once allowed, its requests going the page\'s way', async function() {
proxied.length = 0;
const videoTab = await browser.getWindowHandle();
// Into the player of the case before (its page stays): a test no longer starts in the frame
// the one before ended in (setupGuard.mjs's root afterEach, 2026-10-11).
await enterPlayer();
// A player in a page has no permissions API: its button opens the permissions page.
await (await browser.$('.mainplayer .vpn_button')).click();
let permsTab;
Expand Down
17 changes: 16 additions & 1 deletion tests/e2e/setupGuard.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export async function guardSetup(setup) {
}

// The configs' mochaOpts.rootHooks: the setup's failure first, the more useful reason, then
// bidi.mjs's check.
// bidi.mjs's check; and after every test, the window's top again.
export const rootHooks = {
beforeEach() {
if (setupError) {
Expand All @@ -38,4 +38,19 @@ export const rootHooks = {
}
bidiRootHooks.beforeEach();
},
// A test that ended in a frame (a player's) could leave the next test's first browser.url()
// waiting in a frame the navigation removed, until the 120 s timeout: on CI's Linux runner,
// each hang came in a test after one that ended in the player's frame, before its first step
// (autoplay-next-episode, main and #449, 2026-10-11; not every such test hung - a race in the
// driver). framed-player.e2e.mjs did this itself. A window or a session already gone is no
// news; anything else is said, so a reset that stops working shows.
async afterEach() {
try {
await globalThis.browser?.switchFrame(null);
} catch (e) {
if (!/no such (window|frame)|invalid session|session (deleted|not created)/i.test(String(e?.message || e))) {
console.warn('e2e: back to the window\'s top failed after a test:', e);
}
}
},
};
14 changes: 14 additions & 0 deletions tests/unit/e2eHarness.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ describe('guardSetup and rootHooks', () => {
globalThis.browser = {isBidi: false, requestedCapabilities: {}};
expect(() => rootHooks.beforeEach()).toThrow(/BiDi is not connected/);
});

it('leave every test at the top of its window, also where that fails or no browser is up', async () => {
// A test that ended in a frame left the next one's first navigation waiting in it (2026-10-11).
const frames = [];
globalThis.browser = {switchFrame: async (to) => frames.push(to)};
await rootHooks.afterEach();
expect(frames).toEqual([null]);
globalThis.browser = {switchFrame: async () => {
throw new Error('no such window');
}};
await expect(rootHooks.afterEach()).resolves.toBeUndefined();
delete globalThis.browser;
await expect(rootHooks.afterEach()).resolves.toBeUndefined();
});
});

describe('writeFixture', () => {
Expand Down
Loading