2020-10-30 20:09:25 +00:00
|
|
|
(testing)=
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2020-05-19 16:14:56 +00:00
|
|
|
# Testing and benchmarking
|
|
|
|
|
|
|
|
## Testing
|
|
|
|
|
2022-05-30 23:17:47 +00:00
|
|
|
### Running the Python test suite
|
|
|
|
|
|
|
|
You can use either Selenium or Playwright to run the pytest suite of tests.
|
2020-05-19 16:14:56 +00:00
|
|
|
|
|
|
|
Install the following dependencies into the default Python installation:
|
|
|
|
|
|
|
|
```bash
|
2022-05-30 23:17:47 +00:00
|
|
|
pip install pytest pytest-instafail pytest-httpserver
|
|
|
|
```
|
|
|
|
|
|
|
|
There are 3 test locations that are collected by pytest,
|
|
|
|
|
|
|
|
- `src/tests/`: general Pyodide tests and tests running the CPython test suite
|
|
|
|
- `pyodide-build/pyodide_build/tests/`: tests related to Pyodide build system
|
|
|
|
(do not require selenium or playwright to run)
|
|
|
|
- `packages/*/test_*`: package specific tests.
|
|
|
|
|
|
|
|
#### Selenium (default)
|
|
|
|
|
|
|
|
```
|
|
|
|
pip install selenium
|
2020-05-19 16:14:56 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
Install [geckodriver](https://github.com/mozilla/geckodriver/releases) and
|
|
|
|
[chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads)
|
|
|
|
and check that they are in your `PATH`.
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
### Running the Python test suite
|
|
|
|
|
|
|
|
To run the test suite, run `pytest` from the root directory of Pyodide:
|
2020-05-19 16:14:56 +00:00
|
|
|
|
|
|
|
```bash
|
2021-11-21 17:26:33 +00:00
|
|
|
pytest
|
2020-05-19 16:14:56 +00:00
|
|
|
```
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
You can run the tests from a specific file with:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
pytest path/to/test/file.py
|
|
|
|
```
|
|
|
|
|
|
|
|
To speed things up you may wish to filter out two of the browsers. Node runs
|
|
|
|
tests the fastest so:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
pytest -k "not chrome and not fire"
|
|
|
|
```
|
|
|
|
|
|
|
|
is often helpful. Some browsers sometimes produce informative errors than others
|
|
|
|
so if you are getting confusing errors it is worth rerunning the test on each
|
|
|
|
browser. If you are still confused, try {ref}`manual-testing` which is more
|
|
|
|
flexible.
|
|
|
|
|
|
|
|
There are 5 test locations that are collected by pytest:
|
|
|
|
|
|
|
|
- `src/tests/`: general Pyodide tests and tests running the CPython test suite
|
|
|
|
system.
|
|
|
|
- `pyodide-build/pyodide_build/tests/`: tests related to Pyodide build system
|
|
|
|
(do not require selenium to run)
|
|
|
|
- `packages/test_common.py`: common tests for packages.
|
|
|
|
- `packages/*/test_*`: package specific tests.
|
|
|
|
|
|
|
|
#### Running tests with Playwright
|
|
|
|
|
|
|
|
By default, the tests will be run with Selenium. It is possible to run tests
|
|
|
|
with playwright instead as follows.
|
|
|
|
|
|
|
|
First install playwright
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2022-05-30 23:17:47 +00:00
|
|
|
```bash
|
|
|
|
pip install playwright && python -m playwright install
|
|
|
|
```
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
Then use the `--runner` argument to specify to run tests with playwright.
|
2022-05-30 23:17:47 +00:00
|
|
|
|
|
|
|
```bash
|
|
|
|
pytest --runner playwright
|
|
|
|
```
|
2020-11-09 12:28:02 +00:00
|
|
|
|
2021-07-06 08:48:35 +00:00
|
|
|
### Running the JavaScript test suite
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
To run tests on the JavaScript Pyodide package using Mocha, run the following
|
|
|
|
commands,
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
```sh
|
2021-07-06 08:48:35 +00:00
|
|
|
cd src/js
|
|
|
|
npm test
|
|
|
|
```
|
|
|
|
|
|
|
|
To check TypeScript type definitions run,
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
```sh
|
2021-07-06 08:48:35 +00:00
|
|
|
npx tsd
|
|
|
|
```
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
(manual-testing)=
|
|
|
|
|
2020-05-19 16:14:56 +00:00
|
|
|
### Manual interactive testing
|
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
To run tests manually:
|
2020-05-19 16:14:56 +00:00
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
1. Build Pyodide, perhaps in the docker image
|
2020-05-19 16:14:56 +00:00
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
2. From outside of the docker image, `cd` into the `dist` directory and run
|
|
|
|
`python -m http.server`.
|
2020-05-19 16:14:56 +00:00
|
|
|
|
2022-04-11 23:01:40 +00:00
|
|
|
3. Once the webserver is running, simple interactive testing can be run by
|
|
|
|
visiting the URL: `http://localhost:<PORT>/console.html`. It's recommended to
|
|
|
|
use `pyodide.runPython` in the browser console rather than using the repl.
|
2020-05-19 16:14:56 +00:00
|
|
|
|
|
|
|
## Benchmarking
|
|
|
|
|
|
|
|
To run common benchmarks to understand Pyodide's performance, begin by
|
|
|
|
installing the same prerequisites as for testing. Then run:
|
|
|
|
|
|
|
|
```bash
|
2022-03-02 18:11:36 +00:00
|
|
|
PYODIDE_PACKAGES="numpy,matplotlib" make benchmark
|
2020-05-19 16:14:56 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
## Linting
|
|
|
|
|
2022-05-31 12:00:37 +00:00
|
|
|
We lint with `pre-commit`.
|
|
|
|
|
2022-01-04 15:46:00 +00:00
|
|
|
Python is linted with `flake8`, `black` and `mypy`.
|
2022-05-31 12:00:37 +00:00
|
|
|
JavaScript, markdown, yaml, and html are linted with `prettier`.
|
2022-01-04 15:46:00 +00:00
|
|
|
C is linted with `clang-format`.
|
2020-05-19 16:14:56 +00:00
|
|
|
|
|
|
|
To lint the code, run:
|
|
|
|
|
|
|
|
```bash
|
2022-05-31 12:00:37 +00:00
|
|
|
pre-commit run -a
|
|
|
|
```
|
|
|
|
|
|
|
|
You can have the linter automatically run whenever you commit by running
|
|
|
|
|
|
|
|
```bash
|
|
|
|
pip install pre-commit
|
|
|
|
pre-commit install
|
2020-05-19 16:14:56 +00:00
|
|
|
```
|
2021-01-11 17:25:55 +00:00
|
|
|
|
2022-05-31 12:00:37 +00:00
|
|
|
and this can later be disabled with
|
|
|
|
|
|
|
|
```bash
|
|
|
|
pre-commit uninstall
|
|
|
|
```
|
|
|
|
|
|
|
|
If you don't lint your code, certain lint errors will be fixed automatically by
|
|
|
|
`pre-commit.ci` which will push fixes to your branch. If you want to push more
|
|
|
|
commits, you will either have to pull in the remote changes or force push.
|
|
|
|
|
2021-01-11 17:25:55 +00:00
|
|
|
## Testing framework
|
|
|
|
|
2022-06-02 01:07:12 +00:00
|
|
|
(run-in-pyodide)=
|
|
|
|
|
2021-01-11 17:25:55 +00:00
|
|
|
### run_in_pyodide
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2021-03-03 08:11:50 +00:00
|
|
|
Many tests simply involve running a chunk of code in Pyodide and ensuring it
|
2021-01-11 17:25:55 +00:00
|
|
|
doesn't error. In this case, one can use the `run_in_pyodide` decorate from
|
2022-07-31 10:00:45 +00:00
|
|
|
`pytest_pyodide.decorator`, e.g.
|
2021-01-11 17:25:55 +00:00
|
|
|
|
|
|
|
```python
|
2022-07-31 10:00:45 +00:00
|
|
|
from pytest_pyodide import run_in_pyodide
|
2021-01-11 17:25:55 +00:00
|
|
|
|
|
|
|
@run_in_pyodide
|
2022-05-26 02:47:43 +00:00
|
|
|
def test_add(selenium):
|
2021-01-11 17:25:55 +00:00
|
|
|
assert 1 + 1 == 2
|
|
|
|
```
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2022-05-26 02:47:43 +00:00
|
|
|
In this case, the body of the function will automatically be run in Pyodide. The
|
2022-06-02 01:07:12 +00:00
|
|
|
decorator can also be called with a `packages` argument to load packages before
|
|
|
|
running the test. For example:
|
2021-07-26 23:00:27 +00:00
|
|
|
|
2021-01-11 17:25:55 +00:00
|
|
|
```python
|
2022-07-31 10:00:45 +00:00
|
|
|
from pytest_pyodide import run_in_pyodide
|
2021-01-11 17:25:55 +00:00
|
|
|
|
2022-05-26 02:47:43 +00:00
|
|
|
@run_in_pyodide(packages = ["regex"])
|
|
|
|
def test_regex(selenium_standalone):
|
2021-01-11 17:25:55 +00:00
|
|
|
import regex
|
|
|
|
assert regex.search("o", "foo").end() == 2
|
|
|
|
```
|
2022-06-02 01:07:12 +00:00
|
|
|
|
|
|
|
If your `run_in_pyodide` test is failing, it will generate much better error
|
|
|
|
messages if the packages `pytest` and `tblib` are available in Pyodide, so it is
|
|
|
|
recommended that you build them:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
PYODIDE_PACKAGES="pytest, tblib, whatever-else" make -C packages
|
|
|
|
```
|
|
|
|
|
|
|
|
If you need to xfail your test on a certain browser, you can use
|
|
|
|
`pytest.mark.xfail_browsers`. You can also use `@run_in_pyodide` with
|
|
|
|
`pytest.mark.parametrize`, with `hypothesis`, etc. `@run_in_pyodide` MUST be the
|
|
|
|
innermost decorator. Any decorators inside of `@run_in_pyodide` will be have no
|
|
|
|
effect on the behavior of the test.
|
|
|
|
|
|
|
|
```python
|
2022-07-31 10:00:45 +00:00
|
|
|
from pytest_pyodide import run_in_pyodide
|
2022-06-02 01:07:12 +00:00
|
|
|
|
|
|
|
@pytest.mark.parametrize("x", [1, 2, 3])
|
|
|
|
@run_in_pyodide(packages = ["regex"])
|
|
|
|
def test_type_of_int(selenium, x):
|
|
|
|
assert type(x) is int
|
|
|
|
```
|
|
|
|
|
|
|
|
These arguments must be picklable. You can also use fixtures as long as the
|
|
|
|
return values of the fixtures are picklable (most commonly, if they are `None`).
|
|
|
|
As a special case, the function will see the `selenium` fixture as `None` inside
|
|
|
|
the test.
|
|
|
|
|
|
|
|
It is possible to use `run_in_pyodide` as an inner function:
|
|
|
|
|
|
|
|
```py
|
|
|
|
def test_inner_function(selenium):
|
|
|
|
@run_in_pyodide
|
|
|
|
def inner_function(selenium, x):
|
|
|
|
assert x == 6
|
|
|
|
return 7
|
|
|
|
|
|
|
|
assert inner_function(selenium_mock, 6) == 7
|
|
|
|
```
|
|
|
|
|
|
|
|
Again both the arguments and return value must be pickleable.
|
|
|
|
|
|
|
|
Also, the function will not see closure variables at all:
|
|
|
|
|
|
|
|
```py
|
|
|
|
def test_inner_function_closure(selenium):
|
|
|
|
x = 6
|
|
|
|
@run_in_pyodide
|
|
|
|
def inner_function(selenium):
|
|
|
|
assert x == 6
|
|
|
|
return 7
|
|
|
|
|
|
|
|
# Raises `NameError: 'x' is not defined`
|
|
|
|
assert inner_function(selenium_mock) == 7
|
|
|
|
```
|
|
|
|
|
|
|
|
### Custom test marks
|
|
|
|
|
|
|
|
We support four test marks:
|
|
|
|
|
|
|
|
`@pytest.mark.skip_refcount_check` and `pytest.mark.skip_pyproxy_check` disable
|
|
|
|
respectively the check for JavaScript references and the check for PyProxies.
|
|
|
|
If a test creates JavaScript references or PyProxies and does not clean them up,
|
|
|
|
by default the tests will fail. If a test is known to leak objects, it is
|
|
|
|
possible to disable these checks with these markers.
|
|
|
|
|
|
|
|
`pytest.mark.driver_timeout(timeout)`: Set script timeout in WebDriver. If the
|
|
|
|
test is known to take a long time, you can extend the deadline with this marker.
|
|
|
|
|
|
|
|
`pytest.mark.xfail_browsers(chrome="why chrome fails")`: xfail a test in
|
|
|
|
specific browsers.
|