Roles, Request Mocking & CI
Roles — Reusable Auth
import { Role, Selector } from 'testcafe';
const regularUser = Role('https://example.com/login', async t => {
await t
.typeText('#email', 'user@example.com')
.typeText('#password', 'secret123')
.click('button[type=submit]');
});
test('authenticated user sees dashboard', async t => {
await t.useRole(regularUser); // TestCafe caches/reuses the login state
await t.expect(Selector('.dashboard').exists).ok();
});Mocking API Responses
import { RequestMock } from 'testcafe';
// Deterministically test error-handling UI without needing the real
// backend to actually be coaxed into a 500 error state
const mockServerError = RequestMock()
.onRequestTo('https://api.example.com/orders')
.respond({ error: 'Internal Server Error' }, 500);
test.requestHooks(mockServerError)('shows error banner on API failure', async t => {
await t.expect(Selector('.error-banner').innerText).contains('Something went wrong');
});Screenshots & Debugging
test('checkout flow', async t => {
await t.click('#add-to-cart');
await t.takeScreenshot(); // saved to the configured screenshots directory
// TestCafe can also auto-screenshot on test failure via CLI config —
// useful for debugging a CI run after the factConcurrency & Test Isolation
Running with -c N against a shared test environment/database risks concurrent tests interfering with each other — two tests creating a user with the same expected username, or one test's cleanup deleting data another still needs. Generate unique, randomly-suffixed test data per run and avoid shared mutable fixtures between concurrently-running tests.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free