Skip to content

Commit

Permalink
added example test
Browse files Browse the repository at this point in the history
  • Loading branch information
abhaybharti committed Jan 30, 2024
1 parent e8bbed0 commit 4c12123
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 52 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ _☝ If you like the project, please give a ⭐ on [GitHub](https://github.com/a

### Sample Web Test

`test('Navigate to Google @smoke', async({page}) => { await page.goto('https://www.google.com/') await expect(page).toHaveTitle('Google') })`
> Note: Refer to [sample-web-test](https://github.com/abhaybharti/playwright-framework-template/tree/master/src/tests/web/example)
### Sample Web Load Test

Expand Down
48 changes: 26 additions & 22 deletions src/helper/api/apiHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ import { StringLiteral } from "typescript";
export class ApiHelper {
private apiContext: any;

/**
* The constructor function initializes a new context for the API.
* @param {any} apiContext - The `apiContext` parameter is an object that represents the context of an
* API. It is used to store and manage information related to the API, such as authentication
* credentials, request headers, and other configuration settings.
*/
/**
* The constructor function initializes a new context for the API.
* @param {any} apiContext - The `apiContext` parameter is an object that represents the context of an
* API. It is used to store and manage information related to the API, such as authentication
* credentials, request headers, and other configuration settings.
*/
constructor(apiContext: any) {
this.apiContext = apiContext.newContext();
}

/**
* The function `hitApiEndPoint` is an asynchronous function that takes in an operation type, an
* endpoint, a payload, and a status code, and then invokes the corresponding API method based on the
* operation type.
* @param {string} operationType - The `operationType` parameter is a string that specifies the type of
* operation to be performed on the API endpoint. It can have one of the following values: "get",
* "post", "delete", or "put".
* @param {string} endPoint - The `endPoint` parameter is a string that represents the URL or endpoint
* of the API that you want to hit. It specifies the location where the API is hosted and the specific
* resource or action you want to perform.
* @param {object} payload - The `payload` parameter is an object that contains the data to be sent in
* the request body for POST and PUT operations. It can include any relevant information that needs to
* be sent to the API endpoint.
* @param {number} statusCode - The `statusCode` parameter is the expected HTTP status code that the
* API endpoint should return.
*/
/**
* The function `hitApiEndPoint` is an asynchronous function that takes in an operation type, an
* endpoint, a payload, and a status code, and then invokes the corresponding API method based on the
* operation type.
* @param {string} operationType - The `operationType` parameter is a string that specifies the type of
* operation to be performed on the API endpoint. It can have one of the following values: "get",
* "post", "delete", or "put".
* @param {string} endPoint - The `endPoint` parameter is a string that represents the URL or endpoint
* of the API that you want to hit. It specifies the location where the API is hosted and the specific
* resource or action you want to perform.
* @param {object} payload - The `payload` parameter is an object that contains the data to be sent in
* the request body for POST and PUT operations. It can include any relevant information that needs to
* be sent to the API endpoint.
* @param {number} statusCode - The `statusCode` parameter is the expected HTTP status code that the
* API endpoint should return.
*/
async hitApiEndPoint(
operationType: string,
endPoint: string,
Expand Down Expand Up @@ -140,4 +140,8 @@ export class ApiHelper {
`${statusCode} status code was not displayed`
).toBeOK();
}

async getToken() {
return "tokenvalue";
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
// @ts-check
import { test, expect } from "@playwright/test";
import { WebHelper } from "../../../helper/web/webHelper";

test.beforeEach(async ({ page }) => {
await page.goto("https://demo.playwright.dev/todomvc");
});

const TODO_ITEMS = ["buy some cheese", "feed the cat", "book a doctors appointment"];
test("Sample Web Test", async ({ page, browser }) => {
const browserContext = await browser.newContext();

const webHelper = new WebHelper(page, browserContext);
});

const TODO_ITEMS = [
"buy some cheese",
"feed the cat",
"book a doctors appointment",
];

test.describe("New Todo", () => {
test("should allow me to add todo items", async ({ page }) => {
Expand All @@ -24,12 +34,17 @@ test.describe("New Todo", () => {
await newTodo.press("Enter");

// Make sure the list now has two todo items.
await expect(page.getByTestId("todo-title")).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
await expect(page.getByTestId("todo-title")).toHaveText([
TODO_ITEMS[0],
TODO_ITEMS[1],
]);

await checkNumberOfTodosInLocalStorage(page, 2);
});

test("should clear text input field when an item is added", async ({ page }) => {
test("should clear text input field when an item is added", async ({
page,
}) => {
// create a new todo locator
const newTodo = page.getByPlaceholder("What needs to be done?");

Expand All @@ -42,7 +57,9 @@ test.describe("New Todo", () => {
await checkNumberOfTodosInLocalStorage(page, 1);
});

test("should append new items to the bottom of the list", async ({ page }) => {
test("should append new items to the bottom of the list", async ({
page,
}) => {
// Create 3 items.
await createDefaultTodos(page);

Expand Down Expand Up @@ -76,11 +93,17 @@ test.describe("Mark all as completed", () => {
await page.getByLabel("Mark all as complete").check();

// Ensure all todos have 'completed' class.
await expect(page.getByTestId("todo-item")).toHaveClass(["completed", "completed", "completed"]);
await expect(page.getByTestId("todo-item")).toHaveClass([
"completed",
"completed",
"completed",
]);
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
});

test("should allow me to clear the complete state of all items", async ({ page }) => {
test("should allow me to clear the complete state of all items", async ({
page,
}) => {
const toggleAll = page.getByLabel("Mark all as complete");
// Check and then immediately uncheck.
await toggleAll.check();
Expand All @@ -90,7 +113,9 @@ test.describe("Mark all as completed", () => {
await expect(page.getByTestId("todo-item")).toHaveClass(["", "", ""]);
});

test("complete all checkbox should update state when items are completed / cleared", async ({ page }) => {
test("complete all checkbox should update state when items are completed / cleared", async ({
page,
}) => {
const toggleAll = page.getByLabel("Mark all as complete");
await toggleAll.check();
await expect(toggleAll).toBeChecked();
Expand Down Expand Up @@ -168,12 +193,20 @@ test.describe("Item", () => {
const todoItems = page.getByTestId("todo-item");
const secondTodo = todoItems.nth(1);
await secondTodo.dblclick();
await expect(secondTodo.getByRole("textbox", { name: "Edit" })).toHaveValue(TODO_ITEMS[1]);
await secondTodo.getByRole("textbox", { name: "Edit" }).fill("buy some sausages");
await expect(secondTodo.getByRole("textbox", { name: "Edit" })).toHaveValue(
TODO_ITEMS[1]
);
await secondTodo
.getByRole("textbox", { name: "Edit" })
.fill("buy some sausages");
await secondTodo.getByRole("textbox", { name: "Edit" }).press("Enter");

// Explicitly assert the new text value.
await expect(todoItems).toHaveText([TODO_ITEMS[0], "buy some sausages", TODO_ITEMS[2]]);
await expect(todoItems).toHaveText([
TODO_ITEMS[0],
"buy some sausages",
TODO_ITEMS[2],
]);
await checkTodosInLocalStorage(page, "buy some sausages");
});
});
Expand All @@ -191,45 +224,76 @@ test.describe("Editing", () => {
await expect(
todoItem.locator("label", {
hasText: TODO_ITEMS[1],
}),
})
).toBeHidden();
await checkNumberOfTodosInLocalStorage(page, 3);
});

test("should save edits on blur", async ({ page }) => {
const todoItems = page.getByTestId("todo-item");
await todoItems.nth(1).dblclick();
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).fill("buy some sausages");
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).dispatchEvent("blur");

await expect(todoItems).toHaveText([TODO_ITEMS[0], "buy some sausages", TODO_ITEMS[2]]);
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.fill("buy some sausages");
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.dispatchEvent("blur");

await expect(todoItems).toHaveText([
TODO_ITEMS[0],
"buy some sausages",
TODO_ITEMS[2],
]);
await checkTodosInLocalStorage(page, "buy some sausages");
});

test("should trim entered text", async ({ page }) => {
const todoItems = page.getByTestId("todo-item");
await todoItems.nth(1).dblclick();
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).fill(" buy some sausages ");
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).press("Enter");

await expect(todoItems).toHaveText([TODO_ITEMS[0], "buy some sausages", TODO_ITEMS[2]]);
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.fill(" buy some sausages ");
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.press("Enter");

await expect(todoItems).toHaveText([
TODO_ITEMS[0],
"buy some sausages",
TODO_ITEMS[2],
]);
await checkTodosInLocalStorage(page, "buy some sausages");
});

test("should remove the item if an empty text string was entered", async ({ page }) => {
test("should remove the item if an empty text string was entered", async ({
page,
}) => {
const todoItems = page.getByTestId("todo-item");
await todoItems.nth(1).dblclick();
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).fill("");
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).press("Enter");
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.press("Enter");

await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
});

test("should cancel edits on escape", async ({ page }) => {
const todoItems = page.getByTestId("todo-item");
await todoItems.nth(1).dblclick();
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).fill("buy some sausages");
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).press("Escape");
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.fill("buy some sausages");
await todoItems
.nth(1)
.getByRole("textbox", { name: "Edit" })
.press("Escape");
await expect(todoItems).toHaveText(TODO_ITEMS);
});
});
Expand Down Expand Up @@ -261,7 +325,9 @@ test.describe("Clear completed button", () => {

test("should display the correct text", async ({ page }) => {
await page.locator(".todo-list li .toggle").first().check();
await expect(page.getByRole("button", { name: "Clear completed" })).toBeVisible();
await expect(
page.getByRole("button", { name: "Clear completed" })
).toBeVisible();
});

test("should remove completed items when clicked", async ({ page }) => {
Expand All @@ -272,10 +338,14 @@ test.describe("Clear completed button", () => {
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
});

test("should be hidden when there are no items that are completed", async ({ page }) => {
test("should be hidden when there are no items that are completed", async ({
page,
}) => {
await page.locator(".todo-list li .toggle").first().check();
await page.getByRole("button", { name: "Clear completed" }).click();
await expect(page.getByRole("button", { name: "Clear completed" })).toBeHidden();
await expect(
page.getByRole("button", { name: "Clear completed" })
).toBeHidden();
});
});

Expand Down Expand Up @@ -369,7 +439,9 @@ test.describe("Routing", () => {
});

test("should highlight the currently applied filter", async ({ page }) => {
await expect(page.getByRole("link", { name: "All" })).toHaveClass("selected");
await expect(page.getByRole("link", { name: "All" })).toHaveClass(
"selected"
);

//create locators for active and completed links
const activeLink = page.getByRole("link", { name: "Active" });
Expand Down Expand Up @@ -411,7 +483,10 @@ async function checkNumberOfTodosInLocalStorage(page, expected) {
*/
async function checkNumberOfCompletedTodosInLocalStorage(page, expected) {
return await page.waitForFunction((e) => {
return JSON.parse(localStorage["react-todos"]).filter((i) => i.completed).length === e;
return (
JSON.parse(localStorage["react-todos"]).filter((i) => i.completed)
.length === e
);
}, expected);
}

Expand Down
10 changes: 10 additions & 0 deletions src/tests/web/example/frame.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import test from "@playwright/test";
import { Console, log } from "console";

test("iframe", async ({ page }) => {
await page.goto("http://rahulshettyacademy.com/AutomationPractice/");
const framesPage = await page.frameLocator("#courses-iframe");
framesPage.locator("li a[href*='lifetime-access]:visible").click();
const textCheck = await framesPage.locator(".text h2").textContent();
console.log(textCheck);
});
25 changes: 25 additions & 0 deletions src/tests/web/example/networkTest.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import test from "@playwright/test";
import { ApiHelper } from "../../../helper/api/apiHelper";

let token: string;

test.beforeAll(async ({ browser }) => {
const context = await browser.newContext();
const apiContent = await context.newPage();
const apiHelper = new ApiHelper(apiContent);

//save token value returned from getToken() function in token variable
token = await apiHelper.getToken();
});

test("Network Test -> Inject token generated through API into browser", async ({
page,
}) => {
//executed JavaScript to inject token into browser
page.addInitScript((value) => {
window.localStorage.setItem("token", value);
}, token);

//when script hits URL, browser will open as logged in using above generated token
await page.goto("https://www.xxxx.com");
});
29 changes: 29 additions & 0 deletions src/tests/web/example/route.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import test from "@playwright/test";

let fakePayloadOrders = { data: [], message: "No Users" };

test("Intercept Network call and Fake API response", async ({ page }) => {
await page.goto("http://xxxx.com");
await page.route("http://xxxx.com/abc/ird", async (route) => {
//go the response
const response = await page.request.fetch(route.request());
let body = JSON.stringify(fakePayloadOrders);

//send response to browser and override respond body
route.fulfill({
status: 200,
body: body,
});
});
});

test("Intercept Network request", async ({ page }) => {
await page.goto("http://xxxx.com");

//intercept request send to server & respond by url value passed in route.continue
await page.route("http://xxxx.com/abc/ird", async (route) => {
route.continue({
url: "http://xxxx.com/abc/123455",
});
});
});

0 comments on commit 4c12123

Please sign in to comment.