@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.
- package/.cursor/rules/dcl-styled-components.mdc +849 -0
- package/.cursor/rules/dcl-testing.mdc +356 -0
- package/catalog.json +2568 -2
- package/package.json +2 -2
|
@@ -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
|