Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
URL=https://practicesoftwaretesting.com
URL=https://practicesoftwaretesting.com
LOGIN_PREFIX=/auth/login
USER_EMAIL=customer@practicesoftwaretesting.com
USER_PASSWORD=welcome01
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Binary file added example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "",
Expand Down
10 changes: 5 additions & 5 deletions pages/login/loginPage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Locator, type Page } from "@playwright/test";
import { Locator, Page } from "@playwright/test";

export class LoginPage {
readonly page: Page;
Expand All @@ -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();
}
}
13 changes: 7 additions & 6 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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"] },
},
// {
Expand Down
Binary file added simple-test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/api/api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions tests/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
78 changes: 41 additions & 37 deletions tests/checkout/checkoutChallenge.spec.ts
Original file line number Diff line number Diff line change
@@ -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");
}
);
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions tests/fixtures/example.spec.ts
Original file line number Diff line number Diff line change
@@ -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" });
});
16 changes: 16 additions & 0 deletions tests/fixtures/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { test as base } from "@playwright/test";

type Fixture = {
whatYouSay: string;
};

const fixture = base.extend<Fixture>({

whatYouSay: async ({}, use: any) => {
console.log("What do you say?");
await use();
console.log("Finished saying.");
}
});

export default fixture;
45 changes: 45 additions & 0 deletions tests/fixtures/setLoginContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test as base, expect } from "@playwright/test";

type LoginContext = {
loginFixture: string;
};

type WorkerContext = {
workerFixture: string;
};

const loginContext = base.extend<LoginContext, WorkerContext>({
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;
28 changes: 19 additions & 9 deletions tests/homepage/home.spec.ts
Original file line number Diff line number Diff line change
@@ -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", {
Expand Down Expand Up @@ -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");
}
);
});
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 7 additions & 4 deletions tests/login/login.spec.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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");
});
Loading