or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dependency-constraints.mdglobal-configuration.mdindex.mdrule-testing.mdtest-cases.mdutilities.md

test-cases.mddocs/

0

# Test Case Configuration

1

2

Comprehensive test case definition system with support for valid and invalid scenarios, autofix testing, and suggestion validation.

3

4

## Capabilities

5

6

### Test Suite Structure

7

8

Container for organizing valid and invalid test cases for rule testing.

9

10

```typescript { .api }

11

/**

12

* Container for test cases passed to the run method

13

*/

14

interface RunTests<MessageIds extends string, Options extends readonly unknown[]> {

15

/** Array of valid test cases that should not trigger rule violations */

16

readonly valid: readonly (string | ValidTestCase<Options>)[];

17

/** Array of invalid test cases that should trigger rule violations */

18

readonly invalid: readonly InvalidTestCase<MessageIds, Options>[];

19

}

20

```

21

22

**Usage Examples:**

23

24

```typescript

25

import { RuleTester } from "@typescript-eslint/rule-tester";

26

27

const ruleTester = new RuleTester();

28

29

ruleTester.run("my-rule", myRule, {

30

valid: [

31

// Simple string cases

32

"const x = 1;",

33

"function foo() { return 'hello'; }",

34

35

// Complex cases with configuration

36

{

37

code: "interface User { name: string; }",

38

name: "interface declaration should be allowed",

39

},

40

],

41

invalid: [

42

{

43

code: "var x = 1;",

44

errors: [{ messageId: "noVar" }],

45

output: "const x = 1;",

46

},

47

],

48

});

49

```

50

51

### Valid Test Cases

52

53

Configuration for test cases that should not trigger any rule violations.

54

55

```typescript { .api }

56

/**

57

* Configuration for valid test cases that should not trigger rule violations

58

*/

59

interface ValidTestCase<Options extends readonly unknown[]> {

60

/** Code for the test case */

61

readonly code: string;

62

/** Name for the test case for better test output */

63

readonly name?: string;

64

/** The fake filename for the test case (useful for rules that check filenames) */

65

readonly filename?: string;

66

/** Options for the rule being tested */

67

readonly options?: Readonly<Options>;

68

/** Language-specific options for the test case */

69

readonly languageOptions?: TestLanguageOptions;

70

/** Settings for the test case */

71

readonly settings?: Readonly<SharedConfigurationSettings>;

72

/** Constraints that must pass in the current environment for the test to run */

73

readonly dependencyConstraints?: DependencyConstraint;

74

/** Run this case exclusively for debugging in supported test frameworks */

75

readonly only?: boolean;

76

/** Skip this case in supported test frameworks */

77

readonly skip?: boolean;

78

/** Function to execute before testing the case */

79

readonly before?: () => void;

80

/** Function to execute after testing the case regardless of its result */

81

readonly after?: () => void;

82

}

83

```

84

85

**Usage Examples:**

86

87

```typescript

88

const validTestCases: ValidTestCase<[{ allowUnions: boolean }]>[] = [

89

// Minimal test case

90

{

91

code: "const x = 1;",

92

},

93

94

// Test case with name and options

95

{

96

code: "type Status = 'active' | 'inactive';",

97

name: "union types should be allowed when option is enabled",

98

options: [{ allowUnions: true }],

99

},

100

101

// Test case with specific filename

102

{

103

code: "export default class Component {}",

104

filename: "Component.tsx",

105

languageOptions: {

106

parserOptions: {

107

ecmaFeatures: { jsx: true },

108

},

109

},

110

},

111

112

// Test case with environment constraints

113

{

114

code: "const promise: Promise<string> = Promise.resolve('hello');",

115

dependencyConstraints: {

116

typescript: ">=4.0.0",

117

},

118

},

119

120

// Test case with setup and teardown

121

{

122

code: "console.log('test');",

123

before: () => {

124

jest.spyOn(console, 'log').mockImplementation(() => {});

125

},

126

after: () => {

127

jest.restoreAllMocks();

128

},

129

},

130

131

// Debugging specific test case

132

{

133

code: "function debug() { return 'debugging'; }",

134

name: "debug function",

135

only: true, // Run only this test case

136

},

137

];

138

```

139

140

### Invalid Test Cases

141

142

Configuration for test cases that should trigger rule violations with expected errors and fixes.

143

144

```typescript { .api }

145

/**

146

* Configuration for invalid test cases that should trigger rule violations

147

*/

148

interface InvalidTestCase<MessageIds extends string, Options extends readonly unknown[]>

149

extends ValidTestCase<Options> {

150

/** Constraints that must pass in the current environment for the test to run */

151

readonly dependencyConstraints?: DependencyConstraint;

152

/** Expected errors that should be reported */

153

readonly errors: readonly TestCaseError<MessageIds>[];

154

/** Expected code after autofixes are applied */

155

readonly output?: string | string[] | null;

156

}

157

```

158

159

**Usage Examples:**

160

161

```typescript

162

const invalidTestCases: InvalidTestCase<"noVar" | "preferConst", []>[] = [

163

// Basic invalid test case

164

{

165

code: "var x = 1;",

166

errors: [{ messageId: "noVar" }],

167

output: "const x = 1;",

168

},

169

170

// Test case with specific error location

171

{

172

code: "function foo() {\n var x = 1;\n return x;\n}",

173

errors: [{

174

messageId: "noVar",

175

line: 2,

176

column: 3,

177

endLine: 2,

178

endColumn: 6,

179

}],

180

output: "function foo() {\n const x = 1;\n return x;\n}",

181

},

182

183

// Test case with multiple errors

184

{

185

code: "var a = 1; var b = 2;",

186

errors: [

187

{ messageId: "noVar", line: 1, column: 1 },

188

{ messageId: "noVar", line: 1, column: 12 },

189

],

190

output: "const a = 1; const b = 2;",

191

},

192

193

// Multi-pass autofix (array of outputs)

194

{

195

code: "var a = 1; var b = a;",

196

errors: [

197

{ messageId: "noVar" },

198

{ messageId: "preferConst" },

199

],

200

output: [

201

"let a = 1; var b = a;", // First pass

202

"const a = 1; let b = a;", // Second pass

203

"const a = 1; const b = a;", // Final pass

204

],

205

},

206

207

// Test case with no autofix

208

{

209

code: "eval('var x = 1');",

210

errors: [{ messageId: "noEval" }],

211

output: null, // Explicitly no autofix expected

212

},

213

214

// Test case with suggestions

215

{

216

code: "function foo(x: any) { return x; }",

217

errors: [{

218

messageId: "noAny",

219

type: "TSAnyKeyword",

220

suggestions: [

221

{

222

messageId: "useUnknown",

223

output: "function foo(x: unknown) { return x; }",

224

},

225

{

226

messageId: "useGeneric",

227

output: "function foo<T>(x: T) { return x; }",

228

},

229

],

230

}],

231

},

232

];

233

```

234

235

### Test Case Errors

236

237

Expected error configuration for invalid test cases with detailed location and suggestion information.

238

239

```typescript { .api }

240

/**

241

* Expected error configuration for invalid test cases

242

*/

243

interface TestCaseError<MessageIds extends string> {

244

/** Reported message ID (required) */

245

readonly messageId: MessageIds;

246

/** The 1-based line number of the reported start location */

247

readonly line?: number;

248

/** The 1-based column number of the reported start location */

249

readonly column?: number;

250

/** The 1-based line number of the reported end location */

251

readonly endLine?: number;

252

/** The 1-based column number of the reported end location */

253

readonly endColumn?: number;

254

/** The type of the reported AST node */

255

readonly type?: AST_NODE_TYPES | AST_TOKEN_TYPES;

256

/** The data used to fill the message template */

257

readonly data?: ReportDescriptorMessageData;

258

/** Expected suggestions for fixing the error */

259

readonly suggestions?: readonly SuggestionOutput<MessageIds>[] | null;

260

}

261

```

262

263

**Usage Examples:**

264

265

```typescript

266

// Minimal error expectation

267

const simpleError: TestCaseError<"noVar"> = {

268

messageId: "noVar",

269

};

270

271

// Detailed error expectation with location

272

const detailedError: TestCaseError<"noVar"> = {

273

messageId: "noVar",

274

line: 1,

275

column: 1,

276

endLine: 1,

277

endColumn: 4,

278

type: "VariableDeclaration",

279

};

280

281

// Error with template data

282

const errorWithData: TestCaseError<"unexpectedType"> = {

283

messageId: "unexpectedType",

284

data: {

285

expected: "string",

286

actual: "number",

287

},

288

};

289

290

// Error with suggestions

291

const errorWithSuggestions: TestCaseError<"noAny"> = {

292

messageId: "noAny",

293

suggestions: [

294

{

295

messageId: "useUnknown",

296

output: "function foo(x: unknown) { return x; }",

297

},

298

{

299

messageId: "useGeneric",

300

output: "function foo<T>(x: T) { return x; }",

301

data: { genericName: "T" },

302

},

303

],

304

};

305

```

306

307

### Suggestion Output

308

309

Expected suggestion configuration for rule suggestions with their expected outputs.

310

311

```typescript { .api }

312

/**

313

* Expected suggestion configuration for rule suggestions

314

*/

315

interface SuggestionOutput<MessageIds extends string> {

316

/** Suggestion message ID (required) */

317

readonly messageId: MessageIds;

318

/** Expected output after applying the suggestion (required) */

319

readonly output: string;

320

/** The data used to fill the message template */

321

readonly data?: ReportDescriptorMessageData;

322

}

323

```

324

325

**Usage Examples:**

326

327

```typescript

328

const suggestions: SuggestionOutput<"useUnknown" | "useGeneric">[] = [

329

// Simple suggestion

330

{

331

messageId: "useUnknown",

332

output: "function foo(x: unknown) { return x; }",

333

},

334

335

// Suggestion with template data

336

{

337

messageId: "useGeneric",

338

output: "function foo<T>(x: T) { return x; }",

339

data: {

340

genericName: "T",

341

paramName: "x",

342

},

343

},

344

];

345

```

346

347

## Language Options

348

349

```typescript { .api }

350

/**

351

* Language-specific options for individual test cases

352

*/

353

interface TestLanguageOptions {

354

/** The absolute path for the parser */

355

readonly parser?: Readonly<Parser.LooseParserModule>;

356

/** Options for the parser */

357

readonly parserOptions?: Readonly<ParserOptions>;

358

/** The additional global variables */

359

readonly globals?: Readonly<Linter.GlobalsConfig>;

360

/** Environments for the test case */

361

readonly env?: Readonly<Linter.EnvironmentConfig>;

362

}

363

```

364

365

**Usage Examples:**

366

367

```typescript

368

// TypeScript with JSX support

369

const tsxLanguageOptions: TestLanguageOptions = {

370

parserOptions: {

371

ecmaVersion: 2022,

372

sourceType: "module",

373

ecmaFeatures: {

374

jsx: true,

375

},

376

project: "./tsconfig.json",

377

},

378

};

379

380

// Browser environment with globals

381

const browserLanguageOptions: TestLanguageOptions = {

382

env: {

383

browser: true,

384

es2022: true,

385

},

386

globals: {

387

window: "readonly",

388

document: "readonly",

389

console: "readonly",

390

},

391

};

392

393

// Node.js environment

394

const nodeLanguageOptions: TestLanguageOptions = {

395

env: {

396

node: true,

397

es2022: true,

398

},

399

globals: {

400

process: "readonly",

401

Buffer: "readonly",

402

},

403

};

404

```