本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-02-26
fixture `MyFixture`;
test('Test1', async t => {
/* Test 1 Code */
});
// 会被跳过
test.skip('Test2', async t => {
/* Test 2 Code */
});
// 会被跳过
test('Test3', async t => {
/* Test 4 Code */
});
// 只会执行这一条,但是如果当前 fixture 也是 fixture.only
// 那么该fixture下所有没有被skip的test都会执行 尽管你只在某一个test上设置了only
test.only('Test4', async t => {
/* Test 5 Code */
});
fixture 钩子函数有:
fixture
.page('www.test.com')
.before(async ctx => {
// 在测试开始前执行 参数是执行上下文
ctx.someVal = 1;
})
.beforeEach(async t => {
// 在每个test执行前,参数是 t: TestController
})
.after(async ctx => {
})
.afterEach(async t => {
})
text('demo1', async t => {
console.log(t.fixtureCtx.someVal); // 1
})
test 钩子函数有:
// 钩子函数的参数都是 t: TestController
test.before(async t => {
console.log(t);
})
('demo2', async t => {
await t.navigateTo(_CONFIG.INDEX);
await t.expect(userAccount.textContent).match(/\d{3}\*{4}\d{3}/);
}).after(async t => {
// 进行解绑 恢复初始状态
await t.click(actionBtn);
await unbind_page.unbindAccount(i);
})
可以使用 metadata 为 fixture/test 进行配置标签,然后使用 filter.fixtureMeta/filter.testMeta 来进行过滤。
命令行式:
# 只跑 device=mobile,env=production 标签的测试
testcafe chrome my-tests --fixture-meta device=mobile,env=production
testcafe chrome my-tests --test-meta device=mobile,env=production
或者修改配置文件.testcaferc.json
:
{
"filter": {
"fixtureMeta": {
"device": "mobile",
"env": "production"
},
"testMeta": {
"device": "mobile",
"env": "production"
}
}
}
配置的方式:
fixture `My fixture`
.meta('fixtureID', 'f-0001')
.meta({ author: 'John', creationDate: '05/03/2018' });
test
.meta('testID', 't-0005')
.meta({ severity: 'critical', testedAPIVersion: '1.0' })
('MyTest', async t => { /* ... */});
import { Selector } from 'testcafe';
const article = Selector('#article-content');
// or
const article = Selector(() => {
return document.getElementById('article-content');
});
Selector()
选择器函数会返回一个 Selector 类型的对象。拥有对应元素DOM属性和获取属性值的方法,返回的都是Promise
封装的。同时也拥有继续查找的方法,这些也都是返回一个 Selector 对象。
interface SelectorAPI {
childElementCount: Promise<number>;
childNodeCount: Promise<number>;
hasChildElements: Promise<boolean>;
hasChildNodes: Promise<boolean>;
nodeType: Promise<number>;
textContent: Promise<string>;
attributes: Promise<{[name: string]: string}>;
boundingClientRect: Promise<TextRectangle>;
checked: Promise<boolean | undefined>;
classNames: Promise<string[]>;
clientHeight: Promise<number>;
clientLeft: Promise<number>;
clientTop: Promise<number>;
clientWidth: Promise<number>;
focused: Promise<boolean>;
id: Promise<string>;
innerText: Promise<string>;
namespaceURI: Promise<string | null>;
offsetHeight: Promise<number>;
offsetLeft: Promise<number>;
offsetTop: Promise<number>;
offsetWidth: Promise<number>;
selected: Promise<boolean | undefined>;
selectedIndex: Promise<number | undefined>;
scrollHeight: Promise<number>;
scrollLeft: Promise<number>;
scrollTop: Promise<number>;
scrollWidth: Promise<number>;
style: Promise<{[prop: string]: string}>;
tagName: Promise<string>;
value: Promise<string | undefined>;
visible: Promise<boolean>;
hasClass(className: string): Promise<boolean>;
getStyleProperty(propertyName: string): Promise<string>;
getAttribute(attributeName: string): Promise<string>;
getBoundingClientRectProperty(propertyName: string): Promise<number>;
hasAttribute(attributeName: string): Promise<boolean>;
nth(index: number): Selector;
withText(text: string): Selector;
withText(re: RegExp): Selector;
withExactText(text: string): Selector;
withAttribute(attrName: string | RegExp, attrValue?: string | RegExp): Selector;
filter(cssSelector: string): Selector;
filter(filterFn: (node: Element, idx: number) => boolean,
dependencies?: {[key: string]: any}): Selector;
filterVisible(): Selector;
filterHidden(): Selector;
find(cssSelector: string): Selector;
find(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
parent(): Selector;
parent(index: number): Selector;
parent(cssSelector: string): Selector;
parent(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
child(): Selector;
child(index: number): Selector;
child(cssSelector: string): Selector;
child(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
sibling(): Selector;
sibling(index: number): Selector;
sibling(cssSelector: string): Selector;
sibling(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
nextSibling(): Selector;
nextSibling(index: number): Selector;
nextSibling(cssSelector: string): Selector;
nextSibling(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
prevSibling(): Selector;
prevSibling(index: number): Selector;
prevSibling(cssSelector: string): Selector;
prevSibling(filterFn: (node: Element, idx: number, originNode: Element) => boolean,
dependencies?: {[key: string]: any}): Selector;
exists: Promise<boolean>;
count: Promise<number>;
addCustomDOMProperties(props: {[prop: string]: (node: Element) => any}): Selector;
addCustomMethods(methods: {[method: string]: (node: Element, ...methodParams: any[]) => any }, opts?: {returnDOMNodes?: boolean}): Selector;
with(options?: SelectorOptions): Selector;
}
所以在获取属性的时候,都需要 await
const button = Selector('button').withText("A button number"); // buttons: Selector
const classNames = await button.classNames;
await t.expect(classNames).contains('btn');
// 或者直接传 Promise<any> 给 t.expect()
await t.expect(button.classNames).contains('btn');
还有对应扩展的 Vue、React、Angular Selector。 具体介绍
存储捕捉测试执行期间收到的请求发送和响应。
import { RequestLogger } from 'testcafe';
const wxMapLogger = RequestLogger(indexListNavItem[4].link, {
// logResponseHeaders
logResponseBody: true,
// stringifyResponseBody: true, // 要与 logResponseBody 一起使用
// logRequestHeaders
// logRequestBody
// stringifyRequestBody
// 以上属性都接收 Boolean 值作为选项,默认均为 false
});
fixture `My fixture`
.page `http://example.com`
.requestHooks(wxMapLogger);
test('My test', async t => {
await t
.click('.btn')
.wait(1000)
.expect(wxMapLogger.contains(r => r.response.statusCode === 200)).ok()
.expect(wxMapLogger.count(r => r.response.statusCode === 200)).eql(1);
});
requestMock 用来拦截请求和模拟响应。
import { RequestMock } from 'testcafe';
var mock = RequestMock()
.onRequestTo('https://api.mycorp.com/users/id/135865')
.respond({
name: 'John Hearts',
position: 'CTO'
})
.onRequestTo(/internal.mycorp.com/)
.respond(null, 404);
fixture `My fixture`
.page `https://mycorp.com`
.requestHooks(mock);
test('My test', async t => { /* ... */ });
自定义请求钩子,具体查看
import { RequestHook } from 'testcafe';
class JwtBearerAuthorization extends RequestHook {
constructor () {
super();
}
onRequest (e) {
e.requestOptions.headers['Authorization'] = 'generate token here';
}
onResponse (e) {
}
}