commit d659852b9d1910ef5cc3d7737889646f3fbb44ad Author: Kira Date: Wed Sep 13 15:21:21 2023 -0700 Initial Commit; creating Playwright tests diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75e854d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b88b38d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,67 @@ +{ + "name": "automated-web-testing-with-javascript-and-playwright", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "automated-web-testing-with-javascript-and-playwright", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.37.1" + } + }, + "node_modules/@playwright/test": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.1.tgz", + "integrity": "sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.37.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/@types/node": { + "version": "20.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz", + "integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright-core": { + "version": "1.37.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.1.tgz", + "integrity": "sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d2c8376 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "automated-web-testing-with-javascript-and-playwright", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test":"playwright test --headed" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.37.1" + } +} diff --git a/page-objects/ProductsPage.js b/page-objects/ProductsPage.js new file mode 100644 index 0000000..0f5cf82 --- /dev/null +++ b/page-objects/ProductsPage.js @@ -0,0 +1,27 @@ +import { expect } from "@playwright/test" + +export class ProductsPage { + + constructor(page) { + this.page = page + this.addButtons = page.locator('[data-qa="product-button"]') + } + + visit = async () => { + await this.page.goto("/") + //console.log("Buttons --- " + await this.page.locator('[data-qa="product-button"]').count()) + } + + addProductToBasket = async (productIndex) => { + //data-qa="product-button" + console.log("--- addProductToBasket("+ productIndex +")") + + const specificAddButton = this.addButtons.nth(productIndex) + await specificAddButton.waitFor() + await expect(specificAddButton).toHaveText("Add To Basket") + await specificAddButton.click() + await expect(specificAddButton).toHaveText("Remove from Basket") + + } + +} \ No newline at end of file diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..ab12500 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,109 @@ +// @ts-check +const { devices } = require('@playwright/test'); + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + + +/** + * @see https://playwright.dev/docs/test-configuration + * @type {import('@playwright/test').PlaywrightTestConfig} + */ +const config = { + testDir: './tests', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000 + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'line', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://localhost:2221', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + + // { + // name: 'firefox', + // use: { + // ...devices['Desktop Firefox'], + // }, + // }, + + // { + // name: 'webkit', + // use: { + // ...devices['Desktop Safari'], + // }, + // }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // port: 3000, + // }, +}; + +module.exports = config; diff --git a/tests/example.spec.js b/tests/example.spec.js new file mode 100644 index 0000000..fa038c7 --- /dev/null +++ b/tests/example.spec.js @@ -0,0 +1,44 @@ +// @ts-check +// const { test, expect } = require('@playwright/test'); + +// test.skip('homepage has title and links to intro page', async ({ page }) => { +// await page.goto('https://playwright.dev/'); + +// // Expect a title "to contain" a substring. +// await expect(page).toHaveTitle(/Playwright/); + +// // create a locator +// const getStarted = page.getByRole('link', { name: 'Get started' }); + +// // Expect an attribute "to be strictly equal" to the value. +// await expect(getStarted).toHaveAttribute('href', '/docs/intro'); + +// // Click the get started link. +// await getStarted.click(); + +// // Expects the URL to contain intro. +// await expect(page).toHaveURL(/.*intro/); + +// await page.pause(); +// }); + +// test.skip('2', async ({ page }) => { +// await page.goto('https://playwright.dev/'); + +// // Expect a title "to contain" a substring. +// await expect(page).toHaveTitle(/Playwright/); + +// // create a locator +// const getStarted = page.getByRole('link', { name: 'Get started' }); + +// // Expect an attribute "to be strictly equal" to the value. +// await expect(getStarted).toHaveAttribute('href', '/docs/intro'); + +// // Click the get started link. +// await getStarted.click(); + +// // Expects the URL to contain intro. +// await expect(page).toHaveURL(/.*intro/); + +// await page.pause(); +// }); diff --git a/tests/new_user_full_journey.spec.js b/tests/new_user_full_journey.spec.js new file mode 100644 index 0000000..5c2a332 --- /dev/null +++ b/tests/new_user_full_journey.spec.js @@ -0,0 +1,19 @@ +import {test} from "@playwright/test" +import {ProductsPage} from "../page-objects/ProductsPage.js" + +test.only("New user full end-to-end test journey", async ({page}) => { + + // init + const productsPage = new ProductsPage(page) + + // 1. Visit + await productsPage.visit() + // 2. Add to Basket + await productsPage.addProductToBasket(0) + await productsPage.addProductToBasket(1) + await productsPage.addProductToBasket(2) + + + // Hold + await page.pause(); +}) \ No newline at end of file diff --git a/tests/product_page_add_item.spec.js b/tests/product_page_add_item.spec.js new file mode 100644 index 0000000..5e6fa3d --- /dev/null +++ b/tests/product_page_add_item.spec.js @@ -0,0 +1,37 @@ +import { test, expect } from "@playwright/test" + +test("Product Page: Add To Basket", async ({ page }) => { + await page.goto("/") + + //const addToBasketButton = page.locator('div').filter({ hasText: /^499\$Add to Basket$/ }).getByRole('button') + + const addToBasketButton = page.locator('[data-qa="product-button"]').first() + const basketCounter = page.locator('[data-qa="header-basket-count"]') + const checkoutLink = page.getByRole('link', { name: 'Checkout' }) + + addToBasketButton.waitFor() + basketCounter.waitFor() + checkoutLink.waitFor() + + await expect(addToBasketButton).toHaveText("Add to Basket") + await expect(basketCounter).toHaveText("0") + + await addToBasketButton.click() + await expect(addToBasketButton).toHaveText("Remove from Basket") + await expect(basketCounter).toHaveText("1") + + await page.pause(); + + await checkoutLink.click() + await page.waitForURL("/basket") + + + //console.log("Buttons --- " + await page.locator('[data-qa="product-button"]').count()) +}) + + +// productPage.visit() +// productPage.sortProductsByCheapest +// productPage.addItemToBasket(1) +// navigation.moveToCheckout() +// basket.removeCheapestItem()