You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:03:27