Testing the Client¶
The Javascript client part of Isso is tested by the Jest testing framework.
Note
Improvements to Isso’s test coverage and/or different testing strategies are always welcome! Please see the Contribute page for further information.
Sections covered in this document:
Unit tests¶
The unit tests that cover the frontend client ensure that the individual components are working fine in isolation.
Note
Reminder: You can also run these tests with Docker conveniently.
Install the needed Jest
-related packages
(listed as optionalDependencies
in package.json
):
$ npm install
Then run the unit tests:
$ npm run test-unit
You should receive output that looks similar to the following:
> test-unit
> jest --config isso/js/jest-unit.config.js isso/js/tests/unit/
PASS isso/js/tests/unit/isso.test.js
PASS isso/js/tests/unit/config.test.js
PASS isso/js/tests/unit/utils.test.js
Test Suites: 3 passed, 3 total
Tests: 3 passed, 3 total
Snapshots: 1 passed, 1 total
Time: 0.907 s, estimated 1 s
Ran all test suites matching /isso\/js\/tests\/unit\//i.
If you receive an error saying 1 snapshot failed
see
Updating snapshots
End-to-End Integration tests¶
For the end-to-end integration tests, the Python server part needs to be up and running - this part of the test suite pretends to be a real user sitting in front of a keyboard.
Note
Reminder: You can also run these tests with Docker conveniently.
The tests are run using the puppeteer browser automation tool. It runs a real Chromium browser in the background and can be instrumented to allow simulation of user interaction.
First, ensure all the client files are built and that the server part is ready to be run. Refer to Install from Source for details. Here’s the important part:
$ make init
$ make js
Start the server and ensure that the comment database is empty:
$ mv comments.db comments.db.bak
$ virtualenv --download .venv
$ source .venv/bin/activate
(.venv) $ isso -c contrib/isso-dev.cfg run
Install the necessary puppeteer
-related Javascript packages:
$ npm install --no-save jest jest-puppeteer puppeteer
Note
This will take some time as a headless chromium
browser needs to be
downloaded, which requires about 400Mb of space.
Then run the integration tests:
$ npm run tests-integration
You should receive output that looks similar to the following:
> test-integration
> jest --config isso/js/jest-integration.config.js isso/js/tests/integration/
PASS isso/js/tests/integration/puppet.test.js
✓ window.Isso functions should be idempotent (87 ms)
✓ should have correct ISSO_ENDPOINT on page (26 ms)
✓ should display "Isso Demo" text on page (34 ms)
✓ should fill Postbox with valid data and receive 201 reply (319 ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 0.752 s, estimated 21 s
Ran all test suites matching /isso\/js\/tests\/integration\//i.
If you receive an error saying 1 snapshot failed
see
Updating snapshots
Troubleshooting timeouts¶
Are you getting the following error?
thrown: "Exceeded timeout of 5000 ms for a hook.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
The solution is to run make init js
to re-generate the client files.
Explanation: This is actually a very sneaky error and consists
of``puppeteer`` waiting on a non-existent element selector on the page. Open
http://localhost:8080/demo
and you’ll see that in fact the Isso widget is
not rendering. This type of error can happen if you switch between branches
often and inadvertently have the wrong (incompatible) bundled client
embed.dev.js
, which is kept between branches because it is ignored via
.gitignore
.
Skip downloading Chromium¶
The downloaded browser will be saved to node_modules/puppeteer/.local-chromium/
.
You can set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
in your environment to
skip downloading the bundled browser and instead use the locally installed
version of Chrome/Chromium via e.g. PUPPETEER_EXECUTABLE_PATH=$(which chromium)
.
For further information, see puppeteer docs: Environment variables.
Warning
Running puppeteer
like this is discouraged as it cannot be
guaranteed that the versions of Chromium and puppeteer
are in sync. This
method can save you a lot of disk space and bandwidth, but in case of any
errors, please retry after clearing node_modules
and re-installing the
puppeteer
-related modules without those environment variables set.
Screenshot comparison¶
To ensure visual consistency for when somebody e.g. changes the CSS files, the end-to-end testing suite also checks before-and-after screenshots. These screenshots are stored in the integration tests folder.
To generate updated screenshots, you must run the following commands. (For help on setting up Docker, see Docker)
$ make docker-generate-screenshots
This will run the test isso/js/tests/screenshots/screenshots.test.js
and output
.png
files. Now compare those screenshots against the known-to-be-good
.hash
files:
$ make docker-compare-screenshots
In case you have created a change that causes the resulting images to be different (and you are sure the visual changes are desired), you need generate new hashes:
$ make docker-update-screenshots
Then commit those generated .hash
files in
isso/js/tests/screenshots/reference/*.png.hash
to git.
Warning
Please only check in hashes rendered through the Docker environment as otherwise the screenshots could be skewed by aliasing and font rendering settings from your OS.
Also note that ImageMagick identify
outputs different hash values on
older Ubuntu versions - another reason to stick to the Docker environment
for consistency.
Testing standards¶
A good starting point are the MailChimp standards
You may use ES6
syntax in tests (the restriction for ES5
syntax is only
for the production client code which needs to run on as many browsers as
possible).
Try not to introduce any race conditions - especially the asynchronous code is very tricky to get right.
The current test suite was written largely by one of the main project leads, who happens to know very little about testing (or even Javascript in general). Feel free to suggest improvements and change this!
Updating snapshots¶
The Jest
tests make use of snapshots. Say you want to ensure that the Postbox <textarea>
always looks like this:
<div class="isso-textarea-wrapper">
<div class="isso-textarea isso-placeholder">
Type Comment Here (at least 3 chars)</div>
<div class="isso-preview">[...]</div>
</div>
You could write this as:
let expected_html = '<div class="isso-textarea-wrapper> [...]';
expect($(".isso-textarea-wrapper").innerHTML.toBe(expected_html);
But then your resulting test files would quickly grow quite messy, especially
for large components where the expected_html
block would span whole pages.
That is why Jest
offers to check in those expected blocks as snapshots
,
which will saved into e.g. isso/js/tests/unit/__snapshots__/*.snap
expect($(".isso-textarea-wrapper").innerHTML).toMatchSnapshot();
If you have created a commit which changes the HTML that is generated on the
client side (and you’re sure it is correct) or written a new test case that
uses snapshots, check in or update the snapshot file by running
npm run test-unit -- -u
(or npm run test-integration -- -u
for
integration tests with the dev server running). You should see something like
the following:
npx jest --config isso/js/jest-unit.config.js isso/js/tests/unit/ -u
PASS isso/js/tests/unit/isso.test.js
› 1 snapshot updated.
Make a new commit for the changes to the snapshot - here’s an example:
isso: tests/unit: Update isso.js snapshot
Prepending `isso-` to the element classes causes a change in
the generated HTML and necessitates an update of the
snapshot.
Attention
This section of the Isso documentation is incomplete. Please help by expanding it.
Click the Edit on GitHub
button in the top right corner and read the
GitHub Issue named
Improve & Expand Documentation
for further information.
What’s missing?
Unit tests:
Jest, how to write good tests (link to MailChimp standards)
How to update and check in snapshots
Integration tests:
How Puppeteer works
How to take advantage of
jest-puppeteer
specialexpect
functions
Running client tests in general:
Ways of running tests inside and outside of docker containers
Link to the GitHub actions that run on every Pull Request
… and other things about client testing that should be documented.