← All skills

TestCafe Skill

E2e testingJavaScriptTypeScript

Copy and Paste in your Terminal

npx skills add https://github.com/LambdaTest/agent-skills.git --skill testcafe-skill

Advanced patterns

Advanced topics and patterns for experienced users.

TestCafe — Advanced Patterns & Playbook

Page Model Pattern

import { Selector, t } from 'testcafe';

class LoginPage {
  emailInput = Selector('#email');
  passwordInput = Selector('#password');
  submitBtn = Selector('button').withText('Sign In');
  errorMsg = Selector('.error-message');

  async login(email: string, password: string) {
    await t
      .typeText(this.emailInput, email)
      .typeText(this.passwordInput, password)
      .click(this.submitBtn);
  }
}

class ProductPage {
  products = Selector('.product-card');
  cartCount = Selector('.cart-badge');
  sortDropdown = Selector('#sort');

  product(name: string) { return this.products.withText(name); }

  async addToCart(name: string) {
    await t.click(this.product(name).find('.add-to-cart'));
  }

  async sortBy(option: string) {
    await t.click(this.sortDropdown).click(Selector('option').withText(option));
  }
}

// Test
const login = new LoginPage();
const products = new ProductPage();

fixture('Shopping').page('http://localhost:3000');

test('Add product to cart', async t => {
  await login.login('user@test.com', 'password');
  await products.addToCart('Widget');
  await t.expect(products.cartCount.innerText).eql('1');
});

Roles (Authentication State)

import { Role } from 'testcafe';

const adminRole = Role('http://localhost:3000/login', async t => {
  await t.typeText('#email', 'admin@test.com')
         .typeText('#password', 'password')
         .click('#submit');
}, { preserveUrl: true });

test('Admin dashboard', async t => {
  await t.useRole(adminRole);
  await t.expect(Selector('h1').innerText).eql('Admin Dashboard');
});

Request Hooks

import { RequestMock, RequestLogger } from 'testcafe';

const mockAPI = RequestMock()
  .onRequestTo('/api/users')
  .respond({ users: [{ id: 1, name: 'Alice' }] }, 200, { 'content-type': 'application/json' });

const logger = RequestLogger('/api/', { logResponseBody: true, logResponseHeaders: true });

fixture('API Tests').page('http://localhost:3000').requestHooks(mockAPI, logger);

test('Uses mocked API', async t => {
  await t.expect(Selector('.user-name').innerText).eql('Alice');
  await t.expect(logger.contains(r => r.response.statusCode === 200)).ok();
});

Client Functions & Custom Selectors

import { ClientFunction } from 'testcafe';

const getLocalStorage = ClientFunction(key => localStorage.getItem(key));
const scrollToBottom = ClientFunction(() => window.scrollTo(0, document.body.scrollHeight));

test('Infinite scroll', async t => {
  await scrollToBottom();
  await t.expect(Selector('.item').count).gte(20);
});

Anti-Patterns

  • await t.wait(5000) — use smart assertions with auto-retry: expect(el).ok()
  • ❌ Raw CSS strings in tests — use Page Model with named Selectors
  • ❌ Skipping Role for auth — duplicated login logic across tests
  • ClientFunction for simple assertions — use built-in Selector assertions