behavior-testing
# Behavior Testing Skill
What this skill does
# Behavior Testing Skill
## Trigger
- Nach Feature-Implementation
- Wenn Tests nur DOM-Rendering pruefen ("smoke tests")
- Wenn Code-Review Luecken in der Test-Abdeckung findet
- `/behavior-tests` Slash-Command
## Problem
Standard-Tests (via AI-Generation oder Copilot) pruefen oft nur "wird gerendert?", nicht "funktioniert es?". Das fuehrt zu:
- Buttons ohne Funktionalitaet bestehen alle Tests
- API-Aufrufe mit falschen Argumenten werden nie erkannt
- State-Verlust bei Navigation/Re-Mount bleibt unsichtbar
- Fehlende Error-UI wird nie getestet
## 4 Test-Kategorien (PFLICHT)
### 1. API-Contract Tests
**Was:** Verifiziere, dass API-Funktionen mit den richtigen Argumenten aufgerufen werden.
**Warum:** Falsche Argumente (fehlende Language-Parameter, falsche Endpoints) sind unsichtbar in Rendering-Tests.
```typescript
// SCHLECHT: Prueft nur DOM
it('sends message', async () => {
await sendMessage('hello');
expect(screen.getByText('hello')).toBeInTheDocument(); // DOM only!
});
// GUT: Prueft API-Contract
it('sends message with correct language', async () => {
await sendMessage('hello');
expect(mockApi).toHaveBeenCalledWith(
'hello',
expect.any(Array), // history
'en', // language code
);
});
```
**Checkliste:**
- [ ] Mock der API-Funktion mit `vi.fn()`
- [ ] Pruefe Aufruf-Argumente mit `toHaveBeenCalledWith`
- [ ] Pruefe Anzahl der Aufrufe mit `toHaveBeenCalledTimes`
- [ ] Pruefe was bei API-Fehler passiert (Error-UI sichtbar?)
### 2. State-Persistence Tests
**Was:** Verifiziere, dass State nach Re-Mount, Page-Refresh oder Auth-Wechsel korrekt bleibt.
**Warum:** sessionStorage/localStorage-Bugs, Zustand-Resets bei Login/Logout.
```typescript
// Prueft sessionStorage-Persistenz
it('persists counter to sessionStorage', async () => {
render(<Chat />);
await sendMessage('test');
expect(sessionStorage.getItem('key')).toBe('1');
});
// Prueft Auth-Transition
it('resets counter on login', () => {
sessionStorage.setItem('key', '5');
useAuthStore.setState({ isAuthenticated: true });
// Effect should reset
expect(sessionStorage.getItem('key')).toBe('0');
});
```
**Checkliste:**
- [ ] sessionStorage/localStorage vor und nach Aktionen pruefen
- [ ] Auth-State-Wechsel testen (logged-in -> logged-out und umgekehrt)
- [ ] Zustand-Store direkt mit `setState` manipulieren fuer Edge-Cases
- [ ] Default-State nach Store-Reset pruefen
### 3. Error-Boundary Tests
**Was:** Verifiziere, dass Fehler dem User angezeigt werden und die App nicht crasht.
**Warum:** Fehlende Error-UI ist die haeufigste UX-Luecke.
```typescript
// API-Fehler -> Error-UI
it('shows error on checkout failure', async () => {
mockPost.mockRejectedValueOnce(new Error('Server error'));
fireEvent.click(checkoutButton);
await waitFor(() => {
expect(screen.getByText(/error|fehler/i)).toBeInTheDocument();
});
});
// 204 No Content -> kein Crash
it('handles 204 No Content', async () => {
mockFetch({ ok: true, status: 204, text: () => Promise.resolve('') });
const result = await apiClient.get('/api/logout');
expect(result).toEqual({});
});
```
**Checkliste:**
- [ ] API-Rejection -> Error-Message sichtbar
- [ ] Leere Responses (204, empty body) -> kein Crash
- [ ] Rate-Limit (429) -> Retry-Info angezeigt
- [ ] Non-JSON Error-Body -> graceful degradation
### 4. Security-Boundary Tests
**Was:** Verifiziere Input-Validation, Auth-Gates und Redirect-Sicherheit.
**Warum:** XSS-Praevention, Open-Redirect-Verhinderung, Rate-Limit-Enforcement.
```typescript
// Input-Laenge
it('rejects input over 2000 chars', async () => {
await sendMessage('a'.repeat(2001));
expect(mockApi).not.toHaveBeenCalled();
expect(screen.getByText(/maximum/i)).toBeInTheDocument();
});
// URL-Validation
it('blocks non-stripe.com redirect URLs', async () => {
mockPost.mockResolvedValueOnce({ url: 'https://evil.com/steal' });
fireEvent.click(checkoutButton);
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument();
});
});
// CSRF-Token
it('attaches CSRF token to POST but not GET', async () => {
document.cookie = 'csrf_token=abc123';
await apiClient.post('/api/data', {});
expect(fetchMock).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
headers: expect.objectContaining({ 'X-CSRF-Token': 'abc123' }),
}),
);
});
```
**Checkliste:**
- [ ] Input-Laenge-Limits werden client-seitig enforced
- [ ] Auth-Gate blockiert unauthentifizierte User
- [ ] Plan-Gate blockiert Free-Plan bei Premium-Features
- [ ] Redirect-URLs werden auf erlaubte Domains geprueft
- [ ] CSRF-Token wird bei POST angehaengt, nicht bei GET
- [ ] Credentials: 'include' auf allen Requests
## Implementierungs-Workflow
1. **Identifiziere Luecken**: Lies bestehende Tests. Pruefe ob sie nur `toBeInTheDocument()` nutzen.
2. **Mock die APIs**: `vi.mock()` fuer Service-Module, `vi.fn()` fuer einzelne Funktionen.
3. **Setze State direkt**: `useAuthStore.setState({...})` statt ueber UI navigieren.
4. **Pruefe Aufrufe**: `toHaveBeenCalledWith()` ist wichtiger als `toBeInTheDocument()`.
5. **Teste Fehlerpfade**: Jeder `try/catch` im Produktionscode braucht einen Test.
## Dateibenennung
```
# Bestehende Rendering-Tests behalten:
ComponentName.test.tsx
# Neue Behavior-Tests daneben:
ComponentName.behavior.test.tsx
# Oder in describe-Bloecken trennen:
describe('rendering', () => { ... }); // bestehend
describe('behavior', () => { ... }); // neu
describe('error handling', () => { ... }); // neu
```
## Anti-Patterns
| Anti-Pattern | Problem | Loesung |
|-------------|---------|---------|
| Nur `toBeInTheDocument()` | Prueft nicht ob Button funktioniert | `toHaveBeenCalledWith()` |
| Kein API-Mock | Test ruft echte API auf | `vi.mock()` + `vi.fn()` |
| Happy-Path only | Fehler-UI wird nie getestet | `mockRejectedValueOnce()` |
| State-Annahmen | Store wird nicht zurueckgesetzt | `beforeEach` + `setState` |
| Kein Auth-Kontext | Tests laufen nur als eingeloggt | Teste beide Zustaende |
## Referenz-Implementierung
Siehe: `Website/Relaunch 2026 01/services/__tests__/apiClient.test.ts` (Error-Boundary + Security-Boundary Muster)
Siehe: `Website/Relaunch 2026 01/components/__tests__/MultilingualChat.behavior.test.tsx` (API-Contract + State-Persistence Muster)
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.