Skip to content

Commit 89f46e2

Browse files
committed
UI testing with Galata
1 parent 5cb80e8 commit 89f46e2

File tree

71 files changed

+5224
-58
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+5224
-58
lines changed

.github/workflows/build.yml

+25-52
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,31 @@ jobs:
8585
- name: JavaScript prettyfier
8686
run: yarn run prettier:check
8787

88+
- name: Install Galata
89+
run: yarn install
90+
working-directory: ui-tests
91+
92+
- name: Launch JupyterLab
93+
run: yarn run start-jlab:detached
94+
working-directory: ui-tests
95+
96+
- name: Wait for JupyterLab
97+
uses: ifaxity/wait-on-action@v1
98+
with:
99+
resource: http-get://localhost:8888/api
100+
timeout: 20000
101+
102+
- name: Run UI Tests
103+
run: yarn run test
104+
working-directory: ui-tests
105+
106+
- name: Upload UI Test artifacts
107+
if: always()
108+
uses: actions/upload-artifact@v2
109+
with:
110+
name: ui-test-output
111+
path: ui-tests/test-output
112+
88113
# - name: JavaScript tests
89114
# run: yarn run test
90115
# working-directory: js
@@ -106,58 +131,6 @@ jobs:
106131
name: dist ${{ github.run_number }}
107132
path: ./dist
108133

109-
# visual-regression-tests:
110-
# runs-on: ubuntu-latest
111-
# needs: [build]
112-
113-
# steps:
114-
# - name: Checkout
115-
# uses: actions/checkout@v2
116-
117-
# - name: Setup conda
118-
# uses: conda-incubator/setup-miniconda@v2
119-
# with:
120-
# activate-environment: bqplot-test
121-
# environment-file: test-environment.yml
122-
# python-version: 3.9
123-
# mamba-version: "*"
124-
# auto-activate-base: false
125-
# channels: conda-forge
126-
127-
# - uses: actions/download-artifact@v2
128-
# with:
129-
# name: dist ${{ github.run_number }}
130-
# path: ./dist
131-
132-
# - name: Install the package
133-
# run: pip install -vv bqplot*.whl
134-
# working-directory: dist
135-
136-
# - name: Install Galata
137-
# run: yarn install
138-
# working-directory: ui-tests
139-
140-
# - name: Launch JupyterLab
141-
# run: yarn run start-jlab:detached
142-
# working-directory: ui-tests
143-
144-
# - name: Wait for JupyterLab
145-
# uses: ifaxity/wait-on-action@v1
146-
# with:
147-
# resource: http-get://localhost:8888/api
148-
# timeout: 20000
149-
150-
# - name: Run UI Tests
151-
# run: yarn run test
152-
# working-directory: ui-tests
153-
154-
# - name: Upload UI Test artifacts
155-
# if: always()
156-
# uses: actions/upload-artifact@v2
157-
# with:
158-
# name: ui-test-output
159-
# path: ui-tests/test-output
160-
161134
install:
162135
runs-on: ${{ matrix.os }}-latest
163136
needs: [build]

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,5 @@ bqplot_gl/labextension/*.tgz
154154

155155
# Packed lab extensions
156156
bqplot_gl/labextension
157+
158+
ui-tests/test-output/*

babel.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ module.exports = {
99
},
1010
},
1111
],
12+
'@babel/preset-typescript',
1213
],
1314
};

bqplot_gl/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
# Copyright (c) The bqplot Development Team.
55
# Distributed under the terms of the Modified BSD License.
66

7-
version_info = (0, 1, 0, 'dev')
7+
version_info = (0, 1, 0)
88
__version__ = ".".join(map(str, version_info))

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"devDependencies": {
6262
"@babel/core": "^7.5.0",
6363
"@babel/preset-env": "^7.5.0",
64+
"@babel/preset-typescript": "^7.15.0",
6465
"@jupyterlab/builder": "^3.0.0",
6566
"@phosphor/application": "^1.6.0",
6667
"@phosphor/widgets": "^1.6.0",

src/ScatterGLView.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16+
import { ColorScale } from 'bqscales';
1617
import { Mark, symbol as bqSymbol, deepCopy, Scale } from 'bqplot';
1718
import * as d3 from 'd3';
1819
import * as _ from 'underscore';
@@ -56,9 +57,9 @@ const color_to_array_rgba = function (color: any, default_color?: any) {
5657
}
5758
};
5859

59-
const create_colormap = function (scale: any) {
60+
const create_colormap = function (scale: ColorScale) {
6061
// convert the d3 color scale to a texture
61-
const colors = scale ? scale.model.color_range : ['#ff0000', '#ff0000'];
62+
const colors = scale ? scale.model.colorRange : [0, 1];
6263
const color_scale = d3
6364
.scaleLinear()
6465
.range(colors)

src/plugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Widget } from '@phosphor/widgets';
77

88
import { IJupyterWidgetRegistry } from '@jupyter-widgets/base';
99

10-
import * as widgetExports from './figure';
10+
import * as widgetExports from './index';
1111

1212
import { MODULE_NAME, MODULE_VERSION } from './version';
1313

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"compilerOptions": {
33
"declaration": true,
4-
"esModuleInterop":true,
4+
"esModuleInterop": true,
55
"lib": ["es2015", "dom"],
66
"module": "commonjs",
77
"moduleResolution": "node",

ui-tests/README.md

+36

ui-tests/galata-config.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"testId": "test"
3+
}

ui-tests/jupyter_server_config.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
c.ServerApp.port = 8888
2+
c.ServerApp.token = ""
3+
c.ServerApp.password = ""
4+
c.ServerApp.disable_check_xsrf = True
5+
c.ServerApp.open_browser = False
6+
c.LabApp.open_browser = False
7+
c.LabApp.expose_app_in_browser = True

ui-tests/package.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "bqplot-gl-ui-tests",
3+
"version": "1.0.0",
4+
"description": "bqplot-gl UI Tests",
5+
"private": true,
6+
"scripts": {
7+
"start-jlab": "jupyter lab --config ./jupyter_server_config.py",
8+
"start-jlab:detached": "yarn run start-jlab&",
9+
"clean": "rimraf tests/notebooks/.ipynb_checkpoints && rimraf test-output",
10+
"test": "yarn run clean && galata --image-match-threshold 0.33",
11+
"update-references": "galata --update-references"
12+
},
13+
"author": "bqplot",
14+
"license": "Apache-2.0",
15+
"dependencies": {
16+
"@jupyterlab/galata": "3.0.11-2",
17+
"klaw-sync": "^6.0.0",
18+
"rimraf": "^3.0.2"
19+
}
20+
}

ui-tests/tests/bqplot.test.ts

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright (c) Jupyter Development Team.
2+
// Distributed under the terms of the Modified BSD License.
3+
4+
import { galata, describe, test } from '@jupyterlab/galata';
5+
import * as path from 'path';
6+
import * as klaw from 'klaw-sync';
7+
8+
jest.setTimeout(600000);
9+
10+
const filterUpdateNotebooks = item => {
11+
const basename = path.basename(item.path);
12+
return basename.includes('_update');
13+
}
14+
15+
const testCellOutputs = async (theme: 'JupyterLab Light' | 'JupyterLab Dark') => {
16+
const paths = klaw('tests/notebooks', {filter: item => !filterUpdateNotebooks(item), nodir: true});
17+
const notebooks = paths.map(item => path.basename(item.path));
18+
19+
let results = [];
20+
21+
const contextPrefix = theme == 'JupyterLab Light' ? 'light_' : 'dark_';
22+
galata.theme.setTheme(theme);
23+
24+
for (const notebook of notebooks) {
25+
galata.context.capturePrefix = contextPrefix + notebook;
26+
27+
await galata.notebook.open(notebook);
28+
expect(await galata.notebook.isOpen(notebook)).toBeTruthy();
29+
await galata.notebook.activate(notebook);
30+
expect(await galata.notebook.isActive(notebook)).toBeTruthy();
31+
32+
let numCellImages = 0;
33+
34+
const getCaptureImageName = (id: number): string => {
35+
return `cell-${id}`;
36+
};
37+
38+
await galata.notebook.runCellByCell({
39+
onAfterCellRun: async (cellIndex: number) => {
40+
const cell = await galata.notebook.getCellOutput(cellIndex);
41+
if (cell) {
42+
if (
43+
await galata.capture.screenshot(
44+
getCaptureImageName(numCellImages),
45+
cell
46+
)
47+
) {
48+
numCellImages++;
49+
}
50+
}
51+
}
52+
});
53+
54+
for (let c = 0; c < numCellImages; ++c) {
55+
results.push(await galata.capture.compareScreenshot(getCaptureImageName(c)));
56+
}
57+
58+
await galata.notebook.close(true);
59+
}
60+
61+
for (const result of results) {
62+
expect(result).toBe('same');
63+
}
64+
}
65+
66+
const testPlotUpdates = async (theme: 'JupyterLab Light' | 'JupyterLab Dark') => {
67+
const paths = klaw('tests/notebooks', {filter: item => filterUpdateNotebooks(item), nodir: true});
68+
const notebooks = paths.map(item => path.basename(item.path));
69+
70+
let results = [];
71+
72+
const contextPrefix = theme == 'JupyterLab Light' ? 'light_' : 'dark_';
73+
galata.theme.setTheme(theme);
74+
75+
for (const notebook of notebooks) {
76+
galata.context.capturePrefix = contextPrefix + notebook;
77+
78+
await galata.notebook.open(notebook);
79+
expect(await galata.notebook.isOpen(notebook)).toBeTruthy();
80+
await galata.notebook.activate(notebook);
81+
expect(await galata.notebook.isActive(notebook)).toBeTruthy();
82+
83+
let numCellImages = 0;
84+
85+
const getCaptureImageName = (id: number): string => {
86+
return `cell-${id}`;
87+
};
88+
89+
await galata.notebook.runCellByCell({
90+
onAfterCellRun: async (cellIndex: number) => {
91+
// Always get first cell output which must contain the plot
92+
const cell = await galata.notebook.getCellOutput(0);
93+
if (cell) {
94+
if (
95+
await galata.capture.screenshot(
96+
getCaptureImageName(numCellImages),
97+
cell
98+
)
99+
) {
100+
numCellImages++;
101+
}
102+
}
103+
}
104+
});
105+
106+
for (let c = 0; c < numCellImages; ++c) {
107+
results.push(await galata.capture.compareScreenshot(getCaptureImageName(c)));
108+
}
109+
110+
await galata.notebook.close(true);
111+
}
112+
113+
for (const result of results) {
114+
expect(result).toBe('same');
115+
}
116+
};
117+
118+
describe('bqplot Visual Regression', () => {
119+
beforeAll(async () => {
120+
await galata.resetUI();
121+
});
122+
123+
afterAll(async () => {
124+
galata.context.capturePrefix = '';
125+
});
126+
127+
test('Upload files to JupyterLab', async () => {
128+
await galata.contents.moveDirectoryToServer(
129+
path.resolve(__dirname, `./notebooks`),
130+
'uploaded'
131+
);
132+
expect(
133+
await galata.contents.fileExists('uploaded/scatter.ipynb')
134+
).toBeTruthy();
135+
});
136+
137+
test('Refresh File Browser', async () => {
138+
await galata.filebrowser.refresh();
139+
});
140+
141+
test('Open directory uploaded', async () => {
142+
await galata.filebrowser.openDirectory('uploaded');
143+
expect(
144+
await galata.filebrowser.isFileListedInBrowser('scatter.ipynb')
145+
).toBeTruthy();
146+
});
147+
148+
test('Light theme: Check bqplot first renders', async () => {
149+
await testCellOutputs('JupyterLab Light');
150+
});
151+
152+
test('Dark theme: Check bqplot first renders', async () => {
153+
await testCellOutputs('JupyterLab Dark');
154+
});
155+
156+
test('Light theme: Check bqplot update plot properties', async () => {
157+
await testPlotUpdates('JupyterLab Light');
158+
});
159+
160+
test('Dark theme: Check bqplot update plot properties', async () => {
161+
await testPlotUpdates('JupyterLab Dark');
162+
});
163+
164+
test('Open home directory', async () => {
165+
await galata.filebrowser.openHomeDirectory();
166+
});
167+
168+
test('Delete uploaded directory', async () => {
169+
await galata.contents.deleteDirectory('uploaded');
170+
});
171+
});

0 commit comments

Comments
 (0)