I am new to Cypress and I am trying to handle the usage of new application tabs.
I have a button without a link
When clicking on this button, a new tab is opened with a random id in the URL (eg. '/ticket/{some-id}')
I have a Cypress test project with typescript. I am trying to take that link of the new tab and use it in the current test runner browser.
I have followed the examples from https://glebbahmutov.com/blog/cypress-tips-and-tricks/#deal-with-windowopen but I have some errors:
Error for .wrappedMethod: https://i.sstatic.net/Sq2Yq.png : Property 'wrappedMethod' does not exist on type '((url?: string | URL, target?: string, features?: string) => Window) & ((url?: string | URL, target?: string, features?: string) => Window)'.
Error for .as('open'): https://i.sstatic.net/E3u2b.png : Property 'as' does not exist on type 'SinonStub<any[], any>'.
Note: This error is happening only for .ts files. The method works for .js file. But I need to have the tests in typescript
Could someone please help me understand if I need some specific dependencies/ configuration to make it work?
This is my code: tsconfig.json:
{
"compilerOptions": {
"baseUrl": "../node_modules",
"target": "es6",
"module": "commonjs",
"allowJs": true,
"lib": ["es6", "dom", "dom.iterable"],
"types": ["cypress", "@testing-library/cypress", "node"]
},
"include": ["**/*.ts", "cypress.config.ts.test"]
}
package.json:
{
"name": "E2E test suite",
"version": "1.0.0",
"description": "Cypress e2e tests",
"main": "index.js",
"scripts": {
"cy:open": "cypress open",
"cy:run": "cypress run",
"format": "prettier . --write"
},
"dependencies": {
"@cspell/eslint-plugin": "^8.4.1",
"dotenv": "^16.0.0",
"faker": "^6.6.6",
"npx": "^10.2.2"
},
"devDependencies": {
"@bahmutov/cy-api": "^2.2.6",
"@cypress/puppeteer": "^0.1.3",
"@faker-js/faker": "^8.4.1",
"@testing-library/cypress": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"@typescript-eslint/parser": "^7.1.0",
"chai": "^5.0.3",
"cypress": "^13.7.0",
"cypress-await": "^1.6.2",
"cypress-codegen": "^2.0.0",
"cypress-wait-until": "^3.0.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"prettier": "^3.2.5",
"typescript": "^4.2.3"
}
}
test.cy.ts class:
import { parkingLotAccessPage } from '../../support/pageObjects/pageElements/parkingLot/parking-lot-access.page';
describe('Parking Lot Access', () => {
beforeEach(() => {
cy.visit('/');
});
it('should successfully access parking lot while still available spaces', function () {
cy.window().then((win) => {
cy.stub(win, 'open')
.callsFake((url, target) => {
expect(target).to.be.undefined;
return win.open.wrappedMethod.call(win, url, '_self');
})
.as('open');
});
parkingLotAccessPage.openBarrierButton().click();
});
});
parkingLotAccessPage.page.ts Page Object:
class ParkingLotAccessPage {
private elements = {
openBarrierButton: () => cy.get('.barrier-button'),
};
get openBarrierButton() {
return this.elements.openBarrierButton;
}
}
export const parkingLotAccessPage = new ParkingLotAccessPage();
cypress.config.ts:
import { defineConfig } from 'cypress';
require('dotenv').config();
export default defineConfig({
screenshotOnRunFailure: false,
video: false,
defaultCommandTimeout: 10000,
retries: {
runMode: 2
},
env: {
apiUrl: process.env.BASE_API ?? 'http://localhost:8080',
userPassword: process.env.USER_PASSWORD,
userName: process.env.USER_NAME,
adminPassword: process.env.ADMIN_PASSWORD,
adminUserName: process.env.ADMIN_NAME
},
e2e: {
baseUrl: process.env.BASE_URL ?? 'http://localhost:3000',
supportFile: 'cypress/support/e2e.ts'
}
});
The cy.stub()
command uses Sinon under the hood, so the first thing you need is the sinon types:
npm install --save @types/sinon
and add in tsconfig.json
{
"compilerOptions": {
...
"types": ["cypress", "@testing-library/cypress", "node", "@types/sinon/index.d.ts"]
Then in the test you can solve #1 wrappedMethod with a cast, and #2 .as()
by reversing the chaining order
cy.window().then((win) => {
cy.stub(win, 'open')
.as('open')
.callsFake((url, target) => {
expect(target).to.be.undefined;
return (win.open as sinon.SinonStub).wrappedMethod.call(win, url, '_self')
})
})
Here is the Cypress/Typescript test with the code to trigger window.open
made generic (will work without the app)
cy.window().then(win => {
cy.stub(win, 'open')
.as('open')
.callsFake((url, target) => {
expect(target).to.be.undefined
return (win.open as sinon.SinonStub).wrappedMethod.call(win, url, '_self')
})
})
cy.window().then(win => {
win.open('https://example.com')
})
cy.get('@open')
.should('have.been.calledOnceWithExactly', 'https://example.com')