@dcl/asset-packs 2.7.1 → 2.7.2-20251128172211.commit-d80a654

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,356 @@
1
+ ---
2
+ description: "Comprehensive testing standards for all Decentraland projects: React, Redux, Node, E2E, and more."
3
+ globs: **/*.spec.ts,**/*.test.ts,**/*.spec.tsx,**/*.test.tsx
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # Testing
8
+
9
+ ## Scope
10
+
11
+ These standards MUST be applied to all files that match the following patterns, always:
12
+
13
+ - `src/**/*.test.ts`
14
+ - `src/**/*.spec.ts`
15
+ - `src/**/*.test.tsx`
16
+ - `src/**/*.spec.tsx`
17
+
18
+ > **Note:** The globs should be as specific as possible to avoid false positives. Adjust them if your project structure is different.
19
+
20
+ ## Rules
21
+
22
+ 1. **MUST** (required)
23
+
24
+ - Use Jest and TypeScript for all tests.
25
+ - Organize tests with `describe` (context: "when", "and") and `it` (behavior: "should ...").
26
+ - Each context variant must have its own describe block with "when" or "and"
27
+ - Use "when" for main contexts and "and" for nested contexts
28
+ - Do NOT use "when" in it() descriptions - the context is already defined in the describe
29
+ - it() descriptions must be specific and descriptive about the expected behavior
30
+ - Prefer specific outcomes over generic ones (e.g., "should respond with a 500 and the error" vs "should return 500 status")
31
+ - Use `beforeEach` for setup, never mix with `beforeAll`.
32
+ - All test variables, input data, and mocks must be declared and assigned in beforeEach
33
+ - Do NOT define input variables inside it() blocks
34
+ - Each describe context should have its own beforeEach for its specific setup
35
+ - Mocks and test data must be scoped to the specific describe context where they are needed
36
+ - Do NOT create mocks in global beforeEach that are only used in specific describe contexts
37
+ - Each describe context should create its own mocks and test data in its own beforeEach
38
+ - Use `afterEach` to clean up mocks, test data, and side effects to ensure test isolation.
39
+ - Use `let` for mutable, `const` for immutable variables. Type variables explicitly.
40
+ - Have one assertion per `it` unless justified for performance or testing multiple aspects of the same behavior.
41
+ - Test behavior, not implementation. Focus on what the code does, not how.
42
+ - Use `jest.fn()` for mocks, prefer `mockReturnValueOnce`/`mockResolvedValueOnce`, and reset mocks in `afterEach`.
43
+ - Keep tests independent and use clear, explicit descriptions.
44
+ - Use semantic naming: `describe` with "when", "and"; `it` with "should"; write full, meaningful sentences.
45
+
46
+ **Example:**
47
+
48
+ ```typescript
49
+ describe("when the user clicks the button", () => {
50
+ let onClick: jest.Mock;
51
+
52
+ beforeEach(() => {
53
+ onClick = jest.fn();
54
+ render(<MyButton onClick={onClick} />);
55
+ });
56
+
57
+ afterEach(() => {
58
+ jest.resetAllMocks();
59
+ // Clean up any other state or data here
60
+ });
61
+
62
+ it("should call onClick", async () => {
63
+ await userEvent.click(screen.getByRole("button"));
64
+ expect(onClick).toHaveBeenCalled();
65
+ });
66
+ });
67
+ ```
68
+
69
+ 2. **SHOULD** (recommended)
70
+
71
+ - Use React Testing Library and accessible queries (`getByRole`, `getByLabelText`, etc.) for React components.
72
+ - Test reducers with action creators, selectors as functions, sagas with `redux-saga-test-plan`.
73
+ - Use `supertest` for API tests and Cypress for E2E.
74
+ - Place test files next to the code they test, named `*.spec.ts(x)` or `*.test.ts(x)`.
75
+ - Test accessibility and keyboard navigation.
76
+ - Use meaningful test descriptions and keep tests independent.
77
+ - Place test utilities in a `__tests__/` directory when needed.
78
+
79
+ 3. **AI VALIDATION** (when rules are created by AI)
80
+
81
+ - MUST validate that all existing tests follow the updated rules
82
+ - MUST check for proper mock scoping in all test files
83
+ - MUST ensure mocks are not created in global beforeEach unless truly needed globally
84
+ - MUST verify that each describe context has its own beforeEach for specific setup
85
+ - MUST run linter checks on all test files after rule updates
86
+
87
+ **Example:**
88
+
89
+ ```typescript
90
+ // Good
91
+ it("should disable submit button when form is invalid", () => {
92
+ // test
93
+ });
94
+ // Bad
95
+ it("should work as expected", () => {
96
+ // test
97
+ });
98
+ ```
99
+
100
+ ## Examples
101
+
102
+ ```typescript
103
+ // ❌ Incorrect - Global mocks used in specific contexts
104
+
105
+ describe("when testing API endpoints", () => {
106
+ let validAuthChain: AuthChain;
107
+ let invalidAuthChain: AuthChain;
108
+
109
+ beforeEach(async () => {
110
+ // Creating mocks that are only used in specific describe contexts
111
+ validAuthChain = createValidAuthChain();
112
+ invalidAuthChain = createInvalidAuthChain();
113
+ });
114
+
115
+ describe("and the request is valid", () => {
116
+ it("should respond with 200", () => {
117
+ // Uses validAuthChain - but it was created globally
118
+ });
119
+ });
120
+
121
+ describe("and the request is invalid", () => {
122
+ it("should respond with 400", () => {
123
+ // Uses invalidAuthChain - but it was created globally
124
+ });
125
+ });
126
+ });
127
+
128
+ // ✅ Correct - Mocks scoped to specific contexts
129
+
130
+ describe("when testing API endpoints", () => {
131
+ beforeEach(async () => {
132
+ // Only global setup that's truly needed everywhere
133
+ port = await getPort();
134
+ baseUrl = `http://localhost:${port}`;
135
+ });
136
+
137
+ describe("and the request is valid", () => {
138
+ let validAuthChain: AuthChain;
139
+
140
+ beforeEach(async () => {
141
+ // Create mock only for this specific context
142
+ validAuthChain = createValidAuthChain();
143
+ });
144
+
145
+ it("should respond with 200", () => {
146
+ // Uses validAuthChain - created in this context
147
+ });
148
+ });
149
+
150
+ describe("and the request is invalid", () => {
151
+ let invalidAuthChain: AuthChain;
152
+
153
+ beforeEach(() => {
154
+ // Create mock only for this specific context
155
+ invalidAuthChain = createInvalidAuthChain();
156
+ });
157
+
158
+ it("should respond with 400", () => {
159
+ // Uses invalidAuthChain - created in this context
160
+ });
161
+ });
162
+ });
163
+ ```
164
+
165
+ ```typescript
166
+ // ❌ Incorrect
167
+
168
+ describe("form", () => {
169
+ it("should work", () => {
170
+ // ...
171
+ });
172
+ });
173
+
174
+ // ✅ Correct
175
+
176
+ describe("when the form is submitted", () => {
177
+ let mockSubmit: jest.Mock;
178
+
179
+ beforeEach(() => {
180
+ mockSubmit = jest.fn();
181
+ });
182
+
183
+ afterEach(() => {
184
+ jest.resetAllMocks();
185
+ // Clean up any other state or data here
186
+ });
187
+
188
+ describe("and the input is valid", () => {
189
+ let validInput: any;
190
+
191
+ beforeEach(() => {
192
+ validInput = { name: "test", email: "test@test.com" };
193
+ });
194
+
195
+ it("should call the onSubmit callback", () => {
196
+ mockSubmit();
197
+ expect(mockSubmit).toHaveBeenCalled();
198
+ });
199
+ });
200
+
201
+ describe("and the input is invalid", () => {
202
+ let invalidInput: any;
203
+
204
+ beforeEach(() => {
205
+ invalidInput = { name: "", email: "invalid" };
206
+ });
207
+
208
+ it("should display a validation error", () => {
209
+ /* ... */
210
+ });
211
+ });
212
+ });
213
+ ```
214
+
215
+ ## Common Mistakes to Avoid
216
+
217
+ ❌ **Wrong: Using "when" in it() descriptions**
218
+
219
+ ```typescript
220
+ it('should fail when email is missing', () => { // WRONG
221
+ ```
222
+
223
+ ✅ **Correct: Context in describe, behavior in it()**
224
+
225
+ ```typescript
226
+ describe('when email is missing', () => {
227
+ it('should return 400 status', () => { // CORRECT
228
+ ```
229
+
230
+ ❌ **Wrong: Defining variables inside it()**
231
+
232
+ ```typescript
233
+ it('should work', () => {
234
+ const testData = { email: 'test' }; // WRONG
235
+ ```
236
+
237
+ ✅ **Correct: Variables in beforeEach**
238
+
239
+ ```typescript
240
+ describe('when testing email', () => {
241
+ let testData: any;
242
+
243
+ beforeEach(() => {
244
+ testData = { email: 'test' }; // CORRECT
245
+ });
246
+ ```
247
+
248
+ ❌ **Wrong: Global mocks for specific contexts**
249
+
250
+ ```typescript
251
+ describe('when testing API', () => {
252
+ let validMock: any
253
+ let invalidMock: any
254
+
255
+ beforeEach(() => {
256
+ validMock = createValidMock() // WRONG - only used in one context
257
+ invalidMock = createInvalidMock() // WRONG - only used in one context
258
+ })
259
+ ```
260
+
261
+ ✅ **Correct: Scoped mocks**
262
+
263
+ ```typescript
264
+ describe('when testing API', () => {
265
+ describe('and request is valid', () => {
266
+ let validMock: any
267
+
268
+ beforeEach(() => {
269
+ validMock = createValidMock() // CORRECT - scoped to this context
270
+ })
271
+ })
272
+
273
+ describe('and request is invalid', () => {
274
+ let invalidMock: any
275
+
276
+ beforeEach(() => {
277
+ invalidMock = createInvalidMock() // CORRECT - scoped to this context
278
+ })
279
+ })
280
+ ```
281
+
282
+ ❌ **Wrong: Flat structure without context separation**
283
+
284
+ ```typescript
285
+ describe('form', () => {
286
+ it('should work with valid input', () => { // WRONG
287
+ it('should fail with invalid input', () => { // WRONG
288
+ ```
289
+
290
+ ✅ **Correct: Nested describes for different contexts**
291
+
292
+ ```typescript
293
+ describe('when the form is submitted', () => {
294
+ describe('and the input is valid', () => {
295
+ it('should call onSubmit', () => { // CORRECT
296
+ });
297
+ describe('and the input is invalid', () => {
298
+ it('should show error', () => { // CORRECT
299
+ });
300
+ });
301
+ ```
302
+
303
+ ❌ **Wrong: Generic it() descriptions**
304
+
305
+ ```typescript
306
+ it('should return 500 status', () => { // TOO GENERIC
307
+ it('should work', () => { // TOO GENERIC
308
+ ```
309
+
310
+ ✅ **Correct: Specific and descriptive it() descriptions**
311
+
312
+ ```typescript
313
+ it('should respond with a 500 and the error', () => { // SPECIFIC
314
+ it('should propagate the error to the client', () => { // DESCRIPTIVE
315
+ it('should return 400 status when email is missing', () => { // SPECIFIC
316
+ it('should display validation error message', () => { // DESCRIPTIVE
317
+ ```
318
+
319
+ ## Validation Checklist
320
+
321
+ Before writing tests, ensure:
322
+
323
+ - [ ] MUST and SHOULD sections are clearly defined
324
+ - [ ] Each "when" and "and" context has its own describe block
325
+ - [ ] All variables are declared and assigned in beforeEach
326
+ - [ ] it() descriptions use "should" without "when"
327
+ - [ ] it() descriptions are specific and descriptive about expected behavior
328
+ - [ ] Context is defined in describe, not repeated in it()
329
+ - [ ] Each describe has appropriate beforeEach/afterEach
330
+ - [ ] Tests are independent and don't share state
331
+ - [ ] Prefer specific outcomes over generic ones
332
+ - [ ] Mocks and test data are scoped to specific describe contexts
333
+ - [ ] No global mocks unless truly needed across all contexts
334
+ - [ ] Each describe context creates its own mocks in its own beforeEach
335
+ - [ ] Specific code examples are included
336
+ - [ ] Incorrect (❌) and correct (✅) patterns are shown
337
+ - [ ] Rules are specific and actionable
338
+ - [ ] Scope clearly defines file patterns
339
+ - [ ] Description is concise and descriptive
340
+ - [ ] Glob patterns are appropriate for common
341
+ - [ ] Rules follow the established format and structure
342
+ - [ ] Content is comprehensive and well-organized
343
+ - [ ] Examples are relevant and demonstrate best practices
344
+ - [ ] Context is properly defined and not repeated
345
+ - [ ] Each section has appropriate setup and cleanup
346
+ - [ ] AI validation rules are included for rule updates
347
+
348
+ ## AI Rule Update Validation
349
+
350
+ When AI creates or updates testing rules, it MUST:
351
+
352
+ 1. Validate existing tests - Check all test files for compliance with new rules
353
+ 2. Check mock scoping - Ensure mocks are properly scoped to their contexts
354
+ 3. Run linter - Verify no linting errors after rule updates
355
+ 4. Update examples - Provide clear examples of correct vs incorrect patterns
356
+ 5. Test the rules - Ensure the rules work as intended with real test files