From 8ae710509377f4c24389e3cd9c67d0845535aa20 Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Fri, 28 May 2021 09:09:39 +0300 Subject: [PATCH 1/6] [20] Updated Helpers to handle popups. Added tests --- example/tests/helpers.test.js | 31 +++++++++++++++++++++++++++++++ framework/helpers.js | 14 ++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/example/tests/helpers.test.js b/example/tests/helpers.test.js index 7c0c372..cec5ec6 100644 --- a/example/tests/helpers.test.js +++ b/example/tests/helpers.test.js @@ -1,4 +1,5 @@ import { Element, Helpers } from "test-juggler"; +import helpers from "../../framework/helpers"; const fs = require("fs"); describe("Helpers", () => { @@ -95,4 +96,34 @@ describe("Helpers", () => { expect(regex.test(text)).toBeTruthy(); expect(text.length).toEqual(8); }); + + it("should accept opened alerts", async () => { + //Arrange + const pageWithAcceptAlertsSetup = await browser.newPage(); + await Helpers.acceptPopupsOnPage(pageWithAcceptAlertsSetup); + const resultElement = new Element("#result", pageWithAcceptAlertsSetup); + + //Act + await pageWithAcceptAlertsSetup.goto("http://the-internet.herokuapp.com/javascript_alerts"); + await pageWithAcceptAlertsSetup.click("button[onclick='jsAlert()']"); + const resultElementText = await resultElement.text(); + + //Assert + expect(resultElementText).toMatch("You successfully clicked an alert"); + }); + + it("should close opened alerts", async () => { + //Arrange + const pageWithDismissAlertsSetup = await browser.newPage(); + await Helpers.dismissPopupsOnPage(pageWithDismissAlertsSetup); + const resultElement = new Element("#result", pageWithDismissAlertsSetup); + + //Act + await pageWithDismissAlertsSetup.goto("http://the-internet.herokuapp.com/javascript_alerts"); + await pageWithDismissAlertsSetup.click("button[onclick='jsAlert()']"); + const resultElementText = await resultElement.text(); + + //Assert + expect(resultElementText).toMatch("You successfully clicked an alert"); + }); }); \ No newline at end of file diff --git a/framework/helpers.js b/framework/helpers.js index 05c1e1f..d71c060 100644 --- a/framework/helpers.js +++ b/framework/helpers.js @@ -46,6 +46,20 @@ class Helpers { console.log(`Generated a random text: ${result}`); return result; } + + async acceptPopupsOnPage(page) { + await page.on("dialog", dialog => { + console.log(`Alert was detected: '${dialog.message()}'`); + dialog.accept(); + }); + } + + async dismissPopupsOnPage(page) { + await page.on("dialog", dialog => { + console.log(`Alert was detected: '${dialog.message()}'`); + dialog.dismiss(); + }); + } } export default new Helpers(); \ No newline at end of file From 5ddaa1aa133a4f08d61b2dd53f257f5ac12e0687 Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Fri, 28 May 2021 09:10:23 +0300 Subject: [PATCH 2/6] [20] Updated Element to use page or use global one by default --- framework/Element.js | 49 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/framework/Element.js b/framework/Element.js index 8cc1460..e8e2b94 100644 --- a/framework/Element.js +++ b/framework/Element.js @@ -6,8 +6,9 @@ const defaultTimeout = config.defaultTimeout; const shortTimeout = config.shortTimeout; export default class Element { - constructor(selector) { - this.selector = selector; + constructor(selector, elementPage = page) { + this.selector = selector, + this.page = elementPage } newChildElement(childSelector) { @@ -20,7 +21,7 @@ export default class Element { async wait(timeout = defaultTimeout) { console.log(`Waiting for ${this.selector} ...`); - const elementHandle = await page.waitForSelector(this.selector, { timeout: timeout }); + const elementHandle = await this.page.waitForSelector(this.selector, { timeout: timeout }); if (config.captureScreenshots) { await Helpers.takeScreenshot(); } @@ -29,7 +30,7 @@ export default class Element { async waitUntilVisible(timeout = defaultTimeout) { console.log(`Waiting for ${this.selector} to be visible...`); - const elementHandle = await page.waitForSelector(this.selector, { state: "visible", timeout: timeout }); + const elementHandle = await this.page.waitForSelector(this.selector, { state: "visible", timeout: timeout }); if (config.captureScreenshots) { await Helpers.takeScreenshot(); } @@ -38,7 +39,7 @@ export default class Element { async waitUntilInvisible(timeout = defaultTimeout) { console.log(`Waiting for ${this.selector} to be invisible...`); - await page.waitForSelector(this.selector, { state: "hidden", timeout: timeout }); + await this.page.waitForSelector(this.selector, { state: "hidden", timeout: timeout }); if (config.captureScreenshots) { await Helpers.takeScreenshot(); } @@ -58,36 +59,36 @@ export default class Element { console.log(`Clicking ${this.selector} ...`); if (xOffset != null || yOffset != null) { const coordinates = await this.getCoordinates(xOffset, yOffset); - await page.click(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); + await this.page.click(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); } - else await page.click(this.selector); + else await this.page.click(this.selector); } async doubleClick(xOffset = null, yOffset = null) { console.log(`Double clicking ${this.selector} ...`); if (xOffset != null || yOffset != null) { const coordinates = await this.getCoordinates(xOffset, yOffset); - await page.dblclick(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); + await this.page.dblclick(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); } - else await page.dblclick(this.selector); + else await this.page.dblclick(this.selector); } async rightClick(xOffset = null, yOffset = null) { console.log(`Right clicking ${this.selector} ...`); if (xOffset != null || yOffset != null) { const coordinates = await this.getCoordinates(xOffset, yOffset); - await page.click(this.selector, { position: { x: coordinates.x, y: coordinates.y }, button: "right" } ); + await this.page.click(this.selector, { position: { x: coordinates.x, y: coordinates.y }, button: "right" } ); } - else await page.click(this.selector, { button: "right" }); + else await this.page.click(this.selector, { button: "right" }); } async hover(xOffset = null, yOffset = null) { console.log(`Hovering mouse on to ${this.selector} ...`); if (xOffset != null || yOffset != null) { const coordinates = await this.getCoordinates(xOffset, yOffset); - await page.hover(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); + await this.page.hover(this.selector, { position: { x: coordinates.x, y: coordinates.y } }); } - else await page.hover(this.selector); + else await this.page.hover(this.selector); } async exists() { @@ -119,15 +120,15 @@ export default class Element { } async dragAndDrop(destination) { - const sourceElement = await page.waitForSelector(this.selector); - const destinationElement = await page.waitForSelector(destination.selector); + const sourceElement = await this.page.waitForSelector(this.selector); + const destinationElement = await this.page.waitForSelector(destination.selector); const sourceBox = await sourceElement.boundingBox(); const destinationBox = await destinationElement.boundingBox(); console.log(`Drag and dropping ${this.selector} to ${destination.selector} ...`); - await page.mouse.move(sourceBox.x + sourceBox.width / 2, sourceBox.y + sourceBox.height / 2); - await page.mouse.down(); - await page.mouse.move(destinationBox.x + destinationBox.width / 2, destinationBox.y + destinationBox.height / 2); - await page.mouse.up(); + await this.page.mouse.move(sourceBox.x + sourceBox.width / 2, sourceBox.y + sourceBox.height / 2); + await this.page.mouse.down(); + await this.page.mouse.move(destinationBox.x + destinationBox.width / 2, destinationBox.y + destinationBox.height / 2); + await this.page.mouse.up(); } async text() { @@ -153,10 +154,10 @@ export default class Element { async clearText() { console.log(`Clearing the text value for ${this.selector} ...`); await this.click(); - await page.keyboard.down("Control"); - await page.keyboard.press("A"); - await page.keyboard.up("Control"); - await page.keyboard.press("Backspace"); + await this.page.keyboard.down("Control"); + await this.page.keyboard.press("A"); + await this.page.keyboard.up("Control"); + await this.page.keyboard.press("Backspace"); } async takeScreenshot() { @@ -216,7 +217,7 @@ export default class Element { async downloadFile(filePath) { if (!path.isAbsolute(filePath)) filePath = process.cwd().replace(/\\/g, "/") + filePath; const [download] = await Promise.all([ - page.waitForEvent("download"), + this.page.waitForEvent("download"), this.click(), ]); await download.saveAs(filePath); From fbbb198b11005867012cef20c109676635b93382 Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Fri, 28 May 2021 09:10:55 +0300 Subject: [PATCH 3/6] [20] Updated test selector for test --- example/tests/elementActions.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/tests/elementActions.test.js b/example/tests/elementActions.test.js index ce0ad89..7398f23 100644 --- a/example/tests/elementActions.test.js +++ b/example/tests/elementActions.test.js @@ -296,7 +296,7 @@ describe("Element Actions", () => { //Arrange const expectedXCoordinate = 640; //width: default viewport 1280px / 2 const expectedYCoordinate = 25; //height: top bar 50px / 2 - const rectangleCanvas = new Element(".top-bar__network._fixed"); + const rectangleCanvas = new Element(".top-bar__network"); await page.goto("https://stackoverflow.com/users/login"); //Act From 047152ea52954c3a4f0ab1e9a4be21b46ccb6ae2 Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Fri, 28 May 2021 09:29:55 +0300 Subject: [PATCH 4/6] [20] Updating interceptor class and tests to contain page --- example/tests/interceptor.test.js | 33 +++++++++++++++++++------------ framework/interceptor.js | 24 ++++++++++++---------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/example/tests/interceptor.test.js b/example/tests/interceptor.test.js index 2fb9c7f..4aef0c6 100644 --- a/example/tests/interceptor.test.js +++ b/example/tests/interceptor.test.js @@ -2,10 +2,12 @@ import { Element, Interceptor } from "test-juggler"; const DemoQaSite = "https://demoqa.com/books"; const DemoOpenCartSite = "https://demo.opencart.com/"; -const successMessage = new Element(".alert-success"); -const addToCartButton = new Element(".product-layout:nth-child(1) > div button:nth-child(1)"); -const loadingWrapper = new Element("#loading-wrapper"); -const booksWrapper = new Element(".books-wrapper"); +let page; +let successMessage; +let addToCartButton; +let loadingWrapper; +let booksWrapper; +let interceptor; describe("Interceptor", () => { beforeEach(async () => { @@ -13,12 +15,17 @@ describe("Interceptor", () => { //this is workaraound to avoid 'Request is already handled!' error. Shoud be removed when https://github.com/smooth-code/jest-puppeteer/issues/308 defect is fixed. const context = await browser.newContext(); page = await context.newPage(); + successMessage = new Element(".alert-success", page); + addToCartButton = new Element(".product-layout:nth-child(1) > div button:nth-child(1)", page); + loadingWrapper = new Element("#loading-wrapper", page); + booksWrapper = new Element(".books-wrapper", page); + interceptor = new Interceptor(page); }); it("should block requests by any url fragment using Regex pattern while test case running", async () => { //Arrange const requestUrlRegex = /BookStore/; - await Interceptor.abortRequests(requestUrlRegex); + await interceptor.abortRequests(requestUrlRegex); //Act await page.goto(DemoQaSite); @@ -41,13 +48,13 @@ describe("Interceptor", () => { //Act await page.goto(DemoQaSite); - await loadingWrapper.waitUntilInvisible(); + await booksWrapper.waitUntilVisible(); //Assert await expect(booksWrapper.exists()).resolves.toBeTruthy(); //Act - await Interceptor.abortRequests(requestUrlGlob); + await interceptor.abortRequests(requestUrlGlob); await page.reload(); await loadingWrapper.waitUntilVisible(); @@ -59,7 +66,7 @@ describe("Interceptor", () => { //Arrange const requestUrlGlob = "**/BookStore/**"; - await Interceptor.abortRequestsAfterAction(page.goto(DemoQaSite), requestUrlGlob); + await interceptor.abortRequestsAfterAction(page.goto(DemoQaSite), requestUrlGlob); //Assert await loadingWrapper.waitUntilVisible(); @@ -69,7 +76,7 @@ describe("Interceptor", () => { //Act await page.reload(); - await loadingWrapper.waitUntilInvisible(); + await booksWrapper.waitUntilVisible(); //Assert await expect(booksWrapper.exists()).resolves.toBeTruthy(); @@ -86,7 +93,7 @@ describe("Interceptor", () => { }); //Act - await Interceptor.abortRequestsAfterAction(addToCartButton.click()); + await interceptor.abortRequestsAfterAction(addToCartButton.click()); //Assert await expect(successMessage.isVisible()).resolves.toBeFalsy(); @@ -95,7 +102,7 @@ describe("Interceptor", () => { it("should count all requests", async () => { //Act - var totalRequests = await Interceptor.getAllRequestsData(page.goto(DemoOpenCartSite)); + var totalRequests = await interceptor.getAllRequestsData(page.goto(DemoOpenCartSite)); //Assert expect(totalRequests.length > 0).toBeTruthy(); @@ -108,7 +115,7 @@ describe("Interceptor", () => { await page.goto(DemoOpenCartSite); //Act - var responseAfterAction = await Interceptor.waitForResponseAfterAction(addToCartButton.click(), responseUrlFragment); + var responseAfterAction = await interceptor.waitForResponseAfterAction(addToCartButton.click(), responseUrlFragment); //Assert await expect(successMessage.isVisible()).resolves.toBeTruthy(); @@ -122,7 +129,7 @@ describe("Interceptor", () => { await page.goto(DemoOpenCartSite); //Act - var requestAfterAction = await Interceptor.waitForRequestAfterAction(addToCartButton.click()); + var requestAfterAction = await interceptor.waitForRequestAfterAction(addToCartButton.click()); //Assert await expect(successMessage.isVisible()).resolves.toBeTruthy(); diff --git a/framework/interceptor.js b/framework/interceptor.js index 823452b..60e7109 100644 --- a/framework/interceptor.js +++ b/framework/interceptor.js @@ -1,14 +1,19 @@ const fs = require("fs"); -class Interceptor { +export default class Interceptor { + + constructor(interceptorPage = page) { + this.page = interceptorPage + } + async takeScreenshot(filename) { const targetDir = `./logs/${jasmine["currentSuite"].fullName}/${jasmine["currentTest"].description}`; fs.mkdirSync(targetDir, { recursive: true }); - await page.screenshot({ path: `${targetDir}/${filename || Date.now()}.png` }); + await this.page.screenshot({ path: `${targetDir}/${filename || Date.now()}.png` }); } async abortRequests(requestUrlFragment = "**") { - await page.route(requestUrlFragment, route => { + await this.page.route(requestUrlFragment, route => { route.abort(); console.log(`Aborted request Url: '${route.request().url()}'`); } ); @@ -17,8 +22,8 @@ class Interceptor { async abortRequestsAfterAction(action, requestUrlFragment = "", waitDuration = 500) { await this.abortRequests(requestUrlFragment); await action; - await page.waitForTimeout(waitDuration); - await page.unroute(requestUrlFragment); + await this.page.waitForTimeout(waitDuration); + await this.page.unroute(requestUrlFragment); } async getAllRequestsData(action) { @@ -26,25 +31,24 @@ class Interceptor { const requestLogger = request => { requestsData.push(request); }; - page.on("request", requestLogger); + this.page.on("request", requestLogger); await action; - page.removeListener("request", requestLogger); + this.page.removeListener("request", requestLogger); return requestsData; } async waitForRequestAfterAction(action, requestUrlFragment = "") { - const requestAferAction = await page.waitForRequest(request => request.url().indexOf(requestUrlFragment) > -1); + const requestAferAction = await this.page.waitForRequest(request => request.url().indexOf(requestUrlFragment) > -1); await action; console.log(`Url: '${requestAferAction.url()}'`); return requestAferAction; } async waitForResponseAfterAction(action, responsetUrlFragment = "") { - const responseAferAction = await page.waitForResponse(response => response.url().indexOf(responsetUrlFragment) > -1); + const responseAferAction = await this.page.waitForResponse(response => response.url().indexOf(responsetUrlFragment) > -1); await action; console.log(`Url: '${responseAferAction.url()}'`); return responseAferAction; } } -export default new Interceptor(); \ No newline at end of file From af0b429c4d26953f64b0863968fac8eb9a59320c Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Fri, 28 May 2021 10:48:34 +0300 Subject: [PATCH 5/6] [20] Removed unused import, empty line --- example/tests/helpers.test.js | 1 - framework/interceptor.js | 1 - 2 files changed, 2 deletions(-) diff --git a/example/tests/helpers.test.js b/example/tests/helpers.test.js index cec5ec6..b486042 100644 --- a/example/tests/helpers.test.js +++ b/example/tests/helpers.test.js @@ -1,5 +1,4 @@ import { Element, Helpers } from "test-juggler"; -import helpers from "../../framework/helpers"; const fs = require("fs"); describe("Helpers", () => { diff --git a/framework/interceptor.js b/framework/interceptor.js index 60e7109..562b6e9 100644 --- a/framework/interceptor.js +++ b/framework/interceptor.js @@ -1,7 +1,6 @@ const fs = require("fs"); export default class Interceptor { - constructor(interceptorPage = page) { this.page = interceptorPage } From 5a19cc1d99e994774c171a0d3a149f0eb6642214 Mon Sep 17 00:00:00 2001 From: Jelena Rybakova Date: Mon, 31 May 2021 14:02:49 +0300 Subject: [PATCH 6/6] [20] Updated initialization of child Element --- framework/Element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/Element.js b/framework/Element.js index e8e2b94..c057fd7 100644 --- a/framework/Element.js +++ b/framework/Element.js @@ -11,12 +11,12 @@ export default class Element { this.page = elementPage } - newChildElement(childSelector) { + newChildElement(childSelector, childElementPage = page) { var isXPathSlector = (selector) => selector.startsWith("//"); if (isXPathSlector(this.selector) != isXPathSlector(childSelector)) { throw "Cannot combine different selectors types!"; } - return new Element(`${this.selector} ${childSelector}`); + return new Element(`${this.selector} ${childSelector}`, childElementPage); } async wait(timeout = defaultTimeout) {