Skip to content

Commit f663fd2

Browse files
committed
test(e2e): share the lab-URL pattern and skip reason across the suite
Move the booted-server URL regex (was duplicated inline in three tests and a local const in a fourth) and the 'set JLAB_TEST_PYTHON_PATH' skip reason into helpers as LAB_URL and NEEDS_PYTHON, and use them everywhere so every server-backed test waits on and skips for the same thing. No behavior change. Note: AI-assisted (Claude Code). Manually verified: full e2e suite green locally with --workers=1 (10 passed), eslint and prettier clean.
1 parent 21bf292 commit f663fd2

5 files changed

Lines changed: 43 additions & 31 deletions

File tree

test/e2e/helpers.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ import { mkdtempSync, rmSync, writeFileSync } from 'fs';
44
import { join } from 'path';
55
import { tmpdir } from 'os';
66

7+
// A booted JupyterLab server URL: the labview navigates here once a session is
8+
// up. Shared so every server-backed test waits on the same pattern.
9+
export const LAB_URL = /https?:\/\/(127\.0\.0\.1|localhost):\d+/;
10+
11+
// The env-backed tests need a real Python with jupyterlab; CI provisions one and
12+
// points JLAB_TEST_PYTHON_PATH at it. Shared so the skip reason reads the same
13+
// everywhere.
14+
export const NEEDS_PYTHON =
15+
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab';
16+
717
// A fresh userData dir per launch keeps tests independent. Electron's native
818
// --user-data-dir flag is honored because the app reads app.getPath('userData')
919
// (see getUserDataDir in utils) and only overrides it on Snap. Returns the app

test/e2e/jupyter-isolation.test.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ import { expect, test } from '@playwright/test';
22
import { existsSync, readdirSync } from 'fs';
33
import { homedir } from 'os';
44
import { join } from 'path';
5-
import { cleanup, launchApp, pageByTitle, pageByUrl } from './helpers';
5+
import {
6+
cleanup,
7+
LAB_URL,
8+
launchApp,
9+
NEEDS_PYTHON,
10+
pageByTitle,
11+
pageByUrl
12+
} from './helpers';
613

714
// Needs a real Python env with jupyterlab. CI provisions one and points
815
// JLAB_TEST_PYTHON_PATH at it. Skipped when absent so the suite stays green
@@ -34,10 +41,7 @@ function listDir(dir: string): string[] {
3441
}
3542

3643
test('the embedded Jupyter server writes only to the per-launch temp dirs', async () => {
37-
test.skip(
38-
!pythonPath,
39-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
40-
);
44+
test.skip(!pythonPath, NEEDS_PYTHON);
4145
test.setTimeout(120000);
4246

4347
const realRuntime = realRuntimeDir();
@@ -53,7 +57,7 @@ test('the embedded Jupyter server writes only to the per-launch temp dirs', asyn
5357

5458
// Booting the labview means a real Jupyter server came up. Only then is it
5559
// meaningful to inspect where it wrote its runtime files.
56-
await pageByUrl(app, /https?:\/\/(127\.0\.0\.1|localhost):\d+/);
60+
await pageByUrl(app, LAB_URL);
5761

5862
// The server used the redirected runtime dir: a connection file landed there.
5963
const tempRuntimeFiles = listDir(tempRuntime);

test/e2e/python-env.test.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import { expect, test } from '@playwright/test';
2-
import { cleanup, launchApp, pageByTitle, pageByUrl } from './helpers';
2+
import {
3+
cleanup,
4+
LAB_URL,
5+
launchApp,
6+
NEEDS_PYTHON,
7+
pageByTitle,
8+
pageByUrl
9+
} from './helpers';
310

411
// Needs a real Python env with jupyterlab. CI provisions one and points
512
// JLAB_TEST_PYTHON_PATH at it; locally, set it to any python that has jupyterlab
613
// installed. Skipped when absent so the suite stays green everywhere.
714
const pythonPath = process.env.JLAB_TEST_PYTHON_PATH;
815

916
test('with a seeded Python env, New notebook opens the labview', async () => {
10-
test.skip(
11-
!pythonPath,
12-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
13-
);
17+
test.skip(!pythonPath, NEEDS_PYTHON);
1418
test.setTimeout(120000);
1519
const { app, userDataDir, jupyterDir } = await launchApp({ pythonPath });
1620
try {
@@ -23,7 +27,7 @@ test('with a seeded Python env, New notebook opens the labview', async () => {
2327
// The session boots a real Jupyter server (via the seeded env) and the
2428
// labview WebContentsView navigates to it. Assert it reached the local
2529
// server URL rather than driving the JupyterLab DOM through Electron.
26-
const lab = await pageByUrl(app, /https?:\/\/(127\.0\.0\.1|localhost):\d+/);
30+
const lab = await pageByUrl(app, LAB_URL);
2731
expect(lab.url()).toMatch(/\/lab/);
2832
} finally {
2933
await app.close();

test/e2e/remote-session.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { tmpdir } from 'os';
77
import {
88
cleanup,
99
launchApp,
10+
NEEDS_PYTHON,
1011
pageByLocator,
1112
pageByTitle,
1213
pageByUrl
@@ -97,10 +98,7 @@ async function startRemoteServer(
9798
}
9899

99100
test('Connect to a running server opens its labview', async () => {
100-
test.skip(
101-
!pythonPath,
102-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
103-
);
101+
test.skip(!pythonPath, NEEDS_PYTHON);
104102
test.setTimeout(150000);
105103

106104
const rootDir = mkdtempSync(join(tmpdir(), 'jlab-e2e-remote-'));

test/e2e/session-actions.test.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { stubDialog } from 'electron-playwright-helpers';
33
import { mkdtempSync, rmSync, writeFileSync } from 'fs';
44
import { tmpdir } from 'os';
55
import { join } from 'path';
6-
import { cleanup, launchApp, pageByTitle, pageByUrl } from './helpers';
6+
import {
7+
cleanup,
8+
LAB_URL,
9+
launchApp,
10+
NEEDS_PYTHON,
11+
pageByTitle,
12+
pageByUrl
13+
} from './helpers';
714

815
// These cover the welcome-page session actions other than New notebook (which
916
// python-env.test.ts already exercises): New session (blank lab), Open folder,
@@ -14,8 +21,6 @@ import { cleanup, launchApp, pageByTitle, pageByUrl } from './helpers';
1421
// path so no native file picker blocks the run.
1522
const pythonPath = process.env.JLAB_TEST_PYTHON_PATH;
1623

17-
const LAB_URL = /https?:\/\/(127\.0\.0\.1|localhost):\d+/;
18-
1924
// The welcome page renders a single unified "Open..." action on macOS and two
2025
// separate "Open File..." / "Open Folder..." actions elsewhere, so select the
2126
// link by platform. The macOS link drives the same showOpenDialog with both
@@ -31,10 +36,7 @@ const openFileLink =
3136
: '#open-file-link';
3237

3338
test('New session opens a blank labview', async () => {
34-
test.skip(
35-
!pythonPath,
36-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
37-
);
39+
test.skip(!pythonPath, NEEDS_PYTHON);
3840
test.setTimeout(120000);
3941
const { app, userDataDir, jupyterDir } = await launchApp({ pythonPath });
4042
try {
@@ -51,10 +53,7 @@ test('New session opens a blank labview', async () => {
5153
});
5254

5355
test('Open folder boots a session in the chosen directory', async () => {
54-
test.skip(
55-
!pythonPath,
56-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
57-
);
56+
test.skip(!pythonPath, NEEDS_PYTHON);
5857
test.setTimeout(120000);
5958
const projectDir = mkdtempSync(join(tmpdir(), 'jlab-e2e-project-'));
6059
const { app, userDataDir, jupyterDir } = await launchApp({ pythonPath });
@@ -79,10 +78,7 @@ test('Open folder boots a session in the chosen directory', async () => {
7978
});
8079

8180
test('Open file boots a session for the chosen notebook', async () => {
82-
test.skip(
83-
!pythonPath,
84-
'set JLAB_TEST_PYTHON_PATH to a python with jupyterlab'
85-
);
81+
test.skip(!pythonPath, NEEDS_PYTHON);
8682
test.setTimeout(120000);
8783
const projectDir = mkdtempSync(join(tmpdir(), 'jlab-e2e-project-'));
8884
const notebook = join(projectDir, 'opened.ipynb');

0 commit comments

Comments
 (0)