0
# User Roles
1
2
TestCafe's Role system enables testing user authentication workflows by creating reusable user sessions that can be switched between during test execution.
3
4
## Capabilities
5
6
### Role Creation
7
8
Create user roles with authentication logic and session state.
9
10
```javascript { .api }
11
/**
12
* Creates a user role with authentication workflow
13
* @param loginUrl - URL where authentication should be performed
14
* @param initFn - Async function containing login logic
15
* @param options - Role configuration options
16
* @returns Role object that can be used to switch user context
17
*/
18
function Role(
19
loginUrl: string,
20
initFn: (t: TestController) => Promise<void>,
21
options?: RoleOptions
22
): Role;
23
24
interface Role {
25
/** Anonymous role for unauthenticated users */
26
static anonymous: Role;
27
}
28
29
interface RoleOptions {
30
/** Preserve cookies across role switches */
31
preserveUrl?: boolean;
32
}
33
```
34
35
**Usage Examples:**
36
37
```javascript
38
import { Role } from 'testcafe';
39
40
// Regular user role
41
const regularUser = Role('https://example.com/login', async t => {
42
await t
43
.typeText('#username', 'user@example.com')
44
.typeText('#password', 'password123')
45
.click('#login-button');
46
});
47
48
// Admin user role
49
const adminUser = Role('https://example.com/admin/login', async t => {
50
await t
51
.typeText('#admin-username', 'admin@example.com')
52
.typeText('#admin-password', 'admin123')
53
.click('#admin-login-button')
54
.expect(Selector('.admin-dashboard').exists).ok();
55
});
56
57
// Guest user (anonymous)
58
const guestUser = Role.anonymous;
59
60
fixture('User Roles')
61
.page('https://example.com');
62
63
test('Regular user workflow', async t => {
64
await t
65
.useRole(regularUser)
66
.expect(Selector('.user-dashboard').exists).ok()
67
.click('#profile-link')
68
.expect(Selector('.profile-page').exists).ok();
69
});
70
71
test('Admin user workflow', async t => {
72
await t
73
.useRole(adminUser)
74
.expect(Selector('.admin-panel').exists).ok()
75
.click('#manage-users')
76
.expect(Selector('.user-management').exists).ok();
77
});
78
```
79
80
### Role Switching
81
82
Switch between different user roles during test execution.
83
84
```javascript { .api }
85
/**
86
* Switches to specified user role
87
* @param role - Role to switch to (created with Role function)
88
* @returns Promise resolving to test controller for chaining
89
*/
90
useRole(role: Role): Promise<TestController>;
91
```
92
93
**Usage Examples:**
94
95
```javascript
96
const user1 = Role('https://example.com/login', async t => {
97
await t
98
.typeText('#username', 'user1@example.com')
99
.typeText('#password', 'pass1');
100
});
101
102
const user2 = Role('https://example.com/login', async t => {
103
await t
104
.typeText('#username', 'user2@example.com')
105
.typeText('#password', 'pass2');
106
});
107
108
test('Multi-user collaboration', async t => {
109
// Start as user1
110
await t
111
.useRole(user1)
112
.click('#create-document')
113
.typeText('#document-title', 'Shared Document')
114
.click('#share-button')
115
.typeText('#share-email', 'user2@example.com')
116
.click('#send-invite');
117
118
// Switch to user2
119
await t
120
.useRole(user2)
121
.navigateTo('https://example.com/documents')
122
.expect(Selector('.shared-document').withText('Shared Document').exists).ok()
123
.click('.shared-document')
124
.typeText('.document-content', 'User2 contribution');
125
126
// Switch back to user1
127
await t
128
.useRole(user1)
129
.navigateTo('https://example.com/documents/shared')
130
.expect(Selector('.document-content').innerText).contains('User2 contribution');
131
});
132
```
133
134
### Anonymous Role
135
136
Test unauthenticated user workflows using the anonymous role.
137
138
```javascript { .api }
139
/**
140
* Anonymous role representing unauthenticated users
141
*/
142
Role.anonymous: Role;
143
```
144
145
**Usage Examples:**
146
147
```javascript
148
const authenticatedUser = Role('https://example.com/login', async t => {
149
await t
150
.typeText('#username', 'user@example.com')
151
.typeText('#password', 'password123')
152
.click('#login-button');
153
});
154
155
test('Anonymous user restrictions', async t => {
156
// Start as anonymous user
157
await t
158
.useRole(Role.anonymous)
159
.navigateTo('https://example.com/protected')
160
.expect(Selector('.login-required-message').exists).ok();
161
162
// Try to access restricted features
163
await t
164
.navigateTo('https://example.com/dashboard')
165
.expect(Selector('.redirect-to-login').exists).ok();
166
});
167
168
test('Login flow from anonymous', async t => {
169
// Start anonymous, then authenticate
170
await t
171
.useRole(Role.anonymous)
172
.navigateTo('https://example.com')
173
.click('#login-link')
174
.useRole(authenticatedUser)
175
.expect(Selector('.welcome-message').exists).ok();
176
});
177
```
178
179
### Role State Preservation
180
181
Roles automatically preserve authentication state between uses.
182
183
```javascript { .api }
184
// Role state is automatically preserved
185
const userRole = Role('https://example.com/login', async t => {
186
await t
187
.typeText('#username', 'user@example.com')
188
.typeText('#password', 'password123')
189
.click('#login-button');
190
});
191
```
192
193
**Usage Examples:**
194
195
```javascript
196
const persistentUser = Role('https://example.com/login', async t => {
197
await t
198
.typeText('#username', 'persistent@example.com')
199
.typeText('#password', 'password123')
200
.click('#login-button')
201
.expect(Selector('.dashboard').exists).ok();
202
});
203
204
test('First use of role', async t => {
205
await t
206
.useRole(persistentUser)
207
.click('#settings')
208
.typeText('#theme-preference', 'dark')
209
.click('#save-settings');
210
});
211
212
test('Second use of role (state preserved)', async t => {
213
await t
214
.useRole(persistentUser) // No re-authentication needed
215
.navigateTo('https://example.com/settings')
216
.expect(Selector('#theme-preference').value).eql('dark');
217
});
218
219
test('Role state across different tests', async t => {
220
await t
221
.useRole(persistentUser)
222
.expect(Selector('.user-name').innerText).eql('persistent@example.com')
223
.navigateTo('https://example.com/profile')
224
.expect(Selector('.profile-data').exists).ok();
225
});
226
```
227
228
### Complex Authentication Flows
229
230
Handle complex authentication scenarios including multi-step login and OAuth.
231
232
```javascript { .api }
233
// Multi-step authentication
234
const mfaUser = Role('https://example.com/login', async t => {
235
// Step 1: Username and password
236
await t
237
.typeText('#username', 'mfa-user@example.com')
238
.typeText('#password', 'password123')
239
.click('#login-button');
240
241
// Step 2: MFA code
242
await t
243
.expect(Selector('#mfa-code-input').exists).ok()
244
.typeText('#mfa-code-input', '123456')
245
.click('#verify-mfa');
246
247
// Step 3: Verify login success
248
await t
249
.expect(Selector('.dashboard').exists).ok();
250
});
251
252
// OAuth simulation
253
const oauthUser = Role('https://example.com/oauth/login', async t => {
254
await t
255
.click('#google-login-button')
256
.switchToWindow(w => w.url.includes('accounts.google.com'))
257
.typeText('#email', 'oauth-user@gmail.com')
258
.click('#next')
259
.typeText('#password', 'oauth-password')
260
.click('#signin')
261
.switchToWindow(w => w.url.includes('example.com'))
262
.expect(Selector('.oauth-success').exists).ok();
263
});
264
```
265
266
**Usage Examples:**
267
268
```javascript
269
test('Multi-factor authentication', async t => {
270
await t
271
.useRole(mfaUser)
272
.expect(Selector('.security-dashboard').exists).ok()
273
.click('#security-settings')
274
.expect(Selector('.mfa-enabled').exists).ok();
275
});
276
277
test('OAuth user permissions', async t => {
278
await t
279
.useRole(oauthUser)
280
.expect(Selector('.google-connected').exists).ok()
281
.click('#sync-google-data')
282
.expect(Selector('.sync-successful').exists).ok();
283
});
284
285
// Role with custom validation
286
const validatedUser = Role('https://example.com/login', async t => {
287
await t
288
.typeText('#username', 'validated@example.com')
289
.typeText('#password', 'password123')
290
.click('#login-button');
291
292
// Custom validation
293
const welcomeMessage = await Selector('.welcome').innerText;
294
if (!welcomeMessage.includes('validated@example.com')) {
295
throw new Error('Login validation failed');
296
}
297
}, { preserveUrl: true });
298
```
299
300
### Role Error Handling
301
302
Handle authentication failures and role switching errors.
303
304
```javascript { .api }
305
// Roles with error handling
306
const fragileUser = Role('https://example.com/login', async t => {
307
try {
308
await t
309
.typeText('#username', 'fragile@example.com')
310
.typeText('#password', 'password123')
311
.click('#login-button');
312
313
// Wait for login to complete or fail
314
await t.expect(Selector('.dashboard, .login-error').exists).ok();
315
316
// Check if login failed
317
const hasError = await Selector('.login-error').exists;
318
if (hasError) {
319
throw new Error('Authentication failed');
320
}
321
} catch (error) {
322
console.log('Role initialization failed:', error.message);
323
throw error;
324
}
325
});
326
```
327
328
**Usage Examples:**
329
330
```javascript
331
test('Handle role authentication failure', async t => {
332
try {
333
await t.useRole(fragileUser);
334
335
// This will only execute if role authentication succeeded
336
await t.expect(Selector('.dashboard').exists).ok();
337
338
} catch (error) {
339
// Handle authentication failure
340
console.log('Authentication failed, testing anonymous flow');
341
342
await t
343
.useRole(Role.anonymous)
344
.navigateTo('https://example.com/public')
345
.expect(Selector('.public-page').exists).ok();
346
}
347
});
348
349
// Conditional role usage
350
test('Conditional authentication', async t => {
351
const shouldAuthenticate = process.env.TEST_AUTH === 'true';
352
353
if (shouldAuthenticate) {
354
await t.useRole(authenticatedUser);
355
await t.expect(Selector('.private-content').exists).ok();
356
} else {
357
await t.useRole(Role.anonymous);
358
await t.expect(Selector('.public-content').exists).ok();
359
}
360
});
361
```
362
363
### Role Best Practices
364
365
Recommended patterns for role usage and organization.
366
367
```javascript
368
// Organize roles in separate file
369
// roles.js
370
export const users = {
371
admin: Role('https://example.com/admin/login', async t => {
372
await t
373
.typeText('#username', 'admin@example.com')
374
.typeText('#password', 'admin123')
375
.click('#login-button');
376
}),
377
378
regular: Role('https://example.com/login', async t => {
379
await t
380
.typeText('#username', 'user@example.com')
381
.typeText('#password', 'user123')
382
.click('#login-button');
383
}),
384
385
guest: Role.anonymous
386
};
387
388
// test file
389
import { users } from './roles';
390
391
fixture('User Workflows')
392
.page('https://example.com');
393
394
test('Admin workflow', async t => {
395
await t.useRole(users.admin);
396
// Admin-specific tests
397
});
398
399
test('Regular user workflow', async t => {
400
await t.useRole(users.regular);
401
// Regular user tests
402
});
403
```