diff --git a/.env b/.env index c7c3cba..6801219 100644 --- a/.env +++ b/.env @@ -1 +1,4 @@ -URL=https://practicesoftwaretesting.com \ No newline at end of file +URL=https://practicesoftwaretesting.com +LOGIN_PREFIX=/auth/login +USER_EMAIL=customer@practicesoftwaretesting.com +USER_PASSWORD=welcome01 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4dd9d6b..2627b84 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ "files.autoSave": "afterDelay", "screencastMode.onlyKeyboardShortcuts": true, "terminal.integrated.fontSize": 18, - "workbench.colorTheme": "Visual Studio Dark", + "workbench.colorTheme": "GitHub Dark", "workbench.fontAliasing": "antialiased", "workbench.statusBar.visible": true, "liveServer.settings.root": "/docs", diff --git a/example.png b/example.png new file mode 100644 index 0000000..e0116a6 Binary files /dev/null and b/example.png differ diff --git a/package.json b/package.json index f9eee43..1f6c954 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ "test:first": "npx playwright test --grep @first", "test:local": "BASE_URL=http://localhost:4200 npx playwright test", "test:report": "npx playwright test && npx playwright show-report", - "test:ui": "npx playwright test --ui" + "test:ui": "npx playwright test --ui", + "codegen": "npx playwright codegen", + "install:drivers": "npx playwright install", + "update:snapshots": "npx playwright test --update-snapshots" }, "keywords": [], "author": "", diff --git a/pages/login/loginPage.ts b/pages/login/loginPage.ts index aeaca3e..a1869cb 100644 --- a/pages/login/loginPage.ts +++ b/pages/login/loginPage.ts @@ -1,4 +1,4 @@ -import { type Locator, type Page } from "@playwright/test"; +import { Locator, Page } from "@playwright/test"; export class LoginPage { readonly page: Page; @@ -13,12 +13,12 @@ export class LoginPage { } async goto() { - await this.page.goto(process.env.URL + "/auth/login"); + await this.page.goto(`${process.env.URL}${process.env.LOGIN_PREFIX}`); } - async login(email: string, password: string) { - await this.emailInput.fill(email); - await this.passwordInput.fill(password); + async login(email?: string, password?: string) { + await this.emailInput.fill(email ?? process.env.USER_EMAIL ?? ""); + await this.passwordInput.fill(password ?? process.env.USER_PASSWORD ?? ""); await this.loginButton.click(); } } diff --git a/playwright.config.ts b/playwright.config.ts index e1d54b5..31d37d6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -15,12 +15,13 @@ export default defineConfig({ timeout: 30_000, globalTimeout: 10 * 60 * 1000, testDir: "./tests", + testMatch: /.*\.spec\.ts/, /* 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 2 times and locally 1 time */ - retries: process.env.CI ? 2 : 1, + retries: process.env.CI ? 3 : 1, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ @@ -41,13 +42,13 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ - { - name: "setup", - testMatch: /.*\.setup\.ts/, - }, + // { + // name: "setup", + // testMatch: /.*\.setup\.ts/, + // }, { name: "chromium", - dependencies: ["setup"], + // dependencies: ["setup"], use: { ...devices["Desktop Chrome"], permissions: ["clipboard-read"] }, }, // { diff --git a/simple-test.png b/simple-test.png new file mode 100644 index 0000000..6ce7738 Binary files /dev/null and b/simple-test.png differ diff --git a/tests/api/api.spec.ts b/tests/api/api.spec.ts index b57f866..3061bf1 100644 --- a/tests/api/api.spec.ts +++ b/tests/api/api.spec.ts @@ -4,7 +4,7 @@ test("GET /products", async ({ request }) => { const apiUrl = "https://api.practicesoftwaretesting.com"; const response = await request.get(apiUrl + "/products"); - expect(response.status()).toBe(200); + expect(response.status()).toBe(200 * 1); const body = await response.json(); expect(body.data.length).toBe(9); expect(body.total).toBe(50); diff --git a/tests/auth.setup.ts b/tests/auth.setup.ts index fc44e9b..468054c 100644 --- a/tests/auth.setup.ts +++ b/tests/auth.setup.ts @@ -1,11 +1,12 @@ import { test as setup, expect } from "@playwright/test"; -setup("Create customer 01 auth", async ({ page, context }) => { +setup.skip("Create customer 01 auth", async ({ page, context }) => { const email = "customer@practicesoftwaretesting.com"; const password = "welcome01"; const customer01AuthFile = ".auth/customer01.json"; + const baseURL = `${setup.info().project?.use?.baseURL}/auth/login`; - await page.goto("https://practicesoftwaretesting.com/auth/login"); + await page.goto(baseURL); await page.getByTestId("email").fill(email); await page.getByTestId("password").fill(password); diff --git a/tests/checkout/checkoutChallenge.spec.ts b/tests/checkout/checkoutChallenge.spec.ts index fa7f95c..4d38df5 100644 --- a/tests/checkout/checkoutChallenge.spec.ts +++ b/tests/checkout/checkoutChallenge.spec.ts @@ -1,43 +1,47 @@ import { test, expect } from "@playwright/test"; +import loginContext from "../fixtures/setLoginContext"; -test.describe("Checkout challenge", async () => { - test.use({ storageState: ".auth/customer01.json" }); - - test.beforeEach(async ({ page }) => { +loginContext.describe("Checkout challenge", async () => { + loginContext.beforeEach(async ({ page, loginFixture }) => { await page.goto("https://practicesoftwaretesting.com"); }); - test("buy now pay later", async ({ page, headless }) => { - await page.getByText("Claw Hammer with Shock Reduction Grip").click(); - await page.getByTestId("add-to-cart").click(); - await expect(page.getByTestId("cart-quantity")).toHaveText("1"); - await page.getByTestId("nav-cart").click(); - await page.getByTestId("proceed-1").click(); - await page.getByTestId("proceed-2").click(); - await expect( - page.locator(".step-indicator").filter({ hasText: "2" }) - ).toHaveCSS("background-color", "rgb(51, 153, 51)"); - await page.getByTestId("address").fill("123 Testing Way"); - await page.getByTestId("city").fill("Sacramento"); - await page.getByTestId("state").fill("California"); - await page.getByTestId("country").fill("USA"); - await page.getByTestId("postcode").fill("98765"); - await page.getByTestId("proceed-3").click(); - await expect(page.getByTestId("finish")).toBeDisabled(); - await page.getByTestId("payment-method").selectOption("Buy Now Pay Later"); - await page - .getByTestId("monthly_installments") - .selectOption("6 Monthly Installments"); - await page.getByTestId("finish").click(); - await expect(page.locator(".help-block")).toHaveText( - "Payment was successful" - ); - headless - ? await test.step("visual test", async () => { - await expect(page).toHaveScreenshot("checkout.png", { - mask: [page.getByTitle("Practice Software Testing - Toolshop")], - }); - }) - : console.log("Running in Headed mode, no screenshot comparison"); - }); + loginContext( + "buy now pay later", + async ({ loginFixture, page, headless }) => { + await page.getByText("Claw Hammer with Shock Reduction Grip").click(); + await page.getByTestId("add-to-cart").click(); + await expect(page.getByTestId("cart-quantity")).toHaveText("1"); + await page.getByTestId("nav-cart").click(); + await page.getByTestId("proceed-1").click(); + await page.getByTestId("proceed-2").click(); + await expect( + page.locator(".step-indicator").filter({ hasText: "2" }) + ).toHaveCSS("background-color", "rgb(51, 153, 51)"); + await page.getByTestId("street").fill("123 Testing Way"); + await page.getByTestId("city").fill("Sacramento"); + await page.getByTestId("state").fill("California"); + await page.getByTestId("country").fill("USA"); + await page.getByTestId(/postal/i).fill("98765"); + await page.getByTestId("proceed-3").click(); + await expect(page.getByTestId("finish")).toBeDisabled(); + await page + .getByTestId("payment-method") + .selectOption("Buy Now Pay Later"); + await page + .getByTestId("monthly_installments") + .selectOption("6 Monthly Installments"); + await page.getByTestId("finish").click(); + await expect(page.locator(".help-block")).toHaveText( + "Payment was successful" + ); + headless + ? await test.step("visual test", async () => { + await expect(page).toHaveScreenshot("checkout1.png", { + mask: [page.getByTitle("Practice Software Testing - Toolshop")], + }); + }) + : console.log("Running in Headed mode, no screenshot comparison"); + } + ); }); diff --git a/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout-chromium-win32.png b/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout-chromium-win32.png new file mode 100644 index 0000000..ad3c2fb Binary files /dev/null and b/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout-chromium-win32.png differ diff --git a/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout1-chromium-win32.png b/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout1-chromium-win32.png new file mode 100644 index 0000000..ce9e6f1 Binary files /dev/null and b/tests/checkout/checkoutChallenge.spec.ts-snapshots/checkout1-chromium-win32.png differ diff --git a/tests/fixtures/example.spec.ts b/tests/fixtures/example.spec.ts new file mode 100644 index 0000000..2a447e1 --- /dev/null +++ b/tests/fixtures/example.spec.ts @@ -0,0 +1,41 @@ +import fixture from "./fixture"; +import loginContext from "./setLoginContext"; +import { test, expect } from "@playwright/test"; + +fixture.skip("say hello", async ({ whatYouSay }) => { + console.log("Hello, Playwright!"); +}); + +fixture.skip("say where is my candle", async ({}) => { + console.log("Where is my candle?"); +}); + +fixture.skip("say goodbye", async ({}) => { + console.log("Goodbye, Playwright!"); +}); + +loginContext("login and say hello worker01", async ({ loginFixture, workerFixture, page }: { loginFixture: any; workerFixture: any }) => { + console.log(loginFixture); + await page.locator("body").screenshot({ path: "example.png" }); + console.log("Hello after login fixture!"); + console.log(workerFixture); +}); + +loginContext("login and say hello worker02", async ({ loginFixture, workerFixture }: { loginFixture: any; workerFixture: any }) => { + console.log(loginFixture); + console.log("Hello after login fixture!"); + console.log(workerFixture); +}); + +test("just a simple test", async ({ page }) => { + page.goto("https://playwright.dev/docs/locators"); + + await expect(page.getByRole("heading", { name: "Sign up" })).toBeVisible(); + await page.getByRole("checkbox", { name: "Subscribe" }).check(); + + await expect(page.getByRole("checkbox", { name: "Subscribe" }), "CheckBox is not Checked!").toBeChecked(); + + await page.getByRole("button", { name: /submit/i }).click(); + + await page.locator("body").getByRole("checkbox", { name: "Subscribe" }).screenshot({ path: "simple-test.png" }); +}); diff --git a/tests/fixtures/fixture.ts b/tests/fixtures/fixture.ts new file mode 100644 index 0000000..c49836a --- /dev/null +++ b/tests/fixtures/fixture.ts @@ -0,0 +1,16 @@ +import { test as base } from "@playwright/test"; + +type Fixture = { + whatYouSay: string; +}; + +const fixture = base.extend({ + + whatYouSay: async ({}, use: any) => { + console.log("What do you say?"); + await use(); + console.log("Finished saying."); + } +}); + +export default fixture; diff --git a/tests/fixtures/setLoginContext.ts b/tests/fixtures/setLoginContext.ts new file mode 100644 index 0000000..9933763 --- /dev/null +++ b/tests/fixtures/setLoginContext.ts @@ -0,0 +1,45 @@ +import { test as base, expect } from "@playwright/test"; + +type LoginContext = { + loginFixture: string; +}; + +type WorkerContext = { + workerFixture: string; +}; + +const loginContext = base.extend({ + loginFixture: async ({ page, context }, use: any) => { + // Setup code for the fixture can go here + + const email = "customer@practicesoftwaretesting.com"; + const password = "welcome01"; + const customer01AuthFile = ".auth/customer01_fixture.json"; + const baseURL = "https://practicesoftwaretesting.com/auth/login"; + + await page.goto(baseURL); + + await page.getByTestId("email").fill(email); + await page.getByTestId("password").fill(password); + await page.getByTestId("login-submit").click(); + + await expect(page.getByTestId("nav-menu")).toContainText("Jane Doe"); + await context.storageState({ path: customer01AuthFile }); + + // end of base coding + await use(); + console.log("Tearing down login fixture with context."); + }, + workerFixture: [ + async ({}, use: any, workerInfo) => { + const message = `Setting up worker fixture. ${workerInfo.workerIndex}`; + console.log(message); + // Setup code for the worker fixture can go here + await use(message); + console.log("Tearing down worker fixture."); + }, + { scope: "worker" }, + ], +}); + +export default loginContext; diff --git a/tests/homepage/home.spec.ts b/tests/homepage/home.spec.ts index a9c6a60..d8acade 100644 --- a/tests/homepage/home.spec.ts +++ b/tests/homepage/home.spec.ts @@ -1,10 +1,16 @@ import { test, expect } from "@playwright/test"; +import loginContext from "../fixtures/setLoginContext"; -test.describe("Home page with no auth", () => { +test.describe.parallel("Home page with no auth", () => { test.beforeEach(async ({ page }) => { await page.goto("https://practicesoftwaretesting.com/"); + await page.waitForLoadState("networkidle"); }); + test.afterEach(async ({ page }) => { + console.log(`Finished test: ${test.info().title}`); + }); + test("visual test", async ({ page }) => { await page.waitForLoadState("networkidle"); await expect(page).toHaveScreenshot("home-page-no-auth.png", { @@ -33,24 +39,28 @@ test.describe("Home page with no auth", () => { await page.getByTestId("search-query").fill("Thor Hammer"); await page.getByTestId("search-submit").click(); await expect(productGrid.getByRole("link")).toHaveCount(1); + expect(await productGrid.getByRole("link").count()).toBe(1); await expect(page.getByAltText("Thor Hammer")).toBeVisible(); }); }); -test.describe("Home page customer 01 auth", () => { - test.use({ storageState: ".auth/customer01.json" }); - test.beforeEach(async ({ page }) => { +loginContext.describe("Home page customer 01 auth", () => { + loginContext.beforeEach(async ({ page }) => { await page.goto("https://practicesoftwaretesting.com/"); }); - test("visual test authorized", async ({ page }) => { + loginContext("visual test authorized", async ({ page }) => { await page.waitForLoadState("networkidle"); await expect(page).toHaveScreenshot("home-page-customer01.png", { mask: [page.getByTitle("Practice Software Testing - Toolshop")], }); }); - test("check customer 01 is signed in", async ({ page }) => { - await expect(page.getByTestId("nav-sign-in")).not.toBeVisible(); - await expect(page.getByTestId("nav-menu")).toContainText("Jane Doe"); - }); + + loginContext( + "check customer 01 is signed in", + async ({ loginFixture, page }) => { + await expect(page.getByTestId("nav-sign-in")).not.toBeVisible(); + await expect(page.getByTestId("nav-menu")).toContainText("Jane Doe"); + } + ); }); diff --git a/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-darwin.png b/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-darwin.png deleted file mode 100644 index 053d2eb..0000000 Binary files a/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-darwin.png and /dev/null differ diff --git a/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-win32.png b/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-win32.png new file mode 100644 index 0000000..2ac2146 Binary files /dev/null and b/tests/homepage/home.spec.ts-snapshots/home-page-customer01-chromium-win32.png differ diff --git a/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-darwin.png b/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-darwin.png deleted file mode 100644 index 055d140..0000000 Binary files a/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-darwin.png and /dev/null differ diff --git a/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-win32.png b/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-win32.png new file mode 100644 index 0000000..3cca759 Binary files /dev/null and b/tests/homepage/home.spec.ts-snapshots/home-page-no-auth-chromium-win32.png differ diff --git a/tests/login/login.spec.ts b/tests/login/login.spec.ts index 28adc0d..1ba5621 100644 --- a/tests/login/login.spec.ts +++ b/tests/login/login.spec.ts @@ -1,7 +1,7 @@ import { test, expect } from "@playwright/test"; import { LoginPage } from "../../pages/login/loginPage"; -test("login without page object", async ({ page }) => { +test("login without page object", { tag: ["@no_pom", "@login"] }, async ({ page }) => { await page.goto("https://practicesoftwaretesting.com/"); await page.locator('[data-test="nav-sign-in"]').click(); await page @@ -20,8 +20,11 @@ test("login without page object", async ({ page }) => { test("Login with page object", async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.goto(); - await loginPage.emailInput.fill("customer@practicesoftwaretesting.com"); - await loginPage.passwordInput.fill("welcome01"); - await loginPage.loginButton.click(); + // await loginPage.emailInput.fill("customer@practicesoftwaretesting.com"); + // await loginPage.passwordInput.fill("welcome01"); + // await loginPage.loginButton.click(); + + await loginPage.login(); + await expect(page.getByTestId("nav-menu")).toContainText("Jane Doe"); }); diff --git a/tests/saptest/saptest.spec.ts b/tests/saptest/saptest.spec.ts new file mode 100644 index 0000000..bcc1c06 --- /dev/null +++ b/tests/saptest/saptest.spec.ts @@ -0,0 +1,49 @@ +import { test, expect } from "@playwright/test"; + +test("test", { tag: "@sap-page"}, async ({ page }) => { + await page.goto("https://adg08101.github.io/react-vite/"); + await page.getByRole("link", { name: "Form" }).click(); + await page.getByPlaceholder("Username").click(); + await page.getByPlaceholder("Username").fill("none__"); + await page.getByPlaceholder("Username").press("ArrowLeft"); + await page.getByPlaceholder("Username").fill("none_to_"); + await page.getByPlaceholder("Username").press("ArrowRight"); + await page.getByPlaceholder("Username").fill("none_to_add"); + await page.getByPlaceholder("Username").press("Tab"); + await page.getByPlaceholder("Email").fill("adg08101"); + await page.getByPlaceholder("Email").press("Alt+6"); + await page.getByPlaceholder("Email").press("Alt+4"); + await page.getByPlaceholder("Email").fill("adg08101@gmail./com"); + await page.getByPlaceholder("Email").press("ArrowLeft"); + await page.getByPlaceholder("Email").press("ArrowLeft"); + await page.getByPlaceholder("Email").press("ArrowLeft"); + await page.getByPlaceholder("Email").fill("adg08101@gmail.ccom"); + await page.getByPlaceholder("Email").press("End"); + await page.getByPlaceholder("Email").fill("adg08101@gmail.cco"); + await page.getByPlaceholder("Email").press("ArrowLeft"); + await page.getByPlaceholder("Email").press("ArrowLeft"); + await page.getByPlaceholder("Email").fill("adg08101@gmail.co"); + await page.getByPlaceholder("Email").press("End"); + await page.getByPlaceholder("Email").fill("adg08101@gmail.com"); + await page.getByPlaceholder("Email").press("Tab"); + await page.getByPlaceholder("Password").fill("noe__"); + await page.getByPlaceholder("Password").press("ArrowLeft"); + await page.getByPlaceholder("Password").fill("noe_to_"); + await page.getByPlaceholder("Password").press("ArrowRight"); + await page.getByPlaceholder("Password").fill("noe_to_add"); + await page.getByRole("combobox").selectOption("Cuba"); + await page.getByRole("button", { name: "Send" }).click(); + await page.locator("div:nth-child(2) > button:nth-child(5)").dblclick(); + page.once("dialog", (dialog) => { + console.log(`Dialog message: ${dialog.message()}`); + dialog.dismiss().catch(() => {}); + }); + await page.locator("div:nth-child(2) > button").first().click(); + await page.getByRole("heading", { name: "Wireless Mouse" }).click(); + await page.getByText("Total price: $").click(); + page.once("dialog", (dialog) => { + console.log(`Dialog message: ${dialog.message()}`); + dialog.dismiss().catch(() => {}); + }); + await page.getByRole("button", { name: "Remove" }).click(); +});