docs(selectors&ci): brush up respective sections

This commit is contained in:
Pavel Feldman 2020-04-20 10:38:25 -07:00
parent 621df5d68b
commit 4d8c057d9c
4 changed files with 79 additions and 78 deletions

View file

@ -34,9 +34,13 @@
1. Scraping and verification
- Screenshots
- Evaluation
1. Selector engines
- Built-in engines
- Custom engines
1. [Continuous integration](./ci.md)
- [Docker](./ci.md#docker)
- [GitHub Actions](./ci.md#github-actions)
- [Azure Pipelines](./ci.md#azure-pipelines)
- [Travis CI](./ci.md#travis-ci)
- [CircleCI](./ci.md#circleci)
- [AppVeyor](./ci.md#appveyor)
1. Test runners
- Jest
- Mocha
@ -44,7 +48,6 @@
- Jasmine
- Jasmine
- Storybooks
1. Continuous integration
- Git Hub Action
- Docker images
- Troubleshooting
1. [Extensibility](./extensibility.md)
- [Custom selector engines](./extensibility.md#custom-selector-engines)

View file

@ -1,9 +1,10 @@
# Getting started on CI
# Continuous integration.md
Playwright tests can be executed to run on your CI environments. To simplify this, we have created sample configurations for common CI providers that can be used to bootstrap your setup.
#### Contents
- [Docker](#docker)
- [GitHub](#github-actions)
- [GitHub Actions](#github-actions)
- [Azure Pipelines](#azure-pipelines)
- [Travis CI](#travis-ci)
- [CircleCI](#circleci)
@ -11,6 +12,8 @@ Playwright tests can be executed to run on your CI environments. To simplify thi
Broadly, configuration on CI involves **ensuring system dependencies** are in place, **installing Playwright and browsers** (typically with `npm install`), and **running tests** (typically with `npm test`). Windows and macOS build agents do not require any additional system dependencies. Linux build agents can require additional dependencies, depending on the Linux distribution.
<br/>
## Docker
We have a [pre-built Docker image](docker/README.md) which can either be used directly, or as a reference to update your existing Docker definitions.

View file

@ -109,31 +109,57 @@ await frame.fill('#username-input', 'John');
## Selectors
Playwright APIs that interact with elements accept selectors as the first argument, used to search for the element. Playwright can search for elements with CSS selectors, XPath, HTML attributes like `id`, `data-test-id` and text content.
Playwright can search for elements using CSS selectors, XPath selectors, HTML attributes like `id`, `data-test-id` and even text content.
Note that all selectors except for XPath pierce shadow DOM automatically.
You can explicitly specify the selector engine you are using or let Playwright detect it.
All selector engines except for XPath pierce shadow DOM by default. If you want to enforce regular DOM selection, you can use the `*:light` versions of the selectors. You don't typically need to though.
Learn more about selectors and selector engines [here](./selectors.md).
Some examples below:
```js
// Auto-detected CSS notation
await page.click('div');
// Explicit CSS notation
await page.click('css=div');
// Auto-detected XPath notation
await page.click('xpath=//html/body/div');
// Explicit XPath notation
await page.click('//html/body/div');
// Auto-detected text notation
await page.click('"Login"');
// Explicit text notation
await page.click('text="Login"');
// Using data-test-id= selector engine
await page.click('data-test-id=foo');
```
Selectors using different engines can be combined using the `>>` separator. Learn more about selectors and selector engines [here](./selectors.md).
```js
// CSS and XPath selector engines are automatically detected
await page.click('div');
await page.click('//html/body/div');
```
```js
// Find node by text substring
await page.click('text=Hello w');
```
```js
// Explicit CSS and XPath notation
await page.click('css=div');
await page.click('xpath=//html/body/div');
```
```js
// Only search light DOM, outside WebComponent shadow DOM:
await page.click('css:light=div');
```
Selectors using the same or different engines can be combined using the `>>` separator. For example,
```js
await page.click('css=article >> css=.bar > .baz >> css=span[attr=value]');
```
is equivalent to
```js
document
.querySelector('article')
.querySelector('.bar > .baz')
.querySelector('span[attr=value]')
```
<br/>
@ -148,17 +174,32 @@ Actions like `click` and `fill` auto-wait for the element to be visible and acti
```js
// Will wait for #search element to be in DOM
// Playwright waits for #search element to be in DOM
await page.fill('#search', 'query');
// Will wait for it to stop animating and accept clicks
```
```js
// Playwright waits for element to stop animating
// and accept clicks.
await page.click('#search');
```
You can explicitly wait for element to become available in DOM and to become visible:
```js
await page.waitForSelector('#search', { waitFor: 'visible' });
```
... or to become hidden or detached
```js
await page.waitForSelector('#search', { waitFor: 'detached' });
```
#### API reference
- [page.click(selector[, options])](./api.md#pageclickselector-options)
- [page.fill(selector, value[, options])](./api.md#pagefillselector-value-options)
- [page.waitForSelector(selector[, options])](./api.md#pagewaitforselectorselector-options)
<br/>

View file

@ -120,49 +120,3 @@ Malformed selector starting with `"` is assumed to be a text selector. For examp
### id, data-testid, data-test-id, data-test and their :light counterparts
Attribute engines are selecting based on the corresponding atrribute value. For example: `data-test-id=foo` is equivalent to `css=[data-test-id="foo"]`, and `id:light=foo` is equivalent to `css:light=[id="foo"]`.
## Custom selector engines
Playwright supports custom selector engines, registered with [selectors.register(name, script[, options])](api.md#selectorsregistername-script-options).
Selector engine should have the following properties:
- `create` function to create a relative selector from `root` (root is either a `Document`, `ShadowRoot` or `Element`) to a `target` element.
- `query` function to query first element matching `selector` relative to the `root`.
- `queryAll` function to query all elements matching `selector` relative to the `root`.
By default the engine is run directly in the frame's JavaScript context and, for example, can call an application-defined function. To isolate the engine from any JavaScript in the frame, but leave access to the DOM, resgister the engine with `{contentScript: true}` option. Content script engine is safer because it is protected from any tampering with the global objects, for example altering `Node.prototype` methods. All built-in selector engines run as content scripts. Note that running as a content script is not guaranteed when the engine is used together with other custom engines.
An example of registering selector engine that queries elements based on a tag name:
```js
// Must be a function that evaluates to a selector engine instance.
const createTagNameEngine = () => ({
// Creates a selector that matches given target when queried at the root.
// Can return undefined if unable to create one.
create(root, target) {
return root.querySelector(target.tagName) === target ? target.tagName : undefined;
},
// Returns the first element matching given selector in the root's subtree.
query(root, selector) {
return root.querySelector(selector);
},
// Returns all elements matching given selector in the root's subtree.
queryAll(root, selector) {
return Array.from(root.querySelectorAll(selector));
}
});
// Register the engine. Selectors will be prefixed with "tag=".
await selectors.register('tag', createTagNameEngine);
// Now we can use 'tag=' selectors.
const button = await page.$('tag=button');
// We can combine it with other selector engines using `>>` combinator.
await page.click('tag=div >> span >> "Click me"');
// We can use it in any methods supporting selectors.
const buttonCount = await page.$$eval('tag=button', buttons => buttons.length);
```