javi-forge 1.2.0 → 1.3.0
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/ci-local/ci-local.sh +20 -8
- package/package.json +1 -1
- package/ai-config/.skillignore +0 -15
- package/ai-config/AUTO_INVOKE.md +0 -300
- package/ai-config/agents/_TEMPLATE.md +0 -93
- package/ai-config/agents/business/api-designer.md +0 -1657
- package/ai-config/agents/business/business-analyst.md +0 -1331
- package/ai-config/agents/business/product-strategist.md +0 -206
- package/ai-config/agents/business/project-manager.md +0 -178
- package/ai-config/agents/business/requirements-analyst.md +0 -1277
- package/ai-config/agents/business/technical-writer.md +0 -1679
- package/ai-config/agents/creative/ux-designer.md +0 -205
- package/ai-config/agents/data-ai/ai-engineer.md +0 -487
- package/ai-config/agents/data-ai/analytics-engineer.md +0 -953
- package/ai-config/agents/data-ai/data-engineer.md +0 -173
- package/ai-config/agents/data-ai/data-scientist.md +0 -672
- package/ai-config/agents/data-ai/mlops-engineer.md +0 -814
- package/ai-config/agents/data-ai/prompt-engineer.md +0 -772
- package/ai-config/agents/development/angular-expert.md +0 -620
- package/ai-config/agents/development/backend-architect.md +0 -795
- package/ai-config/agents/development/database-specialist.md +0 -212
- package/ai-config/agents/development/frontend-specialist.md +0 -686
- package/ai-config/agents/development/fullstack-engineer.md +0 -668
- package/ai-config/agents/development/golang-pro.md +0 -338
- package/ai-config/agents/development/java-enterprise.md +0 -400
- package/ai-config/agents/development/javascript-pro.md +0 -422
- package/ai-config/agents/development/nextjs-pro.md +0 -474
- package/ai-config/agents/development/python-pro.md +0 -570
- package/ai-config/agents/development/react-pro.md +0 -487
- package/ai-config/agents/development/rust-pro.md +0 -246
- package/ai-config/agents/development/spring-boot-4-expert.md +0 -326
- package/ai-config/agents/development/typescript-pro.md +0 -336
- package/ai-config/agents/development/vue-specialist.md +0 -605
- package/ai-config/agents/infrastructure/cloud-architect.md +0 -472
- package/ai-config/agents/infrastructure/deployment-manager.md +0 -358
- package/ai-config/agents/infrastructure/devops-engineer.md +0 -455
- package/ai-config/agents/infrastructure/incident-responder.md +0 -519
- package/ai-config/agents/infrastructure/kubernetes-expert.md +0 -705
- package/ai-config/agents/infrastructure/monitoring-specialist.md +0 -674
- package/ai-config/agents/infrastructure/performance-engineer.md +0 -658
- package/ai-config/agents/orchestrator.md +0 -241
- package/ai-config/agents/quality/accessibility-auditor.md +0 -1204
- package/ai-config/agents/quality/code-reviewer-compact.md +0 -123
- package/ai-config/agents/quality/code-reviewer.md +0 -363
- package/ai-config/agents/quality/dependency-manager.md +0 -743
- package/ai-config/agents/quality/e2e-test-specialist.md +0 -1005
- package/ai-config/agents/quality/performance-tester.md +0 -1086
- package/ai-config/agents/quality/security-auditor.md +0 -133
- package/ai-config/agents/quality/test-engineer.md +0 -453
- package/ai-config/agents/specialists/api-designer.md +0 -87
- package/ai-config/agents/specialists/backend-architect.md +0 -73
- package/ai-config/agents/specialists/code-reviewer.md +0 -77
- package/ai-config/agents/specialists/db-optimizer.md +0 -75
- package/ai-config/agents/specialists/devops-engineer.md +0 -83
- package/ai-config/agents/specialists/documentation-writer.md +0 -78
- package/ai-config/agents/specialists/frontend-developer.md +0 -75
- package/ai-config/agents/specialists/performance-analyst.md +0 -82
- package/ai-config/agents/specialists/refactor-specialist.md +0 -74
- package/ai-config/agents/specialists/security-auditor.md +0 -74
- package/ai-config/agents/specialists/test-engineer.md +0 -81
- package/ai-config/agents/specialists/ux-consultant.md +0 -76
- package/ai-config/agents/specialized/agent-generator.md +0 -1190
- package/ai-config/agents/specialized/blockchain-developer.md +0 -149
- package/ai-config/agents/specialized/code-migrator.md +0 -892
- package/ai-config/agents/specialized/context-manager.md +0 -978
- package/ai-config/agents/specialized/documentation-writer.md +0 -1078
- package/ai-config/agents/specialized/ecommerce-expert.md +0 -1756
- package/ai-config/agents/specialized/embedded-engineer.md +0 -1714
- package/ai-config/agents/specialized/error-detective.md +0 -1034
- package/ai-config/agents/specialized/fintech-specialist.md +0 -1659
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +0 -1988
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +0 -2136
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +0 -4503
- package/ai-config/agents/specialized/freelance-project-planner.md +0 -722
- package/ai-config/agents/specialized/game-developer.md +0 -1963
- package/ai-config/agents/specialized/healthcare-dev.md +0 -1620
- package/ai-config/agents/specialized/mobile-developer.md +0 -188
- package/ai-config/agents/specialized/parallel-plan-executor.md +0 -506
- package/ai-config/agents/specialized/plan-executor.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +0 -3493
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +0 -778
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +0 -918
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +0 -1537
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +0 -2633
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +0 -5610
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +0 -335
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +0 -215
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +0 -260
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +0 -379
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +0 -355
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +0 -279
- package/ai-config/agents/specialized/template-writer.md +0 -347
- package/ai-config/agents/specialized/test-runner.md +0 -99
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +0 -244
- package/ai-config/agents/specialized/wave-executor.md +0 -138
- package/ai-config/agents/specialized/workflow-optimizer.md +0 -1114
- package/ai-config/commands/git/changelog.md +0 -32
- package/ai-config/commands/git/ci-local.md +0 -70
- package/ai-config/commands/git/commit.md +0 -35
- package/ai-config/commands/git/fix-issue.md +0 -23
- package/ai-config/commands/git/pr-create.md +0 -42
- package/ai-config/commands/git/pr-review.md +0 -50
- package/ai-config/commands/git/worktree.md +0 -39
- package/ai-config/commands/refactoring/cleanup.md +0 -24
- package/ai-config/commands/refactoring/dead-code.md +0 -40
- package/ai-config/commands/refactoring/extract.md +0 -31
- package/ai-config/commands/testing/e2e.md +0 -30
- package/ai-config/commands/testing/tdd.md +0 -36
- package/ai-config/commands/testing/test-coverage.md +0 -30
- package/ai-config/commands/testing/test-fix.md +0 -24
- package/ai-config/commands/workflow/generate-agents-md.md +0 -85
- package/ai-config/commands/workflow/planning.md +0 -47
- package/ai-config/commands/workflows/compound.md +0 -89
- package/ai-config/commands/workflows/diagnose.md +0 -70
- package/ai-config/commands/workflows/discover.md +0 -86
- package/ai-config/commands/workflows/plan.md +0 -77
- package/ai-config/commands/workflows/review.md +0 -78
- package/ai-config/commands/workflows/work.md +0 -75
- package/ai-config/config.yaml +0 -18
- package/ai-config/hooks/_TEMPLATE.md +0 -96
- package/ai-config/hooks/block-dangerous-commands.md +0 -75
- package/ai-config/hooks/commit-guard.md +0 -90
- package/ai-config/hooks/context-loader.md +0 -73
- package/ai-config/hooks/improve-prompt.md +0 -91
- package/ai-config/hooks/learning-log.md +0 -72
- package/ai-config/hooks/model-router.md +0 -86
- package/ai-config/hooks/secret-scanner.md +0 -64
- package/ai-config/hooks/skill-validator.md +0 -102
- package/ai-config/hooks/task-artifact.md +0 -114
- package/ai-config/hooks/validate-workflow.md +0 -100
- package/ai-config/prompts/base.md +0 -71
- package/ai-config/prompts/modes/debug.md +0 -34
- package/ai-config/prompts/modes/deploy.md +0 -40
- package/ai-config/prompts/modes/research.md +0 -32
- package/ai-config/prompts/modes/review.md +0 -33
- package/ai-config/prompts/review-policy.md +0 -79
- package/ai-config/skills/_TEMPLATE.md +0 -157
- package/ai-config/skills/backend/api-gateway/SKILL.md +0 -254
- package/ai-config/skills/backend/bff-concepts/SKILL.md +0 -239
- package/ai-config/skills/backend/bff-spring/SKILL.md +0 -364
- package/ai-config/skills/backend/chi-router/SKILL.md +0 -396
- package/ai-config/skills/backend/error-handling/SKILL.md +0 -255
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +0 -323
- package/ai-config/skills/backend/fastapi/SKILL.md +0 -302
- package/ai-config/skills/backend/gateway-spring/SKILL.md +0 -390
- package/ai-config/skills/backend/go-backend/SKILL.md +0 -457
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +0 -274
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +0 -352
- package/ai-config/skills/backend/graphql-spring/SKILL.md +0 -398
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +0 -283
- package/ai-config/skills/backend/grpc-spring/SKILL.md +0 -445
- package/ai-config/skills/backend/jwt-auth/SKILL.md +0 -412
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +0 -259
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +0 -261
- package/ai-config/skills/backend/search-concepts/SKILL.md +0 -263
- package/ai-config/skills/backend/search-spring/SKILL.md +0 -375
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +0 -172
- package/ai-config/skills/backend/websockets/SKILL.md +0 -532
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +0 -423
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +0 -195
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +0 -340
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +0 -440
- package/ai-config/skills/data-ai/langchain/SKILL.md +0 -238
- package/ai-config/skills/data-ai/mlflow/SKILL.md +0 -302
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +0 -290
- package/ai-config/skills/data-ai/powerbi/SKILL.md +0 -352
- package/ai-config/skills/data-ai/pytorch/SKILL.md +0 -274
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +0 -321
- package/ai-config/skills/data-ai/vector-db/SKILL.md +0 -301
- package/ai-config/skills/database/graph-databases/SKILL.md +0 -218
- package/ai-config/skills/database/graph-spring/SKILL.md +0 -361
- package/ai-config/skills/database/pgx-postgres/SKILL.md +0 -512
- package/ai-config/skills/database/redis-cache/SKILL.md +0 -343
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +0 -388
- package/ai-config/skills/database/timescaledb/SKILL.md +0 -320
- package/ai-config/skills/docs/api-documentation/SKILL.md +0 -293
- package/ai-config/skills/docs/docs-spring/SKILL.md +0 -377
- package/ai-config/skills/docs/mustache-templates/SKILL.md +0 -190
- package/ai-config/skills/docs/technical-docs/SKILL.md +0 -447
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +0 -441
- package/ai-config/skills/frontend/frontend-design/SKILL.md +0 -54
- package/ai-config/skills/frontend/frontend-web/SKILL.md +0 -368
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +0 -396
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +0 -439
- package/ai-config/skills/frontend/zod-validation/SKILL.md +0 -417
- package/ai-config/skills/frontend/zustand-state/SKILL.md +0 -350
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +0 -244
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +0 -378
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +0 -435
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +0 -420
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +0 -456
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +0 -546
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +0 -474
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +0 -315
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +0 -504
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +0 -448
- package/ai-config/skills/prompt-improver/SKILL.md +0 -125
- package/ai-config/skills/quality/ghagga-review/SKILL.md +0 -216
- package/ai-config/skills/references/hooks-patterns/SKILL.md +0 -238
- package/ai-config/skills/references/mcp-servers/SKILL.md +0 -275
- package/ai-config/skills/references/plugins-reference/SKILL.md +0 -110
- package/ai-config/skills/references/skills-reference/SKILL.md +0 -420
- package/ai-config/skills/references/subagent-templates/SKILL.md +0 -193
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +0 -410
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +0 -408
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +0 -386
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +0 -324
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +0 -289
- package/ai-config/skills/testing/testcontainers/SKILL.md +0 -299
- package/ai-config/skills/testing/vitest-testing/SKILL.md +0 -381
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +0 -118
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +0 -299
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +0 -158
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +0 -117
- package/ai-config/skills/workflow/git-github/SKILL.md +0 -334
- package/ai-config/skills/workflow/git-github/references/examples.md +0 -160
- package/ai-config/skills/workflow/git-workflow/SKILL.md +0 -214
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +0 -277
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +0 -401
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +0 -199
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +0 -100
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +0 -73
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +0 -178
- package/schemas/agent.schema.json +0 -34
- package/schemas/ai-config.schema.json +0 -28
- package/schemas/plugin.schema.json +0 -62
- package/schemas/skill.schema.json +0 -44
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: vitest-testing
|
|
3
|
-
description: >
|
|
4
|
-
Frontend testing patterns with Vitest, Testing Library, and MSW for React applications.
|
|
5
|
-
Trigger: Vitest, testing library, MSW, frontend testing, React testing, unit test, component test
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Write
|
|
9
|
-
- Bash
|
|
10
|
-
- Grep
|
|
11
|
-
metadata:
|
|
12
|
-
author: plataforma-industrial
|
|
13
|
-
version: "2.0"
|
|
14
|
-
tags: [vitest, testing, react, msw, testing-library, frontend]
|
|
15
|
-
updated: "2026-02"
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
# Frontend Testing with Vitest
|
|
19
|
-
|
|
20
|
-
Comprehensive testing patterns for React applications with Vitest, Testing Library, and MSW.
|
|
21
|
-
|
|
22
|
-
## Stack
|
|
23
|
-
|
|
24
|
-
```yaml
|
|
25
|
-
Vitest: 1.3+
|
|
26
|
-
@testing-library/react: 14.2+
|
|
27
|
-
@testing-library/user-event: 14.5+
|
|
28
|
-
MSW: 2.2+
|
|
29
|
-
happy-dom: 13.3+
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Configuration
|
|
33
|
-
|
|
34
|
-
### vitest.config.ts
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { defineConfig } from 'vitest/config';
|
|
38
|
-
import react from '@vitejs/plugin-react';
|
|
39
|
-
import { resolve } from 'path';
|
|
40
|
-
|
|
41
|
-
export default defineConfig({
|
|
42
|
-
plugins: [react()],
|
|
43
|
-
test: {
|
|
44
|
-
globals: true,
|
|
45
|
-
environment: 'happy-dom',
|
|
46
|
-
setupFiles: ['./src/test/setup.ts'],
|
|
47
|
-
include: ['src/**/*.{test,spec}.{ts,tsx}'],
|
|
48
|
-
coverage: {
|
|
49
|
-
provider: 'v8',
|
|
50
|
-
reporter: ['text', 'json', 'html'],
|
|
51
|
-
thresholds: {
|
|
52
|
-
global: { branches: 80, functions: 80, lines: 80, statements: 80 },
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
resolve: {
|
|
57
|
-
alias: {
|
|
58
|
-
'@': resolve(__dirname, './src'),
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Setup File
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// src/test/setup.ts
|
|
68
|
-
import '@testing-library/jest-dom/vitest';
|
|
69
|
-
import { cleanup } from '@testing-library/react';
|
|
70
|
-
import { afterEach, beforeAll, afterAll, vi } from 'vitest';
|
|
71
|
-
import { server } from '@/mocks/server';
|
|
72
|
-
|
|
73
|
-
// Mock matchMedia
|
|
74
|
-
Object.defineProperty(window, 'matchMedia', {
|
|
75
|
-
writable: true,
|
|
76
|
-
value: vi.fn().mockImplementation((query) => ({
|
|
77
|
-
matches: false,
|
|
78
|
-
media: query,
|
|
79
|
-
addEventListener: vi.fn(),
|
|
80
|
-
removeEventListener: vi.fn(),
|
|
81
|
-
})),
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// MSW Server
|
|
85
|
-
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
|
|
86
|
-
afterEach(() => {
|
|
87
|
-
cleanup();
|
|
88
|
-
server.resetHandlers();
|
|
89
|
-
});
|
|
90
|
-
afterAll(() => server.close());
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Component Testing
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
// src/components/Card/Card.test.tsx
|
|
97
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
98
|
-
import { render, screen } from '@testing-library/react';
|
|
99
|
-
import userEvent from '@testing-library/user-event';
|
|
100
|
-
import { Card } from './Card';
|
|
101
|
-
|
|
102
|
-
const mockItem = {
|
|
103
|
-
id: 'item-1',
|
|
104
|
-
name: 'Test Item',
|
|
105
|
-
status: 'active',
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
describe('Card', () => {
|
|
109
|
-
it('renders item information', () => {
|
|
110
|
-
render(<Card item={mockItem} />);
|
|
111
|
-
|
|
112
|
-
expect(screen.getByText('Test Item')).toBeInTheDocument();
|
|
113
|
-
expect(screen.getByText('active')).toBeInTheDocument();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('calls onClick when clicked', async () => {
|
|
117
|
-
const user = userEvent.setup();
|
|
118
|
-
const onClick = vi.fn();
|
|
119
|
-
|
|
120
|
-
render(<Card item={mockItem} onClick={onClick} />);
|
|
121
|
-
await user.click(screen.getByRole('article'));
|
|
122
|
-
|
|
123
|
-
expect(onClick).toHaveBeenCalledWith(mockItem.id);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('shows alert status when flagged', () => {
|
|
127
|
-
const alertItem = { ...mockItem, status: 'alert' };
|
|
128
|
-
render(<Card item={alertItem} />);
|
|
129
|
-
|
|
130
|
-
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Hook Testing
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// src/hooks/useData.test.ts
|
|
139
|
-
import { describe, it, expect } from 'vitest';
|
|
140
|
-
import { renderHook, waitFor } from '@testing-library/react';
|
|
141
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
142
|
-
import { useData } from './useData';
|
|
143
|
-
|
|
144
|
-
const createWrapper = () => {
|
|
145
|
-
const queryClient = new QueryClient({
|
|
146
|
-
defaultOptions: { queries: { retry: false, gcTime: 0 } },
|
|
147
|
-
});
|
|
148
|
-
return ({ children }: { children: React.ReactNode }) => (
|
|
149
|
-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
describe('useData', () => {
|
|
154
|
-
it('fetches data successfully', async () => {
|
|
155
|
-
const { result } = renderHook(() => useData('item-1'), {
|
|
156
|
-
wrapper: createWrapper(),
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
expect(result.current.isLoading).toBe(true);
|
|
160
|
-
|
|
161
|
-
await waitFor(() => {
|
|
162
|
-
expect(result.current.isSuccess).toBe(true);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
expect(result.current.data).toEqual(
|
|
166
|
-
expect.objectContaining({ id: 'item-1' })
|
|
167
|
-
);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('handles error state', async () => {
|
|
171
|
-
const { result } = renderHook(() => useData('non-existent'), {
|
|
172
|
-
wrapper: createWrapper(),
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await waitFor(() => {
|
|
176
|
-
expect(result.current.isError).toBe(true);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Store Testing (Zustand)
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
// src/stores/store.test.ts
|
|
186
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
187
|
-
import { useStore } from './store';
|
|
188
|
-
|
|
189
|
-
describe('Store', () => {
|
|
190
|
-
beforeEach(() => {
|
|
191
|
-
useStore.setState({ items: [], selectedId: null });
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('adds item to store', () => {
|
|
195
|
-
const { addItem } = useStore.getState();
|
|
196
|
-
|
|
197
|
-
addItem({ id: 'item-1', name: 'Test' });
|
|
198
|
-
|
|
199
|
-
expect(useStore.getState().items).toHaveLength(1);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('selects item', () => {
|
|
203
|
-
const { selectItem } = useStore.getState();
|
|
204
|
-
|
|
205
|
-
selectItem('item-1');
|
|
206
|
-
|
|
207
|
-
expect(useStore.getState().selectedId).toBe('item-1');
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## MSW Setup
|
|
213
|
-
|
|
214
|
-
### Server
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
// src/mocks/server.ts
|
|
218
|
-
import { setupServer } from 'msw/node';
|
|
219
|
-
import { handlers } from './handlers';
|
|
220
|
-
|
|
221
|
-
export const server = setupServer(...handlers);
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### Handlers
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
// src/mocks/handlers.ts
|
|
228
|
-
import { http, HttpResponse, delay } from 'msw';
|
|
229
|
-
|
|
230
|
-
const API_URL = 'http://localhost:8080/api/v1';
|
|
231
|
-
|
|
232
|
-
const items = [
|
|
233
|
-
{ id: 'item-1', name: 'Item A', status: 'active' },
|
|
234
|
-
{ id: 'item-2', name: 'Item B', status: 'inactive' },
|
|
235
|
-
];
|
|
236
|
-
|
|
237
|
-
export const handlers = [
|
|
238
|
-
http.get(`${API_URL}/items`, async () => {
|
|
239
|
-
await delay(100);
|
|
240
|
-
return HttpResponse.json({ data: items });
|
|
241
|
-
}),
|
|
242
|
-
|
|
243
|
-
http.get(`${API_URL}/items/:id`, async ({ params }) => {
|
|
244
|
-
const item = items.find((i) => i.id === params.id);
|
|
245
|
-
if (!item) return new HttpResponse(null, { status: 404 });
|
|
246
|
-
return HttpResponse.json(item);
|
|
247
|
-
}),
|
|
248
|
-
|
|
249
|
-
http.post(`${API_URL}/items`, async ({ request }) => {
|
|
250
|
-
const body = await request.json();
|
|
251
|
-
return HttpResponse.json({ id: crypto.randomUUID(), ...body });
|
|
252
|
-
}),
|
|
253
|
-
];
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Override in Tests
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
import { server } from '@/mocks/server';
|
|
260
|
-
import { http, HttpResponse } from 'msw';
|
|
261
|
-
|
|
262
|
-
it('handles server error gracefully', async () => {
|
|
263
|
-
server.use(
|
|
264
|
-
http.get('http://localhost:8080/api/v1/items', () => {
|
|
265
|
-
return new HttpResponse(null, { status: 500 });
|
|
266
|
-
})
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
render(<ItemList />);
|
|
270
|
-
|
|
271
|
-
await waitFor(() => {
|
|
272
|
-
expect(screen.getByText(/error loading/i)).toBeInTheDocument();
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Testing with Providers
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// src/test/utils.tsx
|
|
281
|
-
import { MantineProvider } from '@mantine/core';
|
|
282
|
-
import { render, RenderOptions } from '@testing-library/react';
|
|
283
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
284
|
-
|
|
285
|
-
export function AllProviders({ children }: { children: React.ReactNode }) {
|
|
286
|
-
const queryClient = new QueryClient({
|
|
287
|
-
defaultOptions: { queries: { retry: false } },
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
return (
|
|
291
|
-
<QueryClientProvider client={queryClient}>
|
|
292
|
-
<MantineProvider>{children}</MantineProvider>
|
|
293
|
-
</QueryClientProvider>
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function renderWithProviders(
|
|
298
|
-
ui: React.ReactElement,
|
|
299
|
-
options?: Omit<RenderOptions, 'wrapper'>
|
|
300
|
-
) {
|
|
301
|
-
return render(ui, { wrapper: AllProviders, ...options });
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
export * from '@testing-library/react';
|
|
305
|
-
export { renderWithProviders as render };
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
## Form Testing
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
// src/components/Form/Form.test.tsx
|
|
312
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
313
|
-
import { render, screen, waitFor } from '@/test/utils';
|
|
314
|
-
import userEvent from '@testing-library/user-event';
|
|
315
|
-
import { Form } from './Form';
|
|
316
|
-
|
|
317
|
-
describe('Form', () => {
|
|
318
|
-
it('submits form with valid data', async () => {
|
|
319
|
-
const user = userEvent.setup();
|
|
320
|
-
const onSubmit = vi.fn();
|
|
321
|
-
|
|
322
|
-
render(<Form onSubmit={onSubmit} />);
|
|
323
|
-
|
|
324
|
-
await user.type(screen.getByLabelText(/name/i), 'Test Name');
|
|
325
|
-
await user.selectOptions(screen.getByLabelText(/type/i), 'option1');
|
|
326
|
-
await user.click(screen.getByRole('button', { name: /save/i }));
|
|
327
|
-
|
|
328
|
-
await waitFor(() => {
|
|
329
|
-
expect(onSubmit).toHaveBeenCalledWith({ name: 'Test Name', type: 'option1' });
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
it('shows validation errors', async () => {
|
|
334
|
-
const user = userEvent.setup();
|
|
335
|
-
|
|
336
|
-
render(<Form onSubmit={vi.fn()} />);
|
|
337
|
-
await user.click(screen.getByRole('button', { name: /save/i }));
|
|
338
|
-
|
|
339
|
-
await waitFor(() => {
|
|
340
|
-
expect(screen.getByText(/name is required/i)).toBeInTheDocument();
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
## Scripts
|
|
347
|
-
|
|
348
|
-
```json
|
|
349
|
-
{
|
|
350
|
-
"scripts": {
|
|
351
|
-
"test": "vitest",
|
|
352
|
-
"test:run": "vitest run",
|
|
353
|
-
"test:ui": "vitest --ui",
|
|
354
|
-
"test:coverage": "vitest run --coverage"
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
## Best Practices
|
|
360
|
-
|
|
361
|
-
1. **Test behavior, not implementation** - Test what user sees
|
|
362
|
-
2. **Use user-event over fireEvent** - More realistic
|
|
363
|
-
3. **Query by role/label first** - Accessible queries
|
|
364
|
-
4. **Use findBy for async** - `await screen.findByRole('alert')`
|
|
365
|
-
5. **Avoid testing library internals** - Test hook outputs
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
// Good - Accessible queries
|
|
369
|
-
screen.getByRole('button', { name: /submit/i });
|
|
370
|
-
screen.getByLabelText(/email/i);
|
|
371
|
-
|
|
372
|
-
// Avoid - Implementation detail
|
|
373
|
-
screen.getByTestId('submit-btn');
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## Related Skills
|
|
377
|
-
|
|
378
|
-
- `playwright-e2e`: E2E test complement
|
|
379
|
-
- `tanstack-query`: Query testing patterns
|
|
380
|
-
- `mantine-ui`: Component testing
|
|
381
|
-
- `zod-validation`: Schema testing
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ci-local-guide
|
|
3
|
-
description: >
|
|
4
|
-
Guide for using CI-Local to run CI/CD locally before pushing.
|
|
5
|
-
Trigger: run tests locally, CI simulation, pre-push validation, debugging CI failures, Docker CI
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Bash
|
|
9
|
-
- Grep
|
|
10
|
-
metadata:
|
|
11
|
-
author: project-starter-framework
|
|
12
|
-
version: "2.0"
|
|
13
|
-
tags: [ci-cd, testing, docker, pre-push, validation]
|
|
14
|
-
updated: "2026-02"
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# CI-Local Guide
|
|
18
|
-
|
|
19
|
-
Run your CI/CD pipeline locally before pushing to avoid broken builds in GitHub Actions.
|
|
20
|
-
|
|
21
|
-
## Quick Commands
|
|
22
|
-
|
|
23
|
-
### Check Stack Detection
|
|
24
|
-
```bash
|
|
25
|
-
./.ci-local/ci-local.sh detect # Linux/Mac
|
|
26
|
-
.\.ci-local\ci-local.ps1 detect # Windows
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Quick Validation (pre-commit level)
|
|
30
|
-
```bash
|
|
31
|
-
./.ci-local/ci-local.sh quick # Lint + compile
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Full CI Simulation (pre-push level)
|
|
35
|
-
```bash
|
|
36
|
-
./.ci-local/ci-local.sh full # Complete CI in Docker
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Debug Mode (interactive shell)
|
|
40
|
-
```bash
|
|
41
|
-
./.ci-local/ci-local.sh shell # Opens bash in CI container
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Supported Stacks
|
|
45
|
-
|
|
46
|
-
| Stack | Detection | Lint Command | Test Command |
|
|
47
|
-
|-------|-----------|--------------|--------------|
|
|
48
|
-
| Java/Gradle | `build.gradle(.kts)` | `./gradlew spotlessCheck` | `./gradlew test` |
|
|
49
|
-
| Java/Maven | `pom.xml` | `./mvnw spotless:check` | `./mvnw test` |
|
|
50
|
-
| Go | `go.mod` | `golangci-lint run` | `go test ./...` |
|
|
51
|
-
| Rust | `Cargo.toml` | `cargo clippy` | `cargo test` |
|
|
52
|
-
| Node.js | `package.json` | `npm run lint` | `npm test` |
|
|
53
|
-
| Python | `pyproject.toml` | `ruff check .` | `pytest` |
|
|
54
|
-
|
|
55
|
-
## Git Hooks
|
|
56
|
-
|
|
57
|
-
CI-Local installs these hooks automatically:
|
|
58
|
-
|
|
59
|
-
| Hook | Trigger | Checks |
|
|
60
|
-
|------|---------|--------|
|
|
61
|
-
| `pre-commit` | `git commit` | AI attribution, lint, security (Semgrep) |
|
|
62
|
-
| `commit-msg` | After message | No AI attribution in message |
|
|
63
|
-
| `pre-push` | `git push` | Full CI in Docker container |
|
|
64
|
-
|
|
65
|
-
## Bypass Hooks (Emergency Only)
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
git commit --no-verify # Skip pre-commit
|
|
69
|
-
git push --no-verify # Skip pre-push
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Warning**: Only use when absolutely necessary. You risk breaking CI.
|
|
73
|
-
|
|
74
|
-
## Troubleshooting
|
|
75
|
-
|
|
76
|
-
### "Docker not running"
|
|
77
|
-
Start Docker Desktop or run `docker info` to verify.
|
|
78
|
-
|
|
79
|
-
### "Tests pass locally but fail in pre-push"
|
|
80
|
-
That's the point! The pre-push uses Docker to replicate the exact CI environment.
|
|
81
|
-
Debug with:
|
|
82
|
-
```bash
|
|
83
|
-
./.ci-local/ci-local.sh shell
|
|
84
|
-
# You're now in the same environment as CI
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### "Hook blocked my commit"
|
|
88
|
-
Check the error message. Common causes:
|
|
89
|
-
- AI attribution detected (remove `Co-authored-by: Claude` etc.)
|
|
90
|
-
- Lint errors (run `./gradlew spotlessApply`)
|
|
91
|
-
- Security issues (check Semgrep output)
|
|
92
|
-
|
|
93
|
-
## Configuration
|
|
94
|
-
|
|
95
|
-
### Add Custom Semgrep Rules
|
|
96
|
-
Edit `.ci-local/semgrep.yml`:
|
|
97
|
-
```yaml
|
|
98
|
-
rules:
|
|
99
|
-
- id: my-custom-rule
|
|
100
|
-
pattern: $DANGER_PATTERN
|
|
101
|
-
message: "Dangerous pattern detected"
|
|
102
|
-
severity: ERROR
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Modify CI Commands
|
|
106
|
-
Edit the `detect_stack()` function in:
|
|
107
|
-
- `.ci-local/ci-local.sh` (Linux/Mac)
|
|
108
|
-
- `.ci-local/ci-local.ps1` (Windows)
|
|
109
|
-
|
|
110
|
-
## Philosophy
|
|
111
|
-
|
|
112
|
-
> "If it passes locally, it MUST pass in CI."
|
|
113
|
-
|
|
114
|
-
CI-Local ensures:
|
|
115
|
-
1. Same JDK/runtime version as CI
|
|
116
|
-
2. Same Docker image as GitHub Actions
|
|
117
|
-
3. No "works on my machine" syndrome
|
|
118
|
-
4. Fast feedback loop before push
|