or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdbrowser-automation.mdclient-functions.mdelement-selection.mdindex.mdprogrammatic-api.mdrequest-interception.mduser-roles.md

user-roles.mddocs/

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

```