Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: E2E test suite with puppeteer+ipfsd-ctl #1353

Merged
merged 21 commits into from Jan 8, 2020
Merged

Conversation

lidel
Copy link
Member

@lidel lidel commented Dec 5, 2019

Parent: #1164
cc @hugomrdias @hacdias @autonome for visibility/early feedback

This PR adds E2E tests for WebUI that run against HTTP API from real IPFS node

Try with:

$ npm run test:e2e # headless against go-ipfs

Implementation details

The end-to-end tests (e2e) test the full app in a headless Chromium browser. They spawn real IPFS node for HTTP API and a static HTTP server to serve the app.
The purpose of those tests is not being comprehensible, but act as a quick regression and integration suite.

Make sure npm run build is run before starting E2E tests:

$ npm run build
$ npm run test:e2e # end-to-end smoke tests (fast, headless, use go-ipfs)

Customizing E2E Tests

Default behavior can be tweaked via env variables below.

E2E_IPFSD_TYPE

Variable named E2E_IPFSD_TYPE defines which IPFS backend should be used for end-to-end tests.

CI setup of ipfs-webui repo runs tests against both JS and GO implementations:

$ E2E_IPFSD_TYPE=go npm run test:e2e # 'go' is the default (if missing)
$ E2E_IPFSD_TYPE=js npm run test:e2e

It is possible to test against arbitrary versions by tweaking ipfs (js-ipfs)
and go-ipfs-dep (go-ipfs) in devDependencies section of package.json and applying the change via npm i

E2E_API_URL

Instead of spawning a disposable node and repo for tests, one can point the E2E test suite at arbitrary HTTP API running on localhost:

$ E2E_API_URL=http://127.0.0.1:5001 npm run test:e2e

Caveat 1: HTTP API used in tests needs to run on the local machine for Peers screen to pass (they test manual swarm connect to ephemeral /ip4/120.0.0.1/.. multiaddr)

Caveat 2: CORS requests from http://localhost:3001 (static server hosting dev version of webui) need to be added to Access-Control-Allow-Origin whitelist array in node's config:

"API": {
  "HTTPHeaders": {
    "Access-Control-Allow-Origin": [
      "http://localhost:3001"
    ]
  }
}

Can be done ad-hoc via command line:

$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["http://localhost:3001"]'
$ ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'

Debugging E2E tests

Show the browser

By default, the test run headless, so you won't see the browser. To debug test errors, it can be helpful to see the robot clicking around the site.
To disable headless mode and see the browser, set the environment variable DEBUG=true:

$ DEBUG=true npm run test:e2e # e2e in slowed down mode in a browser window

Breakpoints

It is possible to set a "breakpoint" via await jestPuppeteer.debug() to stop tests at a specific line:

jest.setTimeout(600000) // increase test suite timeout
await jestPuppeteer.debug() // puppeteer will pause here

In a continuous integration environment we lint the code, run the unit tests, build the app, start an http server and run the unit e2e tests:

> npm run lint
> npm test
> npm run build
> npm run test:e2e

TODO

  • npm run test:e2e should run headless e2e tests against real go-ipfs
  • DEBUG=true npm run test:e2e should show browser window
  • ipfs (API interface for real node) should be in scope of tests
  • add mechanism and docs for swapping IPFS node used for tests (E2E_IPFSD_TYPE)
  • tests
    • Status page (Peer ID)
    • Files page (multiple files at once)
    • Files page (directory)
      • I was unable to find a way for testing this, but previous test should be enough as it mostly uses the same code paths.
    • Explore page
    • Peers page
    • Settings page
  • switch to ipfsd-ctl v1
  • ensure it runs js/go from node_modules
  • enable linter for test/e2e
  • add option to point at remote HTTP API (E2E_API_URL)

This is initial version that uses jest-puppeteer for end to end
integration/regression tests against real HTTP API.

For now it runs headless chromium against go-ipfs,
but can be extended to run test matrix against js-ipfs as well.

Single file upload acts as a POC test case.
(we don't want to use go-ipfs-dep from ipfsd-ctl
Copy link

@autonome autonome left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor changes, but LGTM otherwise!

test/e2e/e2e.test.js Outdated Show resolved Hide resolved
test/e2e/e2e.test.js Outdated Show resolved Hide resolved
test/e2e/e2e.test.js Outdated Show resolved Hide resolved
test/e2e/e2e.test.js Outdated Show resolved Hide resolved
Copy link
Member

@hacdias hacdias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far looks good! Please let me know when you want a deep review of this!

@lidel lidel marked this pull request as ready for review December 21, 2019 15:28
@lidel
Copy link
Member Author

lidel commented Dec 21, 2019

Ok, I've split tests into separate files but kept them small to test as much they can while still easy to maintain.
When merged, I'll PR js-ipfs repo to run external webui E2E with js-ipfs backend.

Updated README with details about E2E.

@hugomrdias I used new ipfsd-ctl in test/e2e/peers.test.js and test/e2e/setup/global-init.js – would appreciate sanity check, thanks!

Copy link
Member

@hacdias hacdias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you @lidel for taking over this. This is awesome!

beforeAll(async () => {
// spawn an ephemeral local node for manual swarm connect test
const factory = Ctl.createFactory({ type: 'proc', test: true, disposable: true })
ipfsd = await factory.spawn()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you dont need to handle multiple nodes you can use createController

Comment on lines 24 to 40
if (endpoint) {
// create http client for endpoint passed via E2E_API_URL=
ipfs = ipfsClient({ apiAddr: endpoint })
} else {
// use ipfds-ctl to spawn daemon to expose http api used for e2e tests
const type = process.env.E2E_IPFSD_TYPE || 'go'
const factory = Ctl.createFactory({
type,
test: true, // sets up all CORS headers required for accessing HTTP API port of ipfsd node
overrides: { // call findBin here to ensure we use version from devDependencies, and not from ipfsd-ctl
js: { ipfsBin: findBin('js') },
go: { ipfsBin: findBin('go') }
}
})
ipfsd = await factory.spawn()
ipfs = ipfsd.api
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

damn this is totally wrong we need to talk so i can improve the ctl docs :)

Copy link
Member Author

@lidel lidel Jan 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hugomrdias: thanks for the tips, I fixed first two points in bac8428 and opened PR to improve ipfsd-ctl docs in ipfs/js-ipfsd-ctl#421

As for the third point about remote endpoint, I don't think the createController({remote: true, endpoint: process.env.E2E_API_URL }) will work, because E2E_API_URL is the IPFS API, not the one provided by Ctl.createServer.

Running createController({remote: true, endpoint: 'http://127.0.0.1:5001' }) produces error (probably due to 404 for /api/v0/..):

HTTPError: Not Found
    at fn (/home/lidel/project/ipfs-webui/node_modules/ky/umd.js:337:12)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Let me know if I got this wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if aren't using createServer you shouldn't need ctl only http-client right ?

Copy link
Member Author

@lidel lidel Jan 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. We don't use createServer in e2e tests.
If E2E_API_URL is defined it means HTTP API got spawned by a third party, and we just use regular client for connecting to it.

@lidel
Copy link
Member Author

lidel commented Jan 8, 2020

@hugomrdias applied your suggestions (details in #1353 (comment)). Should be good enough.
I'm going to merge this to unblock integration with js-ipfs and go-ipfs CI processes, we can improve things later in separate PRs.

@lidel lidel changed the title feat: e2e test suite against real go-ipfs feat: E2E test suite with puppeteer+ipfsd-ctl Jan 8, 2020
@lidel lidel merged commit 59b2d67 into master Jan 8, 2020
@lidel lidel deleted the feat/end-to-end-tests branch January 8, 2020 12:19
@lidel lidel mentioned this pull request Jan 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants