0
# Test Management
1
2
Advanced test creation, grouping, and macro functionality for organizing complex test suites.
3
4
## Capabilities
5
6
### Test Groups
7
8
Create organized groups of related tests with shared setup, teardown, and configuration.
9
10
```typescript { .api }
11
/**
12
* Create a Japa test group
13
* @param title - Group title
14
* @param callback - Function that receives the group instance for configuration
15
* @returns Group instance
16
*/
17
test.group(title: string, callback: (group: Group) => void): Group;
18
19
interface Group {
20
add(test: Test): void;
21
bail(toggle?: boolean): this;
22
timeout(duration: number): this;
23
retry(count: number): this;
24
setup(handler: GroupHooksHandler<TestContext>): this;
25
teardown(handler: GroupHooksHandler<TestContext>): this;
26
each: {
27
setup(handler: GroupHooksHandler<TestContext>): Group;
28
teardown(handler: GroupHooksHandler<TestContext>): Group;
29
};
30
tap(handler: (test: Test) => void): this;
31
}
32
33
type GroupHooksHandler<Context> = (context: Context) => void | Promise<void>;
34
```
35
36
**Usage Examples:**
37
38
```typescript
39
import { test } from "@japa/runner";
40
import { assert } from "chai";
41
42
test.group("User Authentication", (group) => {
43
let authService: AuthService;
44
45
// Setup before all tests in group
46
group.setup(async () => {
47
authService = new AuthService();
48
await authService.initialize();
49
});
50
51
// Teardown after all tests in group
52
group.teardown(async () => {
53
await authService.cleanup();
54
});
55
56
// Setup before each test in group
57
group.each.setup(async ({ context }) => {
58
context.user = await createTestUser();
59
});
60
61
// Teardown after each test in group
62
group.each.teardown(async ({ context }) => {
63
await deleteTestUser(context.user.id);
64
});
65
66
test("should login with valid credentials", async (ctx) => {
67
const result = await authService.login(ctx.context.user.email, "password");
68
assert.isTrue(result.success);
69
});
70
71
test("should reject invalid credentials", async (ctx) => {
72
const result = await authService.login("invalid@email.com", "wrong");
73
assert.isFalse(result.success);
74
});
75
});
76
77
// Group with timeout and retry configuration
78
test.group("API Integration Tests", (group) => {
79
group.timeout(10000);
80
group.retry(2);
81
82
test("should fetch user data", async (ctx) => {
83
// Test logic here
84
});
85
});
86
```
87
88
### Test Macros
89
90
Create reusable test bound macros that can access the currently executed test.
91
92
```typescript { .api }
93
/**
94
* Create a test bound macro. Within the macro, you can access the
95
* currently executed test to read its context values or define cleanup hooks.
96
* @param callback - Macro function that receives the test instance as first parameter
97
* @returns Function that can be called within tests
98
*/
99
test.macro<T extends (test: Test, ...args: any[]) => any>(
100
callback: T
101
): (...args: OmitFirstArg<Parameters<T>>) => ReturnType<T>;
102
103
type OmitFirstArg<F> = F extends [_: any, ...args: infer R] ? R : never;
104
```
105
106
**Usage Examples:**
107
108
```typescript
109
import { test } from "@japa/runner";
110
import { assert } from "chai";
111
112
// Create a macro for database operations
113
const withDatabase = test.macro((test: Test, tableName: string) => {
114
test.setup(async () => {
115
await createTable(tableName);
116
});
117
118
test.cleanup(async () => {
119
await dropTable(tableName);
120
});
121
122
return {
123
async insert(data: any) {
124
return await db.table(tableName).insert(data);
125
},
126
async find(id: number) {
127
return await db.table(tableName).find(id);
128
},
129
};
130
});
131
132
// Create a macro for API testing
133
const withApiClient = test.macro((test: Test, baseUrl: string) => {
134
let client: ApiClient;
135
136
test.setup(() => {
137
client = new ApiClient(baseUrl);
138
});
139
140
test.cleanup(async () => {
141
await client.close();
142
});
143
144
return client;
145
});
146
147
// Use macros in tests
148
test("should create and retrieve user", async (ctx) => {
149
const db = withDatabase("users");
150
const api = withApiClient("http://localhost:3000");
151
152
const user = await db.insert({ name: "John", email: "john@example.com" });
153
const retrieved = await db.find(user.id);
154
155
assert.equal(retrieved.name, "John");
156
});
157
```
158
159
### Active Test Management
160
161
Functions to access and manage the currently executing test.
162
163
```typescript { .api }
164
/**
165
* Get the currently running test instance
166
* @returns Current test instance or undefined if not in test context
167
*/
168
function getActiveTest(): Test<any> | undefined;
169
170
/**
171
* Get the currently running test instance or throw an error
172
* @returns Current test instance
173
* @throws Error if not in test context
174
*/
175
function getActiveTestOrFail(): Test<any>;
176
```
177
178
**Usage Examples:**
179
180
```typescript
181
import { test, getActiveTest, getActiveTestOrFail } from "@japa/runner";
182
import { assert } from "chai";
183
184
// Helper function that works with current test
185
function addTestMetadata(key: string, value: any) {
186
const currentTest = getActiveTest();
187
if (currentTest) {
188
currentTest.options.meta[key] = value;
189
}
190
}
191
192
// Macro that uses active test
193
const trackTestExecution = test.macro(() => {
194
const currentTest = getActiveTestOrFail();
195
const startTime = Date.now();
196
197
currentTest.cleanup(() => {
198
const duration = Date.now() - startTime;
199
console.log(`Test "${currentTest.title}" took ${duration}ms`);
200
});
201
});
202
203
test("performance test", async (ctx) => {
204
trackTestExecution();
205
addTestMetadata("category", "performance");
206
207
// Test logic here
208
await someAsyncOperation();
209
assert.isTrue(true);
210
});
211
```
212
213
## Types
214
215
### Group Types
216
217
```typescript { .api }
218
interface Group {
219
add(test: Test): void;
220
bail(toggle?: boolean): this;
221
timeout(duration: number): this;
222
retry(count: number): this;
223
setup(handler: GroupHooksHandler<TestContext>): this;
224
teardown(handler: GroupHooksHandler<TestContext>): this;
225
each: {
226
setup(handler: GroupHooksHandler<TestContext>): Group;
227
teardown(handler: GroupHooksHandler<TestContext>): Group;
228
};
229
tap(handler: (test: Test) => void): this;
230
}
231
232
type GroupHooksHandler<Context> = (context: Context) => void | Promise<void>;
233
```
234
235
### Macro Types
236
237
```typescript { .api }
238
type OmitFirstArg<F> = F extends [_: any, ...args: infer R] ? R : never;
239
```