├── tests
├── uploadFiles
│ ├── testfile1.pdf
│ └── testfile2.pdf
├── screenshots
│ ├── 1688987907924HomePage.png
│ ├── 1688988031210FullPage.png
│ └── 1688988283663Macbook.png
├── MouseRightClick.spec.js
├── MouseHover.spec.js
├── Tracing.spec.js
├── recordvideo.spec.js
├── screenshot2.spec.js
├── ParallelTesting.spec.js
├── mytest.spec.js
├── MouseDoubleClick.spec.js
├── HomePageTest.spec.js
├── Tags.spec.js
├── BrowserContext.spec.js
├── HandleInnerFrames.spec.js
├── Reporters.spec.js
├── example.spec.js
├── Softassertions.spec.js
├── RadioButtons.spec.js
├── screenshot.spec.js
├── Inputbox.spec.js
├── AutoSuggestDropDown.spec.js
├── DragAndDrop.spec.js
├── KeyboardActions.spec.js
├── Pomtest.spec.js
├── HandleFrames.spec.js
├── LocatingMultipleElements.spec.js
├── APITests.spec.js
├── Locators.spec.js
├── Grouping.spec.js
├── MultiSelectDropdown.spec.js
├── Hooks2.spec.js
├── Hooks3.spec.js
├── HiddenDropDown.spec.js
├── Annotations.spec.js
├── BootstrapDropdown.spec.js
├── DatePicker.spec.js
├── Hooks1.spec.js
├── UploadFiles.spec.js
├── Locators_builtin.spec.js
├── Checkboxes.spec.js
├── HandlingWindows.spec.js
├── Alerts.spec.js
├── DropDowns.spec.js
├── MouseEvents.spec.js
├── Assertions.spec.js
└── Table.spec.js
├── .gitignore
├── package.json
├── jenkinsfile
├── results.xml
├── pages
├── CartPage.js
├── LoginPage.js
└── HomePage.js
├── playwright.config.js
├── results.json
└── tests-examples
└── demo-todo-app.spec.js
/tests/uploadFiles/testfile1.pdf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/uploadFiles/testfile2.pdf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | /test-results/
3 | /playwright-report/
4 | /playwright/.cache/
5 |
--------------------------------------------------------------------------------
/tests/screenshots/1688987907924HomePage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pavanoltraining/playwrightautomation/HEAD/tests/screenshots/1688987907924HomePage.png
--------------------------------------------------------------------------------
/tests/screenshots/1688988031210FullPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pavanoltraining/playwrightautomation/HEAD/tests/screenshots/1688988031210FullPage.png
--------------------------------------------------------------------------------
/tests/screenshots/1688988283663Macbook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pavanoltraining/playwrightautomation/HEAD/tests/screenshots/1688988283663Macbook.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playwrightautomation",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {},
7 | "keywords": [],
8 | "author": "",
9 | "license": "ISC",
10 | "devDependencies": {
11 | "@playwright/test": "^1.34.2"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 |
3 | stages {
4 | stage('Install dependencies') {
5 | steps {
6 | sh 'npm install'
7 | }
8 | }
9 |
10 | stage('Run tests') {
11 | steps {
12 | sh 'npx playwright test Pomtest.spec.js'
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/MouseRightClick.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}= require('@playwright/test')
2 |
3 | test ('Mouse Right Click', async ({page})=>{
4 |
5 | await page.goto('http://swisnl.github.io/jQuery-contextMenu/demo.html')
6 |
7 | const button=await page.locator('//span[normalize-space()="right click me"]')
8 |
9 | //right click action
10 | await button.click({button: 'right'});
11 |
12 | await page.waitForTimeout(5000)
13 |
14 |
15 | })
--------------------------------------------------------------------------------
/tests/MouseHover.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}= require('@playwright/test')
2 |
3 | test ('Mouse hover', async ({page})=>{
4 |
5 | await page.goto('https://demo.opencart.com/')
6 |
7 | const desktops=await page.locator('//a[normalize-space()="Desktops"]')
8 | const macbook=await page.locator('//a[normalize-space()="Mac (1)"]')
9 |
10 | //mouse hover
11 | await desktops.hover()
12 | await macbook.hover()
13 |
14 | await page.waitForTimeout(5000)
15 |
16 | })
--------------------------------------------------------------------------------
/tests/Tracing.spec.js:
--------------------------------------------------------------------------------
1 |
2 | import { test, expect } from '@playwright/test';
3 |
4 | test('test', async ({ page }) => {
5 | await page.goto('https://www.demoblaze.com/index.html');
6 | await page.getByRole('link', { name: 'Log in' }).click();
7 | await page.locator('#loginusername').fill('pavanol');
8 | await page.locator('#loginpassword').fill('test@123');
9 | await page.getByRole('button', { name: 'Log in' }).click();
10 | await expect(page.locator('#logout')).toBeVisible()
11 | });
--------------------------------------------------------------------------------
/tests/recordvideo.spec.js:
--------------------------------------------------------------------------------
1 |
2 | import { test, expect } from '@playwright/test';
3 |
4 | test('test', async ({ page }) => {
5 | await page.goto('https://www.demoblaze.com/index.html');
6 | await page.getByRole('link', { name: 'Log in' }).click();
7 | await page.locator('#loginusername').fill('pavanol');
8 | await page.locator('#loginpassword').fill('test@123');
9 | await page.getByRole('button', { name: 'Log in' }).click();
10 | await expect(page.locator('#logout')).toBeVisible()
11 | });
--------------------------------------------------------------------------------
/tests/screenshot2.spec.js:
--------------------------------------------------------------------------------
1 | //using
2 | // screenshot: 'on' in config file
3 |
4 | import { test, expect } from '@playwright/test';
5 |
6 | test('test', async ({ page }) => {
7 |
8 | await page.goto('https://www.demoblaze.com/index.html');
9 | await page.getByRole('link', { name: 'Log in' }).click();
10 | await page.locator('#loginusername').fill('pavanol');
11 | await page.locator('#loginpassword').fill('test@123');
12 | await page.getByRole('button', { name: 'Log in' }).click();
13 | });
--------------------------------------------------------------------------------
/tests/ParallelTesting.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 | test.describe.configure({mode: 'parallel'});
3 |
4 | test.describe('Group1',()=>{
5 |
6 | test('Test1', async({page})=>{
7 | console.log('this is test 1....')
8 | })
9 |
10 | test('Test2', async({page})=>{
11 | console.log('this is test 2....')
12 | })
13 |
14 | test('Test3', async({page})=>{
15 | console.log('this is test 3....')
16 | })
17 |
18 |
19 | })
20 |
21 |
--------------------------------------------------------------------------------
/tests/mytest.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | test('test', async ({ page }) => {
4 | await page.goto('https://www.demoblaze.com/index.html');
5 |
6 | await page.getByRole('link', { name: 'Log in' }).click();
7 |
8 | await page.locator('#loginusername').fill('pavanol');
9 |
10 | await page.locator('#loginpassword').fill('test@123');
11 |
12 | await page.getByRole('button', { name: 'Log in' }).click();
13 |
14 | await expect(page.locator('#logout2')).toBeVisible()
15 | });
--------------------------------------------------------------------------------
/tests/MouseDoubleClick.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}= require('@playwright/test')
2 |
3 | test ('Mouse Double Click', async ({page})=>{
4 |
5 | await page.goto('https://testautomationpractice.blogspot.com/')
6 |
7 | const btnCopy=await page.locator('//button[normalize-space()="Copy Text"]')
8 |
9 | //double click
10 | await btnCopy.dblclick()
11 |
12 | const f2=await page.locator('#field2')
13 |
14 | await expect(f2).toHaveValue('Hello World!')
15 |
16 | await page.waitForTimeout(5000)
17 |
18 | })
--------------------------------------------------------------------------------
/results.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/HomePageTest.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('Home Page',async ({page})=>{
4 |
5 | await page.goto('https://www.demoblaze.com/index.html');
6 |
7 | const pageTitle=await page.title();
8 | console.log('Page title is:', pageTitle);
9 |
10 | await expect(page).toHaveTitle('STORE');
11 |
12 | const pageURL=await page.url();
13 | console.log('Page URL is:',pageURL);
14 |
15 | await expect(page).toHaveURL('https://www.demoblaze.com/index.html');
16 |
17 | await page.close();
18 |
19 | } )
20 |
--------------------------------------------------------------------------------
/tests/Tags.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test')
2 |
3 | test('test1@sanity',async({page})=>{
4 | console.log('this is my test1...')
5 | })
6 |
7 |
8 | test('test2@sanity',async({page})=>{
9 | console.log('this is my test2...')
10 | })
11 |
12 |
13 | test('test3@reg',async({page})=>{
14 | console.log('this is my test3...')
15 | })
16 |
17 |
18 | test('test4@reg',async({page})=>{
19 | console.log('this is my test4...')
20 | })
21 |
22 | test('test5@sanity@reg',async({page})=>{
23 | console.log('this is my test5...')
24 | })
--------------------------------------------------------------------------------
/tests/BrowserContext.spec.js:
--------------------------------------------------------------------------------
1 | import { chromium,test, expect } from '@playwright/test';
2 | //const { chromium, test, expect } = require('@playwright/test')
3 |
4 | test("browse context test",async () => {
5 | const browser = await chromium.launch({ headless: false });
6 | const context1 = await browser.newContext();
7 | const context2 = await browser.newContext();
8 |
9 |
10 | const page = await context.newPage();
11 | await page.goto('https://www.demoblaze.com/index.html');
12 |
13 |
14 | console.log(browser.contexts().length);
15 |
16 | await browser.close();
17 | });
18 |
19 |
--------------------------------------------------------------------------------
/tests/HandleInnerFrames.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('Inner frames', async ({ page }) => {
4 |
5 | await page.goto('https://ui.vision/demo/webtest/frames/');
6 |
7 | const frame3=await page.frame({url:'https://ui.vision/demo/webtest/frames/frame_3.html'})
8 | //frame3.locator("input[name='mytext3']").fill('welcome')
9 |
10 | //nested frame
11 | const childFrames=await frame3.childFrames()
12 | await childFrames[0].locator("//*[@id='i5']/div[3]/div").check() // radio button
13 |
14 |
15 | await page.waitForTimeout(5000);
16 |
17 |
18 | });
19 |
--------------------------------------------------------------------------------
/tests/Reporters.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('Test1', async ({ page }) => {
4 | await page.goto('https://www.demoblaze.com/index.html');
5 | await expect(page).toHaveTitle('STORE');
6 | })
7 |
8 | test('Test2', async ({ page }) => {
9 | await page.goto('https://demo.opencart.com/');
10 | await expect(page).toHaveTitle('Your Store');
11 | })
12 |
13 |
14 | test('Test3', async ({ page }) => {
15 | await page.goto('https://demo.nopcommerce.com/');
16 | await expect(page).toHaveTitle('nopCommerce demo store');
17 | })
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/example.spec.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | const { test, expect } = require('@playwright/test');
3 |
4 | test('has title', async ({ page }) => {
5 | await page.goto('https://playwright.dev/');
6 |
7 | // Expect a title "to contain" a substring.
8 | await expect(page).toHaveTitle(/Playwright/);
9 | });
10 |
11 | test('get started link', async ({ page }) => {
12 | await page.goto('https://playwright.dev/');
13 |
14 | // Click the get started link.
15 | await page.getByRole('link', { name: 'Get started' }).click();
16 |
17 | // Expects the URL to contain intro.
18 | await expect(page).toHaveURL(/.*intro/);
19 | });
20 |
--------------------------------------------------------------------------------
/pages/CartPage.js:
--------------------------------------------------------------------------------
1 | exports.CartPage = class CartPage {
2 |
3 | constructor(page) {
4 | this.page = page;
5 | this.noOfProducts= '//tbody[@id="tbodyid"]/tr/td[2]'
6 |
7 | }
8 |
9 | async checkProductInCart(productName) {
10 | const productsInCart=await this.page.$$(this.noOfProducts)
11 | for (const product of productsInCart) {
12 | console.log(await product.textContent())
13 | if (productName === await product.textContent()) {
14 | return true;
15 | break;
16 | }
17 | }
18 |
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/tests/Softassertions.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect} =require('@playwright/test')
2 |
3 |
4 | test("Soft assertions",async ({page})=>{
5 |
6 | await page.goto("https://www.demoblaze.com/index.html")
7 |
8 | //Hard assertions
9 | /* await expect(page).toHaveTitle('STORE123');
10 | await expect(page).toHaveURL("https://www.demoblaze.com/index.html");
11 | await expect(page.locator('.navbar-brand')).toBeVisible();
12 | */
13 | //Soft assertions
14 | await expect.soft(page).toHaveTitle('STORE123');
15 | await expect.soft(page).toHaveURL("https://www.demoblaze.com/index.html");
16 | await expect.soft(page.locator('.navbar-brand')).toBeVisible();
17 |
18 | })
--------------------------------------------------------------------------------
/tests/RadioButtons.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('handle radio button',async ({page})=>{
4 |
5 | await page.goto('https://itera-qa.azurewebsites.net/home/automation');
6 |
7 | //Radio button
8 | await page.locator("//input[@value='option2']").check(); //male
9 | //await page.check("//input[@value='option2']");
10 | await expect(await page.locator("//input[@value='option2']")).toBeChecked();
11 | await expect(await page.locator("//input[@value='option2']").isChecked()).toBeTruthy();//male
12 |
13 | await expect(await page.locator("//input[@value='option1']").isChecked()).toBeFalsy(); //female
14 |
15 |
16 |
17 | await page.waitForTimeout(5000); //pausing code
18 |
19 | })
--------------------------------------------------------------------------------
/tests/screenshot.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | test('page screenshot', async ({ page }) => {
4 | await page.goto('https://demo.opencart.com/')
5 | await page.screenshot({ path:'tests/screenshots/'+Date.now()+'HomePage.png'})
6 | });
7 |
8 | test('Full page screenshot', async ({ page }) => {
9 | await page.goto('https://demo.opencart.com/')
10 | await page.screenshot({ path:'tests/screenshots/'+Date.now()+'FullPage.png',fullPage:true})
11 | });
12 |
13 | test.only('Element screenshot', async ({ page }) => {
14 | await page.goto('https://demo.opencart.com/')
15 | await page.locator('//*[@id="content"]/div[2]/div[1]/form/div').screenshot({ path:'tests/screenshots/'+Date.now()+'Macbook.png'})
16 | });
--------------------------------------------------------------------------------
/tests/Inputbox.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('handle inputbox',async ({page})=>{
4 |
5 | await page.goto('https://itera-qa.azurewebsites.net/home/automation');
6 |
7 | //Inputbox - firstname
8 | await expect(await page.locator("//input[@id='name']")).toBeVisible();
9 | await expect(await page.locator("//input[@id='name']")).toBeEmpty();
10 | await expect(await page.locator("//input[@id='name']")).toBeEditable();
11 | await expect(await page.locator("//input[@id='name']")).toBeEnabled();
12 |
13 |
14 | //await page.locator("//input[@id='name']").fill("John")
15 | await page.fill("//input[@id='name']",'John');
16 |
17 | await page.waitForTimeout(5000); //pausing code
18 |
19 | })
--------------------------------------------------------------------------------
/tests/AutoSuggestDropDown.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('Auto suggest dropdown', async ({page}) =>{
4 | await page.goto('https://www.redbus.in/')
5 |
6 | await page.locator('#src').fill('Delhi');
7 | await page.waitForSelector("//li[contains(@class,'sc-iwsKbI')]/div/text[1]")
8 |
9 | const fromCityOptions=await page.$$("//li[contains(@class,'sc-iwsKbI')]/div/text[1]")
10 |
11 | for(let option of fromCityOptions)
12 | {
13 | const value=await option.textContent()
14 | //console.log(value);
15 | if(value.includes('Anand Vihar'))
16 | {
17 | await option.click()
18 | break;
19 |
20 | }
21 | }
22 |
23 | await page.waitForTimeout(5000);
24 |
25 | })
--------------------------------------------------------------------------------
/tests/DragAndDrop.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}= require('@playwright/test')
2 |
3 | test ('Drag And Drop', async ({page})=>{
4 |
5 | await page.goto('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html')
6 |
7 | const rome=await page.locator('#box6')
8 | const italy=await page.locator('#box106')
9 |
10 | //Appraoch 1
11 | /*await rome.hover()
12 | await page.mouse.down()
13 |
14 | await italy.hover()
15 | await page.mouse.up()
16 | */
17 | //Appraoch 2
18 | await rome.dragTo(italy)
19 |
20 | //WASHINGTON---> US
21 | const washington=await page.locator('#box3')
22 | const usa=await page.locator('#box103')
23 |
24 | await washington.dragTo(usa)
25 |
26 |
27 | await page.waitForTimeout(5000)
28 |
29 | })
--------------------------------------------------------------------------------
/pages/LoginPage.js:
--------------------------------------------------------------------------------
1 | exports.LoginPage =
2 | class LoginPage {
3 |
4 | constructor(page) {
5 | this.page = page;
6 | this.loginLink="#login2"
7 | this.usernameInput = '#loginusername';
8 | this.passwordInput = '#loginpassword';
9 | this.loginButton = '//button[normalize-space()="Log in"]';
10 | }
11 |
12 | async gotoLoginPage(){
13 | await this.page.goto('https://www.demoblaze.com/index.html');
14 | }
15 |
16 | async login(username, password) {
17 | await this.page.locator(this.loginLink).click();
18 | await this.page.locator(this.usernameInput).fill(username);
19 | await this.page.locator(this.passwordInput).fill(password);
20 | await this.page.locator(this.loginButton).click();
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/tests/KeyboardActions.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('Keyboard actions', async ({ page }) => {
4 |
5 | await page.goto("https://gotranscript.com/text-compare")
6 |
7 | //await page.locator('name="text1"').fill("welcome to autoamtion");
8 |
9 | await page.type('[name="text1"]','welcome to automation')
10 |
11 | //Ctrl + A - Select the text
12 | await page.keyboard.press('Meta+A')
13 |
14 | //Ctrl + C - copy the text
15 | await page.keyboard.press('Meta+C')
16 |
17 | //Tab
18 | await page.keyboard.down('Tab')
19 | await page.keyboard.up('Tab')
20 |
21 |
22 | //Ctrl + V - paste the text
23 | await page.keyboard.press('Meta+V')
24 |
25 | await page.waitForTimeout(5000);
26 |
27 | });
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/Pomtest.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 | import { LoginPage } from '../pages/LoginPage';
3 | import { HomePage } from '../pages/HomePage';
4 | import { CartPage} from '../pages/CartPage';
5 |
6 |
7 | test('test', async ({ page }) => {
8 |
9 | //Login
10 | const login=new LoginPage(page);
11 | await login.gotoLoginPage();
12 | await login.login('pavanol','test@123')
13 | await page.waitForTimeout(3000)
14 |
15 | //Home
16 | const home=new HomePage(page)
17 | await home.addProductToCart("Nexus 6")
18 | await page.waitForTimeout(3000)
19 | await home.gotoCart();
20 |
21 | //Cart
22 | const cart=new CartPage(page)
23 | await page.waitForTimeout(3000)
24 | const status=await cart.checkProductInCart('Nexus 6')
25 | expect(await status).toBe(true);
26 | });
--------------------------------------------------------------------------------
/tests/HandleFrames.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('frames', async ({ page }) => {
4 |
5 | await page.goto('https://ui.vision/demo/webtest/frames/');
6 |
7 | //total frames
8 | const allframes=await page.frames()
9 | console.log("Number of frames:",allframes.length)
10 |
11 | //approach 1: using name or url
12 | //const var=await page.frame('name'); // if name is present
13 | //const frame1=await page.frame({url:'https://ui.vision/demo/webtest/frames/frame_1.html'})
14 | //await frame1.fill("[name='mytext1']",'Hello');
15 |
16 |
17 | //appraoch 2- using frame locator
18 | const inputbox=await page.frameLocator("frame[src='frame_1.html']").locator("[name='mytext1']")
19 | inputbox.fill("Hello")
20 |
21 |
22 | await page.waitForTimeout(5000);
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/tests/LocatingMultipleElements.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('LocateElements', async ({ page }) => {
4 |
5 | await page.goto('https://www.demoblaze.com/index.html')
6 |
7 | // Locate and return all the links on the webpage
8 | /*const links = await page.$$('a');
9 |
10 | for (const link of links) {
11 | const linktext = await link.textContent();
12 | console.log(linktext);
13 | }
14 | */
15 |
16 | //Locate all the products displayed on home page
17 | await page.waitForSelector("//div[@id='tbodyid']//h4/a");
18 |
19 | const products = await page.$$("//div[@id='tbodyid']//h4/a")
20 |
21 | for (const product of products) {
22 | const prodName = await product.textContent();
23 | console.log(prodName);
24 | }
25 |
26 | });
--------------------------------------------------------------------------------
/tests/APITests.spec.js:
--------------------------------------------------------------------------------
1 | import { expect, test } from "@playwright/test";
2 |
3 | // Create
4 | test("Create user", async ({ request, baseURL }) => {
5 | const _response = await request.post(`${baseURL}`, {
6 | data: {
7 | "name": "xyz}",
8 | "gender": "male",
9 | "email": "xyzabc245faas@gmail.com",
10 | "status": "inactive"
11 | }, headers: {
12 | "Accept": "application/json"
13 | }
14 | });
15 | expect(_response.status()).toBe(201);
16 | expect(_response.ok()).toBeTruthy();
17 | console.log(await _response.json());
18 | const res = await _response.json();
19 | _number = res.result.task_effective_number;
20 | _sys_id = res.result.sys_id;
21 |
22 | // output as xml
23 | // console.log((await _response.body()).toString());
24 | })
25 | // test("", async ({ page }) => {
26 | // await page.request.get("")
27 | // })
28 |
--------------------------------------------------------------------------------
/pages/HomePage.js:
--------------------------------------------------------------------------------
1 | exports.HomePage = class HomePage {
2 |
3 | constructor(page) {
4 | this.page = page;
5 | this.productList= '//*[@id="tbodyid"]/div/div/div/h4/a';
6 | this.addToCartbtn='//a[normalize-space()="Add to cart"]';
7 | this.cart='#cartur'
8 | }
9 |
10 |
11 | async addProductToCart(productName) {
12 | const productList = await this.page.$$(this.productList);
13 | for (const product of productList) {
14 | if (productName === await product.textContent()) {
15 | await product.click()
16 | break;
17 | }
18 | }
19 | await this.page.on('dialog', async dialog=>{
20 | if(dialog.message().includes('added')){
21 | await dialog.accept();
22 | }
23 | })
24 | await this.page.locator(this.addToCartbtn).click();
25 | }
26 |
27 | async gotoCart() {
28 | await this.page.locator(this.cart).click();
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/tests/Locators.spec.js:
--------------------------------------------------------------------------------
1 | //const {test, expect} = require('@playwright/test')
2 | import {test,expect} from '@playwright/test'
3 |
4 | test('Locators', async ({page})=>{
5 |
6 | await page.goto("https://www.demoblaze.com/index.html")
7 |
8 | //click on login button - property
9 | //await page.locator('id=login2').click()
10 | await page.click('id=login2')
11 |
12 | //provide username - CSS
13 | //await page.locator('#loginusername').fill("pavanol")
14 | await page.fill('#loginusername','pavanol')
15 | //await page.type('#loginusername','pavanol)
16 |
17 | //provide password - CSS
18 | await page.fill("input[id='loginpassword']",'test@123')
19 |
20 | //Click on login button - XPath
21 | await page.click("//button[normalize-space()='Log in']")
22 |
23 | //verify logout link presence - XPath
24 | const logoutlink= await page.locator("//a[normalize-space()='Log out']")
25 |
26 | await expect(logoutlink).toBeVisible();
27 |
28 | await page.close()
29 |
30 | })
--------------------------------------------------------------------------------
/tests/Grouping.spec.js:
--------------------------------------------------------------------------------
1 | //const { test, expect } = require('@playwright/test');
2 | import {test, expect} from '@playwright/test'
3 |
4 | test.beforeAll(async()=>{
5 | console.log('this is beforeAll Hook......')
6 | })
7 | test.afterAll(async()=>{
8 | console.log('this is aftereAll Hook......')
9 | })
10 |
11 | test.beforeEach(async()=>{
12 | console.log('this is beforeEach Hook......')
13 | })
14 |
15 | test.afterEach(async()=>{
16 | console.log('this is afterEach Hook......')
17 | })
18 |
19 | test.describe.skip('Group1',()=>{
20 |
21 | test('Test1', async({page})=>{
22 | console.log('this is test 1....')
23 | })
24 |
25 | test('Test2', async({page})=>{
26 | console.log('this is test 2....')
27 | })
28 | })
29 |
30 |
31 | test.describe('Group 2', ()=>{
32 |
33 | test('Test3', async({page})=>{
34 | console.log('this is test 3....')
35 | })
36 |
37 |
38 | test('Test4', async({page})=>{
39 | console.log('this is test 4....')
40 | })
41 | })
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/MultiSelectDropdown.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test("Handle dropdowns",async ({page})=>{
4 |
5 | await page.goto('https://testautomationpractice.blogspot.com/');
6 |
7 | //Select multiple options from multi select dropdown
8 | //await page.selectOption('#colors',['Blue', 'Red', 'Yellow'])
9 |
10 | //Assertions
11 | //1) check number of options in dropdown
12 | //const options=await page.locator('#colors option')
13 | //await expect(options).toHaveCount(5);
14 |
15 | //2) check number of options in dropdown using JS array
16 | //const options=await page.$$('#colors option')
17 | //console.log("Number of options:",options.length)
18 | //await expect(options.length).toBe(5);
19 |
20 | //3) check presence of value in the dropdown
21 | const content=await page.locator('#colors').textContent()
22 | //await expect(content.includes('Black')).toBeTruthy();
23 | await expect(content.includes('Black')).toBeFalsy;
24 |
25 |
26 | await page.waitForTimeout(5000);
27 |
28 | })
--------------------------------------------------------------------------------
/tests/Hooks2.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | let page;
4 |
5 | test.beforeEach(async ({browser})=>{
6 | page=await browser.newPage();
7 | await page.goto('https://www.demoblaze.com/index.html')
8 | //Login
9 | await page.locator('#login2').click()
10 | await page.locator('#loginusername').fill('pavanol')
11 | await page.locator('#loginpassword').fill('test@123')
12 | await page.locator('//button[normalize-space()="Log in"]').click()
13 | });
14 |
15 | test.afterEach(async()=>{
16 | await page.locator('#logout2').click()
17 | } )
18 |
19 | test('Home Page Test', async () => {
20 | const products=await page.$$('.hrefch')
21 | expect(products).toHaveLength(9)
22 | });
23 |
24 |
25 | test('Add Product to cart Test', async () => {
26 | await page.locator('//a[normalize-space()="Samsung galaxy s6"]').click()
27 | await page.locator('//a[normalize-space()="Add to cart"]').click()
28 |
29 | page.on('dialog', async dialog=>{
30 | expect(dialog.message()).toContain('Product added.')
31 | await dialog.accept()
32 | })
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/tests/Hooks3.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | let page;
4 |
5 | test.beforeAll(async ({browser})=>{
6 | page=await browser.newPage();
7 | await page.goto('https://www.demoblaze.com/index.html')
8 | //Login
9 | await page.locator('#login2').click()
10 | await page.locator('#loginusername').fill('pavanol')
11 | await page.locator('#loginpassword').fill('test@123')
12 | await page.locator('//button[normalize-space()="Log in"]').click()
13 | });
14 |
15 | test.afterAll(async()=>{
16 | await page.locator('#logout2').click()
17 | } )
18 |
19 | test('Home Page Test', async () => {
20 | const products=await page.$$('.hrefch')
21 | expect(products).toHaveLength(9)
22 | });
23 |
24 |
25 | test('Add Product to cart Test', async () => {
26 | await page.locator('//a[normalize-space()="Samsung galaxy s6"]').click()
27 | await page.locator('//a[normalize-space()="Add to cart"]').click()
28 |
29 | page.on('dialog', async dialog=>{
30 | expect(dialog.message()).toContain('Product added.')
31 | await dialog.accept()
32 | })
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/tests/HiddenDropDown.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('Hidden options dropdown', async ({page}) =>{
4 | await page.goto('https://opensource-demo.orangehrmlive.com/web/index.php/auth/login')
5 |
6 | await page.locator("[name='username']").fill('Admin');
7 | await page.locator("[name='password']").fill('admin123');
8 | await page.locator("[type='submit']").click();
9 |
10 | await page.locator("//span[normalize-space()='PIM']").click()
11 |
12 | //click on drop down
13 | await page.locator("//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[2]/form/div[1]/div/div[6]/div/div[2]/div/div/div[2]").click()
14 |
15 | //waiting for options
16 | await page.waitForTimeout(3000);
17 |
18 | const options=await page.$$("//div[@role='listbox']//span")
19 |
20 | for(let option of options)
21 | {
22 | const jobTitle=await option.textContent();
23 | //console.log(jobTitle);
24 | if(jobTitle.includes('QA Engineer'))
25 | {
26 | await option.click();
27 | break;
28 | }
29 | }
30 | await page.waitForTimeout(5000);
31 |
32 |
33 | })
--------------------------------------------------------------------------------
/tests/Annotations.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | // only
4 | /*test.only('test1', async({page})=>{
5 | console.log('this is test1')
6 | })
7 | */
8 | //skip
9 | /*test.skip('test2', async({page})=>{
10 | console.log('this is test2')
11 | })
12 |
13 | test('test3', async({page, browserName})=>{
14 | console.log('this is test3')
15 | if(browserName==='chromium')
16 | {
17 | test.skip()
18 | }
19 | })
20 | */
21 |
22 | //Fixme
23 | /*test('test4', async({page})=>{
24 | test.fixme()
25 | console.log('this is test 4..')
26 |
27 | })
28 | */
29 |
30 | // Fail
31 |
32 | /*test('test5', async({page})=>{
33 | test.fail() //exp
34 | console.log('this is test5....')
35 | expect(1).toBe(2); //If both exp & Actual is failed then test pass
36 | })
37 |
38 | test('test6', async({page, browserName})=>{
39 | console.log('this is test6....')
40 | if(browserName==='firefox')
41 | {
42 | test.fail() //exp
43 | }
44 | })
45 | */
46 |
47 | // slow()
48 |
49 | test('test7', async({page})=>{
50 | test.slow();
51 | // test.setTimeout(5000)
52 | await page.goto('https://www.demoblaze.com/index.html')
53 | console.log('this is test 7..')
54 | })
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tests/BootstrapDropdown.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('Boostrap dropdown', async ({page}) =>{
4 | await page.goto('https://www.jquery-az.com/boots/demo.php?ex=63.0_2')
5 |
6 | await page.locator('.multiselect').click() // click on the dropdown
7 |
8 | //1
9 | //const options=await page.locator('ul>li label input')
10 | //await expect(options).toHaveCount(11);
11 |
12 | //2
13 | //const options=await page.$$('ul>li label input')
14 | //await expect(options.length).toBe(11)
15 |
16 | //3 select options from dropdown
17 | /*const options=await page.$$('ul>li label')
18 | for(let option of options)
19 | {
20 | const value=await option.textContent();
21 | //console.log("value is",value)
22 | if(value.includes('Angular') || value.includes('Java'))
23 | {
24 | await option.click()
25 | }
26 |
27 | }*/
28 |
29 | // delect options
30 | const options=await page.$$('ul>li label')
31 | for(let option of options)
32 | {
33 | const value=await option.textContent();
34 | //console.log("value is",value)
35 | if(value.includes('HTML') || value.includes('CSS'))
36 | {
37 | await option.click()
38 | }
39 |
40 | }
41 |
42 |
43 | await page.waitForTimeout(5000);
44 | })
--------------------------------------------------------------------------------
/tests/DatePicker.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test("Date Picker", async ({ page }) => {
4 |
5 | await page.goto('https://testautomationpractice.blogspot.com/')
6 | // await page.fill('#datepicker','03/15/2024')
7 |
8 | //date picker
9 | const year="2022"
10 | const month="March"
11 | const date="25"
12 |
13 | await page.click('#datepicker') // opens calender
14 |
15 | while(true)
16 | {
17 | const currentYear=await page.locator('.ui-datepicker-year').textContent()
18 | const currentMonth=await page.locator('.ui-datepicker-month').textContent()
19 |
20 | if(currentYear == year && currentMonth==month)
21 | {
22 | break;
23 | }
24 |
25 | // await page.locator('[title="Next"]').click() //Next
26 | await page.locator('[title="Prev"]').click() //Previous
27 | }
28 |
29 | const dates=await page.$$("//a[@class='ui-state-default']")
30 |
31 | //date selection using loop
32 | /* for(const dt of dates)
33 | {
34 | if(await dt.textContent()==date)
35 | {
36 | await dt.click();
37 | break;
38 | }
39 | }
40 | */
41 |
42 | //date selection - wihout loop
43 | await page.click(`//a[@class='ui-state-default'][text()='${date}']`)
44 |
45 |
46 | await page.waitForTimeout(5000);
47 |
48 | });
49 |
--------------------------------------------------------------------------------
/tests/Hooks1.spec.js:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | test('Home Page Test', async ({ page }) => {
4 | await page.goto('https://www.demoblaze.com/index.html')
5 | //Login
6 | await page.locator('#login2').click()
7 | await page.locator('#loginusername').fill('pavanol')
8 | await page.locator('#loginpassword').fill('test@123')
9 | await page.locator('//button[normalize-space()="Log in"]').click()
10 |
11 | //Home Page
12 | const products=await page.$$('.hrefch')
13 | expect(products).toHaveLength(9)
14 |
15 | //Logout
16 | await page.locator('#logout2').click()
17 | });
18 |
19 |
20 | test('Add Product to cart Test', async ({ page }) => {
21 | await page.goto('https://www.demoblaze.com/index.html')
22 | //Login
23 | await page.locator('#login2').click()
24 | await page.locator('#loginusername').fill('pavanol')
25 | await page.locator('#loginpassword').fill('test@123')
26 | await page.locator('//button[normalize-space()="Log in"]').click()
27 |
28 | //Add product to cart
29 | await page.locator('//a[normalize-space()="Samsung galaxy s6"]').click()
30 | await page.locator('//a[normalize-space()="Add to cart"]').click()
31 |
32 | page.on('dialog', async dialog=>{
33 | expect(dialog.message()).toContain('Product added.')
34 | await dialog.accept()
35 | })
36 | //Logout
37 | await page.locator('#logout2').click()
38 |
39 | });
40 |
41 |
--------------------------------------------------------------------------------
/tests/UploadFiles.spec.js:
--------------------------------------------------------------------------------
1 | // Reference : https://playwright.dev/docs/input#upload-files
2 |
3 | const {test, expect}=require('@playwright/test')
4 |
5 | test('Single File',async ({page})=>{
6 |
7 | await page.goto('https://www.foundit.in/')
8 |
9 | await page.waitForSelector('.mqfihd-upload');
10 | await page.locator('.mqfihd-upload').click()
11 |
12 | await page.locator('#file-upload').setInputFiles('tests/uploadFiles/testfile1.pdf')
13 |
14 | await page.waitForTimeout(5000)
15 | })
16 |
17 | test.only('Multiple Files',async ({page})=>{
18 |
19 | await page.goto('https://davidwalsh.name/demo/multiple-file-upload.php')
20 |
21 | await page.locator('#filesToUpload')
22 | .setInputFiles(['tests/uploadFiles/testfile1.pdf',
23 | 'tests/uploadFiles/testfile2.pdf']);
24 |
25 | await page.waitForTimeout(3000)
26 | expect (await page.locator('#fileList li:nth-child(1)')).toHaveText('testfile1.pdf')
27 | expect (await page.locator('#fileList li:nth-child(2)')).toHaveText('testfile2.pdf')
28 |
29 | await page.waitForTimeout(3000)
30 |
31 | //Removing files
32 | await page.locator('#filesToUpload').setInputFiles([])
33 | await page.waitForTimeout(3000)
34 |
35 | expect(await page.locator('#fileList li:nth-child(1)')).toHaveText('No Files Selected')
36 |
37 | await page.waitForTimeout(3000)
38 |
39 | })
40 |
--------------------------------------------------------------------------------
/tests/Locators_builtin.spec.js:
--------------------------------------------------------------------------------
1 | /*
2 | page.getByAltText() - to locate an element, usually image, by its text alternative.
3 | page.getByPlaceholder() - to locate an input by placeholder.
4 | page.getByRole() to locate by explicit and implicit accessibility attributes.
5 | page.getByText() to locate by text content.
6 |
7 | page.getByLabel() to locate a form control by associated label's text.
8 | page.getByTitle() to locate an element by its title attribute.
9 | page.getByTestId() to locate an element based on its data-testid attribute (other attributes can be configured).
10 |
11 | */
12 |
13 | const {test, expect} = require('@playwright/test')
14 |
15 | test('Built-inLocators',async({page})=>{
16 |
17 | await page.goto('https://opensource-demo.orangehrmlive.com/web/index.php/auth/login')
18 |
19 | //page.getByAltText() - to locate an element, usually image, by its text alternative.
20 | const logo=await page.getByAltText('company-branding')
21 | await expect(logo).toBeVisible();
22 |
23 | //page.getByPlaceholder() - to locate an input by placeholder.
24 | await page.getByPlaceholder('Username').fill("Admin")
25 | await page.getByPlaceholder('Password').fill("admin123")
26 |
27 | await page.getByRole('button', {type: 'submit'} ).click()
28 |
29 | const name=await page.locator('//p[@class="oxd-userdropdown-name"]').textContent()
30 |
31 | await expect(await page.getByText(name)).toBeVisible()
32 |
33 | })
--------------------------------------------------------------------------------
/tests/Checkboxes.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test("Handle checkboxes",async ({page})=>{
4 |
5 | await page.goto('https://itera-qa.azurewebsites.net/home/automation');
6 |
7 | //single checkbox
8 | await page.locator("//input[@id='monday' and @type='checkbox']").check();
9 | //await page.check("//input[@id='monday' and @type='checkbox']");
10 |
11 | expect(await page.locator("//input[@id='monday' and @type='checkbox']")).toBeChecked();
12 | expect(await page.locator("//input[@id='monday' and @type='checkbox']").isChecked()).toBeTruthy();
13 | expect(await page.locator("//input[@id='sunday' and @type='checkbox']").isChecked()).toBeFalsy();
14 |
15 | //Multiple checkboxes
16 | const checkboxLocators=[
17 | "//input[@id='monday' and @type='checkbox']",
18 | "//input[@id='sunday' and @type='checkbox']",
19 | "//input[@id='saturday' and @type='checkbox']"
20 | ];
21 |
22 | for(const locator of checkboxLocators) // select multiple checkboxes
23 | {
24 | await page.locator(locator).check();
25 | }
26 |
27 | await page.waitForTimeout(5000);
28 |
29 |
30 | for(const locator of checkboxLocators) // unselect multiple checkboxes which are already selected
31 | {
32 | if(await page.locator(locator).isChecked())
33 | {
34 | await page.locator(locator).uncheck();
35 | }
36 | }
37 | await page.waitForTimeout(5000);
38 | })
--------------------------------------------------------------------------------
/tests/HandlingWindows.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect, chromium } = require('@playwright/test');
2 |
3 | test('Handle Pages/Windows', async () => {
4 |
5 | const browser=await chromium.launch()
6 | const context=await browser.newContext()
7 |
8 | const page1=await context.newPage()
9 | const page2=await context.newPage()
10 |
11 | const allPages=context.pages()
12 | console.log("No Of Pages created:",allPages.length)
13 |
14 | await page1.goto("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
15 | await expect(page1).toHaveTitle("OrangeHRM")
16 |
17 | await page2.goto("https://www.orangehrm.com/")
18 | await expect(page2).toHaveTitle("OrangeHRM HR Software | Free & Open Source HR Software | HRMS | HRIS | OrangeHRM")
19 |
20 | })
21 |
22 | test.only('Handle Multiple Pages/Windows', async () => {
23 |
24 | const browser=await chromium.launch()
25 | const context=await browser.newContext()
26 |
27 | const page1=await context.newPage()
28 | await page1.goto("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
29 | await expect(page1).toHaveTitle("OrangeHRM")
30 |
31 | const pagePromise=context.waitForEvent('page')
32 | await page1.locator('//a[normalize-space()="OrangeHRM, Inc"]').click()
33 |
34 | const newPage= await pagePromise;
35 | await expect(newPage).toHaveTitle("OrangeHRM HR Software | Free & Open Source HR Software | HRMS | HRIS | OrangeHRM")
36 |
37 | await page1.waitForTimeout(3000)
38 | await newPage.waitForTimeout(3000)
39 |
40 | await browser.close()
41 |
42 | })
43 |
--------------------------------------------------------------------------------
/tests/Alerts.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test.skip('Alert with OK', async ({ page }) => {
4 | await page.goto('https://testautomationpractice.blogspot.com/');
5 |
6 | //Enabling Dilaog window handler
7 | page.on('dialog', async dialog=>{
8 | expect(dialog.type()).toContain('alert')
9 | expect(dialog.message()).toContain('I am an alert box!')
10 | await dialog.accept();
11 |
12 | })
13 | await page.click('//button[normalize-space()="Alert"]');
14 | await page.waitForTimeout(5000);
15 |
16 | });
17 |
18 | test.skip('Confirmation Dialod-Alert with OK and cancel', async ({ page }) => {
19 | await page.goto('https://testautomationpractice.blogspot.com/');
20 |
21 | //Enabling dialog window handler
22 | page.on('dialog', async dialog=>{
23 | expect(dialog.type()).toContain('confirm')
24 | expect(dialog.message()).toContain('Press a button!')
25 | await dialog.accept(); // close by using OK button
26 | //await dialog.dismiss(); // close by using cancel
27 |
28 | })
29 | await page.click('//button[normalize-space()="Confirm Box"]');
30 | await expect(page.locator('//p[@id="demo"]')).toHaveText('You pressed OK!')
31 |
32 | await page.waitForTimeout(5000);
33 |
34 | });
35 |
36 | test('Prompt Dialog', async ({ page }) => {
37 | await page.goto('https://testautomationpractice.blogspot.com/');
38 |
39 | //Enabling dialog window handler
40 | page.on('dialog', async dialog=>{
41 | expect(dialog.type()).toContain('prompt')
42 | expect(dialog.message()).toContain('Please enter your name:')
43 | expect(dialog.defaultValue()).toContain('Harry Potter')
44 | await dialog.accept('John');
45 |
46 | })
47 | await page.click('//button[normalize-space()="Prompt"]');
48 | await expect(page.locator('//p[@id="demo"]')).toHaveText('Hello John! How are you today?')
49 |
50 | await page.waitForTimeout(5000);
51 |
52 | });
--------------------------------------------------------------------------------
/tests/DropDowns.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test("Handle dropdowns",async ({page})=>{
4 |
5 | await page.goto('https://testautomationpractice.blogspot.com/');
6 |
7 | //Multiple ways to select option from the dropdown
8 | //await page.locator("#country").selectOption({label:'India'}); //label/ visible text
9 | //await page.locator("#country").selectOption('India'); //visible text
10 | //await page.locator("#country").selectOption({value: 'uk'}); // by using value
11 | //await page.locator("#country").selectOption({index: 1}); // by using index
12 | //await page.selectOption("#country",'India'); //by text
13 |
14 | //Assertions
15 | //1) check number of options in dropdown - Approach1
16 | //const options=await page.locator('#country option')
17 | //await expect(options).toHaveCount(10);
18 |
19 | //2) check number of options in dropdown - Appraoch2
20 | //const options=await page.$$('#country option')
21 | //console.log("Number of options:", options.length)
22 | // await expect(options.length).toBe(10);
23 |
24 | //3) check presence of value in the dropdown - Appraoch1
25 | // const content=await page.locator('#country').textContent()
26 | //await expect(content.includes('India')).toBeTruthy();
27 |
28 | //4) check presence of value in the dropdown - Approach 2 - using looping
29 | /*const options=await page.$$('#country option')
30 | let status=false;
31 | for(const option of options)
32 | {
33 | //console.log(await option.textContent())
34 | let value=await option.textContent();
35 | if(value.includes('France'))
36 | {
37 | status=true;
38 | break;
39 | }
40 | }
41 | expect(status).toBeTruthy();
42 | */
43 |
44 |
45 | //5) select option from dropdown using loop
46 | const options=await page.$$('#country option')
47 | for(const option of options)
48 | {
49 | let value=await option.textContent();
50 | if(value.includes('France'))
51 | {
52 | await page.selectOption("#country", value);
53 | break;
54 | }
55 | }
56 |
57 |
58 | await page.waitForTimeout(5000);
59 |
60 | })
--------------------------------------------------------------------------------
/tests/MouseEvents.spec.js:
--------------------------------------------------------------------------------
1 | const { test, expect } = require('@playwright/test');
2 |
3 | test('Mouse hover',async ({page})=>{
4 |
5 | await page.goto('https://demo.opencart.com/');
6 |
7 | const desktops = await page.locator('//a[normalize-space()="Desktops"]');
8 | const macbook= await page.locator('//a[normalize-space()="Mac (1)"]');
9 |
10 | // Mose hover
11 | await desktops.hover()
12 | await macbook.hover()
13 |
14 | await page.waitForTimeout(5000)
15 |
16 | } )
17 |
18 |
19 | test.skip('Right Click',async ({page})=>{
20 |
21 | await page.goto('http://swisnl.github.io/jQuery-contextMenu/demo.html');
22 |
23 | // Wait for the button to be visible on the page
24 | const button = await page.locator('//span[normalize-space()="right click me"]');
25 |
26 | // Right-click on the button
27 | await button.click({ button: 'right' });
28 | await page.waitForTimeout(5000)
29 |
30 | } )
31 |
32 | test.skip('Double Click',async ({page})=>{
33 |
34 | await page.goto('https://testautomationpractice.blogspot.com/');
35 |
36 | const btnCopy = await page.locator('//button[normalize-space()="Copy Text"]')
37 |
38 | // Double-click on the button
39 | await btnCopy.dblclick();
40 |
41 | const f2= await page.locator('#field2')
42 | await expect(f2).toHaveValue('Hello World!')
43 |
44 | await page.waitForTimeout(5000)
45 | } )
46 |
47 | test.skip('Drag and Drop',async ({page})=>{
48 |
49 | await page.goto('http://www.dhtmlgoodies.com/scripts/drag-drop-custom/demo-drag-drop-3.html');
50 |
51 | // Drag and Drop rome--> italy
52 | const rome = await page.locator('#box6');
53 | const italy = await page.locator('#box106');
54 |
55 | //Approach 1
56 | await rome.hover();
57 | await page.mouse.down();
58 | await italy.hover();
59 | await page.mouse.up();
60 |
61 | //Appraoch 2 - direct
62 | //await rome.dragTo(italy);
63 |
64 | // Drag and Drop Washingtom--> USA
65 | const washington = await page.locator('#box3');
66 | const usa = await page.locator('#box103');
67 | await washington.dragTo(usa);
68 |
69 | await page.waitForTimeout(5000)
70 | } )
71 |
72 |
--------------------------------------------------------------------------------
/tests/Assertions.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test('AssertionsTest',async ({page})=>{
4 |
5 | //open app url
6 | await page.goto('https://demo.nopcommerce.com/register')
7 |
8 | //1) expect(page).toHaveURL() Page has URL
9 | await expect(page).toHaveURL('https://demo.nopcommerce.com/register')
10 |
11 | //2) expect(page).toHaveTitle() Page has title
12 | await expect(page).toHaveTitle('nopCommerce demo store. Register')
13 |
14 | //3) expect(locator).toBeVisible() Element is visible
15 | const logoElement=await page.locator('.header-logo')
16 | await expect(logoElement).toBeVisible()
17 |
18 | //4) expect(locator).toBeEnabled() Control is enabled
19 | const searchStoreBox=await page.locator('#small-searchterms')
20 | await expect(searchStoreBox).toBeEnabled()
21 |
22 | //5) expect(locator).toBeChecked() Radio/Checkbox is checked
23 |
24 | //radio button
25 | const maleRadioButton=await page.locator('#gender-male')
26 | await maleRadioButton.click() // select radio button
27 | await expect(maleRadioButton).toBeChecked()
28 |
29 |
30 | //check box
31 | const newsletterCheckbox=await page.locator('#Newsletter')
32 | await expect(newsletterCheckbox).toBeChecked()
33 |
34 | //6) expect(locator).toHaveAttribute() Element has attribute
35 | const regButton=await page.locator('#register-button')
36 | await expect(regButton).toHaveAttribute('type','submit')
37 |
38 | // 7) expect(locator).toHaveText() Element matches text
39 |
40 | await expect(await page.locator('.page-title h1')).toHaveText('Register') //full text
41 |
42 |
43 | // 8) expect(locator).toContainText() Element contains text
44 | await expect(await page.locator('.page-title h1')).toContainText('Reg') //partial text
45 |
46 |
47 | //9) expect(locator).toHaveValue(value) Input has a value
48 | const emailInput=await page.locator('#Email')
49 | await emailInput.fill('test@demo.com');
50 | await expect(emailInput).toHaveValue('test@demo.com')
51 |
52 | // 10) expect(locator).toHaveCount() List of elements has given length
53 | const options= await page.locator('select[name="DateOfBirthMonth"] option')
54 | await expect(options).toHaveCount(13)
55 | })
56 |
--------------------------------------------------------------------------------
/tests/Table.spec.js:
--------------------------------------------------------------------------------
1 | const {test, expect}=require('@playwright/test')
2 |
3 | test("handling table",async ({page})=>{
4 |
5 | await page.goto('https://testautomationpractice.blogspot.com/');
6 |
7 | const table=await page.locator('#productTable')
8 |
9 | // 1) total number of rows & columns
10 | const columns= await table.locator('thead tr th')
11 | console.log('Number of columns:', await columns.count()) //4
12 | expect(await columns.count()).toBe(4)
13 |
14 | const rows=await table.locator('tbody tr')
15 | console.log('Number of rows:', await rows.count()) //5
16 | expect(await rows.count()).toBe(5)
17 |
18 | //2) select check box for product 4
19 | /* const machedRow= rows.filter({
20 | has: page.locator('td'),
21 | hasText: 'Product 4'
22 | })
23 | await machedRow.locator('input').check()
24 | */
25 |
26 | //3) select multiple products by re-usable function
27 | // await selectProduct(rows,page,'Product 1')
28 | // await selectProduct(rows,page,'Product 3')
29 | // await selectProduct(rows,page,'Product 5')
30 |
31 | //4) print all product details using loop
32 | /* for(let i=0;i0)
52 | {
53 | await pages.nth(p).click()
54 | }
55 | for(let i=0;i {
5 | await page.goto('https://demo.playwright.dev/todomvc');
6 | });
7 |
8 | const TODO_ITEMS = [
9 | 'buy some cheese',
10 | 'feed the cat',
11 | 'book a doctors appointment'
12 | ];
13 |
14 | test.describe('New Todo', () => {
15 | test('should allow me to add todo items', async ({ page }) => {
16 | // create a new todo locator
17 | const newTodo = page.getByPlaceholder('What needs to be done?');
18 |
19 | // Create 1st todo.
20 | await newTodo.fill(TODO_ITEMS[0]);
21 | await newTodo.press('Enter');
22 |
23 | // Make sure the list only has one todo item.
24 | await expect(page.getByTestId('todo-title')).toHaveText([
25 | TODO_ITEMS[0]
26 | ]);
27 |
28 | // Create 2nd todo.
29 | await newTodo.fill(TODO_ITEMS[1]);
30 | await newTodo.press('Enter');
31 |
32 | // Make sure the list now has two todo items.
33 | await expect(page.getByTestId('todo-title')).toHaveText([
34 | TODO_ITEMS[0],
35 | TODO_ITEMS[1]
36 | ]);
37 |
38 | await checkNumberOfTodosInLocalStorage(page, 2);
39 | });
40 |
41 | test('should clear text input field when an item is added', async ({ page }) => {
42 | // create a new todo locator
43 | const newTodo = page.getByPlaceholder('What needs to be done?');
44 |
45 | // Create one todo item.
46 | await newTodo.fill(TODO_ITEMS[0]);
47 | await newTodo.press('Enter');
48 |
49 | // Check that input is empty.
50 | await expect(newTodo).toBeEmpty();
51 | await checkNumberOfTodosInLocalStorage(page, 1);
52 | });
53 |
54 | test('should append new items to the bottom of the list', async ({ page }) => {
55 | // Create 3 items.
56 | await createDefaultTodos(page);
57 |
58 | // create a todo count locator
59 | const todoCount = page.getByTestId('todo-count')
60 |
61 | // Check test using different methods.
62 | await expect(page.getByText('3 items left')).toBeVisible();
63 | await expect(todoCount).toHaveText('3 items left');
64 | await expect(todoCount).toContainText('3');
65 | await expect(todoCount).toHaveText(/3/);
66 |
67 | // Check all items in one call.
68 | await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS);
69 | await checkNumberOfTodosInLocalStorage(page, 3);
70 | });
71 | });
72 |
73 | test.describe('Mark all as completed', () => {
74 | test.beforeEach(async ({ page }) => {
75 | await createDefaultTodos(page);
76 | await checkNumberOfTodosInLocalStorage(page, 3);
77 | });
78 |
79 | test.afterEach(async ({ page }) => {
80 | await checkNumberOfTodosInLocalStorage(page, 3);
81 | });
82 |
83 | test('should allow me to mark all items as completed', async ({ page }) => {
84 | // Complete all todos.
85 | await page.getByLabel('Mark all as complete').check();
86 |
87 | // Ensure all todos have 'completed' class.
88 | await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']);
89 | await checkNumberOfCompletedTodosInLocalStorage(page, 3);
90 | });
91 |
92 | test('should allow me to clear the complete state of all items', async ({ page }) => {
93 | const toggleAll = page.getByLabel('Mark all as complete');
94 | // Check and then immediately uncheck.
95 | await toggleAll.check();
96 | await toggleAll.uncheck();
97 |
98 | // Should be no completed classes.
99 | await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']);
100 | });
101 |
102 | test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => {
103 | const toggleAll = page.getByLabel('Mark all as complete');
104 | await toggleAll.check();
105 | await expect(toggleAll).toBeChecked();
106 | await checkNumberOfCompletedTodosInLocalStorage(page, 3);
107 |
108 | // Uncheck first todo.
109 | const firstTodo = page.getByTestId('todo-item').nth(0);
110 | await firstTodo.getByRole('checkbox').uncheck();
111 |
112 | // Reuse toggleAll locator and make sure its not checked.
113 | await expect(toggleAll).not.toBeChecked();
114 |
115 | await firstTodo.getByRole('checkbox').check();
116 | await checkNumberOfCompletedTodosInLocalStorage(page, 3);
117 |
118 | // Assert the toggle all is checked again.
119 | await expect(toggleAll).toBeChecked();
120 | });
121 | });
122 |
123 | test.describe('Item', () => {
124 |
125 | test('should allow me to mark items as complete', async ({ page }) => {
126 | // create a new todo locator
127 | const newTodo = page.getByPlaceholder('What needs to be done?');
128 |
129 | // Create two items.
130 | for (const item of TODO_ITEMS.slice(0, 2)) {
131 | await newTodo.fill(item);
132 | await newTodo.press('Enter');
133 | }
134 |
135 | // Check first item.
136 | const firstTodo = page.getByTestId('todo-item').nth(0);
137 | await firstTodo.getByRole('checkbox').check();
138 | await expect(firstTodo).toHaveClass('completed');
139 |
140 | // Check second item.
141 | const secondTodo = page.getByTestId('todo-item').nth(1);
142 | await expect(secondTodo).not.toHaveClass('completed');
143 | await secondTodo.getByRole('checkbox').check();
144 |
145 | // Assert completed class.
146 | await expect(firstTodo).toHaveClass('completed');
147 | await expect(secondTodo).toHaveClass('completed');
148 | });
149 |
150 | test('should allow me to un-mark items as complete', async ({ page }) => {
151 | // create a new todo locator
152 | const newTodo = page.getByPlaceholder('What needs to be done?');
153 |
154 | // Create two items.
155 | for (const item of TODO_ITEMS.slice(0, 2)) {
156 | await newTodo.fill(item);
157 | await newTodo.press('Enter');
158 | }
159 |
160 | const firstTodo = page.getByTestId('todo-item').nth(0);
161 | const secondTodo = page.getByTestId('todo-item').nth(1);
162 | const firstTodoCheckbox = firstTodo.getByRole('checkbox');
163 |
164 | await firstTodoCheckbox.check();
165 | await expect(firstTodo).toHaveClass('completed');
166 | await expect(secondTodo).not.toHaveClass('completed');
167 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
168 |
169 | await firstTodoCheckbox.uncheck();
170 | await expect(firstTodo).not.toHaveClass('completed');
171 | await expect(secondTodo).not.toHaveClass('completed');
172 | await checkNumberOfCompletedTodosInLocalStorage(page, 0);
173 | });
174 |
175 | test('should allow me to edit an item', async ({ page }) => {
176 | await createDefaultTodos(page);
177 |
178 | const todoItems = page.getByTestId('todo-item');
179 | const secondTodo = todoItems.nth(1);
180 | await secondTodo.dblclick();
181 | await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]);
182 | await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
183 | await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter');
184 |
185 | // Explicitly assert the new text value.
186 | await expect(todoItems).toHaveText([
187 | TODO_ITEMS[0],
188 | 'buy some sausages',
189 | TODO_ITEMS[2]
190 | ]);
191 | await checkTodosInLocalStorage(page, 'buy some sausages');
192 | });
193 | });
194 |
195 | test.describe('Editing', () => {
196 | test.beforeEach(async ({ page }) => {
197 | await createDefaultTodos(page);
198 | await checkNumberOfTodosInLocalStorage(page, 3);
199 | });
200 |
201 | test('should hide other controls when editing', async ({ page }) => {
202 | const todoItem = page.getByTestId('todo-item').nth(1);
203 | await todoItem.dblclick();
204 | await expect(todoItem.getByRole('checkbox')).not.toBeVisible();
205 | await expect(todoItem.locator('label', {
206 | hasText: TODO_ITEMS[1],
207 | })).not.toBeVisible();
208 | await checkNumberOfTodosInLocalStorage(page, 3);
209 | });
210 |
211 | test('should save edits on blur', async ({ page }) => {
212 | const todoItems = page.getByTestId('todo-item');
213 | await todoItems.nth(1).dblclick();
214 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
215 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur');
216 |
217 | await expect(todoItems).toHaveText([
218 | TODO_ITEMS[0],
219 | 'buy some sausages',
220 | TODO_ITEMS[2],
221 | ]);
222 | await checkTodosInLocalStorage(page, 'buy some sausages');
223 | });
224 |
225 | test('should trim entered text', async ({ page }) => {
226 | const todoItems = page.getByTestId('todo-item');
227 | await todoItems.nth(1).dblclick();
228 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages ');
229 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter');
230 |
231 | await expect(todoItems).toHaveText([
232 | TODO_ITEMS[0],
233 | 'buy some sausages',
234 | TODO_ITEMS[2],
235 | ]);
236 | await checkTodosInLocalStorage(page, 'buy some sausages');
237 | });
238 |
239 | test('should remove the item if an empty text string was entered', async ({ page }) => {
240 | const todoItems = page.getByTestId('todo-item');
241 | await todoItems.nth(1).dblclick();
242 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('');
243 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter');
244 |
245 | await expect(todoItems).toHaveText([
246 | TODO_ITEMS[0],
247 | TODO_ITEMS[2],
248 | ]);
249 | });
250 |
251 | test('should cancel edits on escape', async ({ page }) => {
252 | const todoItems = page.getByTestId('todo-item');
253 | await todoItems.nth(1).dblclick();
254 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
255 | await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape');
256 | await expect(todoItems).toHaveText(TODO_ITEMS);
257 | });
258 | });
259 |
260 | test.describe('Counter', () => {
261 | test('should display the current number of todo items', async ({ page }) => {
262 | // create a new todo locator
263 | const newTodo = page.getByPlaceholder('What needs to be done?');
264 |
265 | // create a todo count locator
266 | const todoCount = page.getByTestId('todo-count')
267 |
268 | await newTodo.fill(TODO_ITEMS[0]);
269 | await newTodo.press('Enter');
270 | await expect(todoCount).toContainText('1');
271 |
272 | await newTodo.fill(TODO_ITEMS[1]);
273 | await newTodo.press('Enter');
274 | await expect(todoCount).toContainText('2');
275 |
276 | await checkNumberOfTodosInLocalStorage(page, 2);
277 | });
278 | });
279 |
280 | test.describe('Clear completed button', () => {
281 | test.beforeEach(async ({ page }) => {
282 | await createDefaultTodos(page);
283 | });
284 |
285 | test('should display the correct text', async ({ page }) => {
286 | await page.locator('.todo-list li .toggle').first().check();
287 | await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible();
288 | });
289 |
290 | test('should remove completed items when clicked', async ({ page }) => {
291 | const todoItems = page.getByTestId('todo-item');
292 | await todoItems.nth(1).getByRole('checkbox').check();
293 | await page.getByRole('button', { name: 'Clear completed' }).click();
294 | await expect(todoItems).toHaveCount(2);
295 | await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
296 | });
297 |
298 | test('should be hidden when there are no items that are completed', async ({ page }) => {
299 | await page.locator('.todo-list li .toggle').first().check();
300 | await page.getByRole('button', { name: 'Clear completed' }).click();
301 | await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden();
302 | });
303 | });
304 |
305 | test.describe('Persistence', () => {
306 | test('should persist its data', async ({ page }) => {
307 | // create a new todo locator
308 | const newTodo = page.getByPlaceholder('What needs to be done?');
309 |
310 | for (const item of TODO_ITEMS.slice(0, 2)) {
311 | await newTodo.fill(item);
312 | await newTodo.press('Enter');
313 | }
314 |
315 | const todoItems = page.getByTestId('todo-item');
316 | const firstTodoCheck = todoItems.nth(0).getByRole('checkbox');
317 | await firstTodoCheck.check();
318 | await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
319 | await expect(firstTodoCheck).toBeChecked();
320 | await expect(todoItems).toHaveClass(['completed', '']);
321 |
322 | // Ensure there is 1 completed item.
323 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
324 |
325 | // Now reload.
326 | await page.reload();
327 | await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
328 | await expect(firstTodoCheck).toBeChecked();
329 | await expect(todoItems).toHaveClass(['completed', '']);
330 | });
331 | });
332 |
333 | test.describe('Routing', () => {
334 | test.beforeEach(async ({ page }) => {
335 | await createDefaultTodos(page);
336 | // make sure the app had a chance to save updated todos in storage
337 | // before navigating to a new view, otherwise the items can get lost :(
338 | // in some frameworks like Durandal
339 | await checkTodosInLocalStorage(page, TODO_ITEMS[0]);
340 | });
341 |
342 | test('should allow me to display active items', async ({ page }) => {
343 | const todoItem = page.getByTestId('todo-item');
344 | await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
345 |
346 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
347 | await page.getByRole('link', { name: 'Active' }).click();
348 | await expect(todoItem).toHaveCount(2);
349 | await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
350 | });
351 |
352 | test('should respect the back button', async ({ page }) => {
353 | const todoItem = page.getByTestId('todo-item');
354 | await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
355 |
356 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
357 |
358 | await test.step('Showing all items', async () => {
359 | await page.getByRole('link', { name: 'All' }).click();
360 | await expect(todoItem).toHaveCount(3);
361 | });
362 |
363 | await test.step('Showing active items', async () => {
364 | await page.getByRole('link', { name: 'Active' }).click();
365 | });
366 |
367 | await test.step('Showing completed items', async () => {
368 | await page.getByRole('link', { name: 'Completed' }).click();
369 | });
370 |
371 | await expect(todoItem).toHaveCount(1);
372 | await page.goBack();
373 | await expect(todoItem).toHaveCount(2);
374 | await page.goBack();
375 | await expect(todoItem).toHaveCount(3);
376 | });
377 |
378 | test('should allow me to display completed items', async ({ page }) => {
379 | await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
380 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
381 | await page.getByRole('link', { name: 'Completed' }).click();
382 | await expect(page.getByTestId('todo-item')).toHaveCount(1);
383 | });
384 |
385 | test('should allow me to display all items', async ({ page }) => {
386 | await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
387 | await checkNumberOfCompletedTodosInLocalStorage(page, 1);
388 | await page.getByRole('link', { name: 'Active' }).click();
389 | await page.getByRole('link', { name: 'Completed' }).click();
390 | await page.getByRole('link', { name: 'All' }).click();
391 | await expect(page.getByTestId('todo-item')).toHaveCount(3);
392 | });
393 |
394 | test('should highlight the currently applied filter', async ({ page }) => {
395 | await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected');
396 |
397 | //create locators for active and completed links
398 | const activeLink = page.getByRole('link', { name: 'Active' });
399 | const completedLink = page.getByRole('link', { name: 'Completed' });
400 | await activeLink.click();
401 |
402 | // Page change - active items.
403 | await expect(activeLink).toHaveClass('selected');
404 | await completedLink.click();
405 |
406 | // Page change - completed items.
407 | await expect(completedLink).toHaveClass('selected');
408 | });
409 | });
410 |
411 | async function createDefaultTodos(page) {
412 | // create a new todo locator
413 | const newTodo = page.getByPlaceholder('What needs to be done?');
414 |
415 | for (const item of TODO_ITEMS) {
416 | await newTodo.fill(item);
417 | await newTodo.press('Enter');
418 | }
419 | }
420 |
421 | /**
422 | * @param {import('@playwright/test').Page} page
423 | * @param {number} expected
424 | */
425 | async function checkNumberOfTodosInLocalStorage(page, expected) {
426 | return await page.waitForFunction(e => {
427 | return JSON.parse(localStorage['react-todos']).length === e;
428 | }, expected);
429 | }
430 |
431 | /**
432 | * @param {import('@playwright/test').Page} page
433 | * @param {number} expected
434 | */
435 | async function checkNumberOfCompletedTodosInLocalStorage(page, expected) {
436 | return await page.waitForFunction(e => {
437 | return JSON.parse(localStorage['react-todos']).filter(i => i.completed).length === e;
438 | }, expected);
439 | }
440 |
441 | /**
442 | * @param {import('@playwright/test').Page} page
443 | * @param {string} title
444 | */
445 | async function checkTodosInLocalStorage(page, title) {
446 | return await page.waitForFunction(t => {
447 | return JSON.parse(localStorage['react-todos']).map(i => i.title).includes(t);
448 | }, title);
449 | }
450 |
--------------------------------------------------------------------------------