Skip to content

Commit

Permalink
Add UI tests (#130)
Browse files Browse the repository at this point in the history
* Add UI tests

* lint

* add yarn.lock

* fixes

* fix workflow

* increase timeout

* timeout

* fix snapshots

* remove snapshots

* update dep on jupyterlab
  • Loading branch information
jtpio authored Jul 24, 2024
1 parent 41622ea commit fe9e28a
Show file tree
Hide file tree
Showing 11 changed files with 4,478 additions and 3 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,56 @@ jobs:
jupyterlite-pyodide-kernel-pytest-${{ github.run_number }}-${{ matrix.os }}-${{ matrix.python-version}}
path: build/reports
if-no-files-found: error

integration-tests:
name: Integration tests
needs: build
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
project: ['default', 'crossoriginisolated']

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1

- uses: actions/download-artifact@v3
with:
path: dist
name: jupyterlite-pyodide-kernel-dist-${{ github.run_number }}

- name: Install the extension
run: |
set -eux
python -m pip install "jupyterlab>=4.2.4,<4.3.0" dist/jupyterlite_pyodide_kernel*.whl
- name: Install dependencies
working-directory: ui-tests
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: 0
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
run: |
jlpm install
jlpm run build
- name: Install browser
run: jlpm playwright install chromium
working-directory: ui-tests

- name: Execute integration tests
working-directory: ui-tests
run: |
jlpm playwright test --project ${{ matrix.project }}
- name: Upload Playwright Test report
if: always()
uses: actions/upload-artifact@v3
with:
name: jupyterlite-pyodide-kernel-playwright-tests
path: |
ui-tests/test-results
ui-tests/playwright-report
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,10 @@ _pypi.ts
.jupyterlite.doit.db
_output
jupyterlite_pyodide_kernel/tests/fixtures/.pyodide*/

# Integration tests
ui-tests/test-results/
ui-tests/playwright-report/

# Yarn cache
.yarn/
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jupyterlite-pyodide-kernel-pyodide = "jupyterlite_pyodide_kernel.addons.pyodide:
dev = [
"build",
"hatch",
"jupyterlab >=4.0.7,<4.1.0a0",
"jupyterlab >=4.2.4,<4.3.0a0",
]

lint = [
Expand Down Expand Up @@ -137,11 +137,11 @@ version_cmd = "python scripts/bump-version.py"

[tool.jupyter-releaser.hooks]
before-bump-version = [
"python -m pip install 'jupyterlab~=4.1.1'",
"python -m pip install 'jupyterlab~=4.2.4'",
"jlpm"
]
before-build-npm = [
"python -m pip install 'jupyterlab~=4.1.1' hatch",
"python -m pip install 'jupyterlab~=4.2.4' hatch",
"python -m pip install -e .[dev]",
"jlpm",
"jlpm build:prod",
Expand Down
11 changes: 11 additions & 0 deletions ui-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Integration Testing

This folder contains the integration tests of the extension.

They are defined using [Playwright](https://playwright.dev/docs/intro) test runner and
[Galata](https://github.com/jupyterlab/jupyterlab/tree/main/galata) helper.

The Playwright configuration is defined in
[playwright.config.js](./playwright.config.js).

The default configuration will produce video for failing tests and an HTML report.
13 changes: 13 additions & 0 deletions ui-tests/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pathlib import Path
from subprocess import run

import jupyterlab

extra_labextensions_path = str(Path(jupyterlab.__file__).parent / "galata")
cmd = f"jupyter lite build --FederatedExtensionAddon.extra_labextensions_path={extra_labextensions_path}"

run(
cmd,
check=True,
shell=True,
)
7 changes: 7 additions & 0 deletions ui-tests/jupyter-lite.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"jupyter-lite-schema-version": 0,
"jupyter-config-data": {
"appName": "JupyterLite UI Tests",
"exposeAppInBrowser": true
}
}
5 changes: 5 additions & 0 deletions ui-tests/jupyter_lite_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"LiteBuildConfig": {
"output_dir": "dist"
}
}
24 changes: 24 additions & 0 deletions ui-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@jupyterlite/pyodide-kernel-ui-tests",
"version": "1.0.0",
"description": "JupyterLite Pyodide kernel integration tests",
"private": true,
"scripts": {
"build": "yarn run clean && python build.py",
"clean": "rimraf dist",
"start": "python -m http.server -b 127.0.0.1 8000 --directory dist",
"start:crossoriginisolated": "npx static-handler --cors --coop --coep --corp ./dist",
"start:detached": "yarn run start&",
"test": "playwright test",
"test:debug": "PWDEBUG=1 playwright test",
"test:report": "http-server ./playwright-report -a localhost -o",
"test:update": "playwright test --update-snapshots"
},
"devDependencies": {
"@playwright/test": "^1.37.0",
"rimraf": "^5.0.5"
},
"dependencies": {
"@jupyterlab/galata": "~5.0.5"
}
}
43 changes: 43 additions & 0 deletions ui-tests/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const baseConfig = require('@jupyterlab/galata/lib/playwright-config');

module.exports = {
...baseConfig,
reporter: [[process.env.CI ? 'dot' : 'list'], ['html']],
use: {
acceptDownloads: true,
appPath: '',
autoGoto: false,
baseURL: 'http://localhost:8000',
trace: 'on-first-retry',
video: 'retain-on-failure',
},
projects: [
{
name: 'default',
use: {
baseURL: 'http://localhost:8000',
},
},
{
name: 'crossoriginisolated',
use: {
baseURL: 'http://localhost:8080',
},
},
],
retries: 1,
webServer: [
{
command: 'yarn start',
port: 8000,
timeout: 120 * 1000,
reuseExistingServer: true,
},
{
command: 'yarn start:crossoriginisolated',
port: 8080,
timeout: 120 * 1000,
reuseExistingServer: true,
},
],
};
53 changes: 53 additions & 0 deletions ui-tests/tests/general.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test } from '@jupyterlab/galata';

import { expect } from '@playwright/test';

const TIMEOUT = 600000;

test.describe('General Tests', () => {
test.setTimeout(TIMEOUT);

test.beforeEach(({ page }) => {
page.on('console', (message) => {
console.log('CONSOLE MSG ---', message.text());
});
});

test('should execute some code', async ({ page }) => {
await page.goto('lab/index.html');

const kernel = page.locator('[title="Python (Pyodide)"]').first();
await kernel.click();

// Wait for kernel to be idle
await page.locator('#jp-main-statusbar').getByText('Idle').waitFor();

await page.notebook.setCell(0, 'code', 'print("ok")');
await page.notebook.runCell(0);

// Wait for kernel to be idle
await page.locator('#jp-main-statusbar').getByText('Idle').waitFor();

const cell = await page.notebook.getCellOutput(0);
const cellContent = await cell?.textContent();
expect(cellContent).toContain('ok');
});

test('the kernel should have access to the file system', async ({ page }) => {
await page.goto('lab/index.html');

// Create a Python notebook
const kernel = page.locator('[title="Python (Pyodide)"]').first();
await kernel.click();

await page.notebook.save();

await page.notebook.setCell(0, 'code', 'import os; os.listdir()');
await page.notebook.runCell(0);

const cell = await page.notebook.getCellOutput(0);
const cellContent = await cell?.textContent();
const name = 'Untitled.ipynb';
expect(cellContent).toContain(name);
});
});
Loading

0 comments on commit fe9e28a

Please sign in to comment.