Skip to content
This repository was archived by the owner on Feb 14, 2024. It is now read-only.

Commit 886b9a4

Browse files
authored
Start ui-tests (#167)
* Start `ui-tests` * Add workflows * Update gitignore * Update workflow * Add basic UI tests config * Add basic execute test * Install lab in workflow * setup conda env instead * Add defaults * Lint step * ignore ui-tests folder for now * Fix linting later * Remove duplicated lint step * Fix artifact name * Lint * Fix ruff * Create notebook * Add workaround for firefox * Add launcher snapshot * Add filesystem test * Update snapshots * Increase test timeout * Only screenshot the launcher * update refs
1 parent 98d0f4b commit 886b9a4

20 files changed

+4769
-9
lines changed

.eslintignore

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ coverage
55
tests
66
src/worker.ts
77
src/web_worker_kernel.ts
8+
9+
# TODO: remove
10+
ui-tests

.github/workflows/build.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949

5050
- uses: actions/upload-artifact@v2
5151
with:
52-
name: dist ${{ github.run_number }}
52+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
5353
path: ./dist
5454

5555
test_isolated:
@@ -66,7 +66,7 @@ jobs:
6666
architecture: 'x64'
6767
- uses: actions/download-artifact@v2
6868
with:
69-
name: dist ${{ github.run_number }}
69+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
7070
path: ./dist
7171
- name: Install and Test
7272
run: |
@@ -92,7 +92,7 @@ jobs:
9292

9393
- uses: actions/download-artifact@v2
9494
with:
95-
name: dist ${{ github.run_number }}
95+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
9696
path: ./dist
9797

9898
- name: Install Conda environment with Micromamba
@@ -125,7 +125,7 @@ jobs:
125125

126126
- uses: actions/download-artifact@v2
127127
with:
128-
name: dist ${{ github.run_number }}
128+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
129129
path: ./dist
130130

131131
- name: Install Conda environment with Micromamba
@@ -153,7 +153,7 @@ jobs:
153153

154154
- uses: actions/download-artifact@v2
155155
with:
156-
name: dist ${{ github.run_number }}
156+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
157157
path: ./dist
158158

159159
- name: Install Conda environment with Micromamba
@@ -181,7 +181,7 @@ jobs:
181181

182182
- uses: actions/download-artifact@v2
183183
with:
184-
name: dist ${{ github.run_number }}
184+
name: jupyterlite-xeus-python-dist-${{ github.run_number }}
185185
path: ./dist
186186

187187
- name: Install Conda environment with Micromamba
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Update Playwright Snapshots
2+
3+
on:
4+
issue_comment:
5+
types: [created, edited]
6+
7+
permissions:
8+
contents: write
9+
pull-requests: write
10+
11+
jobs:
12+
update-snapshots:
13+
if:
14+
${{ github.event.issue.pull_request && contains(github.event.comment.body, 'update
15+
playwright snapshots') }}
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
browser: [firefox, chromium]
21+
22+
steps:
23+
- name: React to the triggering comment
24+
run: |
25+
gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions --raw-field 'content=+1'
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Checkout
30+
uses: actions/checkout@v4
31+
32+
- name: Checkout the branch from the PR that triggered the job
33+
run: |
34+
# PR branch remote must be checked out using https URL
35+
git config --global hub.protocol https
36+
37+
gh pr checkout ${{ github.event.issue.number }}
38+
env:
39+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40+
41+
- name: Base Setup
42+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
43+
44+
- name: Build
45+
run: |
46+
# TODO: install addon
47+
48+
# disable git hooks
49+
git config core.hooksPath no-hooks
50+
51+
- name: Install the test dependencies
52+
run: |
53+
cd ui-tests
54+
jlpm
55+
jlpm build
56+
jlpm playwright install
57+
58+
- name: Update snapshots
59+
uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1
60+
with:
61+
github_token: ${{ secrets.GITHUB_TOKEN }}
62+
npm_client: jlpm
63+
test_folder: ui-tests
64+
start_server_script: 'null'
65+
update_script: test:update --browser ${{ matrix.browser }}
66+
env:
67+
DEBUG: pw:webserver

.github/workflows/ui-tests.yml

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: UI Tests
2+
3+
on: [push, pull_request]
4+
5+
defaults:
6+
run:
7+
shell: bash -l {0}
8+
9+
jobs:
10+
build:
11+
name: Build
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Install Conda environment with Micromamba
19+
uses: mamba-org/setup-micromamba@v1
20+
with:
21+
micromamba-version: '1.5.1-0'
22+
environment-file: environment.yml
23+
cache-environment: true
24+
25+
- name: Install jupyterlite-xeus-python
26+
run: |
27+
jlpm
28+
jlpm run build
29+
python -m pip install -v .
30+
31+
- name: Build UI tests
32+
run: |
33+
cd ui-tests
34+
jlpm
35+
# Build the JupyterLite website
36+
jlpm build
37+
38+
- name: Upload the JupyterLite website
39+
uses: actions/upload-artifact@v3
40+
with:
41+
name: jupyterlite-xeus-python-ui-tests-app-${{ github.run_number }}
42+
path: ./ui-tests/ui-tests-app
43+
44+
ui-tests:
45+
needs: [build]
46+
name: Visual Regression
47+
runs-on: ubuntu-latest
48+
strategy:
49+
fail-fast: false
50+
matrix:
51+
browser: [firefox, chromium]
52+
steps:
53+
- name: Checkout
54+
uses: actions/checkout@v4
55+
56+
- uses: actions/download-artifact@v3
57+
with:
58+
name: jupyterlite-xeus-python-ui-tests-app-${{ github.run_number }}
59+
path: ./ui-tests/ui-tests-app
60+
61+
- name: Base Setup
62+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
63+
64+
- name: Install dependencies and browser
65+
run: |
66+
# Install JupyterLab to get jlpm
67+
python -m pip install jupyterlab~=4.0
68+
cd ui-tests
69+
jlpm
70+
jlpm playwright install ${{ matrix.browser }} --with-deps
71+
72+
- name: Test
73+
run: |
74+
cd ui-tests
75+
jlpm run test --browser ${{ matrix.browser }}
76+
77+
- name: Upload Playwright Test assets
78+
if: always()
79+
uses: actions/upload-artifact@v3
80+
with:
81+
name: jupyterlite-xeux-python-${{ matrix.browser }}-test-assets
82+
path: |
83+
ui-tests/test-results
84+
85+
- name: Upload Playwright Test report
86+
if: always()
87+
uses: actions/upload-artifact@v3
88+
with:
89+
name: jupyterlite-xeus-python-${{ matrix.browser }}-test-report
90+
path: |
91+
ui-tests/playwright-report
92+
93+
- name: Update snapshots
94+
if: failure()
95+
run: |
96+
cd ui-tests
97+
# remove previous snapshots from other browser
98+
jlpm run clean:snapshots
99+
# generate new snapshots
100+
jlpm run test:update --browser ${{ matrix.browser }}
101+
102+
- name: Upload updated snapshots
103+
if: failure()
104+
uses: actions/upload-artifact@v3
105+
with:
106+
name: jupyterlite-xeus-python-${{ matrix.browser }}-updated-snapshots
107+
path: ui-tests/test

.gitignore

+10-1
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,13 @@ jupyterlite_xeus_python/_version.py
135135

136136
# Yarn 3
137137
.pnp*
138-
.yarn
138+
.yarn
139+
140+
# UI tests
141+
ui-tests/playwright-report
142+
ui-tests/test-results
143+
ui-tests/ui-tests-app
144+
145+
# Lint
146+
.eslintcache
147+
.stylelintcache

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ The `jlpm` command is JupyterLab's pinned version of
7676
# Clone the repo to your local environment
7777
# Change directory to the jupyterlite-xeus-python directory
7878
# Install package in development mode
79-
python -m pip install -e .
79+
python -m pip install -e ".[dev]"
8080

8181
# Link your development version of the extension with JupyterLab
8282
jupyter labextension develop . --overwrite

pyproject.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ ignore = [
136136
"tests/*" = ["S101", "F841", "PLR2004"]
137137

138138
# B008 Do not perform function call `typer.Option` in argument defaults
139-
# E501 `subprocess` call: check for execution of untrusted input
139+
# E501 Line too long
140140
# S603 `subprocess` call: check for execution of untrusted input
141141
"jupyterlite_xeus_python/build.py" = ["B008", "E501", "S603"]
142+
143+
# E501 Line too long
144+
# S602 `subprocess` call with `shell=True` identified, security issue
145+
"ui-tests/build.py" = ["E501", "S602"]

ui-tests/.yarnrc.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
enableImmutableInstalls: false
2+
enableInlineBuilds: false
3+
enableTelemetry: false
4+
httpTimeout: 60000
5+
nodeLinker: node-modules
6+
npmRegistryServer: 'https://registry.yarnpkg.com'

ui-tests/build.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
Custom script to build the UI tests app and load the Galata extension
3+
"""
4+
5+
from pathlib import Path
6+
from subprocess import run
7+
8+
import jupyterlab
9+
10+
extra_labextensions_path = str(Path(jupyterlab.__file__).parent / "galata")
11+
cmd = f"jupyter lite build --FederatedExtensionAddon.extra_labextensions_path={extra_labextensions_path}"
12+
13+
run(
14+
cmd,
15+
check=True,
16+
shell=True,
17+
)

ui-tests/jupyter-lite.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"jupyter-lite-schema-version": 0,
3+
"jupyter-config-data": {
4+
"appName": "JupyterLite UI Tests",
5+
"exposeAppInBrowser": true
6+
}
7+
}

ui-tests/jupyter_lite_config.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"LiteBuildConfig": {
3+
"output_dir": "ui-tests-app"
4+
}
5+
}

ui-tests/package.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@jupyterlite/jupyterlite-xeus-python-ui-tests",
3+
"private": true,
4+
"version": "0.1.0",
5+
"author": "JupyterLite Contributors",
6+
"license": "BSD-3-Clause",
7+
"description": "JupyterLite Xeus Python UI Tests",
8+
"scripts": {
9+
"build": "python build.py",
10+
"clean": "rimraf .jupyterlite.doit.db ui-tests-app",
11+
"clean:snapshots": "rimraf -g \"test/**/*-snapshots/*.png\"",
12+
"start": "cd ui-tests-app && python -m http.server -b 127.0.0.1 8000",
13+
"test": "playwright test",
14+
"test:report": "http-server ./playwright-report -a localhost -o",
15+
"test:update": "playwright test --update-snapshots"
16+
},
17+
"dependencies": {
18+
"@jupyterlab/galata": "~5.0.5",
19+
"@playwright/test": "^1.36.2"
20+
},
21+
"devDependencies": {
22+
"rimraf": "^5"
23+
}
24+
}

ui-tests/playwright.config.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const baseConfig = require('@jupyterlab/galata/lib/playwright-config');
2+
3+
module.exports = {
4+
...baseConfig,
5+
retries: 1,
6+
use: {
7+
acceptDownloads: true,
8+
appPath: '',
9+
autoGoto: false,
10+
baseURL: 'http://localhost:8000',
11+
trace: 'retain-on-failure',
12+
video: 'retain-on-failure',
13+
14+
waitForApplication: async ({ baseURL }, use, testInfo) => {
15+
const waitIsReady = async page => {
16+
await page.waitForSelector('.jp-LauncherCard');
17+
};
18+
await use(waitIsReady);
19+
}
20+
},
21+
webServer: [
22+
{
23+
command: 'jlpm run start',
24+
port: 8000,
25+
timeout: 120 * 1000,
26+
reuseExistingServer: true
27+
}
28+
]
29+
};

ui-tests/test/execute.test.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) JupyterLite Contributors
2+
// Distributed under the terms of the Modified BSD License.
3+
4+
import { test } from '@jupyterlab/galata';
5+
6+
import { expect } from '@playwright/test';
7+
8+
import { firefoxWaitForApplication } from './utils';
9+
10+
test.use({ waitForApplication: firefoxWaitForApplication });
11+
12+
test.describe('Code execution', () => {
13+
test.beforeEach(async ({ page }) => {
14+
await page.goto('lab/index.html');
15+
});
16+
17+
test('Basic code execution', async ({ page }) => {
18+
await page.notebook.createNew();
19+
await page.notebook.setCell(0, 'code', '2 + 2');
20+
await page.notebook.run();
21+
const output = await page.notebook.getCellTextOutput(0);
22+
23+
expect(output).toBeTruthy();
24+
expect(output![0]).toBe('4');
25+
});
26+
});

0 commit comments

Comments
 (0)