Skip to content

Commit 62f21bd

Browse files
authored
e2e: improve stability of reticulate tests (#10887)
### Summary This PR intends to improve the reliability and maintainability of reticulate e2e tests... at the end of the day there still is an issue so we will still be seeing some flakes/fails. 😢 ### QA Notes @:reticulate @:web
1 parent a5cf374 commit 62f21bd

18 files changed

+140
-193
lines changed

.github/workflows/test-e2e-ubuntu.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ on:
8686
type: number
8787
skip_extension_test:
8888
required: false
89-
description: "Whether to skip the bootstrap extensions test."
89+
description: "Skip the bootstrap extensions test."
9090
type: boolean
9191
default: true
9292
workers:

.github/workflows/test-e2e-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ on:
6767
type: number
6868
skip_extension_test:
6969
required: false
70-
description: "Whether to skip the bootstrap extensions test."
70+
description: "Skip the bootstrap extensions test."
7171
type: boolean
7272
default: true
7373

test/e2e/infra/workbench.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class Workbench {
117117
this.console = new Console(code, this.quickInput, this.quickaccess, this.hotKeys, this.contextMenu);
118118
this.modals = new Modals(code, this.toasts, this.console);
119119
this.clipboard = new Clipboard(code, this.hotKeys);
120-
this.sessions = new Sessions(code, this.quickaccess, this.quickInput, this.console, this.contextMenu);
120+
this.sessions = new Sessions(code, this.quickaccess, this.quickInput, this.console, this.contextMenu, this.modals);
121121
this.notebooks = new Notebooks(code, this.quickInput, this.quickaccess, this.hotKeys);
122122
this.notebooksVscode = new VsCodeNotebooks(code, this.quickInput, this.quickaccess, this.hotKeys);
123123
this.notebooksPositron = new PositronNotebooks(code, this.quickInput, this.quickaccess, this.hotKeys, this.contextMenu);

test/e2e/pages/console.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ContextMenu, MenuItemState } from './dialog-contextMenu.js';
1212
import { QuickAccess } from './quickaccess.js';
1313

1414
const CONSOLE_INPUT = '.console-input';
15-
const ACTIVE_CONSOLE_INSTANCE = '.console-instance[style*="z-index: auto"]';
15+
export const ACTIVE_CONSOLE_INSTANCE = '.console-instance[style*="z-index: auto"]';
1616
const MAXIMIZE_CONSOLE = '.bottom .codicon-positron-maximize-panel';
1717
const HISTORY_COMPLETION_ITEM = '.history-completion-item';
1818
const EMPTY_CONSOLE = '.positron-console .empty-console';
@@ -278,6 +278,10 @@ export class Console {
278278
await this.code.driver.page.locator(MAXIMIZE_CONSOLE).click();
279279
}
280280

281+
async sendInterrupt() {
282+
await this.hotKeys.sendInterrupt();
283+
}
284+
281285
async pasteCodeToConsole(code: string, sendEnterKey = false) {
282286
await test.step(`Paste code to console: ${code}`, async () => {
283287
const consoleInput = this.activeConsole.locator(CONSOLE_INPUT);

test/e2e/pages/dialog-modals.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class Modals {
4343
try {
4444
this.code.logger.log('Checking for modal dialog box');
4545
// fail fast if the modal is not present
46-
await this.expectToBeVisible();
46+
await this.expectToBeVisible(undefined, { timeout: 5000 });
4747
await this.clickButton('Install');
4848
this.code.logger.log('Installing ipykernel');
4949
await this.toasts.expectToBeVisible();
@@ -89,11 +89,11 @@ export class Modals {
8989
});
9090
}
9191

92-
async expectToBeVisible(title?: string) {
92+
async expectToBeVisible(title?: string, { timeout = 30000 } = {}) {
9393
await test.step(`Verify modal dialog box is visible${title ? ` : ${title}` : ''}`, async () => {
94-
await expect(this.modalBox).toBeVisible({ timeout: 30000 });
94+
await expect(this.modalBox).toBeVisible({ timeout });
9595
if (title) {
96-
await expect(this.modalTitle).toHaveText(title, { timeout: 30000 });
96+
await expect(this.modalTitle).toHaveText(title, { timeout });
9797
}
9898
});
9999
}

test/e2e/pages/dialog-toasts.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@ export class Toasts {
1616

1717
// --- Actions ---
1818

19-
async waitForAppear(timeout = 20000) {
20-
await this.toastNotification.waitFor({ state: 'attached', timeout });
19+
async waitForAppear(title?: string | RegExp, { timeout = 20000 } = {}) {
20+
title
21+
? await this.toastNotification.getByText(title).waitFor({ state: 'attached', timeout })
22+
: await this.toastNotification.waitFor({ state: 'attached', timeout });
2123
}
2224

23-
async waitForDisappear(timeout = 20000) {
24-
await this.toastNotification.waitFor({ state: 'detached', timeout });
25+
async waitForDisappear(title?: string | RegExp, { timeout = 20000 } = {}) {
26+
title
27+
? await this.toastNotification.getByText(title).waitFor({ state: 'detached', timeout })
28+
: await this.toastNotification.waitFor({ state: 'detached', timeout });
2529
}
2630

2731
async clickButton(button: string) {

test/e2e/pages/hotKeys.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ export class HotKeys {
144144
return this.pressHotKeys('Cmd+J O', 'Execute code in console');
145145
}
146146

147+
public async sendInterrupt() {
148+
await this.pressHotKeys('Cmd+C', 'Send interrupt to console');
149+
}
150+
147151
// ----------------------
148152
// --- Layout Views ---
149153
// ----------------------

test/e2e/pages/quickInput.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class QuickInput {
4040
});
4141
}
4242

43-
async waitForQuickInputOpened({ timeout = 10000 }: { timeout?: number } = {}): Promise<void> {
43+
async waitForQuickInputOpened({ timeout = 3000 }: { timeout?: number } = {}): Promise<void> {
4444
await expect(this.code.driver.page.locator(QuickInput.QUICK_INPUT_INPUT)).toBeVisible({ timeout });
4545
}
4646

test/e2e/pages/quickaccess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export class QuickAccess {
139139

140140
// Await for quick input widget opened
141141
try {
142-
await this.quickInput.waitForQuickInputOpened();
142+
await this.quickInput.waitForQuickInputOpened({ timeout: 3000 });
143143
} catch (err) {
144144
await this.code.driver.page.keyboard.press('Escape');
145145
throw err;

test/e2e/pages/sessions.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import test, { expect, Locator, Page } from '@playwright/test';
7-
import { Code, QuickAccess, Console, ContextMenu } from '../infra';
7+
import { Code, QuickAccess, Console, ContextMenu, Modals } from '../infra';
88
import { QuickInput } from './quickInput';
99

1010
// Lazy getters for environment variables - these will be evaluated when accessed, not at module load time
@@ -46,7 +46,7 @@ export class Sessions {
4646
private consoleInstance = (sessionId: string) => this.page.getByTestId(`console-${sessionId}`);
4747
private outputChannel = this.page.getByRole('combobox');
4848

49-
constructor(private code: Code, private quickaccess: QuickAccess, private quickinput: QuickInput, private console: Console, private contextMenu: ContextMenu) { }
49+
constructor(private code: Code, private quickaccess: QuickAccess, private quickinput: QuickInput, private console: Console, private contextMenu: ContextMenu, private modals: Modals) { }
5050

5151
// -- Actions --
5252

@@ -180,8 +180,8 @@ export class Sessions {
180180
* @param options.waitForIdle - wait for the session to display as "idle" (ready)
181181
* @param options.clearConsole - clear the console before restarting
182182
*/
183-
async restart(sessionIdOrName: string, options?: { waitForIdle?: boolean; clearConsole?: boolean }): Promise<void> {
184-
const { waitForIdle = true, clearConsole = true } = options || {};
183+
async restart(sessionIdOrName: string, options?: { waitForIdle?: boolean; clearConsole?: boolean, clickModalButton?: string }): Promise<void> {
184+
const { waitForIdle = true, clearConsole = true, clickModalButton = '' } = options || {};
185185

186186
await test.step(`Restart session: ${sessionIdOrName}`, async () => {
187187
await this.console.focus();
@@ -197,6 +197,10 @@ export class Sessions {
197197
await this.console.restartButton.click();
198198
await this.page.mouse.move(0, 0);
199199

200+
if (clickModalButton) {
201+
await this.modals.clickButton(clickModalButton);
202+
}
203+
200204
if (waitForIdle) {
201205
await expect(this.page.getByText('restarting.')).not.toBeVisible({ timeout: 90000 });
202206
await expect(this.page.locator('.console-instance[style*="z-index: auto"]').getByText('restarted.')).toBeVisible({ timeout: 90000 });
@@ -878,8 +882,7 @@ export class Sessions {
878882
await test.step(`Verify runtime is selected: ${runtimeName}`, async () => {
879883
const normalizedRuntimeName = runtimeName.replace(/-\s\d+$/, '').trim();
880884
await expect(this.sessionPicker).toHaveText(normalizedRuntimeName, { timeout });
881-
}
882-
);
885+
});
883886
}
884887

885888
/**
@@ -945,10 +948,10 @@ export class Sessions {
945948
/**
946949
* Verify: all sessions are "ready" (idle or disconnected)
947950
*/
948-
async expectAllSessionsToBeReady() {
951+
async expectAllSessionsToBeReady({ timeout = 15000 }: { timeout?: number } = {}) {
949952
await test.step('Expect all sessions to be ready', async () => {
950953
await this.expectNoStartUpMessaging();
951-
await expect(this.activeStatusIcon).toHaveCount(0);
954+
await expect(this.activeStatusIcon).toHaveCount(0, { timeout });
952955
});
953956
}
954957

0 commit comments

Comments
 (0)