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
```