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,289 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: playwright-e2e
|
|
3
|
-
description: >
|
|
4
|
-
End-to-end testing with Playwright for web applications using Page Object Model and authentication fixtures.
|
|
5
|
-
Trigger: e2e testing, playwright, browser testing, visual regression, integration tests
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Write
|
|
9
|
-
- Bash
|
|
10
|
-
- Grep
|
|
11
|
-
metadata:
|
|
12
|
-
author: plataforma-industrial
|
|
13
|
-
version: "2.0"
|
|
14
|
-
tags: [testing, e2e, playwright, automation]
|
|
15
|
-
updated: "2026-02"
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
# Playwright E2E Testing
|
|
19
|
-
|
|
20
|
-
## Configuration
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
// playwright.config.ts
|
|
24
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
25
|
-
|
|
26
|
-
export default defineConfig({
|
|
27
|
-
testDir: './e2e',
|
|
28
|
-
fullyParallel: true,
|
|
29
|
-
forbidOnly: !!process.env.CI,
|
|
30
|
-
retries: process.env.CI ? 2 : 0,
|
|
31
|
-
workers: process.env.CI ? 1 : undefined,
|
|
32
|
-
reporter: [
|
|
33
|
-
['html', { outputFolder: 'playwright-report' }],
|
|
34
|
-
['junit', { outputFile: 'results.xml' }],
|
|
35
|
-
],
|
|
36
|
-
use: {
|
|
37
|
-
baseURL: process.env.BASE_URL || 'http://localhost:4321',
|
|
38
|
-
trace: 'on-first-retry',
|
|
39
|
-
screenshot: 'only-on-failure',
|
|
40
|
-
video: 'retain-on-failure',
|
|
41
|
-
},
|
|
42
|
-
projects: [
|
|
43
|
-
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
|
|
44
|
-
{ name: 'chromium', use: { ...devices['Desktop Chrome'] }, dependencies: ['setup'] },
|
|
45
|
-
{ name: 'firefox', use: { ...devices['Desktop Firefox'] }, dependencies: ['setup'] },
|
|
46
|
-
{ name: 'Mobile Chrome', use: { ...devices['Pixel 5'] }, dependencies: ['setup'] },
|
|
47
|
-
],
|
|
48
|
-
webServer: {
|
|
49
|
-
command: 'npm run preview',
|
|
50
|
-
url: 'http://localhost:4321',
|
|
51
|
-
reuseExistingServer: !process.env.CI,
|
|
52
|
-
timeout: 120000,
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Project Structure
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
e2e/
|
|
61
|
-
├── auth.setup.ts # Authentication setup
|
|
62
|
-
├── fixtures/
|
|
63
|
-
│ ├── auth.fixture.ts # Auth fixture
|
|
64
|
-
│ └── api.fixture.ts # API fixture
|
|
65
|
-
├── pages/
|
|
66
|
-
│ ├── BasePage.ts # Base POM
|
|
67
|
-
│ ├── LoginPage.ts # Login POM
|
|
68
|
-
│ └── DashboardPage.ts # Dashboard POM
|
|
69
|
-
├── tests/
|
|
70
|
-
│ ├── auth.spec.ts # Auth tests
|
|
71
|
-
│ └── dashboard.spec.ts # Feature tests
|
|
72
|
-
└── utils/
|
|
73
|
-
├── test-data.ts # Test data factories
|
|
74
|
-
└── helpers.ts # Helper functions
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Authentication Setup
|
|
78
|
-
|
|
79
|
-
```typescript
|
|
80
|
-
// e2e/auth.setup.ts
|
|
81
|
-
import { test as setup, expect } from '@playwright/test';
|
|
82
|
-
|
|
83
|
-
const authFile = 'playwright/.auth/user.json';
|
|
84
|
-
|
|
85
|
-
setup('authenticate', async ({ page }) => {
|
|
86
|
-
await page.goto('/login');
|
|
87
|
-
await page.getByLabel('Email').fill('user@example.com');
|
|
88
|
-
await page.getByLabel('Password').fill('password');
|
|
89
|
-
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
90
|
-
await page.waitForURL('/dashboard');
|
|
91
|
-
await page.context().storageState({ path: authFile });
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Page Object Model
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
// e2e/pages/BasePage.ts
|
|
99
|
-
import { Page, Locator, expect } from '@playwright/test';
|
|
100
|
-
|
|
101
|
-
export abstract class BasePage {
|
|
102
|
-
protected page: Page;
|
|
103
|
-
|
|
104
|
-
constructor(page: Page) {
|
|
105
|
-
this.page = page;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
get navbar(): Locator {
|
|
109
|
-
return this.page.getByRole('navigation');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async logout(): Promise<void> {
|
|
113
|
-
await this.page.getByTestId('user-menu').click();
|
|
114
|
-
await this.page.getByRole('menuitem', { name: 'Logout' }).click();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async expectToast(message: string): Promise<void> {
|
|
118
|
-
await expect(this.page.getByRole('alert').filter({ hasText: message })).toBeVisible();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async waitForLoader(): Promise<void> {
|
|
122
|
-
const loader = this.page.getByTestId('loader');
|
|
123
|
-
if (await loader.isVisible()) {
|
|
124
|
-
await loader.waitFor({ state: 'hidden' });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// e2e/pages/LoginPage.ts
|
|
130
|
-
export class LoginPage extends BasePage {
|
|
131
|
-
readonly emailInput: Locator;
|
|
132
|
-
readonly passwordInput: Locator;
|
|
133
|
-
readonly submitButton: Locator;
|
|
134
|
-
|
|
135
|
-
constructor(page: Page) {
|
|
136
|
-
super(page);
|
|
137
|
-
this.emailInput = page.getByLabel('Email');
|
|
138
|
-
this.passwordInput = page.getByLabel('Password');
|
|
139
|
-
this.submitButton = page.getByRole('button', { name: 'Sign in' });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async goto(): Promise<void> {
|
|
143
|
-
await this.page.goto('/login');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async login(email: string, password: string): Promise<void> {
|
|
147
|
-
await this.emailInput.fill(email);
|
|
148
|
-
await this.passwordInput.fill(password);
|
|
149
|
-
await this.submitButton.click();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Test Examples
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
// e2e/tests/auth.spec.ts
|
|
158
|
-
import { test, expect } from '@playwright/test';
|
|
159
|
-
import { LoginPage } from '../pages/LoginPage';
|
|
160
|
-
|
|
161
|
-
test.describe('Authentication', () => {
|
|
162
|
-
test('successful login redirects to dashboard', async ({ page }) => {
|
|
163
|
-
const loginPage = new LoginPage(page);
|
|
164
|
-
await loginPage.goto();
|
|
165
|
-
await loginPage.login('user@example.com', 'password');
|
|
166
|
-
await expect(page).toHaveURL('/dashboard');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test('invalid credentials show error', async ({ page }) => {
|
|
170
|
-
const loginPage = new LoginPage(page);
|
|
171
|
-
await loginPage.goto();
|
|
172
|
-
await loginPage.login('wrong@email.com', 'wrongpassword');
|
|
173
|
-
await expect(page.getByRole('alert')).toContainText('Invalid');
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// Using stored auth state
|
|
178
|
-
test.describe('Dashboard', () => {
|
|
179
|
-
test.use({ storageState: 'playwright/.auth/user.json' });
|
|
180
|
-
|
|
181
|
-
test('displays data', async ({ page }) => {
|
|
182
|
-
await page.goto('/dashboard');
|
|
183
|
-
await expect(page.getByTestId('sensor-grid')).toBeVisible();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## API Testing
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
// e2e/fixtures/api.fixture.ts
|
|
192
|
-
import { test as base, APIRequestContext } from '@playwright/test';
|
|
193
|
-
|
|
194
|
-
export const test = base.extend<{ api: APIRequestContext }>({
|
|
195
|
-
api: async ({ playwright }, use) => {
|
|
196
|
-
const context = await playwright.request.newContext({
|
|
197
|
-
baseURL: process.env.API_URL || 'http://localhost:8080',
|
|
198
|
-
extraHTTPHeaders: {
|
|
199
|
-
'Authorization': `Bearer ${process.env.TEST_API_TOKEN}`,
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
await use(context);
|
|
203
|
-
await context.dispose();
|
|
204
|
-
},
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// API test example
|
|
208
|
-
test('GET /api/v1/items returns list', async ({ api }) => {
|
|
209
|
-
const response = await api.get('/api/v1/items');
|
|
210
|
-
expect(response.ok()).toBeTruthy();
|
|
211
|
-
const data = await response.json();
|
|
212
|
-
expect(Array.isArray(data.data)).toBe(true);
|
|
213
|
-
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## Visual Regression
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
test('dashboard matches snapshot', async ({ page }) => {
|
|
220
|
-
await page.goto('/dashboard');
|
|
221
|
-
await page.waitForLoadState('networkidle');
|
|
222
|
-
await page.waitForTimeout(500); // Wait for animations
|
|
223
|
-
|
|
224
|
-
await expect(page).toHaveScreenshot('dashboard.png', {
|
|
225
|
-
maxDiffPixels: 100,
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## CI Integration
|
|
231
|
-
|
|
232
|
-
```yaml
|
|
233
|
-
# .github/workflows/e2e.yml
|
|
234
|
-
name: E2E Tests
|
|
235
|
-
on:
|
|
236
|
-
push:
|
|
237
|
-
branches: [main]
|
|
238
|
-
pull_request:
|
|
239
|
-
branches: [main]
|
|
240
|
-
|
|
241
|
-
jobs:
|
|
242
|
-
e2e:
|
|
243
|
-
runs-on: ubuntu-latest
|
|
244
|
-
steps:
|
|
245
|
-
- uses: actions/checkout@v4
|
|
246
|
-
- uses: actions/setup-node@v4
|
|
247
|
-
with:
|
|
248
|
-
node-version: 20
|
|
249
|
-
cache: npm
|
|
250
|
-
- run: npm ci
|
|
251
|
-
- run: npx playwright install --with-deps
|
|
252
|
-
- run: npm run build
|
|
253
|
-
- run: npm run e2e
|
|
254
|
-
- uses: actions/upload-artifact@v4
|
|
255
|
-
if: always()
|
|
256
|
-
with:
|
|
257
|
-
name: playwright-report
|
|
258
|
-
path: playwright-report/
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## Scripts
|
|
262
|
-
|
|
263
|
-
```json
|
|
264
|
-
{
|
|
265
|
-
"scripts": {
|
|
266
|
-
"e2e": "playwright test",
|
|
267
|
-
"e2e:ui": "playwright test --ui",
|
|
268
|
-
"e2e:headed": "playwright test --headed",
|
|
269
|
-
"e2e:debug": "playwright test --debug",
|
|
270
|
-
"e2e:report": "playwright show-report",
|
|
271
|
-
"e2e:codegen": "playwright codegen localhost:4321"
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Best Practices
|
|
277
|
-
|
|
278
|
-
1. **Use Page Object Model** - Encapsulate page interactions
|
|
279
|
-
2. **Wait for network idle** - `await page.waitForLoadState('networkidle')`
|
|
280
|
-
3. **Test isolation** - Each test independent, use `beforeEach`
|
|
281
|
-
4. **Prefer role locators** - `getByRole`, `getByLabel`, `getByText`
|
|
282
|
-
5. **Parameterized tests** - Use loops for multiple scenarios
|
|
283
|
-
|
|
284
|
-
## Related Skills
|
|
285
|
-
|
|
286
|
-
- `vitest-testing`: Unit/integration tests
|
|
287
|
-
- `frontend-web`: Frontend patterns to test
|
|
288
|
-
- `mobile-ionic`: Mobile app testing
|
|
289
|
-
- `devops-infra`: CI test automation
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: testcontainers
|
|
3
|
-
description: >
|
|
4
|
-
Testing con TestContainers en APiGen. PostgreSQL, Redis, integración Spring Boot.
|
|
5
|
-
Trigger: testcontainers, integration test, PostgreSQL test, container test
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Write
|
|
9
|
-
- Edit
|
|
10
|
-
- Bash
|
|
11
|
-
- Grep
|
|
12
|
-
metadata:
|
|
13
|
-
author: apigen-team
|
|
14
|
-
version: "1.0"
|
|
15
|
-
tags: [testing, testcontainers, integration]
|
|
16
|
-
scope: ["**/src/test/**"]
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
# TestContainers
|
|
20
|
-
|
|
21
|
-
## Dependencias
|
|
22
|
-
|
|
23
|
-
```groovy
|
|
24
|
-
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
|
|
25
|
-
testImplementation 'org.testcontainers:junit-jupiter'
|
|
26
|
-
testImplementation 'org.testcontainers:postgresql'
|
|
27
|
-
testImplementation 'org.testcontainers:rabbitmq' // si aplica
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## @ServiceConnection (Spring Boot 3.1+)
|
|
31
|
-
|
|
32
|
-
```java
|
|
33
|
-
@SpringBootTest
|
|
34
|
-
@Testcontainers
|
|
35
|
-
class UserRepositoryIT {
|
|
36
|
-
|
|
37
|
-
@Container
|
|
38
|
-
@ServiceConnection
|
|
39
|
-
static PostgreSQLContainer<?> postgres =
|
|
40
|
-
new PostgreSQLContainer<>("postgres:16-alpine");
|
|
41
|
-
|
|
42
|
-
@Autowired
|
|
43
|
-
private UserRepository userRepository;
|
|
44
|
-
|
|
45
|
-
@Test
|
|
46
|
-
void shouldSaveAndFindUser() {
|
|
47
|
-
var user = User.builder()
|
|
48
|
-
.name("Test User")
|
|
49
|
-
.email("test@example.com")
|
|
50
|
-
.build();
|
|
51
|
-
|
|
52
|
-
var saved = userRepository.save(user);
|
|
53
|
-
|
|
54
|
-
assertThat(saved.getId()).isNotNull();
|
|
55
|
-
assertThat(userRepository.findById(saved.getId()))
|
|
56
|
-
.isPresent()
|
|
57
|
-
.hasValueSatisfying(u -> assertThat(u.getName()).isEqualTo("Test User"));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Container Singleton (Reusable)
|
|
63
|
-
|
|
64
|
-
```java
|
|
65
|
-
public abstract class AbstractContainerIT {
|
|
66
|
-
|
|
67
|
-
@Container
|
|
68
|
-
@ServiceConnection
|
|
69
|
-
protected static final PostgreSQLContainer<?> POSTGRES =
|
|
70
|
-
new PostgreSQLContainer<>("postgres:16-alpine")
|
|
71
|
-
.withDatabaseName("testdb")
|
|
72
|
-
.withUsername("test")
|
|
73
|
-
.withPassword("test")
|
|
74
|
-
.withReuse(true); // Reuse entre tests
|
|
75
|
-
|
|
76
|
-
static {
|
|
77
|
-
POSTGRES.start();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Heredar en tests
|
|
82
|
-
@SpringBootTest
|
|
83
|
-
class UserServiceIT extends AbstractContainerIT {
|
|
84
|
-
// ...
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Multiple Containers
|
|
89
|
-
|
|
90
|
-
```java
|
|
91
|
-
@SpringBootTest
|
|
92
|
-
@Testcontainers
|
|
93
|
-
class FullStackIT {
|
|
94
|
-
|
|
95
|
-
@Container
|
|
96
|
-
@ServiceConnection
|
|
97
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
|
|
98
|
-
|
|
99
|
-
@Container
|
|
100
|
-
@ServiceConnection
|
|
101
|
-
static GenericContainer<?> redis = new GenericContainer<>("redis:7-alpine")
|
|
102
|
-
.withExposedPorts(6379);
|
|
103
|
-
|
|
104
|
-
@DynamicPropertySource
|
|
105
|
-
static void redisProperties(DynamicPropertyRegistry registry) {
|
|
106
|
-
registry.add("spring.data.redis.host", redis::getHost);
|
|
107
|
-
registry.add("spring.data.redis.port", () -> redis.getMappedPort(6379));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
@Autowired
|
|
111
|
-
private UserService userService;
|
|
112
|
-
|
|
113
|
-
@Autowired
|
|
114
|
-
private RedisTemplate<String, Object> redisTemplate;
|
|
115
|
-
|
|
116
|
-
@Test
|
|
117
|
-
void shouldCacheUserInRedis() {
|
|
118
|
-
var user = userService.create(new CreateUserDTO("Test", "test@test.com"));
|
|
119
|
-
|
|
120
|
-
// First call - from DB
|
|
121
|
-
userService.findById(user.getId());
|
|
122
|
-
|
|
123
|
-
// Second call - from cache
|
|
124
|
-
var cached = redisTemplate.opsForValue().get("users::" + user.getId());
|
|
125
|
-
assertThat(cached).isNotNull();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Test Profile (application-test.yml)
|
|
131
|
-
|
|
132
|
-
```yaml
|
|
133
|
-
# src/test/resources/application-test.yml
|
|
134
|
-
spring:
|
|
135
|
-
jpa:
|
|
136
|
-
hibernate:
|
|
137
|
-
ddl-auto: create-drop
|
|
138
|
-
show-sql: true
|
|
139
|
-
flyway:
|
|
140
|
-
enabled: false # TestContainers crea schema
|
|
141
|
-
|
|
142
|
-
logging:
|
|
143
|
-
level:
|
|
144
|
-
org.hibernate.SQL: DEBUG
|
|
145
|
-
org.testcontainers: INFO
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Controller Integration Test
|
|
149
|
-
|
|
150
|
-
```java
|
|
151
|
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
152
|
-
@Testcontainers
|
|
153
|
-
@ActiveProfiles("test")
|
|
154
|
-
class UserControllerIT {
|
|
155
|
-
|
|
156
|
-
@Container
|
|
157
|
-
@ServiceConnection
|
|
158
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
|
|
159
|
-
|
|
160
|
-
@Autowired
|
|
161
|
-
private TestRestTemplate restTemplate;
|
|
162
|
-
|
|
163
|
-
@Autowired
|
|
164
|
-
private UserRepository userRepository;
|
|
165
|
-
|
|
166
|
-
@BeforeEach
|
|
167
|
-
void setUp() {
|
|
168
|
-
userRepository.deleteAll();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@Test
|
|
172
|
-
void shouldCreateUser() {
|
|
173
|
-
var request = new CreateUserRequest("John Doe", "john@example.com");
|
|
174
|
-
|
|
175
|
-
var response = restTemplate.postForEntity(
|
|
176
|
-
"/api/users",
|
|
177
|
-
request,
|
|
178
|
-
UserDTO.class
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
|
|
182
|
-
assertThat(response.getBody()).isNotNull();
|
|
183
|
-
assertThat(response.getBody().name()).isEqualTo("John Doe");
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
@Test
|
|
187
|
-
void shouldReturnNotFoundForInvalidId() {
|
|
188
|
-
var response = restTemplate.getForEntity(
|
|
189
|
-
"/api/users/{id}",
|
|
190
|
-
ProblemDetail.class,
|
|
191
|
-
UUID.randomUUID()
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## WebTestClient (WebFlux style)
|
|
200
|
-
|
|
201
|
-
```java
|
|
202
|
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
203
|
-
@Testcontainers
|
|
204
|
-
class UserControllerWebClientIT {
|
|
205
|
-
|
|
206
|
-
@Container
|
|
207
|
-
@ServiceConnection
|
|
208
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
|
|
209
|
-
|
|
210
|
-
@Autowired
|
|
211
|
-
private WebTestClient webClient;
|
|
212
|
-
|
|
213
|
-
@Test
|
|
214
|
-
void shouldListUsers() {
|
|
215
|
-
webClient.get()
|
|
216
|
-
.uri("/api/users")
|
|
217
|
-
.exchange()
|
|
218
|
-
.expectStatus().isOk()
|
|
219
|
-
.expectBodyList(UserDTO.class)
|
|
220
|
-
.hasSize(0);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
@Test
|
|
224
|
-
void shouldCreateUser() {
|
|
225
|
-
webClient.post()
|
|
226
|
-
.uri("/api/users")
|
|
227
|
-
.bodyValue(new CreateUserRequest("Test", "test@test.com"))
|
|
228
|
-
.exchange()
|
|
229
|
-
.expectStatus().isCreated()
|
|
230
|
-
.expectBody()
|
|
231
|
-
.jsonPath("$.id").exists()
|
|
232
|
-
.jsonPath("$.name").isEqualTo("Test");
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Compilar Proyecto Generado (apigen-server)
|
|
238
|
-
|
|
239
|
-
```java
|
|
240
|
-
@SpringBootTest
|
|
241
|
-
@Testcontainers
|
|
242
|
-
@Tag("slow")
|
|
243
|
-
class GeneratedProjectCompilationIT {
|
|
244
|
-
|
|
245
|
-
@Container
|
|
246
|
-
@ServiceConnection
|
|
247
|
-
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
|
|
248
|
-
|
|
249
|
-
@Autowired
|
|
250
|
-
private GenerationService generationService;
|
|
251
|
-
|
|
252
|
-
@TempDir
|
|
253
|
-
Path tempDir;
|
|
254
|
-
|
|
255
|
-
@Test
|
|
256
|
-
@EnabledIfEnvironmentVariable(named = "CI_COMPILE_GENERATED_PROJECT", matches = "true")
|
|
257
|
-
void generatedJavaProjectShouldCompile() throws Exception {
|
|
258
|
-
var request = GenerationRequest.builder()
|
|
259
|
-
.projectName("test-project")
|
|
260
|
-
.basePackage("com.test")
|
|
261
|
-
.language("java")
|
|
262
|
-
.framework("spring-boot")
|
|
263
|
-
.schema("CREATE TABLE users (id UUID PRIMARY KEY, name VARCHAR(100));")
|
|
264
|
-
.build();
|
|
265
|
-
|
|
266
|
-
byte[] zipBytes = generationService.generate(request);
|
|
267
|
-
|
|
268
|
-
// Extract ZIP
|
|
269
|
-
Path projectDir = extractZip(zipBytes, tempDir);
|
|
270
|
-
|
|
271
|
-
// Compile
|
|
272
|
-
ProcessBuilder pb = new ProcessBuilder("./gradlew", "compileJava", "--no-daemon");
|
|
273
|
-
pb.directory(projectDir.toFile());
|
|
274
|
-
pb.inheritIO();
|
|
275
|
-
|
|
276
|
-
int exitCode = pb.start().waitFor();
|
|
277
|
-
|
|
278
|
-
assertThat(exitCode)
|
|
279
|
-
.withFailMessage("Generated project failed to compile")
|
|
280
|
-
.isZero();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## Best Practices
|
|
286
|
-
|
|
287
|
-
1. **Use @ServiceConnection** - Auto-configura datasource
|
|
288
|
-
2. **Singleton containers** - `withReuse(true)` para velocidad
|
|
289
|
-
3. **@ActiveProfiles("test")** - Config específica de test
|
|
290
|
-
4. **@TempDir** - Para archivos temporales
|
|
291
|
-
5. **@Tag("slow")** - Marcar tests lentos
|
|
292
|
-
6. **@EnabledIf** - Condicionar ejecución en CI
|
|
293
|
-
|
|
294
|
-
## Related Skills
|
|
295
|
-
|
|
296
|
-
- `spring-boot-4`: Spring Boot testing
|
|
297
|
-
- `apigen-architecture`: Estructura de tests
|
|
298
|
-
|
|
299
|
-
|