diff --git a/cypress.config.js b/cypress.config.js
index 97f47c4..c597056 100644
--- a/cypress.config.js
+++ b/cypress.config.js
@@ -2,6 +2,9 @@ const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
+ chromeWebSecurity: false,
+ supportFile: 'cypress/support/commands.js',
+ specPattern: 'cypress/integration/**/*.spec.js',
setupNodeEvents(on, config) {
// implement node event listeners here
},
diff --git a/cypress/fixtures/adBlockerUrls.json b/cypress/fixtures/adBlockerUrls.json
new file mode 100644
index 0000000..3a71cad
--- /dev/null
+++ b/cypress/fixtures/adBlockerUrls.json
@@ -0,0 +1,12 @@
+{
+ "blockAds": "https://pagead2.googlesyndication.com/**",
+ "blockGpt": "https://www.googletagservices.com/tag/js/gpt.js",
+ "blockGtm": "https://www.googletagmanager.com/gtm.js?id=GTM-MX8DD4S",
+ "blockAdPlus": "https://cdn.ad.plus/player/adplus.js",
+ "blockBacktrace": "https://events.backtrace.io/**",
+ "blockGif": "**/*.gif",
+ "blockUserMatch": "**/usermatch.gif**",
+ "blockMerge": "**/merge**",
+ "blockScripts": "**/*.js"
+}
+
diff --git a/cypress/fixtures/credentials.json b/cypress/fixtures/credentials.json
new file mode 100644
index 0000000..029333a
--- /dev/null
+++ b/cypress/fixtures/credentials.json
@@ -0,0 +1,36 @@
+{
+ "users": {
+ "standardUser": {
+ "username": "standard_user",
+ "password": "secret_sauce"
+ },
+ "lockedOutUser": {
+ "username": "locked_out_user",
+ "password": "secret_sauce"
+ },
+ "problemUser": {
+ "username": "problem_user",
+ "password": "secret_sauce"
+ },
+ "performanceGlitchUser": {
+ "username": "performance_glitch_user",
+ "password": "secret_sauce"
+ },
+ "invalidUser": {
+ "username": "invalid_user",
+ "password": "secret_sauce"
+ },
+ "noPassword": {
+ "username": "standard_user",
+ "password": ""
+ },
+ "invalidPassword": {
+ "username": "standard_user",
+ "password": "invalid_password"
+ },
+ "noUsername": {
+ "username": "",
+ "password": "secret_sauce"
+ }
+ }
+}
diff --git a/cypress/integration/alerts.spec.js b/cypress/integration/alerts.spec.js
new file mode 100644
index 0000000..3d6798e
--- /dev/null
+++ b/cypress/integration/alerts.spec.js
@@ -0,0 +1,41 @@
+describe('Alerts Handling on DEMOQA', () => {
+ beforeEach(() => {
+ cy.visitWithAdBlocker('https://demoqa.com/alerts');
+ cy.clock();
+ });
+
+ it('tests the [Alert] button which shows an alert box', () => {
+ cy.on('window:alert', (text) => expect(text).to.contain('You clicked a button'));
+ cy.get('#alertButton').click();
+ });
+
+ it('ensures the [Timer Alert] button triggers after exactly 5 seconds', () => {
+ cy.on('window:alert', (text) => expect(text).to.equal('This alert appeared after 5 seconds'));
+ cy.get('#timerAlertButton').click();
+ cy.tick(5000); // Simulate passing of 5 seconds
+ });
+
+ it('accepts a confirm alert and verifies actions taken on confirmation', () => {
+ cy.on('window:confirm', (str) => {
+ expect(str).to.eq('Do you confirm action?');
+ return true;
+ });
+ cy.get('#confirmButton').click();
+ cy.get('#confirmResult').should('contain', 'You selected Ok');
+ });
+
+ it('cancels a confirm alert and verifies actions taken on cancellation', () => {
+ cy.on('window:confirm', (str) => {
+ expect(str).to.eq('Do you confirm action?');
+ return false;
+ });
+ cy.get('#confirmButton').click();
+ cy.get('#confirmResult').should('contain', 'You selected Cancel');
+ });
+
+ it('accepts a prompt alert and verifies actions taken on confirmation', () => {
+ cy.window().then((win) => cy.stub(win, 'prompt').returns('Cypress Tester'));
+ cy.get('#promtButton').click();
+ cy.get('#promptResult').should('contain', 'You entered Cypress Tester');
+ });
+});
diff --git a/cypress/integration/frames.spec.js b/cypress/integration/frames.spec.js
new file mode 100644
index 0000000..a682074
--- /dev/null
+++ b/cypress/integration/frames.spec.js
@@ -0,0 +1,21 @@
+describe('Frames Handling on DEMOQA', () => {
+ beforeEach(() => {
+ cy.visitWithAdBlocker('https://demoqa.com/frames');
+ });
+
+ const verifyFrameContentAndSize = (frameId, expectedWidth, expectedHeight, expectedText) => {
+ it(`verifies content and dimensions within ${frameId}`, () => {
+ cy.get(frameId)
+ .should('have.attr', 'width', expectedWidth)
+ .and('have.attr', 'height', expectedHeight);
+
+ cy.frameLoaded(frameId);
+ cy.iframe(frameId).within(() => {
+ cy.get('h1#sampleHeading').should('have.text', expectedText);
+ });
+ });
+ };
+
+ verifyFrameContentAndSize('#frame1', '500px', '350px', 'This is a sample page');
+ verifyFrameContentAndSize('#frame2', '100px', '100px', 'This is a sample page');
+});
diff --git a/cypress/integration/sauce_demo.spec.js b/cypress/integration/sauce_demo.spec.js
new file mode 100644
index 0000000..7902ad7
--- /dev/null
+++ b/cypress/integration/sauce_demo.spec.js
@@ -0,0 +1,42 @@
+// saucedemo_tests.cy.js
+describe('Sauce Demo Tests', () => {
+ beforeEach(() => {
+ // Visits the Sauce Demo website before each test
+ cy.visitWithAdBlocker('https://www.saucedemo.com');
+ });
+
+ it('TC_1: Successfully logs in as a standard user', () => {
+ cy.loginWithFixture('standardUser');
+ cy.get('.inventory_list').should('be.visible');
+ });
+
+ it('TC_2: Fails to log in with invalid credentials', () => {
+ cy.loginWithFixture('invalidPassword');
+ cy.log('Attempted login with in with invalid password');
+ cy.get('.error-message-container').then((elem) => {
+ console.log('Error message element:', elem);
+ }).should('be.visible');
+ });
+
+ it('TC_3: Navigates through product pages', () => {
+ cy.loginWithFixture('standardUser');
+ cy.get('.inventory_item_name').first().click();
+ cy.get('.inventory_details').should('be.visible');
+ cy.go('back');
+ cy.get('.inventory_list').should('be.visible');
+ });
+
+ it('TC_4: Adds an item to the cart', () => {
+ cy.loginWithFixture('standardUser');
+ cy.get('.btn_inventory').first().click();
+ cy.get('.shopping_cart_link').click();
+ cy.get('.cart_list').should('be.visible');
+ });
+
+ it('TC_5: Adds all items and completes checkout', () => {
+ cy.loginWithFixture('standardUser');
+ cy.addAllItemsToCart();
+ cy.completeCheckout('John', 'Dow', '12345');
+ cy.get('.complete-header').should('be.visible');
+ });
+});
\ No newline at end of file
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 66ea16e..5c1c82d 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -1,25 +1,78 @@
-// ***********************************************
-// This example commands.js shows you how to
-// create various custom commands and overwrite
-// existing commands.
-//
-// For more comprehensive examples of custom
-// commands please read more here:
-// https://on.cypress.io/custom-commands
-// ***********************************************
-//
-//
-// -- This is a parent command --
-// Cypress.Commands.add('login', (email, password) => { ... })
-//
-//
-// -- This is a child command --
-// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
-//
-//
-// -- This is a dual command --
-// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
-//
-//
-// -- This will overwrite an existing command --
-// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
\ No newline at end of file
+import 'cypress-iframe';
+
+// Helper function to log and throw errors
+function logAndThrow(message) {
+ cy.log(message);
+ throw new Error(message);
+}
+
+// Custom command to visit a URL with ad blockers enabled
+Cypress.Commands.add('visitWithAdBlocker', (url) => {
+ cy.fixture('adBlockerUrls').then(urls => {
+ try {
+ Object.entries(urls).forEach(([key, value]) => {
+ cy.intercept(value, {
+ statusCode: key === 'blockScripts' ? undefined : 200,
+ body: key === 'blockScripts' ? undefined : '',
+ onResponse: key === 'blockScripts' ? (req) => {
+ if (req.url.includes('google') || req.url.includes('adsbygoogle')) {
+ req.destroy();
+ }
+ } : undefined,
+ log: false
+ }).as(key);
+ });
+ cy.visit(url).then(() => cy.log('Visited with ad blockers set up successfully.'));
+ } catch (error) {
+ logAndThrow(`Ad Blocker setup error: ${error.message}`);
+ }
+ });
+});
+
+// Custom command for logging into a site
+Cypress.Commands.add('login', (username, password) => {
+ cy.get('[data-test="username"]').type(username, { log: false }).should('have.value', username);
+ cy.get('[data-test="password"]').type(password, { log: false }).should('have.value', password);
+ cy.get('#login-button').click();
+});
+
+// Custom command to login with a user type from a fixture
+Cypress.Commands.add('loginWithFixture', (userType) => {
+ cy.fixture('credentials').then(credentials => {
+ const user = credentials.users[userType];
+ if (!user) logAndThrow('User type not found in fixture');
+ cy.login(user.username, user.password);
+ });
+});
+
+// Custom command to add an item to the cart by name
+Cypress.Commands.add('addItemToCartByName', (itemName) => {
+ cy.contains('.inventory_item_name', itemName).parents('.inventory_item').within(() => {
+ cy.get('.btn_inventory').click().should('have.class', 'btn_inventory');
+ });
+});
+
+// Custom command to add all items to the cart
+Cypress.Commands.add('addAllItemsToCart', () => {
+ cy.get('.inventory_item').each(element => {
+ cy.wrap(element).find('.btn_inventory').click();
+ });
+});
+
+// Custom command to complete the checkout process
+Cypress.Commands.add('completeCheckout', (firstName, lastName, zipCode) => {
+ cy.get('.shopping_cart_link').click();
+ cy.get('.checkout_button').click();
+ cy.get('#first-name').type(firstName);
+ cy.get('#last-name').type(lastName);
+ cy.get('#postal-code').type(zipCode);
+ cy.get('.btn_primary.cart_button').click();
+ cy.get('.btn_action.cart_button').click(); // This clicks the final 'Finish' button on the checkout page
+});
+
+// Overwriting the 'visit' command to always disable the cache
+Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
+ const noCacheStr = `_noCache=${Math.random()}`;
+ url = url.includes('?') ? `${url}&${noCacheStr}` : `${url}?${noCacheStr}`;
+ return originalFn(url, options);
+});
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
index 0e7290a..f65e7f7 100644
--- a/cypress/support/e2e.js
+++ b/cypress/support/e2e.js
@@ -1,20 +1 @@
-// ***********************************************************
-// This example support/e2e.js is processed and
-// loaded automatically before your test files.
-//
-// This is a great place to put global configuration and
-// behavior that modifies Cypress.
-//
-// You can change the location of this file or turn off
-// automatically serving support files with the
-// 'supportFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/configuration
-// ***********************************************************
-
-// Import commands.js using ES2015 syntax:
-import './commands'
-
-// Alternatively you can use CommonJS syntax:
-// require('./commands')
\ No newline at end of file
+import './commands'
\ No newline at end of file
diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json
index 782b6d0..633ce95 100644
--- a/node_modules/.package-lock.json
+++ b/node_modules/.package-lock.json
@@ -62,6 +62,17 @@
"ms": "^2.1.1"
}
},
+ "node_modules/@types/cypress": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.3.tgz",
+ "integrity": "sha512-OXe0Gw8LeCflkG1oPgFpyrYWJmEKqYncBsD/J0r17r0ETx/TnIGDNLwXt/pFYSYuYTpzcq1q3g62M9DrfsBL4g==",
+ "deprecated": "This is a stub types definition for cypress (https://cypress.io). cypress provides its own type definitions, so you don't need @types/cypress installed!",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "cypress": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
@@ -581,6 +592,15 @@
"node": "^16.0.0 || ^18.0.0 || >=20.0.0"
}
},
+ "node_modules/cypress-iframe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cypress-iframe/-/cypress-iframe-1.0.1.tgz",
+ "integrity": "sha512-Ne+xkZmWMhfq3x6wbfzK/SzsVTCrJru3R3cLXsoSAZyfUtJDamXyaIieHXeea3pQDXF4wE2w4iUuvCYHhoD31g==",
+ "dev": true,
+ "peerDependencies": {
+ "@types/cypress": "^1.1.0"
+ }
+ },
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
diff --git a/node_modules/@types/cypress/LICENSE b/node_modules/@types/cypress/LICENSE
new file mode 100644
index 0000000..2107107
--- /dev/null
+++ b/node_modules/@types/cypress/LICENSE
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
diff --git a/node_modules/@types/cypress/README.md b/node_modules/@types/cypress/README.md
new file mode 100644
index 0000000..8b58d85
--- /dev/null
+++ b/node_modules/@types/cypress/README.md
@@ -0,0 +1,2 @@
+This is a stub types definition for cypress (https://cypress.io).
+cypress provides its own type definitions, so you don't need @types/cypress installed!
\ No newline at end of file
diff --git a/node_modules/@types/cypress/package.json b/node_modules/@types/cypress/package.json
new file mode 100644
index 0000000..bbddfd2
--- /dev/null
+++ b/node_modules/@types/cypress/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "@types/cypress",
+ "version": "1.1.3",
+ "typings": null,
+ "description": "Stub TypeScript definitions entry for cypress, which provides its own types definitions",
+ "main": "",
+ "scripts": {},
+ "author": "",
+ "repository": "https://cypress.io",
+ "license": "MIT",
+ "dependencies": {
+ "cypress": "*"
+ }
+}
\ No newline at end of file
diff --git a/node_modules/cypress-iframe/LICENSE b/node_modules/cypress-iframe/LICENSE
new file mode 100644
index 0000000..8c5040f
--- /dev/null
+++ b/node_modules/cypress-iframe/LICENSE
@@ -0,0 +1,7 @@
+Copyright 2020 Kevin Groat (kgroat)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/node_modules/cypress-iframe/README.md b/node_modules/cypress-iframe/README.md
new file mode 100644
index 0000000..53c6fa1
--- /dev/null
+++ b/node_modules/cypress-iframe/README.md
@@ -0,0 +1,75 @@
+# Cypress iframe
+Adds iframe support to [Cypress](https://www.cypress.io/).
+
+## Installation
+```bash
+npm install -D cypress-iframe
+```
+
+In your `cypress/support/commands.js` file, add the following:
+```js
+import 'cypress-iframe';
+// or
+require('cypress-iframe');
+```
+
+If you're using typescript with cypress, and have not overridden the `types` or `typeRoots` in your tsc compiler options, then everything should work.
+
+If you have overridden them, or if it otherwise doesn't work out-of-the-box, you will also either want to:
+1. Add `///` to the top of your cypress
+1. Add a `globals.d.ts` in the root of your `cypress` directory and add `///` to it
+
+## Usage
+You can now use the three included commands.
+
+### `frameLoaded`
+This command checks that an iframe has loaded onto the page
+
+Example:
+```js
+// This will verify that the iframe is loaded to any page other than 'about:blank'
+cy.frameLoaded()
+
+// This will verify that the iframe is loaded to any url containing the given path part
+cy.frameLoaded({ url: 'https://google.com' })
+cy.frameLoaded({ url: '/join' })
+cy.frameLoaded({ url: '?some=query' })
+cy.frameLoaded({ url: '#/hash/path' })
+
+// You can also give it a selector to check that a specific iframe has loaded
+cy.frameLoaded('#my-frame')
+cy.frameLoaded('#my-frame', { url: '/join' })
+```
+
+### `iframe`
+This will cause subsequent commands to be executed inside of the given iframe
+
+Example:
+```js
+// This will verify that the iframe is loaded to any page other than 'about:blank'
+cy.iframe().find('.some-button').should('be.visible').click()
+cy.iframe().contains('Some hidden element').should('not.be.visible')
+cy.find('#outside-iframe').click() // this will be executed outside the iframe
+
+// You can also give it a selector to find elements inside of a specific iframe
+cy.iframe('#my-frame').find('.some-button').should('be.visible').click()
+cy.iframe('#my-second-frame').contains('Some hidden element').should('not.be.visible')
+```
+
+### `enter`
+This can be used to execute a group of commands within an iframe
+
+Example:
+```js
+// This will verify that the iframe is loaded to any page other than 'about:blank'
+cy.enter().then(getBody => {
+ getBody().find('.some-button').should('be.visible').click()
+ getBody().contains('Some hidden element').should('not.be.visible')
+})
+
+// You can also give it a selector to find elements inside of a specific iframe
+cy.enter('#my-iframe').then(getBody => {
+ getBody().find('.some-button').should('be.visible').click()
+ getBody().contains('Some hidden element').should('not.be.visible')
+})
+```
diff --git a/node_modules/cypress-iframe/dist/index.js b/node_modules/cypress-iframe/dist/index.js
new file mode 100644
index 0000000..14e301e
--- /dev/null
+++ b/node_modules/cypress-iframe/dist/index.js
@@ -0,0 +1,170 @@
+var __assign = (this && this.__assign) || function () {
+ __assign = Object.assign || function(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
+ t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+var __generator = (this && this.__generator) || function (thisArg, body) {
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
+ function verb(n) { return function (v) { return step([n, v]); }; }
+ function step(op) {
+ if (f) throw new TypeError("Generator is already executing.");
+ while (_) try {
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
+ if (y = 0, t) op = [op[0] & 2, t.value];
+ switch (op[0]) {
+ case 0: case 1: t = op; break;
+ case 4: _.label++; return { value: op[1], done: false };
+ case 5: _.label++; y = op[1]; op = [0]; continue;
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
+ default:
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
+ if (t[2]) _.ops.pop();
+ _.trys.pop(); continue;
+ }
+ op = body.call(thisArg, _);
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
+ }
+};
+var _this = this;
+var DEFAULT_OPTS = {
+ log: true,
+ timeout: 30000,
+};
+var DEFAULT_IFRAME_SELECTOR = 'iframe';
+function sleep(timeout) {
+ return new Promise(function (resolve) { return setTimeout(resolve, timeout); });
+}
+function timeout(cb, timeout) {
+ return new Promise(function (resolve) {
+ var done = false;
+ var finish = function () { return done || resolve(); };
+ cb().then(finish);
+ sleep(timeout).then(finish);
+ });
+}
+var frameLoaded = function (selector, opts) {
+ if (selector === undefined) {
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ else if (typeof selector === 'object') {
+ opts = selector;
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ var fullOpts = __assign(__assign({}, DEFAULT_OPTS), opts);
+ var log = fullOpts.log ? Cypress.log({
+ name: 'frame loaded',
+ displayName: 'frame loaded',
+ message: [selector],
+ }).snapshot() : null;
+ return cy.get(selector, { log: false }).then({ timeout: fullOpts.timeout }, function ($frame) { return __awaiter(_this, void 0, void 0, function () {
+ var contentWindow, hasNavigated, loadLog;
+ var _a, _b;
+ return __generator(this, function (_c) {
+ switch (_c.label) {
+ case 0:
+ (_a = log) === null || _a === void 0 ? void 0 : _a.set('$el', $frame);
+ if ($frame.length !== 1) {
+ throw new Error("cypress-iframe commands can only be applied to exactly one iframe at a time. Instead found " + $frame.length);
+ }
+ contentWindow = $frame.prop('contentWindow');
+ hasNavigated = fullOpts.url
+ ? function () {
+ var _a;
+ return typeof fullOpts.url === 'string'
+ ? contentWindow.location.toString().includes(fullOpts.url)
+ : (_a = fullOpts.url) === null || _a === void 0 ? void 0 : _a.test(contentWindow.location.toString());
+ }
+ : function () { return contentWindow.location.toString() !== 'about:blank'; };
+ _c.label = 1;
+ case 1:
+ if (!!hasNavigated()) return [3, 3];
+ return [4, sleep(100)];
+ case 2:
+ _c.sent();
+ return [3, 1];
+ case 3:
+ if (contentWindow.document.readyState === 'complete') {
+ return [2, $frame];
+ }
+ loadLog = Cypress.log({
+ name: 'Frame Load',
+ message: [contentWindow.location.toString()],
+ event: true,
+ }).snapshot();
+ return [4, new Promise(function (resolve) {
+ Cypress.$(contentWindow).on('load', resolve);
+ })];
+ case 4:
+ _c.sent();
+ loadLog.end();
+ (_b = log) === null || _b === void 0 ? void 0 : _b.finish();
+ return [2, $frame];
+ }
+ });
+ }); });
+};
+Cypress.Commands.add('frameLoaded', frameLoaded);
+var iframe = function (selector, opts) {
+ if (selector === undefined) {
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ else if (typeof selector === 'object') {
+ opts = selector;
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ var fullOpts = __assign(__assign({}, DEFAULT_OPTS), opts);
+ var log = fullOpts.log ? Cypress.log({
+ name: 'iframe',
+ displayName: 'iframe',
+ message: [selector],
+ }).snapshot() : null;
+ return cy.frameLoaded(selector, __assign(__assign({}, fullOpts), { log: false })).then(function ($frame) {
+ var _a;
+ (_a = log) === null || _a === void 0 ? void 0 : _a.set('$el', $frame).end();
+ var contentWindow = $frame.prop('contentWindow');
+ return Cypress.$(contentWindow.document.body);
+ });
+};
+Cypress.Commands.add('iframe', iframe);
+var enter = function (selector, opts) {
+ if (selector === undefined) {
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ else if (typeof selector === 'object') {
+ opts = selector;
+ selector = DEFAULT_IFRAME_SELECTOR;
+ }
+ var fullOpts = __assign(__assign({}, DEFAULT_OPTS), opts);
+ var log = fullOpts.log ? Cypress.log({
+ name: 'enter',
+ displayName: 'enter',
+ message: [selector],
+ }).snapshot() : null;
+ return cy.iframe(selector, __assign(__assign({}, fullOpts), { log: false })).then(function ($body) {
+ var _a;
+ (_a = log) === null || _a === void 0 ? void 0 : _a.set('$el', $body).end();
+ return function () { return cy.wrap($body, { log: false }); };
+ });
+};
+Cypress.Commands.add('enter', enter);
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/node_modules/cypress-iframe/dist/index.js.map b/node_modules/cypress-iframe/dist/index.js.map
new file mode 100644
index 0000000..d5a2c95
--- /dev/null
+++ b/node_modules/cypress-iframe/dist/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/node_modules/cypress-iframe/index.d.ts b/node_modules/cypress-iframe/index.d.ts
new file mode 100644
index 0000000..4042cc9
--- /dev/null
+++ b/node_modules/cypress-iframe/index.d.ts
@@ -0,0 +1,18 @@
+///
+
+declare namespace Cypress {
+ interface IframeHandler {
+ (options?: Partial): Chainable
+ (selector: string, options?: Partial): Chainable
+ }
+
+ interface IframeOptions extends Loggable, Timeoutable {
+ url?: RegExp | string
+ }
+
+ interface Chainable {
+ frameLoaded: IframeHandler>
+ iframe: IframeHandler>
+ enter: IframeHandler<() => Chainable>>
+ }
+}
diff --git a/node_modules/cypress-iframe/package.json b/node_modules/cypress-iframe/package.json
new file mode 100644
index 0000000..5afc4a4
--- /dev/null
+++ b/node_modules/cypress-iframe/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "cypress-iframe",
+ "version": "1.0.1",
+ "description": "Adds iframe support to Cypress",
+ "main": "dist/index.js",
+ "types": "index.d.ts",
+ "scripts": {
+ "preversion": "npm test",
+ "postversion": "npm publish",
+ "postpublish": "git push origin --all; git push origin --tags",
+ "prepare": "npm run build",
+ "build": "rm -rf dist && tsc --project ./tsconfig-build.json",
+ "start": "start-server-and-test wp http-get://localhost:9000 \"cypress open\"",
+ "test": "start-server-and-test wp http-get://localhost:9000 \"cypress run\"",
+ "record": "start-server-and-test wp http-get://localhost:9000 \"cypress run --record\"",
+ "wp": "webpack-dev-server"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@gitlab.com/kgroat/cypress-iframe.git"
+ },
+ "keywords": [
+ "cypress",
+ "iframe",
+ "command",
+ "e2e",
+ "test"
+ ],
+ "author": {
+ "name": "Kevin Groat (kgroat)",
+ "email": "kgroat09@gmail.com",
+ "url": "https://www.kgroat.dev/"
+ },
+ "license": "MIT",
+ "bugs": {
+ "url": "https://gitlab.com/kgroat/cypress-iframe/issues"
+ },
+ "homepage": "https://gitlab.com/kgroat/cypress-iframe#readme",
+ "peerDependencies": {
+ "@types/cypress": "^1.1.0"
+ },
+ "devDependencies": {
+ "@cypress/webpack-preprocessor": "^4.1.1",
+ "@types/cypress": "^1.1.0",
+ "@types/node": "^13.7.0",
+ "@types/webpack": "^4.41.3",
+ "@types/webpack-dev-server": "^3.10.0",
+ "cypress": "^3.8.3",
+ "start-server-and-test": "^1.10.8",
+ "ts-loader": "^6.2.1",
+ "ts-node": "^8.6.2",
+ "typescript": "^3.7.5",
+ "webpack": "^4.41.5",
+ "webpack-cli": "^3.3.10",
+ "webpack-dev-server": "^3.10.2"
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 9e8c880..d1cf4c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
- "cypress": "^13.7.3"
+ "cypress": "^13.7.3",
+ "cypress-iframe": "^1.0.1"
}
},
"node_modules/@colors/colors": {
@@ -70,6 +71,17 @@
"ms": "^2.1.1"
}
},
+ "node_modules/@types/cypress": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.3.tgz",
+ "integrity": "sha512-OXe0Gw8LeCflkG1oPgFpyrYWJmEKqYncBsD/J0r17r0ETx/TnIGDNLwXt/pFYSYuYTpzcq1q3g62M9DrfsBL4g==",
+ "deprecated": "This is a stub types definition for cypress (https://cypress.io). cypress provides its own type definitions, so you don't need @types/cypress installed!",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "cypress": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
@@ -589,6 +601,15 @@
"node": "^16.0.0 || ^18.0.0 || >=20.0.0"
}
},
+ "node_modules/cypress-iframe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cypress-iframe/-/cypress-iframe-1.0.1.tgz",
+ "integrity": "sha512-Ne+xkZmWMhfq3x6wbfzK/SzsVTCrJru3R3cLXsoSAZyfUtJDamXyaIieHXeea3pQDXF4wE2w4iUuvCYHhoD31g==",
+ "dev": true,
+ "peerDependencies": {
+ "@types/cypress": "^1.1.0"
+ }
+ },
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
diff --git a/package.json b/package.json
index 2bfb481..95e1f3a 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
- "cypress": "^13.7.3"
+ "cypress": "^13.7.3",
+ "cypress-iframe": "^1.0.1"
}
}