diff --git a/README.md b/README.md index 9f8dd72..9ccb889 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Playwright-Framework-Template - This project is based on Microsoft Playwright, A _☝ If you liked the project, please give a ⭐ on [GitHub](https://github.com/abhaybharti/playwright-framework-template). It will motivate me to add more such project._ +\_☝ If you want new feature to be added or you believe you've encountered a bug [Open an issue] (https://github.com/abhaybharti/playwright-framework-template/issues) . + ## Features - Easy to Configure @@ -39,8 +41,29 @@ _☝ If you liked the project, please give a ⭐ on [GitHub](https://github.com/ ## Getting Started ## Project Structure -- `apiHelper.ts` contains functions for making HTTP requests + +- `src` + - `helper` + - `/api/apiHelper.ts` contains functions for making HTTP requests + - `/load/loadHelper.ts` contains functions generating load on UI/Api + - `/mobile/mobileHelper.ts` contains functions for interacting with mobile apps + - `/web/webHelper.ts` contains functions for interacting with browser +- `tests` contains utility functions + - `api` place to write api tests + - `example` contains example api tests using this framework + - `web` place to write web tests + - `example` contains example api tests using this framework + - `load` place to write load tests + - `example` contains example api tests using this framework + - `mobile` place to write mobile tests + - `example` contains example api tests using this framework - `utils` contains utility functions + - `config` contains config files + - `report` contains report function files + - `dataStore.js` acts as a in-memory data store. It is used to save data that needs to be shared between different test case +- `test-results` contains test results +- `har` contains har file generated by playwright tests +- `logs` contains logs ### Prerequisite diff --git a/src/helper/web/webHelper.ts b/src/helper/web/webHelper.ts index bdafc2a..1905170 100644 --- a/src/helper/web/webHelper.ts +++ b/src/helper/web/webHelper.ts @@ -1,4 +1,5 @@ import { BrowserContext, Page, expect } from "@playwright/test"; +import fs from "fs"; export class WebHelper { readonly webPage: Page; @@ -224,4 +225,131 @@ export class WebHelper { return; }); } + + /** + * The function will setup a listener for alert box, if dialog appears during the test then automatically accepting them. + * Alert box contains only Ok button + */ + async acceptAlertBox(): Promise { + console.log(`Handle Alert Box by clicking on Ok button`); + this.webPage.on("dialog", async (dialog) => dialog.dismiss()); + } + + /** + * The function will setup a listener for Confirm box, if dialog appears during the test then automatically call accept/dismiss method. + * Confirm box contains Ok/Cancel button + */ + async acceptConfirmBox(): Promise { + console.log(`Accept Confirm Box by clicking on Ok button`); + this.webPage.on("dialog", async (dialog) => dialog.accept()); + } + + async dismissConfirmBox(): Promise { + console.log(`Dismiss Confirm Box by clicking on Cancel button`); + this.webPage.on("dialog", async (dialog) => dialog.dismiss()); + } + + /** + * The function will setup a listener for Prompt box, if dialog appears during the test then automatically call accept/dismiss method. + * Prompt box contains text box where user can enter text and submit (using Ok/Cancel button) it. + */ + async handlePromptBox(txtVal: string): Promise { + console.log(`Enter text message in Prompt Box and click on Ok button`); + this.webPage.on("dialog", async (dialog) => dialog.accept(txtVal)); + } + + waitForDialogMessage(page: Page) { + return new Promise((resolve) => { + page.on("dialog", (dialog) => { + resolve(dialog.message()); + }); + }); + } + + /** + * The function will read text message from Alert and return. + */ + async getAlertText(): Promise { + console.log(`Read text message from Alert box`); + let dialogMessage: string; + dialogMessage = await this.waitForDialogMessage( + this.webPage + ).then.toString(); + console.log(dialogMessage); + return dialogMessage; + } + + /** + * The function `getFrame` takes a frame locator as input and calls a method on the `webPage` object + * to locate the frame. + * @param {string} frameLocator - The frameLocator parameter is a string that represents the locator + * or identifier of the frame you want to retrieve. + */ + async getFrame(frameLocator: string) { + return this.webPage.frameLocator(frameLocator); + } + + /** + * The function `getStringFromShadowDom` retrieves the text content from a specified element within + * the Shadow DOM. + * @param {string} locator - The `locator` parameter is a string that represents a CSS selector used + * to locate an element within the Shadow DOM. + * @returns a Promise that resolves to a string. + */ + async getStringFromShadowDom(locator: string): Promise { + return (await this.webPage.locator(locator).textContent()) as string; + } + + /** + * The `downLoadFile` function downloads a file by clicking on a specified locator and waits for the + * download event to occur. + * @param {string} locator - The locator parameter is a string that represents the selector used to + * locate the element on the web page that triggers the file download. It could be an ID, class name, + * CSS selector, or any other valid selector that can be used with the `this.webPage.locator()` + * method to locate the element + * @param {string} expectedFileName - The expectedFileName parameter is a string that represents the + * name of the file that is expected to be downloaded. + * @param {string} savePath - The `savePath` parameter is a string that represents the path where the + * downloaded file will be saved on the local machine. + */ + async downLoadFile( + locator: string, + expectedFileName: string, + savePath: string + ) { + //start download + const [download] = await Promise.all([ + this.webPage.waitForEvent("download"), + this.webPage.locator(locator).click(), + ]); + + await download.saveAs(savePath); + return download; + } + + /** + * The function uploads a file to a web page using the specified file path, file upload locator, and + * upload button locator. + * @param {string} filePath - The file path is the path to the file that you want to upload. It + * should be a string that specifies the location of the file on your computer. + * @param {string} fileUploadLocator - The fileUploadLocator parameter is a string that represents + * the locator of the file upload input element on the web page. This locator is used to identify the + * element where the file will be uploaded to. + * @param {string} uploadBtnLocator - The `uploadBtnLocator` parameter is a string that represents + * the locator of the upload button on the web page. It is used to locate and interact with the + * upload button element on the page. + */ + async uploadFile( + filePath: string, + fileUploadLocator: string, + uploadBtnLocator: string + ) { + if (!fs.existsSync(filePath)) { + console.log(`File ${filePath} does not exist`); + throw new Error(`File not found :${filePath}`); + } + + await this.webPage.setInputFiles(`${fileUploadLocator}`, filePath); + await this.webPage.locator(`${uploadBtnLocator}`).click(); + } } diff --git a/src/tests/web/example/alert.spec.ts b/src/tests/web/example/alert.spec.ts new file mode 100644 index 0000000..64c9846 --- /dev/null +++ b/src/tests/web/example/alert.spec.ts @@ -0,0 +1,65 @@ +import test, { expect } from "@playwright/test"; +import { WebHelper } from "../../../helper/web/webHelper"; + +test("Test 1 : Subscribe on dialog and call dismiss by clicking on Ok button", async ({ + page, + browser, +}) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + + const expectedText = "I am JS Alert"; + //setup listener to handle alert box + webHelper.acceptAlertBox(); + + //write code to open alert box + await webHelper.clickByText("click to open alert box"); + + //Assert + expect(await webHelper.getAlertText()).toBe(expectedText); +}); + +test("Test 2 : Subscribe on dialog and call accept by clicking on Ok button and dismiss by clicking on Cancel button", async ({ + page, + browser, +}) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + + const expectedText = "I am JS Confirm box"; + //setup listener to click on Ok button on confirm box + webHelper.acceptConfirmBox(); + + //write code to open alert box + await webHelper.clickByText("click to open Confirm box"); + + //Assert + expect(await webHelper.getAlertText()).toBe(expectedText); + + //setup listener to click on Cancel button on confirm box + webHelper.dismissConfirmBox(); + + //write code to open alert box + await webHelper.clickByText("click to open Confirm box"); + + //Assert + expect(await webHelper.getAlertText()).toBe(expectedText); +}); + +test("Test 3 : Subscribe on Prompt, enter text in input box and call accept by clicking on Ok button", async ({ + page, + browser, +}) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + + const expectedText = "I am JS Prompt box"; + //setup listener to click on Ok button on confirm box + webHelper.handlePromptBox(expectedText); + + //write code to open alert box + await webHelper.clickByText("click to open Prompt box"); + + //Assert + expect(await webHelper.getAlertText()).toBe(expectedText); +}); diff --git a/src/tests/web/example/downloadfile.spec.ts b/src/tests/web/example/downloadfile.spec.ts new file mode 100644 index 0000000..3712bff --- /dev/null +++ b/src/tests/web/example/downloadfile.spec.ts @@ -0,0 +1,27 @@ +import { test, expect } from "@playwright/test"; +import { WebHelper } from "../../../helper/web/webHelper"; +import fs from "fs"; +import path from "path"; + +test("File Download Test ", async ({ page, browser }) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + + //Arrange + const expectedFileName = "fileToDownload.txt"; + const downloadFolderPath = path.resolve(__dirname, "../test-data"); // path to the folder where the downloaded file will be saved + const savePath = path.join(downloadFolderPath, expectedFileName); + + //Action + await webHelper.downLoadFile( + expectedFileName, + downloadFolderPath, + "locatorOfDownloadLink" + ); + + //Assert + expect(fs.existsSync(savePath)).toBeTruthy(); + + //Clean up : remove downloaded file + fs.unlinkSync(savePath); +}); diff --git a/src/tests/web/example/frame.spec.ts b/src/tests/web/example/frame.spec.ts index 0ffec91..c200dcd 100644 --- a/src/tests/web/example/frame.spec.ts +++ b/src/tests/web/example/frame.spec.ts @@ -1,5 +1,6 @@ import test from "@playwright/test"; import { Console, log } from "console"; +import { WebHelper } from "../../../helper/web/webHelper"; test("iframe", async ({ page }) => { await page.goto("http://rahulshettyacademy.com/AutomationPractice/"); @@ -8,3 +9,9 @@ test("iframe", async ({ page }) => { const textCheck = await framesPage.locator(".text h2").textContent(); console.log(textCheck); }); + +test("Test 2 : Operation on frame", async ({ page, browser }) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + const frameOne = await webHelper.getFrame("iframe[name='courses-iframe']"); +}); diff --git a/src/tests/web/example/uploadfile.spec.ts b/src/tests/web/example/uploadfile.spec.ts new file mode 100644 index 0000000..c783528 --- /dev/null +++ b/src/tests/web/example/uploadfile.spec.ts @@ -0,0 +1,18 @@ +import test, { expect } from "@playwright/test"; +import { WebHelper } from "../../../helper/web/webHelper"; +import path from "path"; + +test("File Upload Test ", async ({ page, browser }) => { + const context = await browser.newContext(); + const webHelper = new WebHelper(page, context); + + //Arrange + const fileName = "uploadFile.txt"; + const filePath = path.resolve(__dirname, `../test-data/${fileName}`); + + //Action + await webHelper.uploadFile(fileName, filePath, "locatorOfUploadLink"); + + //Assert + expect(await webHelper.elementHasText("locatorOfUploadLink", fileName)); +}); diff --git a/src/utils/dataStore.js b/src/utils/dataStore.js index e0f241d..401c53d 100644 --- a/src/utils/dataStore.js +++ b/src/utils/dataStore.js @@ -1,3 +1,5 @@ +/* +This components acts as a in-memory data store. It is used to save data that needs to be shared between different test case*/ let store = {}; function saveData(key, data) {