TestCafe中Role跨文件使用报错及页面重复加载问题咨询
我来帮你搞定这两个TestCafe的实际问题,都是日常写测试时容易踩的坑:
问题一:跨文件调用Role提示undefined的解决办法
你遇到的问题其实是两个小细节没处理对:
- 导出语法写错了:角色定义文件里最后一行是
module.export,但Node.js的正确导出语法是module.exports(多了个s),这个小错误直接导致其他文件无法正确导入你的角色实例,自然会报undefined。 - 导入方式和导出不匹配:你用
import NormalUser from './Support/utilities'导入时,其实拿到的是整个导出对象(包含SuperUser和NormalUser两个角色),但你把这个对象命名成了NormalUser,然后又去访问NormalUser.NormalUser,等于在一个叫NormalUser的对象里找另一个NormalUser属性,这肯定不对。
修正后的角色文件(/Support/utilities)
先把导出语法改对,顺便提一句:你的NormalUser角色里,处理登录错误时用了超级用户的账号(l1),这大概率是笔误,应该换成普通用户的l0,不然登录失败后反而切到超级用户了,不符合预期:
import channelsPage from '..' import config from '../Config/config'; import {Role} from 'testcafe'; import loginPage from '..'; let l1 = require('../support/global').log[1]; let l0 = require('../support/global').log[0]; const SuperUser = Role(config.baseUrl, async t => { await loginPage.logIn(l1.username, l1.password) if (await loginPage.keycloakLoginError.exists) { await loginPage.logIn(l1.username, l1.password) } else { await t.expect(channelsPage.lineupsAndPackages.exists).ok(); await t.expect(channelsPage.createDropUp.exists).ok(); } }) const NormalUser = Role(config.baseUrl, async t => { await loginPage.logIn(l0.username, l0.password) if (await loginPage.keycloakLoginError.exists) { // 这里改成l0的账号,避免切到超级用户 await loginPage.logIn(l0.username, l0.password) } else { await t.expect(channelsPage.lineupsAndPackages.exists).ok(); await t.expect(channelsPage.createDropUp.exists).ok(); } }) // 修正导出语法 module.exports = { SuperUser, NormalUser }
测试文件的正确导入方式
有两种简单的方式:
- 解构导入(推荐):直接导入需要的角色,不用再嵌套访问:
import config from './Config/config'; // 用解构语法只导入NormalUser import { NormalUser } from './Support/utilities'; fixture`SanityTests` .beforeEach(async t => { await t.maximizeWindow() }) .page`${config.baseUrl}`; test('Search', async t => { await t.maximizeWindow(); // 直接用导入的NormalUser await t.useRole(NormalUser) });
- 导入整个对象:如果需要多个角色,可以导入整个对象再访问属性:
import config from './Config/config'; // 把导出的角色对象命名为roles import roles from './Support/utilities'; fixture`SanityTests` .beforeEach(async t => { await t.maximizeWindow() }) .page`${config.baseUrl}`; test('Search', async t => { await t.maximizeWindow(); await t.useRole(roles.NormalUser) });
问题二:避免Role和Fixture重复加载页面的方法
其实TestCafe本身就有优化机制:如果Fixture设置的page和Role构造函数里的URL完全一致(包括协议、域名、路径这些细节),TestCafe不会重复加载页面。如果还是遇到重复加载的情况,可以试试这几个办法:
方法1:给Role加preserveUrl选项
创建Role时添加第三个参数{ preserveUrl: true },这个选项会让TestCafe切换角色时保留当前页面,而不是重新导航到Role指定的URL。适合已经在Fixture中打开页面后再切换角色的场景:
const NormalUser = Role(config.baseUrl, async t => { await loginPage.logIn(l0.username, l0.password) // ... 登录逻辑 }, { preserveUrl: true })
方法2:不设置Fixture的page,让Role负责导航
如果不需要在测试前就打开页面,可以去掉Fixture的.page配置,直接在beforeEach里调用useRole,TestCafe会直接导航到Role指定的URL,自然不会重复加载:
fixture`SanityTests` .beforeEach(async t => { await t.maximizeWindow() // 先切换角色,TestCafe会自动导航到Role的URL await t.useRole(NormalUser) }) // 不要设置.page选项 test('Search', async t => { // 此时已经是登录后的页面,直接写测试逻辑就行 // ... });
方法3:统一URL配置,依赖TestCafe自动优化
确保Fixture的page和Role的URL完全相同(比如都用config.baseUrl),TestCafe会自动识别这种情况,只加载一次页面。如果你的URL有路径差异,比如Fixture设的是config.baseUrl,Role设的是config.baseUrl/login,那肯定会重复加载,所以尽量保持两者一致。
另外,如果实在需要Fixture有起始页面,也可以设成about:blank,然后在beforeEach里调用useRole,这样也能避免不必要的加载。
内容的提问来源于stack exchange,提问作者Monia

