Testcafe的使用

93 阅读2分钟

使用Testcafe搭建一个前端自动化测试框架,要如何开始,需要用到Testcafe的哪些知识

1. 准备开发环境:安装nodeJS 以及 Testcafe

node init
node install testcafe

2. 基本配置文件:新建一个testcaferc.json

在这个配置文件中,定义了当失败时截图的保存规则,

skipJsErros让Testcafe忽略测试网页上发生的Javascript错误。

selectorTimeout指定Testcafe等待一个页面元素的时间,超过这个时间就会报错。

pageLoadTimeout指定Testcafe等待一个网页加载完成的时间,超过这个时间就会开始测试。

assertionTimeout指定Testcafe等待一个断言通过的时间,超过这个时间就会报错。

{
"screenshots":{
    "path": "./screenshots",
    "takeOnFails": true,
    "pathPattern": "${DATE}_${TIME}/${USERAGENT}/${TEST_ID}.png",
    "fullPage": true
},
"skipJsErrors": true,
"selectorTimeout": 50000,
"pageLoadTimeout": 10000,
"assertionTimeout": 20000
}

3. 使用PageObject模式搭建

新建文件夹,名为pages,存放页面对象模型类

新建文件夹,名为tests,创建测试脚本

4. 在pages文件夹下写页面抽象类

以登录页面为例,封装页面类 login,构造器内初始化用户名,密码和登录按钮的定位方式。定义login方法,供外部调用。

export default class login{
constructor() {
    this.userNameInput = Selector("#userName");
    this.passwordInput = Selector("#password");
    this.loginButton = Selector("#login");
}

async login(userName, password){
    await t
       .typeText(this.userNameInput, userName)
       .typeText(this.passwordInput, password)
       .click(this.loginButton)
}
}

以导航栏为例,一般来说,我们会对导航栏单独定义页面对象类。

export defalut class Navigation{
constructor(){
    const a = Selector('a');
    this.homePage = a.withText('Home');
    this.settingPage = a.withText('settings');
}
}

5. 对登录页面使用Role,适应登录不同环境

在Testcafe中,可以使用Role来切换不同的角色。Testcafe会自动保存和恢复Role的认证数据,提高测试效率和灵活性。

Role的生命过程包括:创建、激活、注销。

Role的优点:

  • 只执行一次登录过程,缓存和重用认证数据。
  • 可以在多个网站之间共享认证数据。
  • 可以自动导航到登录页面和返回页面。
  • 可以通过preserveUrl选项来保留登录后的页面。
const userSIT = Role(
`url`,
async () => {
    const userName = process.env['USERNAME'];
    const password = process.env['PASSWORD'];
    const page_login = new Login();
    aswit page_login.login(userName, password);
)

6. 试写一个测试用例

const navigation = new Navigation();
fixture `access settings page`.beforeEach(async() => {
    await t.userRole(userSIT).navigateTo(url);
});

test('access setting page', async () => {
    await t.click(navigation.setting);
}
)

断言一般用哪些方法

# 判断元素文本是否符合预期
await t.expect(element.innerText).eql('result');
# 判断元素值是否符合预期
await t.expect(element.value).eql('result');
# 判断按钮是否存在
await t.expect(this.editBtn.exists).ok();
# 判断元素是否具有该属性
await t.expect(this.editBtn.hasAttribute('disabled'));
# 用包含方法来做模糊查询
await t.expect(getLocation()).contains('heading');

选择元素的常用方法

Selector('.className').filterVisible().withAttribute(value, '111');
Selector('.className').filterVisible().withText();
Selecotr('.className').nth(0).value;
t.typeText(element, value, {replace: true})
const getLocation = ClientFunction(()=> document.location.href));

7. 配置package.json文件

"scripts":{
    "run_e2e_local": "testcafe chrome ./src/tests --reporter html:report/report.html",
    "run_e2e_docker": "testcafe chromium:headless,firefox:headless ./src/tests --reporter html:report/report.html"
}