常用API介绍

本文共--字 阅读约--分钟 | 浏览: -- 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

可以使用 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 => { /* ... */});

Selector

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。 具体介绍

requestLogger

存储捕捉测试执行期间收到的请求发送和响应。

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

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 => { /* ... */ });

RequestHook

自定义请求钩子,具体查看

import { RequestHook } from 'testcafe';

class JwtBearerAuthorization extends RequestHook {
  constructor () {
    super();
  }

  onRequest (e) {
    e.requestOptions.headers['Authorization'] = 'generate token here';
  }

  onResponse (e) {
  }
}