使用TypeScript处理Cypress新标签页遇类型错误求助
问题
我是Cypress新手,正在处理应用中新标签页的场景:点击无链接按钮会打开带随机ID的URL(如/ticket/{some-id})的新标签页,项目基于TypeScript,希望获取新标签页链接并在当前测试浏览器中使用。
参考window.open处理示例后,在.ts文件中出现两个类型错误:
.wrappedMethod报错:类型“((url?: string | URL, target?: string, features?: string) => Window) & ((url?: string | URL, target?: string, features?: string) => Window)”上不存在属性“wrappedMethod”。.as('open')报错:类型“SinonStub<any[], any>”上不存在属性“as”。
注:该方法在.js文件中可正常工作,但需要用TypeScript编写测试,询问是否需要特定依赖或配置解决。
以下是项目配置及代码:
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
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
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' } });
解决方案
1. 解决.wrappedMethod类型错误
Cypress的cy.stub基于Sinon实现,TypeScript中无法直接识别wrappedMethod属性,可通过保存原始方法或类型断言两种方式处理:
方式一:保存原始方法(推荐)
cy.window().then((win) => { const originalOpen = win.open; // 提前保存原始open方法 cy.stub(win, 'open') .callsFake((url, target) => { expect(target).to.be.undefined; return originalOpen.call(win, url, '_self'); // 调用原始方法 }) });
方式二:类型断言
import type { SinonStub } from 'sinon'; cy.window().then((win) => { cy.stub(win, 'open') .callsFake((url, target) => { expect(target).to.be.undefined; return (win.open as SinonStub).wrappedMethod.call(win, url, '_self'); }) });
2. 解决.as('open')类型错误
as是Cypress命令链的方法,而cy.stub返回的是Sinon Stub对象,直接链式调用会触发类型错误。需要用cy.wrap将Stub转换为Cypress命令对象后再设置别名:
cy.window().then((win) => { const originalOpen = win.open; cy.stub(win, 'open') .callsFake((url, target) => { expect(target).to.be.undefined; return originalOpen.call(win, url, '_self'); }) .then(stub => cy.wrap(stub).as('open')); // 转换后设置别名 });
3. 完善TypeScript配置
安装Sinon类型定义依赖:
npm install @types/sinon --save-dev
修改tsconfig.json的types数组,添加sinon:
"types": ["cypress", "@testing-library/cypress", "node", "sinon"]
完整修改后的测试代码
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) => { const originalOpen = win.open; cy.stub(win, 'open') .callsFake((url, target) => { expect(target).to.be.undefined; return originalOpen.call(win, url, '_self'); }) .then(stub => cy.wrap(stub).as('open')); }); parkingLotAccessPage.openBarrierButton().click(); // 验证stub调用参数,获取随机ID的URL cy.get('@open').should('have.been.calledWithMatch', '/ticket/'); }); });
内容的提问来源于stack exchange,提问作者QA Testing
相关产品推荐
相关产品推荐

