From a878da60e2cdf70e20e406fc219615446645e5ce Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Tue, 28 Sep 2021 18:22:06 +0200 Subject: [PATCH 01/13] Create widget for stability testing --- .gitignore | 6 +- .../missing_module_widget/LICENSE.txt | 0 .../missing_module_widget/MANIFEST.in | 24 ++++ .../missing_module_widget/README.md | 76 +++++++++++ .../missing_module_widget/babel.config.js | 13 ++ .../missing_module_widget/install.json | 5 + .../missing_module_widget.json | 5 + .../missing_module_widget/__init__.py | 50 +++++++ .../missing_module_widget/_frontend.py | 12 ++ .../missing_module_widget/_version.py | 8 ++ .../missing_module_widget/example.py | 26 ++++ .../missing_module_widget/package.json | 81 ++++++++++++ .../missing_module_widget/pyproject.toml | 3 + .../missing_module_widget/setup.cfg | 7 + .../widget_lib/missing_module_widget/setup.py | 122 ++++++++++++++++++ .../missing_module_widget/src/extension.ts | 16 +++ .../missing_module_widget/src/index.ts | 5 + .../missing_module_widget/src/plugin.ts | 42 ++++++ .../missing_module_widget/src/version.ts | 20 +++ .../missing_module_widget/src/widget.ts | 50 +++++++ .../missing_module_widget/tsconfig.json | 22 ++++ .../missing_module_widget/webpack.config.js | 90 +++++++++++++ tsconfig.eslint.json | 7 +- 23 files changed, 688 insertions(+), 2 deletions(-) create mode 100644 tests/widget_lib/missing_module_widget/LICENSE.txt create mode 100644 tests/widget_lib/missing_module_widget/MANIFEST.in create mode 100644 tests/widget_lib/missing_module_widget/README.md create mode 100644 tests/widget_lib/missing_module_widget/babel.config.js create mode 100644 tests/widget_lib/missing_module_widget/install.json create mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget.json create mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py create mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py create mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget/_version.py create mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget/example.py create mode 100644 tests/widget_lib/missing_module_widget/package.json create mode 100644 tests/widget_lib/missing_module_widget/pyproject.toml create mode 100644 tests/widget_lib/missing_module_widget/setup.cfg create mode 100644 tests/widget_lib/missing_module_widget/setup.py create mode 100644 tests/widget_lib/missing_module_widget/src/extension.ts create mode 100644 tests/widget_lib/missing_module_widget/src/index.ts create mode 100644 tests/widget_lib/missing_module_widget/src/plugin.ts create mode 100644 tests/widget_lib/missing_module_widget/src/version.ts create mode 100644 tests/widget_lib/missing_module_widget/src/widget.ts create mode 100644 tests/widget_lib/missing_module_widget/tsconfig.json create mode 100644 tests/widget_lib/missing_module_widget/webpack.config.js diff --git a/.gitignore b/.gitignore index cfa182b1a..4cded79db 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,8 @@ tsconfig.tsbuildinfo ui-tests/playwright-report ui-tests/test-results ui-tests/benchmark-results -ui-tests/jlab_root \ No newline at end of file +ui-tests/jlab_root + +tests/widget_lib/**/docs +tests/widget_lib/**/labextension +tests/widget_lib/**/nbextension \ No newline at end of file diff --git a/tests/widget_lib/missing_module_widget/LICENSE.txt b/tests/widget_lib/missing_module_widget/LICENSE.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/widget_lib/missing_module_widget/MANIFEST.in b/tests/widget_lib/missing_module_widget/MANIFEST.in new file mode 100644 index 000000000..932595e64 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/MANIFEST.in @@ -0,0 +1,24 @@ +include README.md + +include pyproject.toml + +include tsconfig.json +include package.json +include webpack.config.js +include missing_module_widget/labextension/*.tgz + + +# Javascript files +graft missing_module_widget/nbextension +graft src +graft css +prune **/node_modules +prune coverage +prune lib + +# Patterns to exclude from any directory +global-exclude *~ +global-exclude *.pyc +global-exclude *.pyo +global-exclude .git +global-exclude .ipynb_checkpoints diff --git a/tests/widget_lib/missing_module_widget/README.md b/tests/widget_lib/missing_module_widget/README.md new file mode 100644 index 000000000..376a6c53c --- /dev/null +++ b/tests/widget_lib/missing_module_widget/README.md @@ -0,0 +1,76 @@ +# missing_module_widget + +[![Build Status](https://travis-ci.org//missing_module_widget.svg?branch=master)](https://travis-ci.org//missing_module_widget) +[![codecov](https://codecov.io/gh//missing_module_widget/branch/master/graph/badge.svg)](https://codecov.io/gh//missing_module_widget) + +A Bugged Widget + +## Installation + +You can install using `pip`: + +```bash +pip install missing_module_widget +``` + +If you are using Jupyter Notebook 5.2 or earlier, you may also need to enable +the nbextension: + +```bash +jupyter nbextension enable --py [--sys-prefix|--user|--system] missing_module_widget +``` + +## Development Installation + +Create a dev environment: + +```bash +conda create -n missing_module_widget-dev -c conda-forge nodejs yarn python jupyterlab +conda activate missing_module_widget-dev +``` + +Install the python. This will also build the TS package. + +```bash +pip install -e ".[test, examples]" +``` + +When developing your extensions, you need to manually enable your extensions with the +notebook / lab frontend. For lab, this is done by the command: + +``` +jupyter labextension develop --overwrite . +yarn run build +``` + +For classic notebook, you need to run: + +``` +jupyter nbextension install --sys-prefix --symlink --overwrite --py missing_module_widget +jupyter nbextension enable --sys-prefix --py missing_module_widget +``` + +Note that the `--symlink` flag doesn't work on Windows, so you will here have to run +the `install` command every time that you rebuild your extension. For certain installations +you might also need another flag instead of `--sys-prefix`, but we won't cover the meaning +of those flags here. + +### How to see your changes + +#### Typescript: + +If you use JupyterLab to develop then you can watch the source directory and run JupyterLab at the same time in different +terminals to watch for changes in the extension's source and automatically rebuild the widget. + +```bash +# Watch the source directory in one terminal, automatically rebuilding when needed +yarn run watch +# Run JupyterLab in another terminal +jupyter lab +``` + +After a change wait for the build to finish and then refresh your browser and the changes should take effect. + +#### Python: + +If you make a change to the python code then you will need to restart the notebook kernel to have it take effect. diff --git a/tests/widget_lib/missing_module_widget/babel.config.js b/tests/widget_lib/missing_module_widget/babel.config.js new file mode 100644 index 000000000..db89fe506 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/babel.config.js @@ -0,0 +1,13 @@ +module.exports = { + sourceMap: 'inline', + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ] + ] +}; diff --git a/tests/widget_lib/missing_module_widget/install.json b/tests/widget_lib/missing_module_widget/install.json new file mode 100644 index 000000000..869a43710 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/install.json @@ -0,0 +1,5 @@ +{ + "packageManager": "python", + "packageName": "missing_module_widget", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package missing_module_widget" +} diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget.json b/tests/widget_lib/missing_module_widget/missing_module_widget.json new file mode 100644 index 000000000..58d06e2ac --- /dev/null +++ b/tests/widget_lib/missing_module_widget/missing_module_widget.json @@ -0,0 +1,5 @@ +{ + "load_extensions": { + "missing_module_widget/extension": true + } +} diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py b/tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py new file mode 100644 index 000000000..7a0ef8d72 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) . +# Distributed under the terms of the Modified BSD License. + +from .example import ExampleWidget +from ._version import __version__, version_info + + +def _jupyter_labextension_paths(): + """Called by Jupyter Lab Server to detect if it is a valid labextension and + to install the widget + Returns + ======= + src: Source directory name to copy files from. Webpack outputs generated files + into this directory and Jupyter Lab copies from this directory during + widget installation + dest: Destination directory name to install widget files to. Jupyter Lab copies + from `src` directory into /labextensions/ directory + during widget installation + """ + return [{ + 'src': 'labextension', + 'dest': 'missing_module_widget', + }] + + +def _jupyter_nbextension_paths(): + """Called by Jupyter Notebook Server to detect if it is a valid nbextension and + to install the widget + Returns + ======= + section: The section of the Jupyter Notebook Server to change. + Must be 'notebook' for widget extensions + src: Source directory name to copy files from. Webpack outputs generated files + into this directory and Jupyter Notebook copies from this directory during + widget installation + dest: Destination directory name to install widget files to. Jupyter Notebook copies + from `src` directory into /nbextensions/ directory + during widget installation + require: Path to importable AMD Javascript module inside the + /nbextensions/ directory + """ + return [{ + 'section': 'notebook', + 'src': 'nbextension', + 'dest': 'missing_module_widget', + 'require': 'missing_module_widget/extension' + }] diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py b/tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py new file mode 100644 index 000000000..d1d93c6d9 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) . +# Distributed under the terms of the Modified BSD License. + +""" +Information about the frontend package of the widgets. +""" + +module_name = "missing_module_widget" +module_version = "^0.1.0" diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/_version.py b/tests/widget_lib/missing_module_widget/missing_module_widget/_version.py new file mode 100644 index 000000000..c47960a8f --- /dev/null +++ b/tests/widget_lib/missing_module_widget/missing_module_widget/_version.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) . +# Distributed under the terms of the Modified BSD License. + +version_info = (0, 1, 0, 'dev') +__version__ = ".".join(map(str, version_info)) diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/example.py b/tests/widget_lib/missing_module_widget/missing_module_widget/example.py new file mode 100644 index 000000000..90e027295 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/missing_module_widget/example.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) . +# Distributed under the terms of the Modified BSD License. + +""" +TODO: Add module docstring +""" + +from ipywidgets import DOMWidget +from traitlets import Unicode +from ._frontend import module_name, module_version + + +class ExampleWidget(DOMWidget): + """TODO: Add docstring here + """ + _model_name = Unicode('ExampleModel').tag(sync=True) + _model_module = Unicode(module_name).tag(sync=True) + _model_module_version = Unicode(module_version).tag(sync=True) + _view_name = Unicode('ExampleView').tag(sync=True) + _view_module = Unicode(module_name).tag(sync=True) + _view_module_version = Unicode(module_version).tag(sync=True) + + value = Unicode('Hello World 2').tag(sync=True) diff --git a/tests/widget_lib/missing_module_widget/package.json b/tests/widget_lib/missing_module_widget/package.json new file mode 100644 index 000000000..b9cc2029e --- /dev/null +++ b/tests/widget_lib/missing_module_widget/package.json @@ -0,0 +1,81 @@ +{ + "name": "missing_module_widget", + "version": "0.1.0", + "description": "A Bugged Widget", + "keywords": [ + "jupyter", + "jupyterlab", + "jupyterlab-extension", + "widgets" + ], + "files": [ + "lib/**/*.js", + "dist/*.js", + "css/*.css" + ], + "main": "lib/index.js", + "types": "./lib/index.d.ts", + "scripts": { + "build": "yarn run build:lib && yarn run build:nbextension && yarn run build:labextension:dev", + "build:prod": "yarn run build:lib && yarn run build:nbextension && yarn run build:labextension", + "build:labextension": "jupyter labextension build .", + "build:labextension:dev": "jupyter labextension build --development True .", + "build:lib": "tsc", + "build:nbextension": "webpack", + "clean": "yarn run clean:lib && yarn run clean:nbextension && yarn run clean:labextension", + "clean:lib": "rimraf lib", + "clean:labextension": "rimraf missing_module_widget/labextension", + "clean:nbextension": "rimraf missing_module_widget/nbextension/static/index.js", + "lint": "eslint . --ext .ts,.tsx --fix", + "lint:check": "eslint . --ext .ts,.tsx", + "prepack": "yarn run build:lib", + "test": "jest", + "watch": "npm-run-all -p watch:*", + "watch:lib": "tsc -w", + "watch:nbextension": "webpack --watch --mode=development", + "watch:labextension": "jupyter labextension watch ." + }, + "dependencies": { + "@jupyter-widgets/base": "^1.1.10 || ^2.0.0 || ^3.0.0 || ^4.0.0" + }, + "devDependencies": { + "@babel/core": "^7.5.0", + "@babel/preset-env": "^7.5.0", + "@jupyterlab/builder": "^3.0.0", + "@phosphor/application": "^1.6.0", + "@phosphor/widgets": "^1.6.0", + "@types/jest": "^26.0.0", + "@types/webpack-env": "^1.13.6", + "@typescript-eslint/eslint-plugin": "^3.6.0", + "@typescript-eslint/parser": "^3.6.0", + "acorn": "^7.2.0", + "css-loader": "^3.2.0", + "eslint": "^7.4.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-prettier": "^3.1.4", + "fs-extra": "^7.0.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^26.0.0", + "mkdirp": "^0.5.1", + "npm-run-all": "^4.1.3", + "prettier": "^2.0.5", + "rimraf": "^2.6.2", + "source-map-loader": "^1.1.3", + "style-loader": "^1.0.0", + "ts-jest": "^26.0.0", + "ts-loader": "^8.0.0", + "typescript": "~4.1.3", + "webpack": "^5.0.0", + "webpack-cli": "^4.0.0" + }, + "jupyterlab": { + "extension": "lib/plugin", + "outputDir": "missing_module_widget/labextension/", + "sharedPackages": { + "@jupyter-widgets/base": { + "bundled": false, + "singleton": true + } + } + } +} \ No newline at end of file diff --git a/tests/widget_lib/missing_module_widget/pyproject.toml b/tests/widget_lib/missing_module_widget/pyproject.toml new file mode 100644 index 000000000..498df1ec9 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["jupyter_packaging==0.7.9", "jupyterlab==3.*", "setuptools>=40.8.0", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/tests/widget_lib/missing_module_widget/setup.cfg b/tests/widget_lib/missing_module_widget/setup.cfg new file mode 100644 index 000000000..a74a31205 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/setup.cfg @@ -0,0 +1,7 @@ +[bdist_wheel] +universal=1 + +[metadata] +long_description = file: README.md +long_description_content_type = text/markdown +license_file = LICENSE.txt diff --git a/tests/widget_lib/missing_module_widget/setup.py b/tests/widget_lib/missing_module_widget/setup.py new file mode 100644 index 000000000..5170a9246 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/setup.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + +from __future__ import print_function +from glob import glob +import os +from os.path import join as pjoin +from setuptools import setup, find_packages + + +from jupyter_packaging import ( + create_cmdclass, + install_npm, + ensure_targets, + combine_commands, + get_version, + skip_if_exists +) + +HERE = os.path.dirname(os.path.abspath(__file__)) + + + + +# The name of the project +name = 'missing_module_widget' + +# Get the version +version = get_version(pjoin(name, '_version.py')) + + +# Representative files that should exist after a successful build +jstargets = [ + pjoin(HERE, name, 'nbextension', 'index.js'), + pjoin(HERE, name, 'labextension', 'package.json'), +] + + +package_data_spec = { + name: [ + 'nbextension/**js*', + 'labextension/**' + ] +} + + +data_files_spec = [ + ('share/jupyter/nbextensions/missing_module_widget', 'missing_module_widget/nbextension', '**'), + ('share/jupyter/labextensions/missing_module_widget', 'missing_module_widget/labextension', '**'), + ('share/jupyter/labextensions/missing_module_widget', '.', 'install.json'), + ('etc/jupyter/nbconfig/notebook.d', '.', 'missing_module_widget.json'), +] + + +cmdclass = create_cmdclass('jsdeps', package_data_spec=package_data_spec, + data_files_spec=data_files_spec) +npm_install = combine_commands( + install_npm(HERE, build_cmd='build:prod'), + ensure_targets(jstargets), +) +cmdclass['jsdeps'] = skip_if_exists(jstargets, npm_install) + + +setup_args = dict( + name = name, + description = 'A Bugged Widget', + version = version, + scripts = glob(pjoin('scripts', '*')), + cmdclass = cmdclass, + packages = find_packages(), + author = '', + author_email = '', + url = 'https://github.com//missing_module_widget', + license = 'BSD', + platforms = "Linux, Mac OS X, Windows", + keywords = ['Jupyter', 'Widgets', 'IPython'], + classifiers = [ + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Framework :: Jupyter', + ], + include_package_data = True, + python_requires=">=3.6", + install_requires = [ + 'ipywidgets>=7.0.0', + ], + extras_require = { + 'test': [ + 'pytest>=4.6', + 'pytest-cov', + 'nbval', + ], + 'examples': [ + # Any requirements for the examples to run + ], + 'docs': [ + 'jupyter_sphinx', + 'nbsphinx', + 'nbsphinx-link', + 'pytest_check_links', + 'pypandoc', + 'recommonmark', + 'sphinx>=1.5', + 'sphinx_rtd_theme', + ], + }, + entry_points = { + }, +) + +if __name__ == '__main__': + setup(**setup_args) diff --git a/tests/widget_lib/missing_module_widget/src/extension.ts b/tests/widget_lib/missing_module_widget/src/extension.ts new file mode 100644 index 000000000..60b11a6ee --- /dev/null +++ b/tests/widget_lib/missing_module_widget/src/extension.ts @@ -0,0 +1,16 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +// Entry point for the notebook bundle containing custom model definitions. +// +// Setup notebook base URL +// +// Some static assets may be required by the custom widget javascript. The base +// url for the notebook is not known at build time and is therefore computed +// dynamically. +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +(window as any).__webpack_public_path__ = + document.querySelector('body')!.getAttribute('data-base-url') + + 'nbextensions/missing_module_widget'; + +export * from './index'; diff --git a/tests/widget_lib/missing_module_widget/src/index.ts b/tests/widget_lib/missing_module_widget/src/index.ts new file mode 100644 index 000000000..e5de9dfeb --- /dev/null +++ b/tests/widget_lib/missing_module_widget/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) +// Distributed under the terms of the Modified BSD License. + +export * from './version'; +export * from './widget'; diff --git a/tests/widget_lib/missing_module_widget/src/plugin.ts b/tests/widget_lib/missing_module_widget/src/plugin.ts new file mode 100644 index 000000000..232b5738d --- /dev/null +++ b/tests/widget_lib/missing_module_widget/src/plugin.ts @@ -0,0 +1,42 @@ +// Copyright (c) +// Distributed under the terms of the Modified BSD License. + +import { Application, IPlugin } from '@phosphor/application'; + +import { Widget } from '@phosphor/widgets'; + +import { IJupyterWidgetRegistry } from '@jupyter-widgets/base'; + +import * as widgetExports from './widget'; + +import { MODULE_NAME, MODULE_VERSION } from './version'; + +const EXTENSION_ID = 'missing_module_widget:plugin'; + +/** + * The example plugin. + */ +const examplePlugin: IPlugin, void> = ({ + id: EXTENSION_ID, + requires: [IJupyterWidgetRegistry], + activate: activateWidgetExtension, + autoStart: true +} as unknown) as IPlugin, void>; +// the "as unknown as ..." typecast above is solely to support JupyterLab 1 +// and 2 in the same codebase and should be removed when we migrate to Lumino. + +export default examplePlugin; + +/** + * Activate the widget extension. + */ +function activateWidgetExtension( + app: Application, + registry: IJupyterWidgetRegistry +): void { + registry.registerWidget({ + name: MODULE_NAME, + version: MODULE_VERSION, + exports: widgetExports + }); +} diff --git a/tests/widget_lib/missing_module_widget/src/version.ts b/tests/widget_lib/missing_module_widget/src/version.ts new file mode 100644 index 000000000..c346bee3f --- /dev/null +++ b/tests/widget_lib/missing_module_widget/src/version.ts @@ -0,0 +1,20 @@ +// Copyright (c) +// Distributed under the terms of the Modified BSD License. + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// eslint-disable-next-line @typescript-eslint/no-var-requires +const data = require('../package.json'); + +/** + * The _model_module_version/_view_module_version this package implements. + * + * The html widget manager assumes that this is the same as the npm package + * version number. + */ +export const MODULE_VERSION = data.version; + +/* + * The current package name. + */ +export const MODULE_NAME = data.name; diff --git a/tests/widget_lib/missing_module_widget/src/widget.ts b/tests/widget_lib/missing_module_widget/src/widget.ts new file mode 100644 index 000000000..a86f9cd09 --- /dev/null +++ b/tests/widget_lib/missing_module_widget/src/widget.ts @@ -0,0 +1,50 @@ +// Copyright (c) +// Distributed under the terms of the Modified BSD License. + +import { + DOMWidgetModel, + DOMWidgetView, + ISerializers +} from '@jupyter-widgets/base'; + +import { MODULE_NAME, MODULE_VERSION } from './version'; + +export class ExampleModel extends DOMWidgetModel { + defaults() { + return { + ...super.defaults(), + _model_name: ExampleModel.model_name, + _model_module: ExampleModel.model_module, + _model_module_version: ExampleModel.model_module_version, + _view_name: ExampleModel.view_name, + _view_module: ExampleModel.view_module, + _view_module_version: ExampleModel.view_module_version, + value: 'Hello World' + }; + } + + static serializers: ISerializers = { + ...DOMWidgetModel.serializers + }; + + static model_name = 'ExampleModel'; + static model_module = MODULE_NAME; + static model_module_version = MODULE_VERSION; + static view_name = 'ExampleView'; + static view_module = MODULE_NAME; + static view_module_version = MODULE_VERSION; +} + +export class ExampleView extends DOMWidgetView { + render() { + this.el.classList.add('custom-widget'); + console.log('trung'); + + this.value_changed(); + this.model.on('change:value', this.value_changed, this); + } + + value_changed() { + this.el.textContent = this.model.get('value'); + } +} diff --git a/tests/widget_lib/missing_module_widget/tsconfig.json b/tests/widget_lib/missing_module_widget/tsconfig.json new file mode 100644 index 000000000..ac571087c --- /dev/null +++ b/tests/widget_lib/missing_module_widget/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "declaration": true, + "esModuleInterop": true, + "lib": ["es2015", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noUnusedLocals": true, + "outDir": "lib", + "resolveJsonModule": true, + "rootDir": "src", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "strictPropertyInitialization": false, + "target": "es2015", + "types": ["jest"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["src/**/__tests__"] +} diff --git a/tests/widget_lib/missing_module_widget/webpack.config.js b/tests/widget_lib/missing_module_widget/webpack.config.js new file mode 100644 index 000000000..1c5edb07d --- /dev/null +++ b/tests/widget_lib/missing_module_widget/webpack.config.js @@ -0,0 +1,90 @@ +const path = require('path'); +const version = require('./package.json').version; + +// Custom webpack rules +const rules = [ + { test: /\.ts$/, loader: 'ts-loader' }, + { test: /\.js$/, loader: 'source-map-loader' }, + { test: /\.css$/, use: ['style-loader', 'css-loader'] } +]; + +// Packages that shouldn't be bundled but loaded at runtime +const externals = ['@jupyter-widgets/base']; + +const resolve = { + // Add '.ts' and '.tsx' as resolvable extensions. + extensions: ['.webpack.js', '.web.js', '.ts', '.js'] +}; + +module.exports = [ + /** + * Notebook extension + * + * This bundle only contains the part of the JavaScript that is run on load of + * the notebook. + */ + { + entry: './src/extension.ts', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'missing_module_widget', 'nbextension'), + libraryTarget: 'amd', + publicPath: '' + }, + module: { + rules: rules + }, + devtool: 'source-map', + externals, + resolve + }, + + /** + * Embeddable missing_module_widget bundle + * + * This bundle is almost identical to the notebook extension bundle. The only + * difference is in the configuration of the webpack public path for the + * static assets. + * + * The target bundle is always `dist/index.js`, which is the path required by + * the custom widget embedder. + */ + { + entry: './src/index.ts', + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'amd', + library: 'missing_module_widget', + publicPath: + 'https://unpkg.com/missing_module_widget@' + version + '/dist/' + }, + devtool: 'source-map', + module: { + rules: rules + }, + externals, + resolve + }, + + /** + * Documentation widget bundle + * + * This bundle is used to embed widgets in the package documentation. + */ + { + entry: './src/index.ts', + output: { + filename: 'embed-bundle.js', + path: path.resolve(__dirname, 'docs', 'source', '_static'), + library: 'missing_module_widget', + libraryTarget: 'amd' + }, + module: { + rules: rules + }, + devtool: 'source-map', + externals, + resolve + } +]; diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 26b091f9b..891dee3ad 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,5 +1,10 @@ { "extends": "./tsconfigbase", - "include": ["packages/**/*", "lint-staged.config.js", "ui-tests"], + "include": [ + "packages/**/*", + "lint-staged.config.js", + "ui-tests", + "tests/widget_lib/missing_module_widget" + ], "types": ["jest"] } From 15fd1e5e29cf5b70b1a66de3fb7415de8d7d620a Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Tue, 28 Sep 2021 21:56:04 +0200 Subject: [PATCH 02/13] throw Error on module render --- tests/widget_lib/missing_module_widget/src/widget.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/widget_lib/missing_module_widget/src/widget.ts b/tests/widget_lib/missing_module_widget/src/widget.ts index a86f9cd09..f9f765425 100644 --- a/tests/widget_lib/missing_module_widget/src/widget.ts +++ b/tests/widget_lib/missing_module_widget/src/widget.ts @@ -36,15 +36,14 @@ export class ExampleModel extends DOMWidgetModel { } export class ExampleView extends DOMWidgetView { - render() { + render(): void { this.el.classList.add('custom-widget'); - console.log('trung'); - + throw new Error('Module not found'); this.value_changed(); this.model.on('change:value', this.value_changed, this); } - value_changed() { + value_changed(): void { this.el.textContent = this.model.get('value'); } } From e3215caf323c40f15afb30f827d819b606edc21b Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Wed, 29 Sep 2021 11:16:43 +0200 Subject: [PATCH 03/13] Rename widget to widget_lib --- .eslintignore | 3 ++- .gitignore | 2 +- .../{missing_module_widget => }/LICENSE.txt | 0 .../{missing_module_widget => }/MANIFEST.in | 7 +++--- .../{missing_module_widget => }/README.md | 20 +++++++-------- .../babel.config.js | 0 tests/widget_lib/install.json | 5 ++++ .../missing_module_widget/install.json | 5 ---- .../missing_module_widget.json | 5 ---- .../{missing_module_widget => }/package.json | 25 ++++++++++++++----- .../pyproject.toml | 0 .../{missing_module_widget => }/setup.cfg | 0 .../{missing_module_widget => }/setup.py | 16 ++++++------ .../src/extension.ts | 2 +- .../{missing_module_widget => }/src/index.ts | 2 +- .../{missing_module_widget => }/src/plugin.ts | 4 +-- .../src/version.ts | 2 +- .../{missing_module_widget => }/src/widget.ts | 13 +++++----- .../{missing_module_widget => }/tsconfig.json | 0 .../webpack.config.js | 11 ++++---- tests/widget_lib/widget_lib.json | 5 ++++ .../__init__.py | 9 +++---- .../_frontend.py | 4 +-- .../_version.py | 2 +- .../example.py | 4 +-- .../widget_lib/nbextension/extension.js | 17 +++++++++++++ tsconfig.eslint.json | 2 +- 27 files changed, 98 insertions(+), 67 deletions(-) rename tests/widget_lib/{missing_module_widget => }/LICENSE.txt (100%) rename tests/widget_lib/{missing_module_widget => }/MANIFEST.in (75%) rename tests/widget_lib/{missing_module_widget => }/README.md (71%) rename tests/widget_lib/{missing_module_widget => }/babel.config.js (100%) create mode 100644 tests/widget_lib/install.json delete mode 100644 tests/widget_lib/missing_module_widget/install.json delete mode 100644 tests/widget_lib/missing_module_widget/missing_module_widget.json rename tests/widget_lib/{missing_module_widget => }/package.json (80%) rename tests/widget_lib/{missing_module_widget => }/pyproject.toml (100%) rename tests/widget_lib/{missing_module_widget => }/setup.cfg (100%) rename tests/widget_lib/{missing_module_widget => }/setup.py (83%) rename tests/widget_lib/{missing_module_widget => }/src/extension.ts (93%) rename tests/widget_lib/{missing_module_widget => }/src/index.ts (81%) rename tests/widget_lib/{missing_module_widget => }/src/plugin.ts (93%) rename tests/widget_lib/{missing_module_widget => }/src/version.ts (95%) rename tests/widget_lib/{missing_module_widget => }/src/widget.ts (83%) rename tests/widget_lib/{missing_module_widget => }/tsconfig.json (100%) rename tests/widget_lib/{missing_module_widget => }/webpack.config.js (86%) create mode 100644 tests/widget_lib/widget_lib.json rename tests/widget_lib/{missing_module_widget/missing_module_widget => widget_lib}/__init__.py (91%) rename tests/widget_lib/{missing_module_widget/missing_module_widget => widget_lib}/_frontend.py (77%) rename tests/widget_lib/{missing_module_widget/missing_module_widget => widget_lib}/_version.py (87%) rename tests/widget_lib/{missing_module_widget/missing_module_widget => widget_lib}/example.py (89%) create mode 100644 tests/widget_lib/widget_lib/nbextension/extension.js diff --git a/.eslintignore b/.eslintignore index 26697c3ce..68b6db135 100644 --- a/.eslintignore +++ b/.eslintignore @@ -23,4 +23,5 @@ coverage .history/ .vscode/ -ui-tests/playwright-report \ No newline at end of file +ui-tests/playwright-report +tests/widget_lib/**/extension.js \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4cded79db..1f07e1800 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ ui-tests/jlab_root tests/widget_lib/**/docs tests/widget_lib/**/labextension -tests/widget_lib/**/nbextension \ No newline at end of file +tests/widget_lib/**/nbextension/index.* \ No newline at end of file diff --git a/tests/widget_lib/missing_module_widget/LICENSE.txt b/tests/widget_lib/LICENSE.txt similarity index 100% rename from tests/widget_lib/missing_module_widget/LICENSE.txt rename to tests/widget_lib/LICENSE.txt diff --git a/tests/widget_lib/missing_module_widget/MANIFEST.in b/tests/widget_lib/MANIFEST.in similarity index 75% rename from tests/widget_lib/missing_module_widget/MANIFEST.in rename to tests/widget_lib/MANIFEST.in index 932595e64..7526efa07 100644 --- a/tests/widget_lib/missing_module_widget/MANIFEST.in +++ b/tests/widget_lib/MANIFEST.in @@ -1,15 +1,16 @@ -include README.md +include LICENSE.txt include pyproject.toml + include tsconfig.json include package.json include webpack.config.js -include missing_module_widget/labextension/*.tgz +include widget_lib/labextension/*.tgz # Javascript files -graft missing_module_widget/nbextension +graft widget_lib/nbextension graft src graft css prune **/node_modules diff --git a/tests/widget_lib/missing_module_widget/README.md b/tests/widget_lib/README.md similarity index 71% rename from tests/widget_lib/missing_module_widget/README.md rename to tests/widget_lib/README.md index 376a6c53c..582392ad9 100644 --- a/tests/widget_lib/missing_module_widget/README.md +++ b/tests/widget_lib/README.md @@ -1,23 +1,23 @@ -# missing_module_widget +# widget_lib -[![Build Status](https://travis-ci.org//missing_module_widget.svg?branch=master)](https://travis-ci.org//missing_module_widget) -[![codecov](https://codecov.io/gh//missing_module_widget/branch/master/graph/badge.svg)](https://codecov.io/gh//missing_module_widget) +[![Build Status](https://travis-ci.org//widget_lib.svg?branch=master)](https://travis-ci.org//widget_lib) +[![codecov](https://codecov.io/gh//widget_lib/branch/master/graph/badge.svg)](https://codecov.io/gh//widget_lib) -A Bugged Widget +A custom Jupyter Widget library for testing Voila ## Installation You can install using `pip`: ```bash -pip install missing_module_widget +pip install widget_lib ``` If you are using Jupyter Notebook 5.2 or earlier, you may also need to enable the nbextension: ```bash -jupyter nbextension enable --py [--sys-prefix|--user|--system] missing_module_widget +jupyter nbextension enable --py [--sys-prefix|--user|--system] widget_lib ``` ## Development Installation @@ -25,8 +25,8 @@ jupyter nbextension enable --py [--sys-prefix|--user|--system] missing_module_wi Create a dev environment: ```bash -conda create -n missing_module_widget-dev -c conda-forge nodejs yarn python jupyterlab -conda activate missing_module_widget-dev +conda create -n widget_lib-dev -c conda-forge nodejs yarn python jupyterlab +conda activate widget_lib-dev ``` Install the python. This will also build the TS package. @@ -46,8 +46,8 @@ yarn run build For classic notebook, you need to run: ``` -jupyter nbextension install --sys-prefix --symlink --overwrite --py missing_module_widget -jupyter nbextension enable --sys-prefix --py missing_module_widget +jupyter nbextension install --sys-prefix --symlink --overwrite --py widget_lib +jupyter nbextension enable --sys-prefix --py widget_lib ``` Note that the `--symlink` flag doesn't work on Windows, so you will here have to run diff --git a/tests/widget_lib/missing_module_widget/babel.config.js b/tests/widget_lib/babel.config.js similarity index 100% rename from tests/widget_lib/missing_module_widget/babel.config.js rename to tests/widget_lib/babel.config.js diff --git a/tests/widget_lib/install.json b/tests/widget_lib/install.json new file mode 100644 index 000000000..a7c954273 --- /dev/null +++ b/tests/widget_lib/install.json @@ -0,0 +1,5 @@ +{ + "packageManager": "python", + "packageName": "widget_lib", + "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package widget_lib" +} diff --git a/tests/widget_lib/missing_module_widget/install.json b/tests/widget_lib/missing_module_widget/install.json deleted file mode 100644 index 869a43710..000000000 --- a/tests/widget_lib/missing_module_widget/install.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packageManager": "python", - "packageName": "missing_module_widget", - "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package missing_module_widget" -} diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget.json b/tests/widget_lib/missing_module_widget/missing_module_widget.json deleted file mode 100644 index 58d06e2ac..000000000 --- a/tests/widget_lib/missing_module_widget/missing_module_widget.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "load_extensions": { - "missing_module_widget/extension": true - } -} diff --git a/tests/widget_lib/missing_module_widget/package.json b/tests/widget_lib/package.json similarity index 80% rename from tests/widget_lib/missing_module_widget/package.json rename to tests/widget_lib/package.json index b9cc2029e..9ba520316 100644 --- a/tests/widget_lib/missing_module_widget/package.json +++ b/tests/widget_lib/package.json @@ -1,7 +1,7 @@ { - "name": "missing_module_widget", + "name": "widget_lib", "version": "0.1.0", - "description": "A Bugged Widget", + "description": "A custom Jupyter Widget library for testing Voila", "keywords": [ "jupyter", "jupyterlab", @@ -13,8 +13,21 @@ "dist/*.js", "css/*.css" ], + "homepage": "https://github.com//widget_lib", + "bugs": { + "url": "https://github.com//widget_lib/issues" + }, + "license": "BSD-3-Clause", + "author": { + "name": "Trung Le", + "email": "" + }, "main": "lib/index.js", "types": "./lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com//widget_lib" + }, "scripts": { "build": "yarn run build:lib && yarn run build:nbextension && yarn run build:labextension:dev", "build:prod": "yarn run build:lib && yarn run build:nbextension && yarn run build:labextension", @@ -24,8 +37,8 @@ "build:nbextension": "webpack", "clean": "yarn run clean:lib && yarn run clean:nbextension && yarn run clean:labextension", "clean:lib": "rimraf lib", - "clean:labextension": "rimraf missing_module_widget/labextension", - "clean:nbextension": "rimraf missing_module_widget/nbextension/static/index.js", + "clean:labextension": "rimraf widget_lib/labextension", + "clean:nbextension": "rimraf widget_lib/nbextension/static/index.js", "lint": "eslint . --ext .ts,.tsx --fix", "lint:check": "eslint . --ext .ts,.tsx", "prepack": "yarn run build:lib", @@ -70,7 +83,7 @@ }, "jupyterlab": { "extension": "lib/plugin", - "outputDir": "missing_module_widget/labextension/", + "outputDir": "widget_lib/labextension/", "sharedPackages": { "@jupyter-widgets/base": { "bundled": false, @@ -78,4 +91,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/widget_lib/missing_module_widget/pyproject.toml b/tests/widget_lib/pyproject.toml similarity index 100% rename from tests/widget_lib/missing_module_widget/pyproject.toml rename to tests/widget_lib/pyproject.toml diff --git a/tests/widget_lib/missing_module_widget/setup.cfg b/tests/widget_lib/setup.cfg similarity index 100% rename from tests/widget_lib/missing_module_widget/setup.cfg rename to tests/widget_lib/setup.cfg diff --git a/tests/widget_lib/missing_module_widget/setup.py b/tests/widget_lib/setup.py similarity index 83% rename from tests/widget_lib/missing_module_widget/setup.py rename to tests/widget_lib/setup.py index 5170a9246..015292bb6 100644 --- a/tests/widget_lib/missing_module_widget/setup.py +++ b/tests/widget_lib/setup.py @@ -26,7 +26,7 @@ # The name of the project -name = 'missing_module_widget' +name = 'widget_lib' # Get the version version = get_version(pjoin(name, '_version.py')) @@ -48,10 +48,10 @@ data_files_spec = [ - ('share/jupyter/nbextensions/missing_module_widget', 'missing_module_widget/nbextension', '**'), - ('share/jupyter/labextensions/missing_module_widget', 'missing_module_widget/labextension', '**'), - ('share/jupyter/labextensions/missing_module_widget', '.', 'install.json'), - ('etc/jupyter/nbconfig/notebook.d', '.', 'missing_module_widget.json'), + ('share/jupyter/nbextensions/widget_lib', 'widget_lib/nbextension', '**'), + ('share/jupyter/labextensions/widget_lib', 'widget_lib/labextension', '**'), + ('share/jupyter/labextensions/widget_lib', '.', 'install.json'), + ('etc/jupyter/nbconfig/notebook.d', '.', 'widget_lib.json'), ] @@ -66,14 +66,14 @@ setup_args = dict( name = name, - description = 'A Bugged Widget', + description = 'A custom Jupyter Widget library for testing Voila', version = version, scripts = glob(pjoin('scripts', '*')), cmdclass = cmdclass, packages = find_packages(), - author = '', + author = 'Trung Le', author_email = '', - url = 'https://github.com//missing_module_widget', + url = 'https://github.com//widget_lib', license = 'BSD', platforms = "Linux, Mac OS X, Windows", keywords = ['Jupyter', 'Widgets', 'IPython'], diff --git a/tests/widget_lib/missing_module_widget/src/extension.ts b/tests/widget_lib/src/extension.ts similarity index 93% rename from tests/widget_lib/missing_module_widget/src/extension.ts rename to tests/widget_lib/src/extension.ts index 60b11a6ee..35d071cfc 100644 --- a/tests/widget_lib/missing_module_widget/src/extension.ts +++ b/tests/widget_lib/src/extension.ts @@ -11,6 +11,6 @@ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion (window as any).__webpack_public_path__ = document.querySelector('body')!.getAttribute('data-base-url') + - 'nbextensions/missing_module_widget'; + 'nbextensions/widget_lib'; export * from './index'; diff --git a/tests/widget_lib/missing_module_widget/src/index.ts b/tests/widget_lib/src/index.ts similarity index 81% rename from tests/widget_lib/missing_module_widget/src/index.ts rename to tests/widget_lib/src/index.ts index e5de9dfeb..4d28a375f 100644 --- a/tests/widget_lib/missing_module_widget/src/index.ts +++ b/tests/widget_lib/src/index.ts @@ -1,4 +1,4 @@ -// Copyright (c) +// Copyright (c) Trung Le // Distributed under the terms of the Modified BSD License. export * from './version'; diff --git a/tests/widget_lib/missing_module_widget/src/plugin.ts b/tests/widget_lib/src/plugin.ts similarity index 93% rename from tests/widget_lib/missing_module_widget/src/plugin.ts rename to tests/widget_lib/src/plugin.ts index 232b5738d..24a7db307 100644 --- a/tests/widget_lib/missing_module_widget/src/plugin.ts +++ b/tests/widget_lib/src/plugin.ts @@ -1,4 +1,4 @@ -// Copyright (c) +// Copyright (c) Trung Le // Distributed under the terms of the Modified BSD License. import { Application, IPlugin } from '@phosphor/application'; @@ -11,7 +11,7 @@ import * as widgetExports from './widget'; import { MODULE_NAME, MODULE_VERSION } from './version'; -const EXTENSION_ID = 'missing_module_widget:plugin'; +const EXTENSION_ID = 'widget_lib:plugin'; /** * The example plugin. diff --git a/tests/widget_lib/missing_module_widget/src/version.ts b/tests/widget_lib/src/version.ts similarity index 95% rename from tests/widget_lib/missing_module_widget/src/version.ts rename to tests/widget_lib/src/version.ts index c346bee3f..fadcda14c 100644 --- a/tests/widget_lib/missing_module_widget/src/version.ts +++ b/tests/widget_lib/src/version.ts @@ -1,4 +1,4 @@ -// Copyright (c) +// Copyright (c) Trung Le // Distributed under the terms of the Modified BSD License. // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/tests/widget_lib/missing_module_widget/src/widget.ts b/tests/widget_lib/src/widget.ts similarity index 83% rename from tests/widget_lib/missing_module_widget/src/widget.ts rename to tests/widget_lib/src/widget.ts index f9f765425..0feaa29ec 100644 --- a/tests/widget_lib/missing_module_widget/src/widget.ts +++ b/tests/widget_lib/src/widget.ts @@ -1,4 +1,4 @@ -// Copyright (c) +// Copyright (c) Trung Le // Distributed under the terms of the Modified BSD License. import { @@ -25,25 +25,26 @@ export class ExampleModel extends DOMWidgetModel { static serializers: ISerializers = { ...DOMWidgetModel.serializers + // Add any extra serializers here }; static model_name = 'ExampleModel'; static model_module = MODULE_NAME; static model_module_version = MODULE_VERSION; - static view_name = 'ExampleView'; - static view_module = MODULE_NAME; + static view_name = 'ExampleView'; // Set to null if no view + static view_module = MODULE_NAME; // Set to null if no view static view_module_version = MODULE_VERSION; } export class ExampleView extends DOMWidgetView { - render(): void { + render() { this.el.classList.add('custom-widget'); - throw new Error('Module not found'); + this.value_changed(); this.model.on('change:value', this.value_changed, this); } - value_changed(): void { + value_changed() { this.el.textContent = this.model.get('value'); } } diff --git a/tests/widget_lib/missing_module_widget/tsconfig.json b/tests/widget_lib/tsconfig.json similarity index 100% rename from tests/widget_lib/missing_module_widget/tsconfig.json rename to tests/widget_lib/tsconfig.json diff --git a/tests/widget_lib/missing_module_widget/webpack.config.js b/tests/widget_lib/webpack.config.js similarity index 86% rename from tests/widget_lib/missing_module_widget/webpack.config.js rename to tests/widget_lib/webpack.config.js index 1c5edb07d..ef0c5bda4 100644 --- a/tests/widget_lib/missing_module_widget/webpack.config.js +++ b/tests/widget_lib/webpack.config.js @@ -27,7 +27,7 @@ module.exports = [ entry: './src/extension.ts', output: { filename: 'index.js', - path: path.resolve(__dirname, 'missing_module_widget', 'nbextension'), + path: path.resolve(__dirname, 'widget_lib', 'nbextension'), libraryTarget: 'amd', publicPath: '' }, @@ -40,7 +40,7 @@ module.exports = [ }, /** - * Embeddable missing_module_widget bundle + * Embeddable widget_lib bundle * * This bundle is almost identical to the notebook extension bundle. The only * difference is in the configuration of the webpack public path for the @@ -55,9 +55,8 @@ module.exports = [ filename: 'index.js', path: path.resolve(__dirname, 'dist'), libraryTarget: 'amd', - library: 'missing_module_widget', - publicPath: - 'https://unpkg.com/missing_module_widget@' + version + '/dist/' + library: 'widget_lib', + publicPath: 'https://unpkg.com/widget_lib@' + version + '/dist/' }, devtool: 'source-map', module: { @@ -77,7 +76,7 @@ module.exports = [ output: { filename: 'embed-bundle.js', path: path.resolve(__dirname, 'docs', 'source', '_static'), - library: 'missing_module_widget', + library: 'widget_lib', libraryTarget: 'amd' }, module: { diff --git a/tests/widget_lib/widget_lib.json b/tests/widget_lib/widget_lib.json new file mode 100644 index 000000000..9b352c6e4 --- /dev/null +++ b/tests/widget_lib/widget_lib.json @@ -0,0 +1,5 @@ +{ + "load_extensions": { + "widget_lib/extension": true + } +} diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py b/tests/widget_lib/widget_lib/__init__.py similarity index 91% rename from tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py rename to tests/widget_lib/widget_lib/__init__.py index 7a0ef8d72..058eacef5 100644 --- a/tests/widget_lib/missing_module_widget/missing_module_widget/__init__.py +++ b/tests/widget_lib/widget_lib/__init__.py @@ -1,13 +1,12 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright (c) . +# Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. from .example import ExampleWidget from ._version import __version__, version_info - def _jupyter_labextension_paths(): """Called by Jupyter Lab Server to detect if it is a valid labextension and to install the widget @@ -22,7 +21,7 @@ def _jupyter_labextension_paths(): """ return [{ 'src': 'labextension', - 'dest': 'missing_module_widget', + 'dest': 'widget_lib', }] @@ -45,6 +44,6 @@ def _jupyter_nbextension_paths(): return [{ 'section': 'notebook', 'src': 'nbextension', - 'dest': 'missing_module_widget', - 'require': 'missing_module_widget/extension' + 'dest': 'widget_lib', + 'require': 'widget_lib/extension' }] diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py b/tests/widget_lib/widget_lib/_frontend.py similarity index 77% rename from tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py rename to tests/widget_lib/widget_lib/_frontend.py index d1d93c6d9..7a9102dd8 100644 --- a/tests/widget_lib/missing_module_widget/missing_module_widget/_frontend.py +++ b/tests/widget_lib/widget_lib/_frontend.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright (c) . +# Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. """ Information about the frontend package of the widgets. """ -module_name = "missing_module_widget" +module_name = "widget_lib" module_version = "^0.1.0" diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/_version.py b/tests/widget_lib/widget_lib/_version.py similarity index 87% rename from tests/widget_lib/missing_module_widget/missing_module_widget/_version.py rename to tests/widget_lib/widget_lib/_version.py index c47960a8f..0e78da25f 100644 --- a/tests/widget_lib/missing_module_widget/missing_module_widget/_version.py +++ b/tests/widget_lib/widget_lib/_version.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright (c) . +# Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. version_info = (0, 1, 0, 'dev') diff --git a/tests/widget_lib/missing_module_widget/missing_module_widget/example.py b/tests/widget_lib/widget_lib/example.py similarity index 89% rename from tests/widget_lib/missing_module_widget/missing_module_widget/example.py rename to tests/widget_lib/widget_lib/example.py index 90e027295..ac19e54e4 100644 --- a/tests/widget_lib/missing_module_widget/missing_module_widget/example.py +++ b/tests/widget_lib/widget_lib/example.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright (c) . +# Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. """ @@ -23,4 +23,4 @@ class ExampleWidget(DOMWidget): _view_module = Unicode(module_name).tag(sync=True) _view_module_version = Unicode(module_version).tag(sync=True) - value = Unicode('Hello World 2').tag(sync=True) + value = Unicode('Hello World').tag(sync=True) diff --git a/tests/widget_lib/widget_lib/nbextension/extension.js b/tests/widget_lib/widget_lib/nbextension/extension.js new file mode 100644 index 000000000..9081b51f8 --- /dev/null +++ b/tests/widget_lib/widget_lib/nbextension/extension.js @@ -0,0 +1,17 @@ +// Entry point for the notebook bundle containing custom model definitions. +// +define(function() { + 'use strict'; + + window['requirejs'].config({ + map: { + '*': { + widget_lib: 'nbextensions/widget_lib/index' + } + } + }); + // Export the required load_ipython_extension function + return { + load_ipython_extension: function() {} + }; +}); diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 891dee3ad..bb9649d15 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -4,7 +4,7 @@ "packages/**/*", "lint-staged.config.js", "ui-tests", - "tests/widget_lib/missing_module_widget" + "tests/widget_lib" ], "types": ["jest"] } From bce5a03335798b81cacae6c9b764f3b400b363de Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 1 Oct 2021 01:09:48 +0200 Subject: [PATCH 04/13] Add stability test --- .github/workflows/ui-tests.yml | 34 ++++-- tests/widget_lib/src/widget.ts | 60 +++++++--- tests/widget_lib/widget_lib/__init__.py | 2 +- tests/widget_lib/widget_lib/example.py | 31 ++++- ui-tests/notebooks/missing_module.ipynb | 66 +++++++++++ ui-tests/notebooks/module_error.ipynb | 66 +++++++++++ ui-tests/notebooks/render_error.ipynb | 111 ++++++++++++++++++ ui-tests/package.json | 4 +- ui-tests/playwright.config.js | 38 ++++-- ui-tests/stability_test/stability.test.ts | 60 ++++++++++ .../missing-module-stability-test-linux.png | Bin 0 -> 8145 bytes .../module-error-stability-test-linux.png | Bin 0 -> 8145 bytes .../render-error-stability-test-linux.png | Bin 0 -> 8145 bytes ... => basics-render-and-benchmark-linux.png} | Bin ... => bqplot-render-and-benchmark-linux.png} | Bin ...specLayout-render-and-benchmark-linux.png} | Bin ...nteractive-render-and-benchmark-linux.png} | Bin ... => ipympl-render-and-benchmark-linux.png} | Bin ... ipyvolume-render-and-benchmark-linux.png} | Bin ...le-widgets-render-and-benchmark-linux.png} | Bin ...ry-strings-render-and-benchmark-linux.png} | Bin 21 files changed, 429 insertions(+), 43 deletions(-) create mode 100644 ui-tests/notebooks/missing_module.ipynb create mode 100644 ui-tests/notebooks/module_error.ipynb create mode 100644 ui-tests/notebooks/render_error.ipynb create mode 100644 ui-tests/stability_test/stability.test.ts create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/missing-module-stability-test-linux.png create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/module-error-stability-test-linux.png create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/render-error-stability-test-linux.png rename ui-tests/tests/voila.test.ts-snapshots/{basics-linux.png => basics-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{bqplot-linux.png => bqplot-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{gridspecLayout-linux.png => gridspecLayout-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{interactive-linux.png => interactive-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{ipympl-linux.png => ipympl-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{ipyvolume-linux.png => ipyvolume-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{multiple-widgets-linux.png => multiple-widgets-render-and-benchmark-linux.png} (100%) rename ui-tests/tests/voila.test.ts-snapshots/{query-strings-linux.png => query-strings-render-and-benchmark-linux.png} (100%) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index b480bbe2b..64b56b0a5 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -26,12 +26,8 @@ jobs: jupyter labextension develop . --overwrite cd ui-tests jlpm install --frozen-lockfile - - - name: Launch Voila - run: | - cd ui-tests - # Mount a volume to overwrite the server configuration - jlpm start 2>&1 > /tmp/jupyterlab_server.log & + cd ../tests/widget_lib + pip install . - name: Install browser run: | @@ -39,7 +35,31 @@ jobs: # Install only Chromium browser jlpm playwright install chromium - - name: Wait for JupyterLab + - name: Launch Voila stability test server + run: | + cd ui-tests + jlpm start-stability 2>&1 > /tmp/jupyterlab_server.log & + + - name: Wait for Voila + uses: ifaxity/wait-on-action@v1 + with: + resource: http-get://localhost:8868/ + timeout: 360000 + + - uses: iterative/setup-cml@v1 + - name: Test-stability + shell: bash + run: | + cd ui-tests + jlpm run test-stability + + - name: Launch Voila + run: | + cd ui-tests + # Mount a volume to overwrite the server configuration + jlpm start 2>&1 > /tmp/jupyterlab_server.log & + + - name: Wait for Voila uses: ifaxity/wait-on-action@v1 with: resource: http-get://localhost:8866/ diff --git a/tests/widget_lib/src/widget.ts b/tests/widget_lib/src/widget.ts index 0feaa29ec..e1c3c7427 100644 --- a/tests/widget_lib/src/widget.ts +++ b/tests/widget_lib/src/widget.ts @@ -9,42 +9,64 @@ import { import { MODULE_NAME, MODULE_VERSION } from './version'; -export class ExampleModel extends DOMWidgetModel { +export class RenderErrorModel extends DOMWidgetModel { defaults() { return { ...super.defaults(), - _model_name: ExampleModel.model_name, - _model_module: ExampleModel.model_module, - _model_module_version: ExampleModel.model_module_version, - _view_name: ExampleModel.view_name, - _view_module: ExampleModel.view_module, - _view_module_version: ExampleModel.view_module_version, + _model_name: RenderErrorModel.model_name, + _model_module: MODULE_NAME, + _model_module_version: MODULE_VERSION, + _view_name: RenderErrorModel.view_name, + _view_module: MODULE_NAME, + _view_module_version: MODULE_VERSION, value: 'Hello World' }; } static serializers: ISerializers = { ...DOMWidgetModel.serializers - // Add any extra serializers here }; - static model_name = 'ExampleModel'; - static model_module = MODULE_NAME; - static model_module_version = MODULE_VERSION; - static view_name = 'ExampleView'; // Set to null if no view - static view_module = MODULE_NAME; // Set to null if no view - static view_module_version = MODULE_VERSION; + static model_name = 'RenderErrorModel'; + static view_name = 'RenderErrorView'; } -export class ExampleView extends DOMWidgetView { - render() { +export class RenderErrorView extends DOMWidgetView { + render(): void { this.el.classList.add('custom-widget'); + throw Error('Failed to render widget'); + } +} + +export class ModuleErrorModel extends DOMWidgetModel { + defaults() { + return { + ...super.defaults(), + _model_name: ModuleErrorModel.model_name, + _model_module: MODULE_NAME, + _model_module_version: MODULE_VERSION, + _view_name: ModuleErrorModel.view_name, + _view_module: MODULE_NAME, + _view_module_version: MODULE_VERSION, + value: 'Hello World' + }; + } - this.value_changed(); - this.model.on('change:value', this.value_changed, this); + initialize(): void { + throw Error('Failed to initialize model.'); } - value_changed() { + static serializers: ISerializers = { + ...DOMWidgetModel.serializers + }; + + static model_name = 'ModuleErrorModel'; + static view_name = 'ModuleErrorView'; +} + +export class ModuleErrorView extends DOMWidgetView { + render(): void { + this.el.classList.add('custom-widget'); this.el.textContent = this.model.get('value'); } } diff --git a/tests/widget_lib/widget_lib/__init__.py b/tests/widget_lib/widget_lib/__init__.py index 058eacef5..8c79bf27e 100644 --- a/tests/widget_lib/widget_lib/__init__.py +++ b/tests/widget_lib/widget_lib/__init__.py @@ -4,7 +4,7 @@ # Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. -from .example import ExampleWidget +from .example import ModuleImportError, ViewRenderError, ModelInitializationError from ._version import __version__, version_info def _jupyter_labextension_paths(): diff --git a/tests/widget_lib/widget_lib/example.py b/tests/widget_lib/widget_lib/example.py index ac19e54e4..99577ced7 100644 --- a/tests/widget_lib/widget_lib/example.py +++ b/tests/widget_lib/widget_lib/example.py @@ -13,14 +13,33 @@ from ._frontend import module_name, module_version -class ExampleWidget(DOMWidget): - """TODO: Add docstring here - """ - _model_name = Unicode('ExampleModel').tag(sync=True) +class ViewRenderError(DOMWidget): + _model_name = Unicode('RenderErrorModel').tag(sync=True) _model_module = Unicode(module_name).tag(sync=True) _model_module_version = Unicode(module_version).tag(sync=True) - _view_name = Unicode('ExampleView').tag(sync=True) + _view_name = Unicode('RenderErrorView').tag(sync=True) + _view_module = Unicode(module_name).tag(sync=True) + _view_module_version = Unicode(module_version).tag(sync=True) + + value = Unicode('Hello RenderError').tag(sync=True) + + +class ModelInitializationError(DOMWidget): + _model_name = Unicode('ModuleErrorModel').tag(sync=True) + _model_module = Unicode(module_name).tag(sync=True) + _model_module_version = Unicode(module_version).tag(sync=True) + _view_name = Unicode('ModuleErrorView').tag(sync=True) + _view_module = Unicode(module_name).tag(sync=True) + _view_module_version = Unicode(module_version).tag(sync=True) + + value = Unicode('Hello ModuleError').tag(sync=True) + + +class ModuleImportError(DOMWidget): + _model_name = Unicode('ModuleImportErrorModel').tag(sync=True) + _model_module = Unicode(module_name).tag(sync=True) + _model_module_version = Unicode(module_version).tag(sync=True) + _view_name = Unicode('ModuleImportErrorView').tag(sync=True) _view_module = Unicode(module_name).tag(sync=True) _view_module_version = Unicode(module_version).tag(sync=True) - value = Unicode('Hello World').tag(sync=True) diff --git a/ui-tests/notebooks/missing_module.ipynb b/ui-tests/notebooks/missing_module.ipynb new file mode 100644 index 000000000..17375d16d --- /dev/null +++ b/ui-tests/notebooks/missing_module.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "4cefa76b-4ad4-4de1-bd90-d1407ebc5f19", + "metadata": {}, + "outputs": [], + "source": [ + "from widget_lib import ModuleImportError\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72c9875e-e74d-4068-ae01-5399bd9195a5", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'First button')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8400bffd-cdb9-4be0-ae67-db2cf3592dfe", + "metadata": {}, + "outputs": [], + "source": [ + "ModuleImportError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94d6c874-ff20-4090-9611-bee3a49f24e3", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'Second button')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/module_error.ipynb b/ui-tests/notebooks/module_error.ipynb new file mode 100644 index 000000000..198c3f9d8 --- /dev/null +++ b/ui-tests/notebooks/module_error.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "4cefa76b-4ad4-4de1-bd90-d1407ebc5f19", + "metadata": {}, + "outputs": [], + "source": [ + "from widget_lib import ModelInitializationError\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72c9875e-e74d-4068-ae01-5399bd9195a5", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'First button')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8400bffd-cdb9-4be0-ae67-db2cf3592dfe", + "metadata": {}, + "outputs": [], + "source": [ + "ModelInitializationError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94d6c874-ff20-4090-9611-bee3a49f24e3", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'Second button')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/render_error.ipynb b/ui-tests/notebooks/render_error.ipynb new file mode 100644 index 000000000..6dc9a181f --- /dev/null +++ b/ui-tests/notebooks/render_error.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "4cefa76b-4ad4-4de1-bd90-d1407ebc5f19", + "metadata": {}, + "outputs": [], + "source": [ + "from widget_lib import ViewRenderError\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "72c9875e-e74d-4068-ae01-5399bd9195a5", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2c9be914d7b041579f10b7bbcb4818d8", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='First button', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "widgets.Button(description = 'First button')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "8400bffd-cdb9-4be0-ae67-db2cf3592dfe", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "321e94a973014418ab8442204754955e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "ViewRenderError()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ViewRenderError()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "94d6c874-ff20-4090-9611-bee3a49f24e3", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "09e6924c6f4b41449f34a17a6b77bac0", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(description='Second button', style=ButtonStyle())" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "widgets.Button(description = 'Second button')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/package.json b/ui-tests/package.json index 5459e9fba..dbb079e29 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -5,8 +5,10 @@ "private": true, "scripts": { "start": "voila ../notebooks --no-browser", + "start-stability": "voila ./notebooks --no-browser --enable_nbextensions=True --port 8868", "start:detached": "yarn run start-jlab&", - "test": "playwright test", + "test": "playwright test --project=render-and-benchmark", + "test-stability": "playwright test --project=stability-test", "test:debug": "PWDEBUG=1 playwright test", "test:report": "http-server ./playwright-report -a localhost -o", "test:update": "playwright test --update-snapshots" diff --git a/ui-tests/playwright.config.js b/ui-tests/playwright.config.js index 2daa0ec71..1c5690db1 100644 --- a/ui-tests/playwright.config.js +++ b/ui-tests/playwright.config.js @@ -1,8 +1,34 @@ const baseConfig = require('@jupyterlab/galata/lib/playwright-config'); module.exports = { - ...baseConfig, - timeout: 240000, + projects: [ + { + ...baseConfig, + name: 'render-and-benchmark', + testDir: 'tests', + timeout: 240000, + use: { + baseURL: 'http://localhost:8866/voila/', + video: 'retain-on-failure' + }, + // Try one retry as some tests are flaky + retries: 0, + workers: 2 + }, + { + ...baseConfig, + name: 'stability-test', + testDir: 'stability_test', + timeout: 240000, + use: { + baseURL: 'http://localhost:8868/voila/', + video: 'retain-on-failure' + }, + // Try one retry as some tests are flaky + retries: 0, + workers: 2 + } + ], reporter: [ [process.env.CI ? 'dot' : 'list'], [ @@ -10,11 +36,5 @@ module.exports = { { outputFile: 'voila-benchmark.json' } ], ['html'] - ], - use: { - baseURL: 'http://localhost:8866/voila/', - video: 'retain-on-failure' - }, - // Try one retry as some tests are flaky - retries: 1 + ] }; diff --git a/ui-tests/stability_test/stability.test.ts b/ui-tests/stability_test/stability.test.ts new file mode 100644 index 000000000..14d7007c3 --- /dev/null +++ b/ui-tests/stability_test/stability.test.ts @@ -0,0 +1,60 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { expect, test } from '@playwright/test'; + +test.describe('Voila stability Tests', () => { + let errorLogs: string; + test.beforeEach(({ page }) => { + page.setDefaultTimeout(120000); + errorLogs = ''; + page.on('console', message => { + if (message.type() === 'error') { + errorLogs += message.text() + '\n'; + } + }); + }); + test.afterEach(async ({ page, browserName }) => { + await page.close({ runBeforeUnload: true }); + }); + test('Should render notebook with missing module', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'missing_module'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('button'); + await page.$('text=Typesetting math: 100%'); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain( + 'Class ModuleImportErrorModel not found in module widget_lib@^0.1.0' + ); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); + + test('Should render notebook with model error', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'module_error'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('button'); + await page.$('text=Typesetting math: 100%'); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain('Error: Failed to initialize model.'); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); + + test('Should render notebook with render error', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'render_error'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('button'); + await page.$('text=Typesetting math: 100%'); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain('Error: Could not create view'); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); +}); diff --git a/ui-tests/stability_test/stability.test.ts-snapshots/missing-module-stability-test-linux.png b/ui-tests/stability_test/stability.test.ts-snapshots/missing-module-stability-test-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..14c99fc62c10e1869106c65d260b96111bcbd8e0 GIT binary patch literal 8145 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 Date: Fri, 1 Oct 2021 15:08:02 +0200 Subject: [PATCH 05/13] Run two projects at same time --- .github/workflows/ui-tests.yml | 7 ---- tests/widget_lib/README.md | 77 +--------------------------------- ui-tests/package.json | 3 +- 3 files changed, 2 insertions(+), 85 deletions(-) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 64b56b0a5..d9381e296 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -46,13 +46,6 @@ jobs: resource: http-get://localhost:8868/ timeout: 360000 - - uses: iterative/setup-cml@v1 - - name: Test-stability - shell: bash - run: | - cd ui-tests - jlpm run test-stability - - name: Launch Voila run: | cd ui-tests diff --git a/tests/widget_lib/README.md b/tests/widget_lib/README.md index 582392ad9..8de78df4a 100644 --- a/tests/widget_lib/README.md +++ b/tests/widget_lib/README.md @@ -1,76 +1 @@ -# widget_lib - -[![Build Status](https://travis-ci.org//widget_lib.svg?branch=master)](https://travis-ci.org//widget_lib) -[![codecov](https://codecov.io/gh//widget_lib/branch/master/graph/badge.svg)](https://codecov.io/gh//widget_lib) - -A custom Jupyter Widget library for testing Voila - -## Installation - -You can install using `pip`: - -```bash -pip install widget_lib -``` - -If you are using Jupyter Notebook 5.2 or earlier, you may also need to enable -the nbextension: - -```bash -jupyter nbextension enable --py [--sys-prefix|--user|--system] widget_lib -``` - -## Development Installation - -Create a dev environment: - -```bash -conda create -n widget_lib-dev -c conda-forge nodejs yarn python jupyterlab -conda activate widget_lib-dev -``` - -Install the python. This will also build the TS package. - -```bash -pip install -e ".[test, examples]" -``` - -When developing your extensions, you need to manually enable your extensions with the -notebook / lab frontend. For lab, this is done by the command: - -``` -jupyter labextension develop --overwrite . -yarn run build -``` - -For classic notebook, you need to run: - -``` -jupyter nbextension install --sys-prefix --symlink --overwrite --py widget_lib -jupyter nbextension enable --sys-prefix --py widget_lib -``` - -Note that the `--symlink` flag doesn't work on Windows, so you will here have to run -the `install` command every time that you rebuild your extension. For certain installations -you might also need another flag instead of `--sys-prefix`, but we won't cover the meaning -of those flags here. - -### How to see your changes - -#### Typescript: - -If you use JupyterLab to develop then you can watch the source directory and run JupyterLab at the same time in different -terminals to watch for changes in the extension's source and automatically rebuild the widget. - -```bash -# Watch the source directory in one terminal, automatically rebuilding when needed -yarn run watch -# Run JupyterLab in another terminal -jupyter lab -``` - -After a change wait for the build to finish and then refresh your browser and the changes should take effect. - -#### Python: - -If you make a change to the python code then you will need to restart the notebook kernel to have it take effect. +## Collection of bugged widgets used to test the stability of `Voila`. diff --git a/ui-tests/package.json b/ui-tests/package.json index dbb079e29..7c2768479 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -7,8 +7,7 @@ "start": "voila ../notebooks --no-browser", "start-stability": "voila ./notebooks --no-browser --enable_nbextensions=True --port 8868", "start:detached": "yarn run start-jlab&", - "test": "playwright test --project=render-and-benchmark", - "test-stability": "playwright test --project=stability-test", + "test": "playwright test", "test:debug": "PWDEBUG=1 playwright test", "test:report": "http-server ./playwright-report -a localhost -o", "test:update": "playwright test --update-snapshots" From 1e4b8b72ba181643320f31ece8625c4e03927cc8 Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 1 Oct 2021 11:47:06 +0000 Subject: [PATCH 06/13] Fix python format (cherry picked from commit 9a43dbfaf67f710b2549de4db60e1a5d1381f7ce) --- tests/widget_lib/setup.py | 38 ++++++++++++------------- tests/widget_lib/widget_lib/__init__.py | 5 +++- tests/widget_lib/widget_lib/example.py | 1 - 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/widget_lib/setup.py b/tests/widget_lib/setup.py index 015292bb6..3aba321e8 100644 --- a/tests/widget_lib/setup.py +++ b/tests/widget_lib/setup.py @@ -23,8 +23,6 @@ HERE = os.path.dirname(os.path.abspath(__file__)) - - # The name of the project name = 'widget_lib' @@ -56,7 +54,7 @@ cmdclass = create_cmdclass('jsdeps', package_data_spec=package_data_spec, - data_files_spec=data_files_spec) + data_files_spec=data_files_spec) npm_install = combine_commands( install_npm(HERE, build_cmd='build:prod'), ensure_targets(jstargets), @@ -65,19 +63,19 @@ setup_args = dict( - name = name, - description = 'A custom Jupyter Widget library for testing Voila', - version = version, - scripts = glob(pjoin('scripts', '*')), - cmdclass = cmdclass, - packages = find_packages(), - author = 'Trung Le', - author_email = '', - url = 'https://github.com//widget_lib', - license = 'BSD', - platforms = "Linux, Mac OS X, Windows", - keywords = ['Jupyter', 'Widgets', 'IPython'], - classifiers = [ + name=name, + description='A custom Jupyter Widget library for testing Voila', + version=version, + scripts=glob(pjoin('scripts', '*')), + cmdclass=cmdclass, + packages=find_packages(), + author='Trung Le', + author_email='', + url='https://github.com//widget_lib', + license='BSD', + platforms="Linux, Mac OS X, Windows", + keywords=['Jupyter', 'Widgets', 'IPython'], + classifiers=[ 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', @@ -89,12 +87,12 @@ 'Programming Language :: Python :: 3.7', 'Framework :: Jupyter', ], - include_package_data = True, + include_package_data=True, python_requires=">=3.6", - install_requires = [ + install_requires=[ 'ipywidgets>=7.0.0', ], - extras_require = { + extras_require={ 'test': [ 'pytest>=4.6', 'pytest-cov', @@ -114,7 +112,7 @@ 'sphinx_rtd_theme', ], }, - entry_points = { + entry_points={ }, ) diff --git a/tests/widget_lib/widget_lib/__init__.py b/tests/widget_lib/widget_lib/__init__.py index 8c79bf27e..333a2d419 100644 --- a/tests/widget_lib/widget_lib/__init__.py +++ b/tests/widget_lib/widget_lib/__init__.py @@ -5,7 +5,10 @@ # Distributed under the terms of the Modified BSD License. from .example import ModuleImportError, ViewRenderError, ModelInitializationError -from ._version import __version__, version_info +from ._version import __version__, version_info # noqa + +__all__ = ['ModuleImportError', 'ViewRenderError', 'ModelInitializationError'] + def _jupyter_labextension_paths(): """Called by Jupyter Lab Server to detect if it is a valid labextension and diff --git a/tests/widget_lib/widget_lib/example.py b/tests/widget_lib/widget_lib/example.py index 99577ced7..5bfb4bf9c 100644 --- a/tests/widget_lib/widget_lib/example.py +++ b/tests/widget_lib/widget_lib/example.py @@ -42,4 +42,3 @@ class ModuleImportError(DOMWidget): _view_name = Unicode('ModuleImportErrorView').tag(sync=True) _view_module = Unicode(module_name).tag(sync=True) _view_module_version = Unicode(module_version).tag(sync=True) - From c9b8b7ec95fbe0c769e11fb17a4acc76395ef89a Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 8 Oct 2021 23:21:53 +0200 Subject: [PATCH 07/13] Add new tests --- tests/widget_lib/widget_lib/__init__.py | 6 +- tests/widget_lib/widget_lib/example.py | 6 +- .../notebooks/missing_module_inside_box.ipynb | 54 ++++++++++++++ .../notebooks/module_error_inside_box.ipynb | 46 ++++++++++++ .../notebooks/render_error_inside_box.ipynb | 46 ++++++++++++ ui-tests/notebooks/wrong_semver.ipynb | 66 ++++++++++++++++++ .../notebooks/wrong_semver_inside_box.ipynb | 46 ++++++++++++ ui-tests/stability_test/stability.test.ts | 29 ++++++++ .../wrong-semver-stability-test-linux.png | Bin 0 -> 8145 bytes 9 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 ui-tests/notebooks/missing_module_inside_box.ipynb create mode 100644 ui-tests/notebooks/module_error_inside_box.ipynb create mode 100644 ui-tests/notebooks/render_error_inside_box.ipynb create mode 100644 ui-tests/notebooks/wrong_semver.ipynb create mode 100644 ui-tests/notebooks/wrong_semver_inside_box.ipynb create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/wrong-semver-stability-test-linux.png diff --git a/tests/widget_lib/widget_lib/__init__.py b/tests/widget_lib/widget_lib/__init__.py index 333a2d419..e0bd3971d 100644 --- a/tests/widget_lib/widget_lib/__init__.py +++ b/tests/widget_lib/widget_lib/__init__.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright (c) Trung Le. # Distributed under the terms of the Modified BSD License. -from .example import ModuleImportError, ViewRenderError, ModelInitializationError +from .example import ModuleImportError, ViewRenderError, ModelInitializationError, WrongVersion from ._version import __version__, version_info # noqa -__all__ = ['ModuleImportError', 'ViewRenderError', 'ModelInitializationError'] +__all__ = ['ModuleImportError', 'ViewRenderError', + 'ModelInitializationError', 'WrongVersion'] def _jupyter_labextension_paths(): diff --git a/tests/widget_lib/widget_lib/example.py b/tests/widget_lib/widget_lib/example.py index 5bfb4bf9c..0af23b9ff 100644 --- a/tests/widget_lib/widget_lib/example.py +++ b/tests/widget_lib/widget_lib/example.py @@ -8,7 +8,7 @@ TODO: Add module docstring """ -from ipywidgets import DOMWidget +from ipywidgets import DOMWidget, Button from traitlets import Unicode from ._frontend import module_name, module_version @@ -42,3 +42,7 @@ class ModuleImportError(DOMWidget): _view_name = Unicode('ModuleImportErrorView').tag(sync=True) _view_module = Unicode(module_name).tag(sync=True) _view_module_version = Unicode(module_version).tag(sync=True) + + +class WrongVersion(Button): + _model_module_version = Unicode('0.0').tag(sync=True) \ No newline at end of file diff --git a/ui-tests/notebooks/missing_module_inside_box.ipynb b/ui-tests/notebooks/missing_module_inside_box.ipynb new file mode 100644 index 000000000..b5e87ddee --- /dev/null +++ b/ui-tests/notebooks/missing_module_inside_box.ipynb @@ -0,0 +1,54 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6e2208b3-955c-4842-84f0-fe70bf40b0e0", + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "from widget_lib import ModuleImportError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea0d27ef-8a31-4191-ad09-33e4194db736", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.HBox([ModuleImportError(), widgets.Button(description='ModuleImportError')])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fadff0a0-f4e6-46a4-8272-0ca10f1b077f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/module_error_inside_box.ipynb b/ui-tests/notebooks/module_error_inside_box.ipynb new file mode 100644 index 000000000..e390f0d82 --- /dev/null +++ b/ui-tests/notebooks/module_error_inside_box.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6e2208b3-955c-4842-84f0-fe70bf40b0e0", + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "from widget_lib import ModelInitializationError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "338bbb1f-e4c8-4fa7-98e6-d5ddfa97747c", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.HBox([ModelInitializationError(), widgets.Button(description='ModelInitializationError')])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/render_error_inside_box.ipynb b/ui-tests/notebooks/render_error_inside_box.ipynb new file mode 100644 index 000000000..9327b6c75 --- /dev/null +++ b/ui-tests/notebooks/render_error_inside_box.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6e2208b3-955c-4842-84f0-fe70bf40b0e0", + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "from widget_lib import ViewRenderError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce2fe832-1c7f-4a08-a247-353e90ac5b83", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.HBox([ViewRenderError(), widgets.Button(description='ViewRenderError')])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/wrong_semver.ipynb b/ui-tests/notebooks/wrong_semver.ipynb new file mode 100644 index 000000000..f4e5b01eb --- /dev/null +++ b/ui-tests/notebooks/wrong_semver.ipynb @@ -0,0 +1,66 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7c6c297e-f753-47cd-9444-0aea73d17cb4", + "metadata": {}, + "outputs": [], + "source": [ + "from widget_lib import WrongVersion\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a03447e8-7c38-432d-985c-f89d6e87da60", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'First button')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dea42641-00d5-4420-9f6f-131110c8e4c8", + "metadata": {}, + "outputs": [], + "source": [ + "WrongVersion()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "207cf497-d839-414a-bb4d-94727637268c", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.Button(description = 'Second button')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/notebooks/wrong_semver_inside_box.ipynb b/ui-tests/notebooks/wrong_semver_inside_box.ipynb new file mode 100644 index 000000000..682b7eb42 --- /dev/null +++ b/ui-tests/notebooks/wrong_semver_inside_box.ipynb @@ -0,0 +1,46 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "6e2208b3-955c-4842-84f0-fe70bf40b0e0", + "metadata": {}, + "outputs": [], + "source": [ + "import ipywidgets as widgets\n", + "from widget_lib import WrongVersion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6abe59b-70b1-4f4f-9aa4-7fd04c87a01b", + "metadata": {}, + "outputs": [], + "source": [ + "widgets.HBox([WrongVersion(), widgets.Button(description='WrongVersion')])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ui-tests/stability_test/stability.test.ts b/ui-tests/stability_test/stability.test.ts index 14d7007c3..eddb0cdb0 100644 --- a/ui-tests/stability_test/stability.test.ts +++ b/ui-tests/stability_test/stability.test.ts @@ -31,6 +31,20 @@ test.describe('Voila stability Tests', () => { ); expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); + test('Should render notebook with missing module in a box', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'missing_module_inside_box'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('button'); + await page.$('text=Typesetting math: 100%'); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain( + 'Class ModuleImportErrorModel not found in module widget_lib@^0.1.0' + ); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); test('Should render notebook with model error', async ({ page, @@ -57,4 +71,19 @@ test.describe('Voila stability Tests', () => { expect(errorLogs).toContain('Error: Could not create view'); expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); + + test('Should render notebook with semver error', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'wrong_semver'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('button'); + await page.$('text=Typesetting math: 100%'); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain( + 'Error: Module @jupyter-widgets/controls, semver range 0.0 is not registered as a widget module' + ); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); }); diff --git a/ui-tests/stability_test/stability.test.ts-snapshots/wrong-semver-stability-test-linux.png b/ui-tests/stability_test/stability.test.ts-snapshots/wrong-semver-stability-test-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..14c99fc62c10e1869106c65d260b96111bcbd8e0 GIT binary patch literal 8145 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 Date: Fri, 15 Oct 2021 14:52:48 +0200 Subject: [PATCH 08/13] Update test for widgets inside box --- ui-tests/stability_test/stability.test.ts | 41 ++++++++++++++++-- ...module-inside-box-stability-test-linux.png | Bin 0 -> 5320 bytes ...-error-inside-box-stability-test-linux.png | Bin 0 -> 5320 bytes ...-error-inside-box-stability-test-linux.png | Bin 0 -> 7234 bytes ...semver-inside-box-stability-test-linux.png | Bin 0 -> 5320 bytes 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/missing-module-inside-box-stability-test-linux.png create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/module-error-inside-box-stability-test-linux.png create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/render-error-inside-box-stability-test-linux.png create mode 100644 ui-tests/stability_test/stability.test.ts-snapshots/wrong-semver-inside-box-stability-test-linux.png diff --git a/ui-tests/stability_test/stability.test.ts b/ui-tests/stability_test/stability.test.ts index eddb0cdb0..ff2997dbc 100644 --- a/ui-tests/stability_test/stability.test.ts +++ b/ui-tests/stability_test/stability.test.ts @@ -31,14 +31,15 @@ test.describe('Voila stability Tests', () => { ); expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); - test('Should render notebook with missing module in a box', async ({ + + test('Should not render notebook with missing module in a box', async ({ page, browserName }, testInfo) => { const notebookName = 'missing_module_inside_box'; await page.goto(`render/${notebookName}.ipynb`); - await page.waitForSelector('button'); - await page.$('text=Typesetting math: 100%'); + // await page.waitForSelector('button'); + // await page.$('text=Typesetting math: 100%'); await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); expect(errorLogs).toContain( 'Class ModuleImportErrorModel not found in module widget_lib@^0.1.0' @@ -59,6 +60,17 @@ test.describe('Voila stability Tests', () => { expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); + test('Should not render notebook with model error in a box', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'module_error_inside_box'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain('Error: Failed to initialize model.'); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); + test('Should render notebook with render error', async ({ page, browserName @@ -71,6 +83,16 @@ test.describe('Voila stability Tests', () => { expect(errorLogs).toContain('Error: Could not create view'); expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); + test('Should not render notebook with render error in a box', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'render_error_inside_box'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain('Error: Could not create a view'); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); test('Should render notebook with semver error', async ({ page, @@ -86,4 +108,17 @@ test.describe('Voila stability Tests', () => { ); expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); }); + + test('Should not render notebook with semver error in a box', async ({ + page, + browserName + }, testInfo) => { + const notebookName = 'wrong_semver_inside_box'; + await page.goto(`render/${notebookName}.ipynb`); + await page.waitForSelector('#MathJax_Message', { state: 'hidden' }); + expect(errorLogs).toContain( + 'Error: Module @jupyter-widgets/controls, semver range 0.0 is not registered as a widget module' + ); + expect(await page.screenshot()).toMatchSnapshot(`${notebookName}.png`); + }); }); diff --git a/ui-tests/stability_test/stability.test.ts-snapshots/missing-module-inside-box-stability-test-linux.png b/ui-tests/stability_test/stability.test.ts-snapshots/missing-module-inside-box-stability-test-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..57143f55e3447177e90fb1df3fddd195bc41ce9a GIT binary patch literal 5320 zcmeAS@N?(olHy`uVBq!ia0y~yURWm5O{KE&L8SWV}FoO7J7+8Q*g8{Pu zNc0eo1Bl`<9+eyogwd2RnjL^?U^Ea$17Wmw7_A~l+XfiT)fVrbaFeOQfi&W~k%p`e1%)78&qol`;+0BJ-yod5s; literal 0 HcmV?d00001 diff --git a/ui-tests/stability_test/stability.test.ts-snapshots/module-error-inside-box-stability-test-linux.png b/ui-tests/stability_test/stability.test.ts-snapshots/module-error-inside-box-stability-test-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..57143f55e3447177e90fb1df3fddd195bc41ce9a GIT binary patch literal 5320 zcmeAS@N?(olHy`uVBq!ia0y~yURWm5O{KE&L8SWV}FoO7J7+8Q*g8{Pu zNc0eo1Bl`<9+eyogwd2RnjL^?U^Ea$17Wmw7_A~l+XfiT)fVrbaFeOQfi&W~k%p`e1%)78&qol`;+0BJ-yod5s; literal 0 HcmV?d00001 diff --git a/ui-tests/stability_test/stability.test.ts-snapshots/render-error-inside-box-stability-test-linux.png b/ui-tests/stability_test/stability.test.ts-snapshots/render-error-inside-box-stability-test-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..690ef6ed56e100262497a08158bc7c072663b5ec GIT binary patch literal 7234 zcmeHL`&*J(9)Gh|tC@0poXy8HtdXSItf|;kLZq6Kc)WGlYRLvbs&9 zwwR+N=*%?LQ##(T@NTUsVhWj=mn5sCS#w2F9e{}BlK6S%Z_vD_8}DN}YFgeCMNgndw%#AO_UoK3|2d;gxo zo08E=i`9!FRUc+>Gn4*{U3?i@Wue(+e@ZzU^J#CV>zv1xJ$Iyw4MMTaBQW+}$NN>c; z>C-qmvmCvB_wL>6KqAl&FW+h3!WYnN*BWREe5U|f4v$-x?SaE)cgO~WJv)~C86JMS zA{`Eg0-$9eq@S_b01v-#_}xDmGbF^sblu)1S9o^>a(70h(%@p>v5T<(d+N@@Mz7hV zI?d}4^?XmTG8;SHKlv!Stk&I?Ie(baS@3W0*;=GN7MiANB{iin+OmwznDMprbl&@tE2H^2buk>!ZQAy!FXL7gA|U!R+ZY;xWi&-MWs+0f8WK z{AFl@cvFPPvLM1!&Ys;&aJjG_acS(wN-X3R(|?m}p37&LR3gFYmJFBpCrfH49+p&H zoEqe@4C9PBF$&ExEqIWdd>q3P4}+4M0t!91mYgV;tU&Q@;w^e<;ne9=S4mLK5DS~97EH4LaivIDZWEX+DTM?9+ENkV`kOa?w8y_0!^{m8MFziV7|gFjZaDOZeE6}Q@f{Ijm=0G-1+dq`1?t-&pscw)XWpzo6kG}{LWJ!Ia_wkG8 z5NWedT>zmN`q6w5C5$ne=LDd9dDmYMDdw0)zh;X$oBTOQ2ls&Xh#cJag>iM`{+Tt> za_;ui`;M1|a)*b9hnPAUk+Y?&=1b#rJ4521yEb zxYbYBMI)H=-AM7nVK?4W~2C}84C1T^uq(CZx-=z82M{WDgiDA|&b7MYF zS1Y=ncjRr!MS}X<4-?k!y2wwRY4j3Mx;jcpf}M0lr^i1kHsB52ISGdG`!u@b$&)?z zg7~+W+WTxLR?RdSDT@XTLnljCo77Tjd84*tiJi+$Bo|E$()LH>AjL4de2kLImhI+&UU0rm@t84XQS0(&HFXT+MLC)*_*@C{+PkEv*zG>Ib4>+{>B_6L5zy zlNBvHi6GyD#Cbz&#yN(k40|dYX8-e92-6ja+vPK6VFLh! z$eCg3>WQ4z8;-Ocaqi9$W9$iawC|$&#fw9ntYn+GI)@9uts~^@UM}41H2Q?E4G&pA z^*97rTY+f=g%`s{`ps%gsQ4lAqLyG4{pR3iy79V2O^KJE!#Z0aEed`VS z!f+;vxEeSA0=7=z977Y6moHz2sg^8DIsxlFR-*qh(IMbC?fR_58#clB^<9GA38(FUo6Gnm8Nu(^T z0O`E+T{%lrQmGbF4D;hKxz}zBEeMILjVh!+hRviFIHus#Q`qAuuS-dou^+CsnH^?( zPmuW^%bR@x{0X+UwmV}7t3z4(QF2OGpj2(Fo?%;zq`Jg$PhBpuFFZ9Cp0t*(%nqZO zO?vYAt#Gg9O_#d^ca4WsP`Yl@qQ9`%rx{4s;2&a0ql9#L*-X#+4Vwd7KLUXu)cvZV zbXvx5Sbu;2yN*w8n`BM+kGcJ|;%de9Q~wKR<*=2*Rt|qUM=n;qTJ>txt5vUmu#;q~ mtyyi&YHLRWm5O{KE&L8SWV}FoO7J7+8Q*g8{Pu zNc0eo1Bl`<9+eyogwd2RnjL^?U^Ea$17Wmw7_A~l+XfiT)fVrbaFeOQfi&W~k%p`e1%)78&qol`;+0BJ-yod5s; literal 0 HcmV?d00001 From ec41364fa9fb8c72acd50a944ff1192c6297aff3 Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 15 Oct 2021 17:27:14 +0200 Subject: [PATCH 09/13] Lint code --- tests/widget_lib/widget_lib/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/widget_lib/widget_lib/example.py b/tests/widget_lib/widget_lib/example.py index 0af23b9ff..4acf3f2eb 100644 --- a/tests/widget_lib/widget_lib/example.py +++ b/tests/widget_lib/widget_lib/example.py @@ -45,4 +45,4 @@ class ModuleImportError(DOMWidget): class WrongVersion(Button): - _model_module_version = Unicode('0.0').tag(sync=True) \ No newline at end of file + _model_module_version = Unicode('0.0').tag(sync=True) From 57fc5349e4b852c8b6a9e4ee7e0ff4d77abddfc4 Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 15 Oct 2021 17:38:55 +0200 Subject: [PATCH 10/13] Update docs for UI test --- docs/source/contribute.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/source/contribute.rst b/docs/source/contribute.rst index 0030450ab..ccfd3b67d 100755 --- a/docs/source/contribute.rst +++ b/docs/source/contribute.rst @@ -217,6 +217,39 @@ Finally, to run the tests: python -m pytest +UI tests with `Playwright` +========================== + +Install the test dependencies and the mock widgets: + +.. code-block:: bash + + python -m pip install jupyterlab~=3.0 numpy bqplot matplotlib ipympl ipyvolume scipy + cd tests/widget_lib + pip install . + +Install `Playwright` and `Chromium` browser: + +.. code-block:: bash + + cd ui-tests + jlpm install --frozen-lockfile + jlpm playwright install chromium + +Start `Voilà` server for snapshot and stability testing: + +.. code-block:: bash + + # In ui-tests folder + jlpm start + jlpm start-stability + +Finally, to run the tests: + +.. code-block:: bash + + jlpm run test + Editing templates ================= From a65b9659814c1649db580cbc4173fdf8df148a5c Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 15 Oct 2021 18:06:28 +0200 Subject: [PATCH 11/13] Split test project --- .eslintignore | 1 + .github/workflows/ui-tests.yml | 7 +++++++ docs/source/contribute.rst | 9 +++++---- ui-tests/package.json | 3 ++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.eslintignore b/.eslintignore index 68b6db135..8e5e20199 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,6 +12,7 @@ node_modules **/schemas **/themes **/templates +**/widget_lib coverage *.map.js *.bundle.js diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index d9381e296..1df0b8c0a 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -46,6 +46,13 @@ jobs: resource: http-get://localhost:8868/ timeout: 360000 + - uses: iterative/setup-cml@v1 + - name: Stability test + shell: bash + run: | + cd ui-tests + jlpm run test-stability + - name: Launch Voila run: | cd ui-tests diff --git a/docs/source/contribute.rst b/docs/source/contribute.rst index ccfd3b67d..e108a3a2f 100755 --- a/docs/source/contribute.rst +++ b/docs/source/contribute.rst @@ -236,19 +236,20 @@ Install `Playwright` and `Chromium` browser: jlpm install --frozen-lockfile jlpm playwright install chromium -Start `Voilà` server for snapshot and stability testing: +Start `Voilà` server and run the snapshot tests: .. code-block:: bash # In ui-tests folder jlpm start - jlpm start-stability + jlpm test -Finally, to run the tests: +To run the stability tests: .. code-block:: bash - jlpm run test + jlpm start-stability + jlpm test-stability Editing templates ================= diff --git a/ui-tests/package.json b/ui-tests/package.json index 7c2768479..314fcc59d 100644 --- a/ui-tests/package.json +++ b/ui-tests/package.json @@ -7,7 +7,8 @@ "start": "voila ../notebooks --no-browser", "start-stability": "voila ./notebooks --no-browser --enable_nbextensions=True --port 8868", "start:detached": "yarn run start-jlab&", - "test": "playwright test", + "test": "playwright test --project render-and-benchmark", + "test-stability": "playwright test --project stability-test", "test:debug": "PWDEBUG=1 playwright test", "test:report": "http-server ./playwright-report -a localhost -o", "test:update": "playwright test --update-snapshots" From f62631e539a9fd32e63d75567594a3c254a7c785 Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 12 Nov 2021 10:04:58 +0100 Subject: [PATCH 12/13] Update screenshot on failed tests --- .github/workflows/ui-tests.yml | 10 ++++++++++ .../voila.test.ts-snapshots/reveal-linux.png | Bin 10853 -> 0 bytes .../reveal-render-and-benchmark-linux.png | Bin 0 -> 10841 bytes 3 files changed, 10 insertions(+) delete mode 100644 ui-tests/tests/voila.test.ts-snapshots/reveal-linux.png create mode 100644 ui-tests/tests/voila.test.ts-snapshots/reveal-render-and-benchmark-linux.png diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 1df0b8c0a..4adcf04e4 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -125,6 +125,16 @@ jobs: path: | ui-tests/playwright-report + - name: Update snapshots + if: failure() + run: | + cd ui-tests + # remove previous snapshots from other browser + jlpm rimraf "tests/**/*-snapshots/*.png" + jlpm rimraf "stability_test/**/*-snapshots/*.png" + # generate new snapshots + jlpm run test:update --browser ${{ matrix.browser }} + - name: Print JupyterLab logs if: always() run: | diff --git a/ui-tests/tests/voila.test.ts-snapshots/reveal-linux.png b/ui-tests/tests/voila.test.ts-snapshots/reveal-linux.png deleted file mode 100644 index 8f1fc566c1f6cdd86415af9dacd26204ae88529e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10853 zcmeHNcT`i^x4s|>B2opUGgxpGL8Y5OP$@QwWdLbG7?q(IBE83gf(VRb0Tp3{QA7wu zq)7=VkU^RZ(mPRlix5aifVVH`Z@stHTkDm7-g;~Kk2m)w=iGhv`S$mH`(UJnnaO5; zX?_GjHXl1`cp5?0!$i1>7}8@27cQ^UCWn#C2H8;rQACaz9y;rvFwt|)-R=^r ze88_--M3^%!#|ZjAA6hI{L9fd+*b|4a>RFGj@pr|d5-QCeGpi&{_tV4!QlzXKYI~T zJJPNbhu)lhZj}7}=78 zxe+!CGrYxjs=I>^qCpg&JEilYACL@LE@AX4x<^BL^DSf@d^9+1iEyJ=CvHW!AlrBT zxc!lhA7J=V3qPpf2NV8a!XHfdg9-nKOlaxKK>FRATr_O-co2lt?C{LOg(0jc$0ckT z(GNx}+f#k`^fg75rwCu|%Z?FcLGWKCj%9yqhb(X3@NRI6^l=`Qj$nmt3j1Mn_!G7H zjaRexaVx4+*eN7+L zbN?jn4f_E~*=5^Ad=5zDUq6pRx>kn&AK2P+GjTntMclC=367_+1! zr1MQfwv#aPgg-##Va;4XTaKd6l0-Z{r)3>Uy{bl#p*IgEx%}%B-RZ|3`)}$>)tMnT zc0Bgrh4hqveO!dBb4f(_Oyk`ceRY$*hA>MlA)nQ17q!2xrr)rEi!W-Q6*D&l)@?1N zK5R>ESQ^HXJg-1X%7X{Yd0-Z6soDCx8wNVMw~+V8G-T!~aj={Rxxeei6-mi9@*7zH zd5^rfHiJWbT~WsJ^`diJe5MD_wdZn!BX<0vp+0;-`Fh7jQnsO&eZVUz+|sByZJh$s zAb1$l7rBmCP$f_xY4KC)peZ5n3}@mJF3L6U?MNGhq+@TIjlkME-mya6#GrbL`Fs$#kvhQJf%}{%lqf2dSn=ZAx&AZC7uT#kI$Vjqw>@f1r6e< z?wH>@lj!@{#^;4>Gl2~YcNX;#Ezl64Lb>kXQYmc#fOk}aba;5pT({B+tDx3kYr z73LL^$4;?q3ob`zg-p5;$H@iNje`ybw zu-Uo>TL2o8v4u2IwXob_0Fm7aN9=5pb)Uyh)?tJykk#f0-4Hf$Ko@46gyDJjI) z)fToVuvA`1Z_WbCnR$Pv%f!TFy#f4Ir&e6LA$g)4j;iK_*qSzWP)7z~tDxzUal ziQGs+FTcklt8MPTyRH3O`~`etd6Olf0?bnDxcFrVa%3$v558@mG;Bi@oaW2$|_{8shvG z$a%7dM@wwEF5S@=DEFfs=KiBw8yXqi&I5!%o;UYkSq)mb_Me|}KRfOL-q|>z# z#6{VbrM(oOUZ4M!klzvpnZ5Mnq7|3w&bf`(JOR2Aj`>j}m3hq}+a+awnB!5MW|)mT zPlDS8#eEp~`uww>JQvSXM4CR0;Y1+8e>;}xHrsJ|E`|&UJp}#OStk(MY&BIc$$jZ2 zr6|<*?eolipaeQ{^_rI+2ZUYxjOi#sh6CmL*F(@vbMe|*2cjx8*>Z z)}*3$J%_I)F`-EJ`SB!#QaZYd9K`$qXqz zO8qs7+I?C8s0lOQQ@=lot-_%tERpsoe%KQakB6SBOlXR2zA6SP#N!nboG}OGVVw|e zs81JK1z-HM^XF|qw%MMuReA$L62{1l3!f&aHB>>^;`Q|#&}Syd4e`MgSYftzvVw|z z8c1-)#i_q|4#5lViE$iRur;^aBOyS9Y~jv;3ySb<{|{Ro)Mk-5($U5On>SaTG1n6Z z%0{(zWMm{l)2+3#XgE;@lqLG`vyWrv0bmBl!;Mp#To{U^lIrSer-i8=;^)8bS{Gcl z&#=kc{o%`%lV)bsm6e7tospH5mEDz^9ZfwwJ!1pt*n`}P*-q%N#zehSWJ~ASq52%x zmRGwT9B*oEm0$$wy=rkidGciC@)8@~QQ1niO-W5nZF!GM<5?a9M9M)ebDja?B zB&Ms^MPsmxJrxx+RivC*I^Q`mJsq30!WpKIq{LQF7WBzu{HE^sQP@3A&COy3J-)UA z0s;xI@EZ~2&kH;TMGj`xVgn}PyrzDJh?!{+___w=l=rS!DnnAlhoTU%TA-jaYr z)94z57N(-Xu}n9$wB*H~e=Xp^`e2pMp@bFL#mqKf)X)sm^4nbV{70VM8eC>i#}<@M zdMISckbM&e7M&(IW_gtSoghH?AN32oo{|dchLyM(Y@pKj@wmEV5|~9;5R`6 zcR&K&d*1pGY0=u%_1b;1Ev}kn5VU5g65)jnSz_C^ZKisD?(QmqX+y$}N2kby5H~EnQmm=BS3b_(x8vuKX(!_Ol_=f$;I^Gk zTCfc{04WzYw*mkIXWt;mN5s#!x}+~qK&sfvAwXg({v6F#=7R&fb}EykLaA4 z?8sFvgI%Cb^%T>1am+(#U5$*m*o7@Ih_!nQ3<(6n-26OPO_PZ}3QkEW5de%ri(Vy3 zWitI`vHts%lmz9mpmutTi;Fg_JwSyCqTGtxwGJE*#lxl!f=efM2Mj-@e^Cq54Q0Mp zP#w#IOv|;|d6}MR)C0g^XY17W>+8!yiai$fs;N{ccI5`#3a35${QKnUnt%3g?@TRCb7O!-lw*wYl;GWdSf zhX+qMD@1`!uEZ_VW0~Xl73r=5LTpY>PT@#$lnn=UgBc(lqHGu_V}%d#DdBuki}mQr zud?l1Y%LtmEFN50o?emQ*i<>?jL!022DIJ0b<26Wx0DE=*IJTi&re1{`Be?oKOu8t zYxU;ao#`=tCEMUvw3&hT#4iu5s&DDfJwwSrX^`c0I?<~^7wAxKyp%pf5k_40B9Z$Ce6pLTlK@@&#p zY3bW&r2)4V4AN+GS^zF{J;tX`Gyn`VH&nUTK@-CL5T`P1zq6B*6725_)$Qt7tSlJL z){JvvPoF+LmEPjy@2_KQY@B>{w-FxSm#lUh@b0-&1i31HDyz-e#bp=TqQQj3iuICp ztZuZG^J>(SL_3SJvau|w(!3LFNkF9`_=?_y$FF@KTa^$M|X=n;+Rf|=? zx!dY(fp`+{0wMNFku0>y z__>7zYC3*t>_X5ah#Y%iIu=z3;!J-<;m~8Z)uu2a0?O8(L#H~Uh66}&WNhqqTkQ2xlyC8#Z@eEXYgQu977%Gpjq^7Pe z8Ms3c)a}(64WXFhmb|-t+U)6|g6cPK-h4QDSP_&g2k6N~LmI?OJ+Bl@Nm&ScutquQ z&YrB21E}1gI>Z4x5d)}3>Bzp=w+cWw*fSmKC#!p9`}{FQj1}Xw^6mr=+XXgU?OFXr5mEUL4PI`;&QIHptu;5S@QLR z&XvzcvCRJKXS&82fzY6uq@BGDtc3~?2(4~n$b5$mI1|Wye0+Qa)H&!;WK2wqe@nW9 zc)BIo<{=R^u2eB(KtOB%ei4lCL_}lgeD3O*#b)hpVZR<9D@ckSx&^2WKoLX-NMWGI z><*r-ubuBj+fz_8upznwLBI=u!8+&Awa00)Gp|-lA0p@vfS$Pmh@S@L1MltaT}fGHWEFn>uqTB=!Id${gsOB0#w$P& zy&95oKPHV#-rJgmS3q5ai9(1*gWf`SdjSED=6R9LPI1UW)d}^S^xIY?O7qiw3PRW! z129#Uk2T%w_)zpce1z~_$_8&_3=#`aL06xi`F3|_XXoI%O=@?bjKdE<+d&%xYXxwO z)tk5G&=gi8GBYzlmySS`hAmYgsEsQ?y`77cRcod?`CMDfHl~ zQhoerft~w!ggE*<&KR)T9W-4ExU<#Dg!$90vSPGL1~${@3n+TvUqw-p&9s*R&kRPu z8Auj%8?8dibhxj=!3wOo;KWhN9mI!TIvt{h79yBaV6=(Oygl;4GZlsNoo-eWAu`d% zFc5_TS{My!v*cWR7!J~#8ESWgKQAFfS7ua}N{a_t% ztn$v#Pg6vIo6)Epvu(R7k{@sH&|}Qjte)39gzpm>x{q1o#m_Ssmf=wyao?`Y&j4 z!rZVjCvR^JI8<>$4gcFeEK9`^gkKE(zW^i2?fD*0kfZ#K*x8dnfBJAD^o>v>c0t>3 zoX*RYpucnH&cPh2d{nI(r37W)fBKf^3kpB~aU!|6xVYsAltBdFH;(=E-{Si3!hoJI zcrK<{rW5o_?%*=S`Y}P4LQRf z4IR|jA^3a7;F#ISDIH>$Tp#sthVS3qz_VV36K}zm8 zPA9Tld?)$KHO!yM{E~+bRf=0Hojp5u*6_3F(d(5vKK{-fj!~>k&J&2HIp%833mSb^ zthMAGKga&uJbPdLA6@)Xv#vT~aDLSUAzQxv=cxa9TfSq`^hF0Q!C_&mq)p)z>QIn= z(|MX2n-ws=ud6X8m(}Fj+V(Ir=r8rRWz+0&dDQMAy@s)gvY%_GSN`_D?>+kZ^`|f6 z=B=-rEO@-vqhyO*%+`K1L~lM;o$~qD$Fk;ZY|=@u=>fBR-_?fuqhyQwNgSY*#RP0ui7p$L~C(5);Ij)^!=d$+35Sj*3;h~3fe@H){;|qY?Fw^n(NmMwCCXj zH;819v&)jY#?TiT{PC;X@UEng;(IuuRJA0Z(R+7Zzm5-{9S!QRwv`UXE3dw|pWiN6 zbjFAq%fzq-i~Dj*gRso9wdw8dHuL#A|8`%sCMvxsn%EW5$5HSOuY z?bGuchi#Rls@yz4X;of5)GQb8=+ymCdJEHm!-mxn7}dKJ$|!%(%d5=RV%_5@y^?6& zK&3pWQpJaGE?>@46)4ME%cR%*E2f`Yzo=eOGQUj8{aydkI>!@qHIcOq+)1Ele&Cg< z)qS*+cIvf`yr$&JAAgOrmpM{KXw3b%fVt0#u}NmHOZ^h+G3nZF(Wg> J%)^e?{tYuYcpLx# diff --git a/ui-tests/tests/voila.test.ts-snapshots/reveal-render-and-benchmark-linux.png b/ui-tests/tests/voila.test.ts-snapshots/reveal-render-and-benchmark-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..5f10df8a9f18510b37a6d2655673d7196fc23add GIT binary patch literal 10841 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 I&-%uH0XbVqmjD0& literal 0 HcmV?d00001 From 4656920634f3c7d84f0ef76a93e70350e46ea66a Mon Sep 17 00:00:00 2001 From: Duc Trung LE Date: Fri, 12 Nov 2021 10:16:04 +0100 Subject: [PATCH 13/13] Set `retries` to 1 --- ui-tests/playwright.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-tests/playwright.config.js b/ui-tests/playwright.config.js index 1c5690db1..4cb41dc4c 100644 --- a/ui-tests/playwright.config.js +++ b/ui-tests/playwright.config.js @@ -12,7 +12,7 @@ module.exports = { video: 'retain-on-failure' }, // Try one retry as some tests are flaky - retries: 0, + retries: 1, workers: 2 }, { @@ -25,7 +25,7 @@ module.exports = { video: 'retain-on-failure' }, // Try one retry as some tests are flaky - retries: 0, + retries: 1, workers: 2 } ],