全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-690-7320

在 Cypress 测试中创建和重用对象数据

在 Cypress 测试中创建和重用对象数据

在 cypress 测试中,直接在异步回调函数外部访问变量常导致 '未定义' 错误。本文将详细讲解如何利用 cypress 的别名(alias)机制,从服务器响应中捕获并封装复杂数据对象。通过 `cy.wrap().as()` 创建别名,再使用 `cy.get().then()` 安全地在后续测试步骤中重用这些数据,从而有效管理测试状态,提升测试代码的健壮性和可维护性。

在 Cypress 端到端测试中,经常需要从前一个步骤(例如 API 响应)中提取数据,并在后续步骤中重用。然而,由于 Cypress 命令的异步性质和其独特的命令队列机制,直接在 cy.then() 回调函数内部定义变量并尝试在外部访问,通常会导致 ReferenceError: [变量名] is not defined 的错误。这正是许多初学者在尝试将响应数据保存为普通 J*aScript 对象并在测试中后续步骤重用时遇到的常见挑战。

理解问题:为什么直接定义变量会失败?

考虑以下场景,我们希望从服务器响应中解析出一个商品对象 Item,并在后续的 cy.addItemToShoppingCart 命令中使用它:

cy.wait('@pageLoaded').then(({ response }) => {
    expect(response.statusCode).to.equal(200);

    let i = randomItem();

    // 在回调函数内部创建对象
    const Item = {
        Id: response.body.items[i].id,
        IpuCode: response.body.items[i].ipuCode,
        Description: response.body.items[i].description,
        PackSize: response.body.items[i].packSize,
        PackType: response.body.items[i].packType,
    };

    cy.log(Item); // 在这里可以正常访问 Item
});

// 尝试在这里重用 Item
// cy.addItemToShoppingCart(Item.IpuCode, pharmacyId, Item.Id, currentDateTime);
// 结果:ReferenceError: Item is not defined

Item 变量是在 cy.then() 的回调函数作用域内定义的。当 Cypress 执行到 cy.addItemToShoppingCart 这行代码时,外部作用域并不知道 Item 变量的存在,因为 cy.then() 的回调函数可能尚未执行,或者即使执行了,其内部变量也不会自动暴露到外部命令队列中。Cypress 的命令是排队执行的,而不是像普通 J*aScript 那样立即执行。

解决方案:使用 Cypress 别名(Aliases)管理对象数据

Cypress 提供了一种强大且优雅的机制来解决这个问题,即使用别名(Aliases)。别名允许我们将数据、DOM 元素或路由请求保存起来,并在测试的任何后续步骤中通过其别名进行引用。对于复杂的数据对象,我们可以使用 cy.wrap() 命令将其包装成一个可别名的 Cypress Subject。

1. 捕获数据并创建别名

首先,在获取到服务器响应并构建出所需的对象后,使用 cy.wrap() 将该对象包装起来,并通过 .as() 命令为其指定一个别名。

医院网站系统 医院网站系统

HTML医院网站系统基于PHP+MYSQL开发,在文章内容网站的基础上,预设了医院概况、新闻动态、环境设备、名医荟萃、专科介绍、就医指南、专家门诊值班表、网上挂号、医疗保健知识、在线咨询等医院网站常用的栏目和测试数据,采用适合医院网站的专用模版,增强了系统的针对性和易用性。系统具有文章、图文、下载、社区、表单、用户等基本系统模块和一系列网站辅助功能,用户也可根据自身特点任意创建和修改栏目,适合创建

医院网站系统 0 查看详情 医院网站系统
cy.wait('@pageLoaded').then(({ response }) => {
    expect(response.statusCode).to.equal(200);

    let i = randomItem();

    // 从响应中提取数据并构建对象
    const itemData = {
        id: response.body.items[i].id,
        ipuCode: response.body.items[i].ipuCode,
        description: response.body.items[i].description,
        packSize: response.body.items[i].packSize,
        packType: response.body.items[i].packType,
    };

    // 使用 cy.wrap() 包装对象并创建别名
    cy.wrap(itemData).as('itemDetails'); // 建议使用驼峰命名法
    cy.log('Aliased Item Details:', itemData);
});

在上述代码中,我们将从响应中解析出的商品信息封装成 itemData 对象,然后使用 cy.wrap(itemData).as('itemDetails') 将其保存为名为 'itemDetails' 的别名。

2. 在后续测试中重用别名对象

要访问已保存的别名对象,需要使用 cy.get('@aliasName') 命令。这个命令会从 Cypress 的内部存储中检索别名所指向的值,并将其作为下一个命令的主题(subject)传递。通常,我们会紧接着使用 .then() 回调函数来处理这个别名对象。

// 在测试的后续步骤中
cy.get('@itemDetails').then(item => {
    // 此时,item 变量就是我们之前保存的 itemDetails 对象
    cy.log('Reusing Aliased Item:', item);

    // 现在可以安全地访问 item 对象的属性
    cy.addItemToShoppingCart(item.ipuCode, pharmacyId, item.id, currentDateTime);
    // ... 其他使用 item 属性的 Cypress 命令
});

通过这种方式,cy.get('@itemDetails') 将等待 itemDetails 别名可用(即 cy.wrap().as('itemDetails') 命令执行完毕),然后将其值传递给 .then() 回调函数。这样就确保了数据的正确传递和可用性,避免了作用域问题。

完整示例代码

// Cypress 测试文件
describe('商品购物车功能测试', () => {

    let pharmacyId = 'somePharmacyId'; // 示例变量
    let currentDateTime = new Date().toISOString(); // 示例变量

    function randomItem() {
        // 模拟随机选择一个商品索引
        return Math.floor(Math.random() * 5); // 假设有5个商品
    }

    it('应该能够从响应中获取商品并添加到购物车', () => {
        // 1. 访问页面并等待 API 响应
        cy.visit('/some-page'); // 假设页面会触发一个名为 '@pageLoaded' 的 API 请求
        cy.intercept('GET', '/api/items*', { fixture: 'items.json' }).as('pageLoaded'); // 模拟 API 响应

        cy.wait('@pageLoaded').then(({ response }) => {
            expect(response.statusCode).to.equal(200);

            let i = randomItem();

            // 2. 从响应中解析数据并创建对象
            const itemData = {
                id: response.body.items[i].id,
                ipuCode: response.body.items[i].ipuCode,
                description: response.body.items[i].description,
                packSize: response.body.items[i].packSize,
                packType: response.body.items[i].packType,
            };

            // 3. 将对象保存为 Cypress 别名
            cy.wrap(itemData).as('itemDetails');
            cy.log('已将商品详情保存为别名:', itemData);
        });

        // 4. 在后续测试步骤中重用别名对象
        cy.get('@itemDetails').then(item => {
            cy.log('从别名中获取商品:', item);
            // 假设 cy.addItemToShoppingCart 是一个自定义 Cypress 命令
            cy.addItemToShoppingCart(item.ipuCode, pharmacyId, item.id, currentDateTime);

            // 进一步的断言或操作
            cy.get('.shopping-cart-item').should('contain', item.description);
            cy.get('.shopping-cart-item').should('contain', item.packSize);
        });
    });
});

// 假设在 cypress/support/commands.js 中定义了自定义命令
// Cypress.Commands.add('addItemToShoppingCart', (ipuCode, pharmacyId, itemId, dateTime) => {
//     cy.request('POST', '/api/add-to-cart', {
//         ipuCode,
//         pharmacyId,
//         itemId,
//         dateTime
//     }).then(response => {
//         expect(response.status).to.equal(200);
//         cy.log('商品已添加到购物车');
//     });
// });

注意事项与最佳实践

  1. 命名约定: 在 J*aScript 中,通常推荐使用驼峰命名法(camelCase)来命名变量和对象属性(例如 ipuCode 而不是 IpuCode)。这有助于保持代码风格的一致性。
  2. 别名范围: Cypress 别名在当前 it 块中是可用的。如果需要在多个 it 块之间共享数据,可以使用 beforeEach 或 before 钩子来定义别名,或者将数据存储到 Cypress.env() 中(但对于测试内部数据,别名通常更合适)。
  3. 单值别名: 即使是单个值,也可以使用 cy.wrap(value).as('aliasName') 来创建别名,然后通过 cy.get('@aliasName').then(value => { /* use value */ }) 来访问。
  4. 清晰的测试流程: 使用别名有助于将数据获取和数据使用逻辑分离,使测试代码更具可读性和可维护性。

总结

通过 Cypress 的别名机制,我们可以有效地管理测试中的异步数据流,避免因 J*aScript 作用域和 Cypress 命令队列特性引起的问题。将从响应中获取的复杂数据对象通过 cy.wrap().as() 保存为别名,并在后续步骤中通过 cy.get('@aliasName').then() 安全地重用,是编写健壮、可维护的 Cypress 测试的关键实践之一。这种方法不仅解决了数据访问问题,也提升了测试代码的结构性和可读性。

以上就是在 Cypress 测试中创建和重用对象数据的详细内容,更多请关注其它相关文章!


# 将其  # 台州最好的网站建设  # 石楼放心选网站推广案例  # 示范合同网站建设方案  # 厦门seo公司报价  # 海原县关键词seo排名优化  # 抖音推广引流的营销方案  # 天津营销推广的方式方法  # 房产网站建设程序  # 手机网站建设6大  # 佛山专业的网站建设团队  # 数据结构  # 在这里  # 测试中  # 购物车  # 可以使用  # javascript  # 有哪些  # 保存为  # 并在  # 回调  # 为什么  # 作用域  # 数据访问  # 路由  # ai  # mac  # 回调函数  # json  # js  # java 


相关文章: 京东京造J1和网易云音乐氧气真无线有什么不同_国产电商蓝牙耳机音质对比  J*aScript教程:根据元素文本内容动态设置背景色  win11开机启动修复循环怎么办 Win11无法进入系统高级启动解决方法【修复】  css滚动动画效果怎么实现_使用Animate.css滚动触发动画类  J*aScript中安全有效地处理localStorage字符串数据  Go语言中动态执行代码字符串的策略与实践  Basecamp怎样用留言钉固定重点_Basecamp用留言钉固定重点【重点标记】  Golang并发任务中错误如何聚合_Golang goroutine error收集方式  163邮箱登录密码 163邮箱忘记密码找回  J*aScript map 迭代中检测空数组元素的有效方法  可靠CSGO开箱平台解析 CSGO开箱网合集  如何优雅地扩展SprykerGlue后端API授权逻辑,使用spryker/glue-backend-api-application-authorization-connector-extension  搜狗浏览器如何使用密码生成器创建强密码 搜狗浏览器内置密码安全工具  如何修改开机登录密码_Windows账户安全设置超详细教程【必学】  Win11怎么合并任务栏图标 Win11开启任务栏合并减少图标占空间【方法】  限制HTML日期输入框的日期选择范围  如何在复杂的电商平台中优雅地管理共享资源并确保正确重定向,使用spryker-shop/resource-share-page模块助你一臂之力  蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接  Yii2模块参数配置指南:正确声明与访问模块级配置  动漫花园资源网使用步骤_动漫花园资源网下载流程  高德地图公交到站提醒失败如何解决 高德提醒权限设置  我的世界官方游戏入口 我的世界官网平台直达链接  C++ explicit关键字防止隐式转换_C++构造函数安全规范  红果短剧网页版官网入口 官方最新网址发布  css绝对定位元素脱离父容器怎么办_确保父元素position非static  AO3同人作品网入口 AO3搜索引擎官网永久地址  解决macOS Tkinter应用双击启动崩溃:PyInstaller打包指南  蛙漫画网页版全站入口 蛙漫热门作品免费浏览  C++的std::forward_list怎么用_C++ STL中单向链表容器的特点与应用  Golang如何优化CPU绑定任务分配策略_Golang CPU任务分配优化实践  J*a中实现Go语言select通道多路复用机制  智慧团建扫码登录入口 智慧团建扫码登录入口官网版​  利用5118提升短视频内容效果_5118短视频关键词优化方法  响应式CSS Grid布局:优化网格项在小屏幕下的堆叠与宽度适配  MongoDB聚合管道:正确匹配对象数组中_id的方法  J*aScript中高效管理与清空动态列表:避免循环陷阱  2026年CSGO开箱网站推荐 CSGO开箱平台精选  word中如何让数字纵向排列_Word数字纵向排列方法  聚水潭ERP登录页面入口 聚水潭ERP官网登录界面  Lar*el 8 多关键词数据库搜索优化实践  文心一言怎样用插件调度API数据_文心一言用插件调度API数据【API调用】  在哪找SublimeJ远程工具_SFTP插件配置教程  小红书网页版入口链接分享 小红书官网直接进  Win11 USB传输速度慢怎么解决 Win11 USB驱动更新与设置  QQ邮箱网页版入口 QQ邮箱官方邮箱登录通道  纯CSS与HTML网格布局的HTML精简策略:SVG与JS方案解析  PHP面向对象编程中避免重复创建PDO数据库连接的最佳实践  UC浏览器网页版登录入口官网 电脑版网址入口  抖音网页版怎么|直播|_抖音网页版开播操作指南  微信网页版登录教程_微信网页版登录入口在哪 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。