diff --git a/docs/src/writing-tests-js.md b/docs/src/writing-tests-js.md index e0a30f152a488..5fa7d073b360c 100644 --- a/docs/src/writing-tests-js.md +++ b/docs/src/writing-tests-js.md @@ -3,90 +3,149 @@ id: writing-tests title: "Writing Tests" --- -Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met. Playwright comes with [auto-wait](./actionability.md) built in meaning it waits for elements to be actionable prior to performing actions. Playwright provides a [test](./api/class-test.md) function to declare tests and the [expect](https://jestjs.io/docs/expect) function to write assertions. +Playwright tests are simple, they + +- **perform actions**, and +- **assert the state** against expectations. + +There is no need to wait for anything prior to performing an action: Playwright +automatically waits for the wide range of [actionability](./actionability.md) +checks to pass prior to performing each action. + +There is also no need to deal with the race conditions when performing the checks - +Playwright assertions are designed in a way that they describe the expectations +that need to be eventually met. + +That's it! These design choices allow Playwright users to forget about flaky +timeouts and racy checks in their tests altogether. **You will learn** -- [How the example test works](/writing-tests.md#the-example-test) +- [How to write the first test](/writing-tests.md#first-test) +- [How to perform actions](/writing-tests.md#actions) - [How to use assertions](/writing-tests.md#assertions) -- [How to use locators](/writing-tests.md#locators) - [How tests run in isolation](/writing-tests.md#test-isolation) - [How to use test hooks](/writing-tests.md#using-test-hooks) -## The Example Test +## First test -Take a look at the example test included when installing Playwright to see how to write a test using [locators](/locators.md) and [web first assertions](/test-assertions.md). +Take a look at the following example to see how to write a test. -```js tab=js-js -// @ts-check -const { test, expect } = require('@playwright/test'); +```js +import { test, expect } = require('@playwright/test'); -test('homepage has Playwright in title and get started link linking to the intro page', async ({ page }) => { +test('has title', async ({ page }) => { await page.goto('https://playwright.dev/'); // Expect a title "to contain" a substring. await expect(page).toHaveTitle(/Playwright/); +}); - // create a locator - const getStarted = page.getByRole('link', { name: 'Get started' }); - - // Expect an attribute "to be strictly equal" to the value. - await expect(getStarted).toHaveAttribute('href', '/docs/intro'); +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); // Click the get started link. - await getStarted.click(); + await page.getByRole('link', { name: 'Get started' }).click(); // Expects the URL to contain intro. await expect(page).toHaveURL(/.*intro/); }); ``` -```js tab=js-ts -import { test, expect } from '@playwright/test'; +:::note +Add `// @ts-check` at the start of each test file when using JavaScript in +VS Code to get automatic type checking. +::: -test('homepage has Playwright in title and get started link linking to the intro page', async ({ page }) => { - await page.goto('https://playwright.dev/'); +## Actions - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/Playwright/); +### Navigation - // create a locator - const getStarted = page.getByRole('link', { name: 'Get started' }); +Most of the tests will start with navigating page to the URL. After that, test +will be able to interact with the page elements. - // Expect an attribute "to be strictly equal" to the value. - await expect(getStarted).toHaveAttribute('href', '/docs/intro'); +```js +await page.goto('https://playwright.dev/'); +``` - // Click the get started link. - await getStarted.click(); +Playwright will wait for page to reach the load state prior to moving forward. +Learn more about the [`method: Page.goto`] options. - // Expects the URL to contain intro. - await expect(page).toHaveURL(/.*intro/); -}); +### Interactions + +Performing actions starts with locating the elements. Playwright uses +[Locators API](./locators.md) for that. Locators represent a way to find +element(s) on the page at any moment, learn more about the +[different types](./locators.md) of locators available. Playwright will wait for the element to be [actionable](./actionability.md) +prior to performing the action, so there is no need to need wait for it to become +available. + + +```js +// Create a locator. +const getStarted = page.getByRole('link', { name: 'Get started' }); +// Click it. +await getStarted.click(); ``` -:::note -Add `// @ts-check` at the start of each test file when using JavaScript in VS Code to get automatic type checking. -::: +In most cases, it'll be written in one line: -### Assertions +```js +await page.getByRole('link', { name: 'Get started' }).click(); +``` + + +### Basic actions + +This is the list of the most popular Playwright actions. Note that there are +many more, so make sure to check the [Locator API](./api/class-locator.md) section to +learn more about them. + +| Action | Description | +| :- | :- | +| [`method: Locator.check`] | Check the input checkbox | +| [`method: Locator.click`] | Click the element | +| [`method: Locator.uncheck`] | Uncheck the input checkbox | +| [`method: Locator.hover`] | Hover mouse over the element | +| [`method: Locator.fill`] | Fill the form field (fast) | +| [`method: Locator.focus`] | Focus the element | +| [`method: Locator.press`] | Press single key | +| [`method: Locator.setInputFiles`] | Pick files to upload | +| [`method: Locator.selectOption`] | Select option in the drop down | +| [`method: Locator.type`] | Type text character by character (slow) | + +## Assertions -Playwright Test uses the [expect](https://jestjs.io/docs/expect) library for [test assertions](./test-assertions.md) which provides matchers like `toEqual`, `toContain`, `toMatch`, `toBe` and many more. Playwright also extends this library with convenience async matchers that will wait until the expected condition is met. +Playwright Test uses the [expect](https://jestjs.io/docs/expect) library for +[test assertions](./test-assertions.md) which provides matchers like +`toEqual`, `toContain`, `toMatch`, `toBe` and many more. It also extends +this library with the convenience async matchers that will wait until the expected condition is met. +Using these matchers allows making the tests non-flaky and resilient. For example, this code will wait until +the page gets the title containing "Playwright": ```js await expect(page).toHaveTitle(/Playwright/); ``` -### Locators -[Locators](./locators.md) are the central piece of Playwright's auto-waiting and retry-ability. Locators represent a way to find element(s) on the page at any moment and are used to perform actions on elements such as `.click` `.fill` etc. +Here is the list of the most popular async assertions. Note that there are [many more](./test-assertions.md) to get familiar with: -```js -const getStarted = page.getByRole('link', { name: 'Get started' }); +| Assertion | Description | +| :- | :- | +| [`method: LocatorAssertions.toBeChecked`] | Checkbox is checked | +| [`method: LocatorAssertions.toBeChecked`] | Checkbox is checked | +| [`method: LocatorAssertions.toBeEnabled`] | Control is enabled | +| [`method: LocatorAssertions.toBeVisible`] | Element is visible | +| [`method: LocatorAssertions.toContainText`] | Element contains text | +| [`method: LocatorAssertions.toHaveAttribute`] | Element has attribute | +| [`method: LocatorAssertions.toHaveCount`] | List of elements has given length | +| [`method: LocatorAssertions.toHaveText`] | Element matches text | +| [`method: LocatorAssertions.toHaveValue`] | Input element has value | +| [`method: PageAssertions.toHaveTitle`] | Page has title | +| [`method: PageAssertions.toHaveURL`] | Page has URL | +| [`method: PageAssertions.toHaveScreenshot#1`] | Page has screenshot | -await expect(getStarted).toHaveAttribute('href', '/docs/installation'); -await getStarted.click(); -``` ### Test Isolation @@ -101,24 +160,7 @@ test('basic test', async ({ page }) => { You can use various [test hooks](./api/class-test.md) such as `test.describe` to declare a group of tests and `test.beforeEach` and `test.afterEach` which are executed before/after each test. Other hooks include the `test.beforeAll` and `test.afterAll` which are executed once per worker before/after all tests. -```js tab=js-js -// @ts-check -const { test, expect } = require("@playwright/test"); - -test.describe("navigation", () => { - test.beforeEach(async ({ page }) => { - // Go to the starting url before each test. - await page.goto("https://playwright.dev/"); - }); - - test("main navigation", async ({ page }) => { - // Assertions use the expect API. - await expect(page).toHaveURL("https://playwright.dev/"); - }); -}); -``` - -```js tab=js-ts +```js import { test, expect } from "@playwright/test"; test.describe("navigation", () => {