These tools test that Overview and plugins work the way we expect.
The code is in Ruby. You don't need to know much Ruby to get started.
- Install Docker
- Install vncviewer and
make sure it's in your
$PATH
. There are manyvncviewer
variants out there, and any of them will work for our purposes.
You can install this into your project's git repository by running:
curl https://raw.githubusercontent.com/overview/overview-integration-tester/master/install.sh \
| bash -s integration-test
This will create integration-test/
with some files and subdirectories.
The rest of this file assumes your current working directory is the root of your
project and you installed to integration-test/
.
Your project is yours, not Overview's. After the installation script, your code is completely standalone. These tools are minimal: it's up to you to configure them fully.
integration-test/config
: Bash-syntax environment variables.integration-test/files/*
: Files you may want to upload. Tests can access these from/app/files/
.integration-test/spec/*_spec.rb
: Feature specifications you create.integration-test/helpers/*_helper.rb
: Extra code that is auto-included before tests. This is a good place to writeModule
s to extendCapybara::Session
.integration-test/docker-compose.yml
: full test environment, used byintegration-test/run-in-docker-compose
For instance, to create a go_to_home
method:
- Create
integration-test/helpers/go_to_home_helper.rb
: `module GoToHomeHelper; def go_to_home; visit '/login'; end; end - In
integration-test/spec/my_feature_spec.rb
, include it:def session_helpers; [ GoToHomeHelper ]; end
- In your test in
integration-test/spec/my_feature_spec.rb
, use it:it 'should go to home'; page.go_to_home; page.assert_selector('h1'); end
To run all tests in a fresh Overview environment, run
integration-test/run-in-docker-compose
This is useful in a Jenkins pipeline:
stage('Integration test') {
sh 'integration-test/run-in-docker-compose || true'
junit 'integration-test/reports/**/*.xml'
}
Pulling, building, spinning up and shutting down all Overview's (and your) containers makes testing slow. You can skip all that:
To run all tests, run integration-test/run
. This expects some environment
variables to describe how to connect to Overview: see integration-test/config
.
This will output to integration-test/test-results.xml
. That's in a format
Jenkins can understand.
Tests can take a long time to run, so you might want to run just one test:
To run one test, run, for instance, integration-test/run my_feature_spec
.
Now, how did we make a test?
Edit integration-test/spec/my_feature_spec.rb
. Or rename it. Or create a new
file with the same structure. Anything in integration-test/spec/*_spec.rb
will
work.
Make sure its first lines are:
#!/usr/bin/env ruby
require './spec/spec_helper'
Make sure it's executable: chmod +x integration-test/spec/my_feature_spec.rb
Now write describe
, before
, after
and it
blocks to test your feature.
Tests are about clicking on things and seeing what happens. The best way to get familiar with that is to actually click on things and see what happens.
Tests involve clicking and typing and looking at a web browser window. But
integration-test/run
is "headless" -- it does not render a web browser
window.
To develop and debug tests, you'll probably want to see a web browser window: exactly the web browser window that the test platform uses, with exactly the same network configuration. We show it, cross-platform, with VNC.
Run integration-test/run-browser
to open a browser.
If you want to upload files in this environment, upload them from
/app/files
. Those are the files the integration tests access.
You can watch a test: integration-test/run-browser spec/my_feature_spec.rb
If your test is failing and Chromium is exiting too quickly for you to debug,
add sleep
in your test code and re-run
integration-test/run-browser my_feature_spec
. You can open Developer Tools
to see why the next line of code is about to fail.
Most importantly: know what to wait for. Integration tests run far, far faster than humans. It's a bug if your test tries to interact with an HTML element that isn't yet loaded, that is being animated, that doesn't have event listeners yet, or that is about to disappear. These are called "races", and they make tests pass sometimes and fail other times. Some races you miss on your development computer will happen on other computers.
Here's how to avoid races. Design your test as a sequence like this:
- Do something
- Wait for its effect(s)
- Do something
- Wait for its effect(s)
- ... and so on
Always comment what you're waiting for and why it's important. Re-run tests a few times before you commit: if your test even fails once, that's a critical bug that you must fix before committing.
For instance, here is good code. It clicks, waits, and then clicks again:
page.click_link('Open dropdown')
page.click_link('Link in the dropdown', wait: WAIT_FAST) # wait for dropdown to open
Use WAIT_FAST
when waiting for JavaScript, WAIT_LOAD
when waiting for an
HTTP response, and WAIT_SLOW
when waiting for a giant backend process.
Use the Docker version of Chromium, not your own. It has a different network configuration, and that's important.
Be careful with iframes. Use page.within_frame('...'). Capybara will give an unhelpful "unable to find visible element" if you look in the wrong iframe. (Iframes can't see one another's contents.)
Here is an example that deals with iframes:
page.click_link('Open popup')
# wait for modal to load
page.assert_selector('#view-app-modal-dialog-iframe', wait: WAIT_LOAD)
# No "#": view-app-... is an id, not a selector
within_frame('view-app-modal-dialog-iframe') do
# wait for iframe _contents_ to load
page.click_link('Close popup', wait: WAIT_LOAD)
end
# wait for iframe to close
page.assert_no_selector('#view-app-modal-dialog-iframe', wait: WAIT_FAST)
Beware Capybara's inconsistent selectors. In page.click_link(selector)
,
selector
is text, id or title. In page.find(selector).click
, selector
is
CSS. Prefer the click_link()
kind (it's more like English), but there will
always be both; don't let Capybara's confusing design confuse you.
Documentation is at https://github.com/teamcapybara/capybara and
http://www.rubydoc.info/github/jnicklas/capybara/Capybara/Session
and other spots online. One detail sets us apart: we do not use
Capybara.default_max_wait_time
because it is terrible.
3.0.1, released 2020-04-09
Changes:
- Re-included "webrick", so specs can require it.
- Re-included "xvfb-run", to fix ./run.
- Nix "curl", which is unused.
To upgrade:
- Change
OVERVIEW_INTEGRATION_TESTER_VERSION
to3.0.1
3.0.0, released 2020-04-08
Changes:
- Upgraded to Chromium 79
- Switched to alpine for even-faster pull
- Upgarded Overview
To upgrade:
- Change
OVERVIEW_INTEGRATION_TESTER_VERSION
to3.0.0
and updateOVERVIEW_VERSION
to at leasta19aeed0cfcc2417a1ddc135f424ecf76748285b
- (To follow changes in
overview-server
project): setDEVELOPMENT_PROJECT_NAME=overview-server
- Nix the
--shm-size
Docker flag from your./run
. - If you modified your
run
script to invokexvfb-run
, remove the--init
Docker flag. - Overwrite your
run
by downloading run-browser @ v3.0.0 - Overwrite your
run-browser
by downloading run-browser @ v3.0.0 - Overwrite your
spec/spec_helper.rb
with spec/spec_helper.rb @ v3.0.0
2.0.0, released 2018-04-10
Changes:
- Upgraded to Chromedriver 2.37 and Chromium 64
- Switched to debian-slim for faster pull
- Upgraded Overview
To upgrade:
- Change
OVERVIEW_INTEGRATION_TESTER_VERSION
to2.0.0
and updateOVERVIEW_VERSION
to at leastba89c4502319969f3bd9248150e8608c085d7c7e
- Add
OV_APPLICATION_SECRET
environment variable tooverview-web
with any String value - Add
overview-convert-pdf
instance, if your tests use any PDF imports - Overwrite
helpers/session_helpers/document_set_helper.rb
. (It now disables OCR when uploading PDFs: that lets you omitoverview-convert-pdfocr
fromdocker-compose.yml
and speed up tests.)
- Fix a bug or add a feature, presumably by writing tests in
test/
and/or editing code inskeleton/
. - Pick a new version number,
X.Y.Z
(consultingVERSION
and semver). docker build docker -t overview/overview-integration-tester:X.Y.Z
./test/test.sh
./release X.Y.Z