adonis install @adonisjs/vow-browser
# Skip Chromium download
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true adonis install @adonisjs/vow-browser
You are viewing the legacy version of AdonisJS. Visit https://adonisjs.com for newer docs. This version will receive security patches until the end of 2021.
AdonisJs makes it simple to write functional tests using the Chrome browser. Under the hood, it uses Puppeteer to launch a web browser and run assertions.
In this guide, we learn about opening a browser programmatically and running tests like a real user is using your application.
Since AdonisJs uses the Chrome engine, you cannot run your tests on multiple browsers like IE or Firefox. Cross-browser testing is usually implemented for frontend JavaScript, which is out of the scope of the AdonisJs documentation. |
Puppeteer comes bundled with Chromium and takes a while to download and install. To skip the Chromium install, pass the PUPPETEER_SKIP_CHROMIUM_DOWNLOAD environment variable. If skipped, make sure to define your custom Chromium path also.
|
As the Browser Provider is not installed by default, we need to pull it from npm
:
adonis install @adonisjs/vow-browser
# Skip Chromium download
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true adonis install @adonisjs/vow-browser
Next, register the provider in the start/app.js
file aceProviders
array:
const aceProviders = [
'@adonisjs/vow-browser/providers/VowBrowserProvider'
]
Now we’ve set up the provider, we can use the Test/Browser
trait to test against a web browser.
Create a new functional test by running the following command:
> adonis make:test hello-world
> Select the type of test to create
Unit test
❯ Functional test
create: test/functional/hello-world.spec.js
Next, open the test file and paste in the following code:
'use strict'
const { test, trait } = use('Test/Suite')('Hello World')
trait('Test/Browser')
test('Visit home page', async ({ browser }) => {
const page = await browser.visit('/')
await page.assertHas('Adonis')
})
Examining our test file…
We register the Test/Browser
trait, providing us a browser
object to make HTTP requests with
We visit the root /
URL and save the reference to the page object
We run an assertion to confirm the page HTML contains the text Adonis
Finally, run all your functional tests via the following command:
> adonis test functional
Hello World
✓ Visit home page (978ms)
PASSED
total : 1
passed : 1
time : 998ms
If the test failed, ensure you haven’t changed the default output of the root / route.
|
If you used the PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
environment variable to install the Browser Provider, then Chromium is not installed by default and you must pass an executable path to Chromium yourself.
First, download Chromium and place it in a Node.js accessible directory
When using the Test/Browser
trait, define your executable path to Chromium:
trait('Test/Browser', {
executablePath: '/absolute/path/to/chromium'
})
Alternatively, define the executable path as an env var in the .env.testing
file:
CHROMIUM_PATH=/absolute/path/to/chromium
The following browser options can be configured via the Test/Browser
trait:
Key | Description |
---|---|
|
Whether to run tests in headless mode or launch a real browser. |
|
Path to the Chromium executable (only required when you don’t use bundled Chromium). |
|
Number of millseconds used for slowing down each browser interaction (can be used to see tests in slow motion). |
|
Log all browser console messages to the terminal. |
trait('Test/Browser', {
headless: false
})
For all other options, see the puppeteer.launch official documentation.
AdonisJs adds a wrapper on top of Puppeteer to make it more suitable for testing.
The following API is for the main browser and page objects.
Calls the Puppeteer page.goto method and has the same signature:
test('Visit home page', async ({ browser }) => {
const page = await browser.visit('/', {
waitUntil: 'load'
})
await page.assertHas('Adonis')
})
You can access the actual Puppeteer page object via the page.page
property:
test('Visit home page', async ({ browser }) => {
const page = await browser.visit('/')
// puppeteer page object
page.page.addScriptTag()
})
The following methods can be used to interact with a webpage.
The page interaction methods support all CSS selectors. |
Type inside an element with the given selector:
const { test, trait } = use('Test/Suite')('Hello World')
trait('Test/Browser')
test('Visit home page', async ({ browser }) => {
const page = await browser.visit('/')
await page
.type('[name="username"]', 'virk')
})
To type multiple values, chain method calls:
await page
.type('[name="username"]', 'virk')
.type('[name="age"]', 22)
Select the value inside a select box:
await page
.select('[name="gender"]', 'Male')
To select multiple values, pass an array:
await page
.select('[name="lunch"]', ['Chicken box', 'Salad'])
Select a radio button based on its value:
await page
.radio('[name="gender"]', 'Male')
Submit a selected form:
await page
.submitForm('form')
// or use a name
await page
.submitForm('form[name="register"]')
Attach one or multiple files:
await page
.attach('[name="profile_pic"]', [
Helpers.tmpPath('profile_pic.jpg')
])
Save a screenshot of the current state of a webpage:
await page
.type('[name="username"]', 'Virk')
.type('[name="age"]', 27)
.screenshot()
There are times when you might have to wait for an action to take effect.
For example, you might have to wait for an element to appear on the page before you can click it, or you might have to wait for a webpage to redirect, and so on.
The following methods can be used to handle such scenarios.
Wait until an element appears inside the DOM:
await page
.waitForElement('div.alert')
.assertHasIn('div.alert', 'Success!')
The default wait timeout is 15 seconds.
|
Wait until an element disappears from the DOM:
await page
.waitUntilMissing('div.alert')
.assertNotExists('div.alert')
Wait until a page has navigated properly to a new URL:
await page
.click('a[href="/there"]')
.waitForNavigation()
.assertPath('/there')
Wait until the passed closure function returns true:
await page
.waitFor(function () {
return !!document.querySelector('body.loaded')
})
The closure is executed in the browser context and has access to variables like window , document , and so on.
|
Pause the webpage for a given timeframe:
await page.pause()
The default pause timeout is 15 seconds.
|
The following methods can be used to read values from a webpage.
Get text for a given element or the entire page:
await page
.getText()
// or
await page
.getText('span.username')
Get HTML for a given element or the entire page:
await page
.getHtml()
// or
await page
.getHtml('div.header')
Find if a given element is visible:
const isVisible = await page
.isVisible('div.alert')
assert.isFalse(isVisible)
Find if an element exists in the DOM:
const hasElement = await page
.hasElement('div.alert')
assert.isFalse(hasElement)
Find whether a checkbox is checked:
const termsChecked = await page
.isChecked('[name="terms"]')
assert.isTrue(termsChecked)
Get the value of a given attribute:
const dataTip = await page
.getAttribute('div.tooltip', 'data-tip')
Get all attributes for a given element selector:
const attributes = await page
.getAttributes('div.tooltip')
Get the value of a given form element:
const value = await page
.getValue('[name="username"]')
assert.equal(value, 'virk')
One way to run assertions is to read the value of target elements and then assert against those values manually.
The AdonisJS browser client provides a number of convenient helper methods to run inline page assertions to simplify the process for you.
Assert the webpage includes the expected text value:
await page
.assertHas('Adonis')
Assert a given selector contains the expected value:
await page
.assertHasIn('div.alert', 'Success!')
Assert the value of an attribute is the same as the expected value:
await page
.assertAttribute('div.tooltip', 'data-tip', 'Some helpful tooltip')
Assert the value for a given form element:
await page
.assertValue('[name="username"]', 'virk')
Assert a checkbox is checked:
await page
.assertIsChecked('[name="terms"]')
Assert a checkbox is not checked:
await page
.assertIsNotChecked('[name="terms"]')
Assert an element is visible:
await page
.assertIsVisible('div.notification')
Assert an element is not visible:
await page
.assertIsNotVisible('div.notification')
Assert the value of a query parameter:
await page
.assertQueryParam('orderBy', 'id')
Assert an element exists inside the DOM:
await page
.assertExists('div.notification')
Assert an element does not exist inside the DOM:
await page
.assertNotExists('div.notification')
Assert the number of elements for a given selector:
await page
.assertCount('table tr', 2)
Assert the value of a function executed on a given selector (fn
is executed in the browser context):
await page
.assertEval('table tr', function (el) {
return el.length
}, 2)
In above example, we count the number of tr
inside a table and assert that count is 2
.
You can also pass arguments ([args]
) to the selector fn
:
await page
.assertEval(
'div.notification',
function (el, attribute) {
return el[attribute]
},
['id'],
'notification-1'
)
In the above example, we assert over a given attribute of the div.notification
element. The given attribute is dynamic and passed as an argument (['id']
).
Assert the output of a given function (fn
is executed in the browser context):
await page
.assertFn(function () {
return document.title
}, 'Welcome to Adonis')
The difference between assertFn and assertEval is that assertEval selects an element before running the function.
|