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

Cypress中如何单次获取JWT Token并在beforeEach中复用?

如何在Cypress中复用单次获取的JWT Token以提升测试效率

问题背景

我正在为新体验模块编写自动化测试,目前后端新API尚未完成,但前端模块已可用,希望提前写好测试,待切换新API后直接启用。新API支持JWT Token认证,当前测试可正常运行但效率低下——每次beforeEach()都会发送POST请求获取Token,存入sessionStorage后再加载页面。测试覆盖3个页面,每个context块对应一个页面的验证逻辑,需求是仅调用一次API获取Token,后续每次加载浏览器时复用该Token。

已尝试的方法及问题

  • 在before()中生成JWT Token,beforeEach()中引用,触发ReferenceError: oc_token未定义
  • 用let替代const,问题依旧
  • 尝试response.body.access_token.invoke('oc_token').as('oc_token'),beforeEach()中用this.oc_token调用,触发TypeError: response.body.access.invoke不是函数
  • 用cy.wrap(response.body.access_token).as('oc_token'),调用this.oc_token时触发TypeError: 无法读取undefined的属性'oc_token'
  • 用cy.fixture(response.body.access_token).as('oc_token'),调用时触发Error ENAMETOOLING:名称过长

当前测试代码结构

describe('New experience test', () => {
  beforeEach(() => {
    cy.interceptFeatureFlags({
      'new-experience-feature-flags': true
    })

    cy.visit(Cypress.config('baseUrl'));
    cy.window().then(w => {
      cy.request({
        method: 'POST',
        url: 'yadda',
        headers: 'stuff',
        body: { payload }
      }).then((response) => {
        expect(response).property('status').to.equal(200)
        const oc_token = response.body.access_token;
        w.sessionStorage.setItem(
          'jwt',
          oc_token
        )
        w.sessionStorage.setItem(
          'other_jwt',
          oc_token
        )
      })
    });
    cy.fixture('new_experience_context.json').then((context) => {
      button(cy).click();
    });
  });

  context('first page', () => {
    it('shows condition', () => {
      thing.should('exist');
    });
  });

  context('second page', () => {
    beforeEach(() => {
      // 跳转到第二页的步骤
    });

    it('shows condition', () => {
      thing.should('exist');
    });
  });

  context('third page', () => {
    beforeEach(() => {
      // 跳转到第二页的步骤
      // 跳转到第三页的步骤
    });

    it('shows condition', () => {
      thing.should('exist');
    });
  });
});

// DOM元素定位函数

尝试过的代码结构

describe('New experience test', () => {

  before(() => {
    cy.request({
      method: 'POST',
      url: 'yadda',
      headers: 'stuff',
      body: { payload }
    }).then((response) => {
      expect(response).property('status').to.equal(200)
      const oc_token = response.body.access_token;
    });
  });

  beforeEach(() => {
    cy.interceptFeatureFlags({
      'new-experience-feature-flags': true
    })

    cy.visit(Cypress.config('baseUrl'));
    cy.window().then(w => {
        w.sessionStorage.setItem(
          'jwt',
          oc_token
        )
        w.sessionStorage.setItem(
          'other_jwt',
          oc_token
        )
      })
    });
    cy.fixture('new_experience_context.json').then((context) => {
      button(cy).click();
    });
  });

解决方案

方法1:使用Cypress环境变量存储Token

在before()中获取Token后存入Cypress环境变量,后续beforeEach()直接取用,无需跨钩子传递局部变量:

describe('New experience test', () => {
  before(() => {
    cy.request({
      method: 'POST',
      url: 'yadda',
      headers: 'stuff',
      body: { payload }
    }).then((response) => {
      expect(response.status).to.equal(200);
      // 将Token存入Cypress环境变量
      Cypress.env('oc_token', response.body.access_token);
    });
  });

  beforeEach(() => {
    cy.interceptFeatureFlags({
      'new-experience-feature-flags': true
    });

    cy.visit(Cypress.config('baseUrl'));
    cy.window().then(w => {
      const oc_token = Cypress.env('oc_token');
      w.sessionStorage.setItem('jwt', oc_token);
      w.sessionStorage.setItem('other_jwt', oc_token);
    });
    
    cy.fixture('new_experience_context.json').then(() => {
      button(cy).click();
    });
  });

  // 各页面测试用例...
});

方法2:使用Cypress别名(正确用法)

若想用别名传递Token,需注意:before()中定义别名后,beforeEach()需用普通函数(不能用箭头函数),通过this.oc_token或cy.get('@oc_token')获取:

describe('New experience test', () => {
  before(() => {
    cy.request({
      method: 'POST',
      url: 'yadda',
      headers: 'stuff',
      body: { payload }
    }).then((response) => {
      expect(response.status).to.equal(200);
      // 用cy.wrap包装Token后存为别名
      cy.wrap(response.body.access_token).as('oc_token');
    });
  });

  beforeEach(function() {
    // 必须用普通函数,箭头函数会导致this指向丢失
    cy.interceptFeatureFlags({
      'new-experience-feature-flags': true
    });

    cy.visit(Cypress.config('baseUrl'));
    // 通过this访问别名
    const oc_token = this.oc_token;
    cy.window().then(w => {
      w.sessionStorage.setItem('jwt', oc_token);
      w.sessionStorage.setItem('other_jwt', oc_token);
    });
    
    cy.fixture('new_experience_context.json').then(() => {
      button(cy).click();
    });
  });

  // 各页面测试用例...
});

关键注意点

  • 局部变量无法跨钩子访问:before()内定义的局部变量oc_token作用域仅限当前钩子,beforeEach()无法直接读取,这是之前报错的核心原因。
  • 箭头函数会破坏this绑定:若用箭头函数定义beforeEach,this.oc_token会取不到值,必须改用普通函数。
  • cy.fixture用途错误:该方法用于加载本地JSON文件,不能直接存储Token,因此之前用它存Token会触发文件名过长错误。

内容的提问来源于stack exchange,提问作者rgorowsky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 12:20:23