docs: add assertions doc (#2585)

* docs: add assertions doc

* docs: assertions and verification split
This commit is contained in:
Arjun Attam 2020-06-22 16:53:56 -07:00 committed by GitHub
parent 687067831a
commit 6cec2dfb7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 248 additions and 117 deletions

View File

@ -16,7 +16,7 @@
- [Pages and frames](./core-concepts.md#pages-and-frames)
- [Selectors](./core-concepts.md#selectors)
- [Auto-waiting](./core-concepts.md#auto-waiting)
- [Node.js and browser execution contexts](./core-concepts.md#nodejs-and-browser-execution-contexts)
- [Execution contexts: Node.js and Browser](./core-concepts.md#execution-contexts-nodejs-and-browser)
- [Object & element handles](./core-concepts.md#object--element-handles)
1. [Input](./input.md)
- [Text input](./input.md#text-input)
@ -43,18 +43,25 @@
- [Handle requests](./network.md#handle-requests)
- [Modify requests](./network.md#modify-requests)
- [Abort requests](./network.md#abort-requests)
1. [Scraping and Verification](./verification.md)
- [Evaluating JavaScript](./verification.md#evaluating-javascript)
- [Capturing screenshot](./verification.md#capturing-screenshot)
1. [Assertions](./assertions.md)
- [Common patterns](./assertions.md#common-patterns)
- [Element Handles](./assertions.md#element-handles)
- [Custom assertions](./assertions.md#custom-assertions)
1. [Verification](./verification.md)
- [Screenshots](./verification.md#screenshots)
- [Console logs](./verification.md#console-logs)
- [Page errors](./verification.md#page-errors)
- [Page events](./verification.md#page-events)
- [Handling exceptions](./verification.md#handling-exceptions)
1. [Navigation and Loading](./loading.md)
- [Overview](./loading.md#)
- [Common scenarios](./loading.md#common-scenarios)
- [Loading a popup](./loading.md#loading-a-popup)
- [Client-side redirects](./loading.md#unusual-client-side-redirects)
- [Navigation after a timeout](./loading.md#click-triggers-navigation-after-a-timeout)
1. [Actionability](./actionability.md)
1. [Test runners](./test-runners.md)
- [Jest / Jasmine](./test-runners.md#jest--jasmine)
- [AVA](./test-runners.md#ava)
- [Mocha](./test-runners.md#mocha)
1. [Continuous Integration](./ci.md)
- [Docker](./ci.md#docker)
- [GitHub Actions](./ci.md#github-actions)
@ -63,11 +70,8 @@
- [CircleCI](./ci.md#circleci)
- [AppVeyor](./ci.md#appveyor)
- [Troubleshooting](./troubleshooting.md)
1. [Test runners](./test-runners.md)
- [Jest / Jasmine](./test-runners.md#jest--jasmine)
- [AVA](./test-runners.md#ava)
- [Mocha](./test-runners.md#mocha)
1. [Selector engines](./selectors.md)
1. [Actionability](./actionability.md)
1. [Extensibility](./extensibility.md)
- [Custom selector engines](./extensibility.md#custom-selector-engines)
1. [API Reference](./api.md)

124
docs/assertions.md Normal file
View File

@ -0,0 +1,124 @@
# Assertions
The Playwright API can be used to read element contents and properties for test assertions. These values are fetched from the browser page and asserted in
Node.js.
The examples in this guide use the built-in [`assert` module](https://nodejs.org/api/assert.html), but they can be used with any assertion library (like [Expect](https://www.npmjs.com/package/expect) or [Chai](https://www.npmjs.com/package/chai)). See [Test runners](test-runners.md) for more info.
<!-- GEN:toc-top-level -->
- [Common patterns](#common-patterns)
- [Element Handles](#element-handles)
- [Custom assertions](#custom-assertions)
<!-- GEN:stop -->
<br/>
## Common patterns
Playwright provides convenience APIs for common assertion tasks, like finding the
text content of an element. These APIs require a [selector](selectors.md) to locate
the element.
```js
// Assert text content
const content = await page.textContent('nav:first-child');
assert(content === 'home');
// Assert inner text
const text = await page.innerText('.selected');
assert(text === 'value');
// Assert inner HTML
const html = await page.innerHTML('div.result');
assert(html === '<p>Result</p>')
// Assert `checked` attribute
const checked = await page.getAttribute('input', 'checked');
assert(checked);
```
#### API reference
- [page.textContent(selector[, options])](api.md#pagetextcontentselector-options)
- [page.innerText(selector[, options])](api.md#pageinnertextselector-options)
- [page.innerHTML(selector[, options])](api.md#pageinnerhtmlselector-options)
- [page.getAttribute(selector, name[, options])](api.md#pagegetattributeselector-name-options)
- [frame.textContent(selector[, options])](api.md#frametextcontentselector-options)
- [frame.innerText(selector[, options])](api.md#frameinnertextselector-options)
- [frame.innerHTML(selector[, options])](api.md#frameinnerhtmlselector-options)
- [frame.getAttribute(selector, name[, options])](api.md#framegetattributeselector-name-options)
<br/>
## Element Handles
[ElementHandle](api.md#class-elementhandle) objects represent in-page DOM
elements. They can be used to assert for multiple properties of the element.
It is recommended to fetch the `ElementHandle` object with
[`page.waitForSelector`](api.md#pagewaitforselectorselector-options) or
[`frame.waitForSelector`](api.md#framewaitforselectorselector-options). These
APIs wait for the element to be visible and then return an `ElementHandle`.
```js
// Get the element handle
const elementHandle = page.waitForSelector('#box');
// Assert bounding box for the element
const boundingBox = await elementHandle.boundingBox();
assert(boundingBox.width === 100);
// Assert attribute for the element
const classNames = await elementHandle.getAttribute('class');
assert(classNames.includes('highlighted'));
```
#### API reference
- [elementHandle.textContent()](api.md#elementhandletextcontent)
- [elementHandle.innerText()](api.md#elementhandleinnertext)
- [elementHandle.innerHTML()](api.md#elementhandleinnerhtml)
- [elementHandle.getAttribute(name)](api.md#elementhandlegetattributename)
- [elementHandle.boundingBox()](api.md#elementhandleboundingbox)
<br/>
## Custom assertions
With Playwright, you can also write custom JavaScript to run in the context of
the browser. This is useful in situations where you want to assert for values
that are not covered by the convenience APIs above.
The following APIs do not auto-wait for the element. It is recommended to use
[`page.waitForSelector`](api.md#pagewaitforselectorselector-options) or
[`frame.waitForSelector`](api.md#framewaitforselectorselector-options).
```js
// Assert local storage value
const userId = page.evaluate(() => window.localStorage.getItem('userId'));
assert(userId);
// Assert value for input element
await page.waitForSelector('#search');
const value = await page.$eval('#search', el => el.value);
assert(value === 'query');
// Assert computed style
const fontSize = await page.$eval('div', el => window.getComputedStyle(el).fontSize);
assert(fontSize === '16px');
// Assert list length
const length = await page.$$eval('li.selected', (items) => items.length);
assert(length === 3);
```
#### API reference
- [page.evaluate(pageFunction[, arg])](api.md#pageevaluatepagefunction-arg)
- [page.$eval(selector, pageFunction[, arg])](api.md#pageevalselector-pagefunction-arg)
- [page.$$eval(selector, pageFunction[, arg])](api.md#pageevalselector-pagefunction-arg-1)
- [frame.evaluate(pageFunction[, arg])](api.md#frameevaluatepagefunction-arg)
- [frame.$eval(selector, pageFunction[, arg])](api.md#frameevalselector-pagefunction-arg)
- [frame.$$eval(selector, pageFunction[, arg])](api.md#frameevalselector-pagefunction-arg-1)
- [elementHandle.$eval(selector, pageFunction[, arg])](api.md#elementhandleevalselector-pagefunction-arg)
- [elementHandle.$$eval(selector, pageFunction[, arg])](api.md#elementhandleevalselector-pagefunction-arg-1)

View File

@ -14,8 +14,8 @@ the following primitives.
- [Pages and frames](#pages-and-frames)
- [Selectors](#selectors)
- [Auto-waiting](#auto-waiting)
- [Node.js and browser execution contexts](#nodejs-and-browser-execution-contexts)
- [Object & element handles](#object--element-handles)
- [Execution contexts: Node.js and Browser](#execution-contexts-nodejs-and-browser)
- [Object & Element handles](#object--element-handles)
<!-- GEN:stop -->
<br/>
@ -227,15 +227,30 @@ await page.waitForSelector('#promo', { state: 'detached' });
<br/>
## Node.js and browser execution contexts
## Execution contexts: Node.js and Browser
Playwright scripts run in your Node.js environment. You page scripts run in the page environment. Those environments don't intersect, they are running in different virtual machines in different processes and potentially on different computers.
IMAGE PLACEHOLDER
Playwright scripts run in your Node.js environment. You page scripts run in the browser page environment. Those environments don't intersect, they are running in different virtual machines in different processes and even potentially on different computers.
The [`page.evaluate`](https://github.com/microsoft/playwright/blob/master/docs/api.md#pageevaluatepagefunction-arg) API can run a JavaScript function in the context
of the web page and bring results back to the Node.js environment. Globals like
`window` and `document` along with the web page runtime can be used in `evaluate`.
of the web page and bring results back to the Node.js environment. Browser globals like
`window` and `document` can be used in `evaluate`.
```js
const href = await page.evaluate(() => document.location.href);
```
If the result is a Promise or if the function is asynchronous evaluate will automatically wait until it's resolved:
```js
const status = await page.evaluate(async () => {
const response = await fetch(location.href);
return response.status;
});
```
### Evaluation
Functions passed inside `page.evaluate` can accept parameters. These parameters are
serialized and sent into your web page over the wire. You can pass primitive types, JSON-alike objects and remote object handles received from the page.
Right:
@ -257,34 +272,33 @@ const result = await page.evaluate(() => {
});
```
Evaluation parameters are serialized and sent into your web page over the wire.
You can pass primitive types, JSON-alike objects and remote object handles received from the page.
#### API reference
- [`page.evaluate(pageFunction[, arg])`](api.md#pageevaluatepagefunction-arg)
- [`frame.evaluate(pageFunction[, arg])`](api.md#frameevaluatepagefunction-arg)
<br/>
## Object & element handles
## Object & Element handles
Playwright has an API to create Node-side handles to the page DOM elements or any other objects inside the page.
These handles live in the Node.js process, whereas the actual objects reside in browser.
IMAGE PLACEHOLDER
Playwright can create Node-side handles to the page DOM elements or any other objects inside the page. These handles live in the Node.js process, whereas the actual objects reside in browser.
There are two types of handles:
- [`JSHandle`](./api.md#class-jshandle) to reference any javascript objects in the page
- [`JSHandle`](./api.md#class-jshandle) to reference any JavaScript objects in the page
- [`ElementHandle`](./api.md#class-elementhandle) to reference DOM elements in the page
Note that since any DOM element in the page is also a javascript object,
Note that since any DOM element in the page is also a JavaScript object,
Playwright's [`ElementHandle`](./api.md#class-elementhandle) extends
[`JSHandle`](./api.md#class-jshandle).
Handles Lifetime:
### Handles Lifecycle
- Handles can be acquired using the page methods [`page.evaluateHandle`](./api.md#pageevaluatehandlepagefunction-arg), [`page.$`](./api.md#pageselector) or [`page.$$`](./api.md#pageselector-1) or
their frame counterparts [`frame.evaluateHandle`](./api.md#frameevaluatehandlepagefunction-arg), [`frame.$`](./api.md#frameselector) or [`frame.$$`](./api.md#frameselector-1).
- Once created, handles will retain object from [garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management)
- Once created, handles will retain object from [garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management).
- Handles will be **automatically disposed** once the page or frame they belong to navigates or closes.
- Handles can be **manually disposed** using [`jsHandle.dispose`](./api.md#jshandledispose) method.
Here is how you can use these handles:
### Example: ElementHandle
```js
// The first parameter of the elementHandle.evaluate callback is the element handle points to.
@ -292,7 +306,7 @@ const ulElementHandle = await page.$('ul');
await ulElementHandle.evaluate(ulElement => getComputedStyle(ulElement).getPropertyValue('display'));
```
Alternatively, handles can be passed as arguments to [`page.evaluate`](./api.md#pageevaluatepagefunction-arg) function:
Handles can also be passed as arguments to [`page.evaluate`](./api.md#pageevaluatepagefunction-arg) function:
```js
// In the page API, you can pass handle as a parameter.
@ -300,6 +314,35 @@ const ulElementHandle = await page.$('ul');
await page.evaluate(uiElement => getComputedStyle(uiElement).getPropertyValue('display'), uiElement);
```
### Example: JSHandle
```js
// Create a new array in the page, write a reference to it in
// window.myArray and get a handle to it.
const myArrayHandle = await page.evaluateHandle(() => {
window.myArray = [1];
return myArray;
});
// Get current length of the array using the handle.
const length = await page.evaluate(
(arg) => arg.myArray.length,
{ myArray: myArrayHandle }
);
// Add one more element to the array using the handle
await page.evaluate((arg) => arg.myArray.push(arg.newElement), {
myArray: myArrayHandle,
newElement: 2
});
// Get current length of the array using window.myArray reference.
const newLength = await page.evaluate(() => window.myArray.length);
// Release the object when it's no longer needed.
await myArrayHandle.dispose();
```
#### API reference
- [class `JSHandle`](./api.md#class-jshandle)
- [class `ElementHandle`](./api.md#class-elementhandle)
@ -307,5 +350,3 @@ await page.evaluate(uiElement => getComputedStyle(uiElement).getPropertyValue('d
- [`page.$`](./api.md#pageselector)
- [`page.$$`](./api.md#pageselector-1)
- [`jsHandle.evaluate`](./api.md#jshandleevaluatepagefunction-arg)
<br/>

View File

@ -1,69 +1,15 @@
# Scraping and verification
# Verification
<!-- GEN:toc-top-level -->
- [Evaluating JavaScript](#evaluating-javascript)
- [Capturing screenshot](#capturing-screenshot)
- [Screenshots](#screenshots)
- [Console logs](#console-logs)
- [Page errors](#page-errors)
- [Page events](#page-events)
- [Handling exceptions](#handling-exceptions)
<!-- GEN:stop -->
<br/>
## Evaluating JavaScript
Execute JavaScript function in the page:
```js
const href = await page.evaluate(() => document.location.href);
```
If the result is a Promise or if the function is asynchronous evaluate will automatically wait until it's resolved:
```js
const status = await page.evaluate(async () => {
const response = await fetch(location.href);
return response.status;
});
```
Get object handle and use it in multiple evaluations:
```js
// Create a new array in the page, write a reference to it in
// window.myArray and get a handle to it.
const myArrayHandle = await page.evaluateHandle(() => {
window.myArray = [1];
return myArray;
});
// Get current length of the array using the handle.
const length = await page.evaluate(
(arg) => arg.myArray.length,
{ myArray: myArrayHandle }
);
// Add one more element to the array using the handle
await page.evaluate((arg) => arg.myArray.push(arg.newElement), {
myArray: myArrayHandle,
newElement: 2
});
// Get current length of the array using window.myArray reference.
const newLength = await page.evaluate(() => window.myArray.length);
// Release the object when it's no longer needed.
await myArrayHandle.dispose();
```
#### API reference
- [page.$(selector)](./api.md#pageselector)
- [page.$$(selector)](./api.md#pageselector-1)
- [page.$eval(selector, pageFunction[, arg])](./api.md#pageevalselector-pagefunction-arg)
- [page.$$eval(selector, pageFunction[, arg])](./api.md#pageevalselector-pagefunction-arg-1)
- [page.evaluate(pageFunction[, arg])](./api.md#pageevaluatepagefunction-arg)
- [page.evaluateHandle(pageFunction[, arg])](./api.md#pageevaluatehandlepagefunction-arg)
<br/>
## Capturing screenshot
## Screenshots
```js
// Save to file
@ -88,7 +34,7 @@ await elementHandle.screenshot({ path: 'screenshot.png' });
<br/>
## Page events
## Console logs
You can listen for various events on the `page` object. Following are just some of the examples of the events you can assert and handle:
@ -103,6 +49,45 @@ page.on('console', msg => {
});
```
#### API reference
- [class: ConsoleMessage](./api.md#class-consolemessage)
- [class: Page](./api.md#class-page)
- [event: 'console'](./api.md#event-console)
<br/>
## Page errors
Listen for uncaught exceptions in the page with the `pagerror` event.
```js
// Log all uncaught errors to the terminal
page.on('pageerror', exception => {
console.log(`Uncaught exception: "${exception}"`);
});
// Navigate to a page with an exception.
await page.goto('data:text/html,<script>throw new Error("Test")</script>');
```
#### API reference
- [class: Page](./api.md#class-page)
- [event: 'pageerror'](./api.md#event-pageerror)
<br/>
## Page events
#### `"requestfailed"`
```js
page.on('requestfailed', request => {
console.log(request.url() + ' ' + request.failure().errorText);
});
```
#### `"dialog"` - handle alert, confirm, prompt
```js
@ -122,30 +107,7 @@ const [popup] = await Promise.all([
#### API reference
- [class: ConsoleMessage](./api.md#class-consolemessage)
- [class: Page](./api.md#class-page)
- [event: 'console'](./api.md#event-console)
- [event: 'requestfailed'](./api.md#event-requestfailed)
- [event: 'dialog'](./api.md#event-dialog)
- [event: 'popup'](./api.md#event-popup)
<br/>
## Handling exceptions
Listen uncaught exceptions in the page:
```js
// Log all uncaught errors to the terminal
page.on('pageerror', exception => {
console.log(`Uncaught exception: "${exception}"`);
});
// Navigate to a page with an exception.
await page.goto('data:text/html,<script>throw new Error("Test")</script>');
```
#### API reference
- [event: 'pageerror'](./api.md#event-pageerror)
<br/>