├── .github └── workflows │ └── playwright.yml ├── .gitignore ├── .vscode └── extensions.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── hars ├── 25cc30e4a440111abd545551113b7bf2e2cad209.bin └── fruits.har ├── package-lock.json ├── package.json ├── playwright.config.ts └── tests ├── api-mocking ├── api-mocking.spec.ts └── readme.md ├── boxed-steps-pom ├── boxed-step-pom.spec.ts ├── boxed-step-pom.ts └── readme.md ├── boxed-steps ├── boxed-step.spec.ts └── readme.md └── clock ├── clock.spec.ts └── readme.md /.github/workflows/playwright.yml: -------------------------------------------------------------------------------- 1 | name: Playwright Tests 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | jobs: 8 | test: 9 | timeout-minutes: 60 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 18 16 | - name: Install dependencies 17 | run: npm ci 18 | - name: Install Playwright Browsers 19 | run: npx playwright install --with-deps 20 | - name: Run Playwright tests 21 | run: npx playwright test 22 | - uses: actions/upload-artifact@v4 23 | if: always() 24 | with: 25 | name: playwright-report 26 | path: playwright-report/ 27 | retention-days: 30 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /test-results/ 3 | /playwright-report/ 4 | /playwright/.cache/ 5 | .DS_Store -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-playwright.playwright" 4 | ] 5 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎭 Playwright Examples 2 | 3 | This repo is used to demonstrate various testing scenarios with [Playwright](https://playwright.dev/) 🎭 with Node.js. 4 | 5 | ## Run Playwright example tests 6 | 7 | ### Install dependencies 8 | 9 | Start by cloning the repo and installing the dependencies: 10 | 11 | ```bash 12 | npm install 13 | ``` 14 | 15 | Use the [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright) to run the tests in the tests folder from VS Code or run the following command in the terminal: 16 | 17 | ```bash 18 | npx playwright test --ui 19 | ``` 20 | 21 | ## Contributing 22 | 23 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 24 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 25 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 26 | 27 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 28 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 29 | provided by the bot. You will only need to do this once across all repos using our CLA. 30 | 31 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 32 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 33 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 34 | 35 | ## Trademarks 36 | 37 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 38 | trademarks or logos is subject to and must follow 39 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 40 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 41 | Any use of third-party trademarks or logos are subject to those third-party's policies. 42 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /hars/25cc30e4a440111abd545551113b7bf2e2cad209.bin: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Strawberry", 4 | "id": 3 5 | }, 6 | { 7 | "name": "Banana", 8 | "id": 1 9 | }, 10 | { 11 | "name": "Tomato", 12 | "id": 5 13 | }, 14 | { 15 | "name": "Pear", 16 | "id": 4 17 | }, 18 | { 19 | "name": "Blackberry", 20 | "id": 64 21 | }, 22 | { 23 | "name": "Kiwi", 24 | "id": 66 25 | }, 26 | { 27 | "name": "Pineapple", 28 | "id": 10 29 | }, 30 | { 31 | "name": "Passionfruit", 32 | "id": 70 33 | }, 34 | { 35 | "name": "Orange", 36 | "id": 2 37 | }, 38 | { 39 | "name": "Raspberry", 40 | "id": 23 41 | }, 42 | { 43 | "name": "Watermelon", 44 | "id": 25 45 | }, 46 | { 47 | "name": "Lemon", 48 | "id": 26 49 | }, 50 | { 51 | "name": "Mango", 52 | "id": 27 53 | }, 54 | { 55 | "name": "Blueberry", 56 | "id": 33 57 | }, 58 | { 59 | "name": "Apple", 60 | "id": 6 61 | }, 62 | { 63 | "name": "Melon", 64 | "id": 41 65 | }, 66 | { 67 | "name": "Lime", 68 | "id": 44 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /hars/fruits.har: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "version": "1.2", 4 | "creator": { 5 | "name": "Playwright", 6 | "version": "1.35.1" 7 | }, 8 | "browser": { 9 | "name": "chromium", 10 | "version": "115.0.5790.24" 11 | }, 12 | "entries": [ 13 | { 14 | "startedDateTime": "2023-07-03T18:00:20.971Z", 15 | "time": 0.903, 16 | "request": { 17 | "method": "GET", 18 | "url": "https://demo.playwright.dev/api-mocking/api/v1/fruits", 19 | "httpVersion": "HTTP/2.0", 20 | "cookies": [], 21 | "headers": [ 22 | { "name": ":authority", "value": "demo.playwright.dev" }, 23 | { "name": ":method", "value": "GET" }, 24 | { "name": ":path", "value": "/api-mocking/api/v1/fruits" }, 25 | { "name": ":scheme", "value": "https" }, 26 | { "name": "accept", "value": "*/*" }, 27 | { "name": "accept-encoding", "value": "gzip, deflate, br" }, 28 | { "name": "accept-language", "value": "en-US" }, 29 | { "name": "cache-control", "value": "max-age=0" }, 30 | { "name": "referer", "value": "https://demo.playwright.dev/api-mocking/" }, 31 | { "name": "sec-fetch-dest", "value": "empty" }, 32 | { "name": "sec-fetch-mode", "value": "cors" }, 33 | { "name": "sec-fetch-site", "value": "same-origin" }, 34 | { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.24 Safari/537.36" } 35 | ], 36 | "queryString": [], 37 | "headersSize": -1, 38 | "bodySize": -1 39 | }, 40 | "response": { 41 | "status": 200, 42 | "statusText": "", 43 | "httpVersion": "HTTP/2.0", 44 | "cookies": [], 45 | "headers": [ 46 | { "name": "accept-ranges", "value": "bytes" }, 47 | { "name": "access-control-allow-origin", "value": "*" }, 48 | { "name": "age", "value": "0" }, 49 | { "name": "cache-control", "value": "max-age=600" }, 50 | { "name": "content-length", "value": "762" }, 51 | { "name": "content-type", "value": "application/octet-stream" }, 52 | { "name": "date", "value": "Mon, 03 Jul 2023 18:00:21 GMT" }, 53 | { "name": "etag", "value": "\"6495697c-2fa\"" }, 54 | { "name": "expires", "value": "Mon, 03 Jul 2023 18:10:21 GMT" }, 55 | { "name": "last-modified", "value": "Fri, 23 Jun 2023 09:44:28 GMT" }, 56 | { "name": "server", "value": "GitHub.com" }, 57 | { "name": "vary", "value": "Accept-Encoding" }, 58 | { "name": "via", "value": "1.1 varnish" }, 59 | { "name": "x-cache", "value": "MISS" }, 60 | { "name": "x-cache-hits", "value": "0" }, 61 | { "name": "x-fastly-request-id", "value": "d56d393516eeca913cb814d35726d5c0a7a84e52" }, 62 | { "name": "x-github-request-id", "value": "C544:114C7:2BA884C:2D0CD20:64A30CB3" }, 63 | { "name": "x-proxy-cache", "value": "MISS" }, 64 | { "name": "x-served-by", "value": "cache-mad2200145-MAD" }, 65 | { "name": "x-timer", "value": "S1688407221.077434,VS0,VE135" } 66 | ], 67 | "content": { 68 | "size": -1, 69 | "mimeType": "application/octet-stream", 70 | "_file": "25cc30e4a440111abd545551113b7bf2e2cad209.bin" 71 | }, 72 | "headersSize": -1, 73 | "bodySize": -1, 74 | "redirectURL": "" 75 | }, 76 | "cache": {}, 77 | "timings": { "send": -1, "wait": -1, "receive": 0.903 } 78 | } 79 | ] 80 | } 81 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playwright-examples", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "playwright-examples", 9 | "version": "0.0.1", 10 | "license": "Apache-2.0", 11 | "devDependencies": { 12 | "@playwright/test": "^1.45.0" 13 | } 14 | }, 15 | "node_modules/@playwright/test": { 16 | "version": "1.45.0", 17 | "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.45.0.tgz", 18 | "integrity": "sha512-TVYsfMlGAaxeUllNkywbwek67Ncf8FRGn8ZlRdO291OL3NjG9oMbfVhyP82HQF0CZLMrYsvesqoUekxdWuF9Qw==", 19 | "dev": true, 20 | "dependencies": { 21 | "playwright": "1.45.0" 22 | }, 23 | "bin": { 24 | "playwright": "cli.js" 25 | }, 26 | "engines": { 27 | "node": ">=18" 28 | } 29 | }, 30 | "node_modules/fsevents": { 31 | "version": "2.3.2", 32 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 33 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 34 | "dev": true, 35 | "hasInstallScript": true, 36 | "optional": true, 37 | "os": [ 38 | "darwin" 39 | ], 40 | "engines": { 41 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 42 | } 43 | }, 44 | "node_modules/playwright": { 45 | "version": "1.45.0", 46 | "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.0.tgz", 47 | "integrity": "sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==", 48 | "dev": true, 49 | "dependencies": { 50 | "playwright-core": "1.45.0" 51 | }, 52 | "bin": { 53 | "playwright": "cli.js" 54 | }, 55 | "engines": { 56 | "node": ">=18" 57 | }, 58 | "optionalDependencies": { 59 | "fsevents": "2.3.2" 60 | } 61 | }, 62 | "node_modules/playwright-core": { 63 | "version": "1.45.0", 64 | "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.0.tgz", 65 | "integrity": "sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==", 66 | "dev": true, 67 | "bin": { 68 | "playwright-core": "cli.js" 69 | }, 70 | "engines": { 71 | "node": ">=18" 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playwright-examples", 3 | "version": "0.0.1", 4 | "description": "This repo is used to demonstrate various testing scenarios with [Playwright](https://playwright.dev/) 🎭 with node.js", 5 | "license": "Apache-2.0", 6 | "devDependencies": { 7 | "@playwright/test": "^1.45.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test'; 2 | 3 | /** 4 | * Read environment variables from file. 5 | * https://github.com/motdotla/dotenv 6 | */ 7 | // require('dotenv').config(); 8 | 9 | /** 10 | * See https://playwright.dev/docs/test-configuration. 11 | */ 12 | export default defineConfig({ 13 | testDir: './tests', 14 | /* Run tests in files in parallel */ 15 | fullyParallel: true, 16 | /* Fail the build on CI if you accidentally left test.only in the source code. */ 17 | forbidOnly: !!process.env.CI, 18 | /* Retry on CI only */ 19 | retries: process.env.CI ? 2 : 0, 20 | /* Opt out of parallel tests on CI. */ 21 | workers: process.env.CI ? 1 : undefined, 22 | /* Reporter to use. See https://playwright.dev/docs/test-reporters */ 23 | reporter: 'html', 24 | /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ 25 | use: { 26 | /* Base URL to use in actions like `await page.goto('/')`. */ 27 | // baseURL: 'http://127.0.0.1:3000', 28 | 29 | /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ 30 | trace: 'on-first-retry', 31 | }, 32 | 33 | /* Configure projects for major browsers */ 34 | projects: [ 35 | { 36 | name: 'chromium', 37 | use: { ...devices['Desktop Chrome'] }, 38 | }, 39 | 40 | { 41 | name: 'firefox', 42 | use: { ...devices['Desktop Firefox'] }, 43 | }, 44 | 45 | { 46 | name: 'webkit', 47 | use: { ...devices['Desktop Safari'] }, 48 | }, 49 | 50 | /* Test against mobile viewports. */ 51 | // { 52 | // name: 'Mobile Chrome', 53 | // use: { ...devices['Pixel 5'] }, 54 | // }, 55 | // { 56 | // name: 'Mobile Safari', 57 | // use: { ...devices['iPhone 12'] }, 58 | // }, 59 | 60 | /* Test against branded browsers. */ 61 | // { 62 | // name: 'Microsoft Edge', 63 | // use: { ...devices['Desktop Edge'], channel: 'msedge' }, 64 | // }, 65 | // { 66 | // name: 'Google Chrome', 67 | // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, 68 | // }, 69 | ], 70 | 71 | /* Run your local dev server before starting the tests */ 72 | // webServer: { 73 | // command: 'npm run start', 74 | // url: 'http://127.0.0.1:3000', 75 | // reuseExistingServer: !process.env.CI, 76 | // }, 77 | }); 78 | -------------------------------------------------------------------------------- /tests/api-mocking/api-mocking.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, type Page } from '@playwright/test'; 2 | 3 | test.describe('Mocking an API call', () => { 4 | 5 | test('mocks a fruit and does not call api', async ({ page }) => { 6 | // Mock the api call before navigating 7 | await page.route('*/**/api/v1/fruits', async (route) => { 8 | const json = [{ name: 'Strawberry', id: 21 }]; 9 | await route.fulfill({ json }); 10 | }); 11 | // Go to the page 12 | await page.goto('https://demo.playwright.dev/api-mocking'); 13 | 14 | // Assert that the Strawberry fruit is visible 15 | await expect(page.getByText('Strawberry')).toBeVisible(); 16 | }); 17 | 18 | }); 19 | 20 | test.describe('Intercepting the request and modifying it', () => { 21 | 22 | test('gets the json from api and adds a new fruit', async ({ page }) => { 23 | // Get the response and add to it 24 | await page.route('*/**/api/v1/fruits', async (route) => { 25 | const response = await route.fetch(); 26 | const json = await response.json(); 27 | json.push({ name: 'Playwright', id: 100 }); 28 | // Fulfill using the original response, while patching the response body 29 | // with the given JSON object. 30 | await route.fulfill({ response, json }); 31 | }); 32 | 33 | // Go to the page 34 | await page.goto('https://demo.playwright.dev/api-mocking'); 35 | 36 | // Assert that the new fruit is visible 37 | await expect(page.getByText('Playwright', { exact: true })).toBeVisible(); 38 | }); 39 | 40 | }); 41 | 42 | test.describe('Mocking with HAR files', () => { 43 | 44 | test('records or updates the HAR file', async ({ page }) => { 45 | // Get the response from the HAR file 46 | await page.routeFromHAR('./hars/fruits.har', { 47 | url: '*/**/api/v1/fruits', 48 | update: true, 49 | }); 50 | 51 | // Go to the page 52 | await page.goto('https://demo.playwright.dev/api-mocking'); 53 | 54 | // Assert that the Playwright fruit is visible 55 | await expect(page.getByText('Strawberry')).toBeVisible(); 56 | }); 57 | 58 | test('gets the json from HAR and checks the new fruit has been added', async ({ page }) => { 59 | // Replay API requests from HAR. 60 | // Either use a matching response from the HAR, 61 | // or abort the request if nothing matches. 62 | await page.routeFromHAR('./hars/fruits.har', { 63 | url: '*/**/api/v1/fruits', 64 | update: false, 65 | }); 66 | 67 | // Go to the page 68 | await page.goto('https://demo.playwright.dev/api-mocking'); 69 | 70 | // Assert that the Playwright fruit is visible 71 | await expect(page.getByText('Strawberry')).toBeVisible(); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/api-mocking/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Playwright - API Mocking 3 | description: "This sample demonstrates how to mock API calls in Playwright tests" 4 | page_type: sample 5 | languages: 6 | - typescript 7 | - javascript 8 | products: 9 | - playwright 10 | urlFragment: api-mocking 11 | --- 12 | 13 | # API Mocking 14 | 15 | This sample demonstrates how to 16 | - mock API calls in Playwright tests 17 | - intercept the request and modifying it 18 | - mock using HAR files 19 | 20 | For more information about the sample see: 21 | 22 | - [Playwright API Mocking demo](https://demo.playwright.dev/api-mocking) 23 | - [Blog post on API Mocking](https://dev.to/playwright/api-mocking-for-your-playwright-tests-47ah) 24 | - [Docs on API Mocking](https://playwright.dev/docs/mock) 25 | - [Release video on our Network Annotations feature which gives you a clearer view of what your API call and fulfillments are doing](https://youtu.be/pJiirfyJwcA) 26 | -------------------------------------------------------------------------------- /tests/boxed-steps-pom/boxed-step-pom.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from '@playwright/test'; 2 | import { MainPage } from './boxed-step-pom' 3 | 4 | 5 | // various test scenarios for adding items to the cart 6 | // comment out the line before the `addAndViewCart` function in one of the tests 7 | // Then run the test to see how box steps hide the implementation details of the step 8 | 9 | test.describe('add to cart scenarios', () => { 10 | test.beforeEach(async ({ page }) => { 11 | const pom = new MainPage(page); 12 | await pom.goto(); 13 | }); 14 | 15 | test('buy now from carousel using pom', async ({ page }) => { 16 | const pom = new MainPage(page); 17 | await page.getByRole('button', { name: 'Buy Now' }).click(); 18 | await pom.addToCart(); 19 | await pom.openCart(); 20 | await pom.expectToBeInCart('Xbox Wireless Controller Lunar Shift Special Edition') 21 | }); 22 | 23 | test('add to cart from search using pom', async ({ page }) => { 24 | const pom = new MainPage(page); 25 | const product = 'Xbox Wireless Controller Mineral Camo Special Edition' 26 | await pom.searchForProduct('xbox'); 27 | await pom.clickOnProductByImage(product); 28 | await pom.addToCart(); 29 | await pom.openCart(); 30 | await pom.expectToBeInCart(product); 31 | }); 32 | 33 | test('add to cart from all products page using pom', async ({ page }) => { 34 | const pom = new MainPage(page); 35 | const product = 'Xbox Wireless Controller Mineral Camo Special Edition' 36 | await pom.clickOnProductPage('All Products'); 37 | await pom.clickOnProductByImage(product); 38 | await pom.addToCart(); 39 | await pom.openCart(); 40 | await pom.expectToBeInCart(product); 41 | }); 42 | 43 | test('add to cart from all laptops page using pom', async ({ page }) => { 44 | const pom = new MainPage(page); 45 | const product = 'Microsoft Surface Pro X 1876 13 Inches Laptop' 46 | await pom.clickOnProductPage('Laptops'); 47 | await pom.clickOnProductByImage(product); 48 | await pom.addToCart(); 49 | await pom.openCart(); 50 | await pom.expectToBeInCart(product); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /tests/boxed-steps-pom/boxed-step-pom.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, Page } from '@playwright/test'; 2 | 3 | export class MainPage { 4 | constructor(private readonly page: Page) { } 5 | 6 | async goto() { 7 | await this.page.goto('https://cloudtesting.contosotraders.com/'); 8 | } 9 | 10 | // using the boxedStep decorator defined below 11 | @boxedStep 12 | async searchForProduct(query: string) { 13 | await this.page.getByPlaceholder('Search by product name or search by image').click(); 14 | await this.page.getByPlaceholder('Search by product name or search by image').fill(query); 15 | await this.page.getByPlaceholder('Search by product name or search by image').press('Enter'); 16 | } 17 | 18 | // using the boxedStep decorator defined below 19 | @boxedStep 20 | async clickOnProductPage(link: string) { 21 | await this.page.getByRole('link', { name: link }).first().click(); 22 | } 23 | 24 | // using the boxedStep decorator defined below 25 | @boxedStep 26 | async clickOnProductByImage(title: string) { 27 | await this.page.getByRole('img', { name: title }).click(); 28 | } 29 | 30 | // using the boxedStep decorator defined below 31 | @boxedStep 32 | async addToCart() { 33 | await this.page.getByRole('button', { name: 'Add To Bag' }).click(); 34 | } 35 | 36 | // using the boxedStep decorator defined below 37 | @boxedStep 38 | async openCart() { 39 | await this.page.getByLabel('cart').click(); 40 | } 41 | 42 | // using the boxedStep decorator defined below 43 | @boxedStep 44 | async expectToBeInCart(title: string) { 45 | await expect(this.page.getByText(title)).toBeVisible(); 46 | } 47 | } 48 | 49 | 50 | // Leveraging TypeScript decorators to wrap functions 51 | // https://www.typescriptlang.org/docs/handbook/decorators.html 52 | // A boxed test.step() gets defined with the name of the method 53 | function boxedStep(target: Function, context: ClassMethodDecoratorContext) { 54 | return function replacementMethod(...args: any) { 55 | const name = this.constructor.name + '.' + (context.name as string); 56 | return test.step(name, async () => { 57 | return await target.call(this, ...args); 58 | }, { box: true }); // Note the "box" option here. 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /tests/boxed-steps-pom/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Playwright - Boxed Steps Page Object Model 3 | description: "This sample demonstrates how to box your test steps to hide implementation details when using the Page Object Model" 4 | page_type: sample 5 | languages: 6 | - typescript 7 | - javascript 8 | products: 9 | - playwright 10 | urlFragment: boxed-steps-pom 11 | --- 12 | 13 | # Box Steps with Page Object Model 14 | 15 | This sample demonstrates how to box your test steps to hide implementation details when using the Page Object Model. 16 | 17 | For more information about the sample see: 18 | 19 | - [Box steps docs](https://playwright.dev/docs/api/class-test#test-step) 20 | - [Release video on box steps](https://youtu.be/KqVuRAlOkm0) 21 | -------------------------------------------------------------------------------- /tests/boxed-steps/boxed-step.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, Page } from '@playwright/test'; 2 | 3 | // various test scenarios for adding items to the cart 4 | // comment out the line before the `addAndViewCart` function in one of the tests 5 | // Then run the test to see how box steps hide the implementation details of the step 6 | 7 | // reusable function to add an item to the cart and view the cart 8 | // we wrap our actions in a test step and set box to true 9 | async function addAndViewCart(page: Page){ 10 | await test.step('add and view cart', async () => { 11 | await page.getByRole('button', { name: 'Add To Bag' }).click(); 12 | await page.getByLabel('cart').click(); 13 | }, { box: true }); // box: true will hide the implementation details of the step 14 | } 15 | 16 | test.describe('add to cart scenarios', () => { 17 | test.beforeEach(async ({ page }) => { 18 | await page.goto('https://cloudtesting.contosotraders.com/') 19 | }); 20 | 21 | test('add to cart from carousel', async ({ page }) => { 22 | await page.getByRole('button', { name: 'Buy Now' }).click(); 23 | await addAndViewCart(page); 24 | await expect(page.getByText('Xbox Wireless Controller Lunar Shift Special Edition')).toBeVisible(); 25 | }); 26 | 27 | test('add to cart from search', async ({ page }) => { 28 | const product = 'Xbox Wireless Controller Mineral Camo Special Edition' 29 | const placeholder = page.getByPlaceholder('Search by product name or search by image') 30 | await placeholder.click(); 31 | await placeholder.fill('xbox'); 32 | await placeholder.press('Enter'); 33 | await page.getByRole('img', { name: product }).click(); 34 | await addAndViewCart(page); 35 | await expect(page.getByText(product)).toBeVisible(); 36 | }); 37 | 38 | test('add to cart from all products page', async ({ page }) => { 39 | const product = 'Xbox Wireless Controller Lunar Shift Special Edition' 40 | await page.getByRole('link', { name: 'All Products' }).first().click(); 41 | await page.getByRole('img', { name: product }).click(); 42 | await addAndViewCart(page); 43 | await expect(page.getByText(product)).toBeVisible(); 44 | }); 45 | 46 | test('add to cart from laptops page', async ({ page }) => { 47 | const product = 'Microsoft Surface Pro X 1876 13 Inches Laptop' 48 | await page.getByRole('link', { name: 'Laptops' }).first().click(); 49 | await page.getByRole('img', { name: product}).click(); 50 | await addAndViewCart(page); 51 | await expect(page.getByText(product)).toBeVisible(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /tests/boxed-steps/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Playwright - Boxed Steps 3 | description: "This sample demonstrates how to box your test steps to hide implementation details" 4 | page_type: sample 5 | languages: 6 | - typescript 7 | - javascript 8 | products: 9 | - playwright 10 | urlFragment: boxed-steps 11 | --- 12 | 13 | # Box Steps 14 | 15 | This sample demonstrates how to box your test steps to hide implementation details. 16 | 17 | For more information about the sample see: 18 | 19 | - [Box steps docs](https://playwright.dev/docs/api/class-test#test-step) 20 | - [Blog post on box steps](https://dev.to/playwright/box-test-steps-in-playwright-15d9) 21 | - [Release video on box steps](https://youtu.be/KqVuRAlOkm0) 22 | -------------------------------------------------------------------------------- /tests/clock/clock.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "@playwright/test"; 2 | 3 | test("set fixed time", async ({ page }) => { 4 | await page.clock.setFixedTime(new Date("2024-02-02T10:00:00")); 5 | await page.goto("https://demo.playwright.dev/clock"); 6 | await expect(page.getByTestId("clock")).toHaveText("10:00:00"); 7 | }); 8 | 9 | test("manually advance time", async ({ page }) => { 10 | await page.clock.install({ time: new Date("2024-02-02T08:00:00") }); 11 | await page.goto("https://demo.playwright.dev/clock"); 12 | 13 | await page.clock.pauseAt(new Date("2024-02-02T10:00:00")); 14 | await expect(page.getByTestId("clock")).toHaveText("10:00:00"); 15 | 16 | await page.clock.fastForward("30:00"); 17 | await expect(page.getByTestId("clock")).toHaveText("10:30:00"); 18 | }); 19 | 20 | test("test inactivity monitoring", async ({ page }) => { 21 | await page.clock.install(); 22 | await page.goto("https://demo.playwright.dev/timer"); 23 | 24 | await expect(page.getByText("Flash offer")).toBeVisible(); 25 | 26 | await page.clock.fastForward("05:00"); 27 | 28 | await expect(page.getByText("Offer Expired")).toBeVisible(); 29 | }); -------------------------------------------------------------------------------- /tests/clock/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Playwright - Clock API 3 | description: "This sample demonstrates how to test a clock using Playwright's clock API with fixed time, manually advancing time and testing inactivity monitoring" 4 | page_type: sample 5 | languages: 6 | - typescript 7 | - javascript 8 | products: 9 | - playwright 10 | urlFragment: clock 11 | --- 12 | 13 | # Clock API 14 | 15 | This sample demonstrates how to test a clock using Playwright's clock API with fixed time, manually advancing time and testing inactivity monitoring. 16 | 17 | For more information about the sample see: 18 | 19 | - [Clock guide](https://playwright.dev/docs/clock) 20 | - [Release video on the Clock API](https://youtu.be/54_aC-rVKHg) 21 | --------------------------------------------------------------------------------