fix: better order
This commit is contained in:
@@ -1,158 +1,329 @@
|
||||
# Les 15: AI-Driven Testing & Quality Assurance
|
||||
|
||||
> 📋 **Lesmateriaal nog niet uitgewerkt**
|
||||
>
|
||||
> De volgende bestanden worden gegenereerd wanneer deze les wordt uitgewerkt:
|
||||
> - Les15-Slide-Overzicht.md
|
||||
> - Les15-Lesplan.md
|
||||
> - Les15-Bijlage-A-Lesopdracht.md
|
||||
> - Les15-Bijlage-B-Huiswerkopdracht.md
|
||||
# Les 15: Vercel AI SDK - AI Features in je App
|
||||
|
||||
---
|
||||
|
||||
## Hoofdstuk
|
||||
**Hoofdstuk 3: Advanced** (Les 8-18)
|
||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
||||
|
||||
## Beschrijving
|
||||
AI voor testen en code kwaliteit.
|
||||
Bouw AI-powered features in je apps met de Vercel AI SDK. Leer hoe je chat interfaces, streaming responses en AI-gegenereerde content implementeert.
|
||||
|
||||
---
|
||||
|
||||
## Te Behandelen
|
||||
|
||||
### Waarom Testen Belangrijk
|
||||
- Vang bugs vroeg
|
||||
- Vertrouwen in refactoring
|
||||
- Documentatie van gedrag
|
||||
### Waarom Vercel AI SDK?
|
||||
|
||||
### Types van Tests
|
||||
**Het probleem:** Direct API calls naar OpenAI/Anthropic zijn complex:
|
||||
- Streaming handmatig implementeren
|
||||
- Error handling
|
||||
- State management
|
||||
|
||||
| Type | Scope |
|
||||
|------|-------|
|
||||
| Unit | Individuele functies |
|
||||
| Component | React components |
|
||||
| Integration | Meerdere units samen |
|
||||
| E2E | Volledige user flows |
|
||||
**De oplossing:** Vercel AI SDK
|
||||
- Simpele React hooks
|
||||
- Built-in streaming
|
||||
- Provider-agnostic (OpenAI, Anthropic, etc.)
|
||||
- Edge-ready
|
||||
|
||||
### AI voor Test Generation
|
||||
- Beschrijf wat te testen
|
||||
- AI schrijft comprehensive suites
|
||||
- Dekt edge cases
|
||||
---
|
||||
|
||||
### Testing Tools
|
||||
### Installatie & Setup
|
||||
|
||||
| Tool | Gebruik |
|
||||
|------|---------|
|
||||
| Vitest | Snelle moderne test runner |
|
||||
| React Testing Library | User perspectief |
|
||||
| MSW | API mocking |
|
||||
| Playwright | E2E testing |
|
||||
```bash
|
||||
npm install ai @ai-sdk/openai
|
||||
# of voor Anthropic:
|
||||
npm install ai @ai-sdk/anthropic
|
||||
```
|
||||
|
||||
### Testing Supabase
|
||||
- Mocken database calls
|
||||
- RLS testen
|
||||
- Edge Functions testen
|
||||
**Environment variable:**
|
||||
```bash
|
||||
# .env.local
|
||||
OPENAI_API_KEY=sk-xxxxx
|
||||
```
|
||||
|
||||
### Code Review met AI
|
||||
- Geautomatiseerde reviews
|
||||
- Issues vinden (security, performance, accessibility)
|
||||
- Fixes suggereren
|
||||
---
|
||||
|
||||
### Debugging met AI
|
||||
- Plak error
|
||||
- AI legt uit en suggereert fix
|
||||
### Core Hooks
|
||||
|
||||
### Code Kwaliteit Metrics
|
||||
- Coverage >70%
|
||||
- Mutation testing
|
||||
- Complexity analyse
|
||||
#### useChat - Voor Conversaties
|
||||
|
||||
### Cursor's AI voor Automated Test Generation
|
||||
```tsx
|
||||
'use client'
|
||||
import { useChat } from 'ai/react'
|
||||
|
||||
### Integration met Workflow
|
||||
- Tests on git push
|
||||
- CI/CD
|
||||
export function ChatComponent() {
|
||||
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen">
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
{messages.map(m => (
|
||||
<div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
|
||||
<span className="inline-block p-2 rounded-lg bg-gray-100">
|
||||
{m.content}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="p-4 border-t">
|
||||
<input
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Type a message..."
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
<button type="submit" disabled={isLoading}>
|
||||
{isLoading ? 'Sending...' : 'Send'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### useCompletion - Voor Single Completions
|
||||
|
||||
```tsx
|
||||
import { useCompletion } from 'ai/react'
|
||||
|
||||
export function SummaryComponent() {
|
||||
const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<textarea
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Paste text to summarize..."
|
||||
/>
|
||||
<button type="submit">Summarize</button>
|
||||
</form>
|
||||
{completion && <p>{completion}</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### API Routes
|
||||
|
||||
**app/api/chat/route.ts:**
|
||||
```typescript
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
import { streamText } from 'ai'
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const { messages } = await req.json()
|
||||
|
||||
const result = streamText({
|
||||
model: openai('gpt-4o-mini'),
|
||||
system: 'You are a helpful cooking assistant. Suggest recipes based on ingredients.',
|
||||
messages,
|
||||
})
|
||||
|
||||
return result.toDataStreamResponse()
|
||||
}
|
||||
```
|
||||
|
||||
**Met custom system prompt:**
|
||||
```typescript
|
||||
const result = streamText({
|
||||
model: openai('gpt-4o-mini'),
|
||||
system: `You are a recipe assistant for the AI Recipe Generator app.
|
||||
|
||||
When the user provides ingredients:
|
||||
1. Suggest 2-3 recipes they could make
|
||||
2. List required additional ingredients (if any)
|
||||
3. Provide brief cooking instructions
|
||||
|
||||
Be concise and practical.`,
|
||||
messages,
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Streaming Responses
|
||||
|
||||
**Waarom streaming?**
|
||||
- Betere UX (user ziet direct resultaat)
|
||||
- Snellere perceived performance
|
||||
- Geen wachten op complete response
|
||||
|
||||
**Hoe het werkt:**
|
||||
1. Server stuurt tokens één voor één
|
||||
2. Client rendert elke token direct
|
||||
3. User ziet "typing" effect
|
||||
|
||||
**Loading indicator:**
|
||||
```tsx
|
||||
{isLoading && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="animate-pulse">●</div>
|
||||
<span>AI is thinking...</span>
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Integratie met Supabase
|
||||
|
||||
**Conversations opslaan:**
|
||||
|
||||
```typescript
|
||||
// Maak tabel in Supabase:
|
||||
// conversations: id, user_id, created_at
|
||||
// messages: id, conversation_id, role, content, created_at
|
||||
|
||||
// Na elke message:
|
||||
async function saveMessage(conversationId: string, role: string, content: string) {
|
||||
await supabase.from('messages').insert({
|
||||
conversation_id: conversationId,
|
||||
role,
|
||||
content
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**In je component:**
|
||||
```tsx
|
||||
const { messages, input, handleSubmit } = useChat({
|
||||
onFinish: async (message) => {
|
||||
await saveMessage(conversationId, message.role, message.content)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Error Handling
|
||||
|
||||
```tsx
|
||||
const { messages, error, reload } = useChat()
|
||||
|
||||
{error && (
|
||||
<div className="p-4 bg-red-100 text-red-700 rounded">
|
||||
<p>Something went wrong. Please try again.</p>
|
||||
<button onClick={reload}>Retry</button>
|
||||
</div>
|
||||
)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Cost Management
|
||||
|
||||
**Model keuze:**
|
||||
| Model | Kosten | Gebruik voor |
|
||||
|-------|--------|--------------|
|
||||
| gpt-4o-mini | Goedkoop | Meeste taken |
|
||||
| gpt-4o | Duur | Complexe reasoning |
|
||||
| claude-3-haiku | Goedkoop | Simpele taken |
|
||||
| claude-3-sonnet | Medium | Balans |
|
||||
|
||||
**Bespaartips:**
|
||||
1. Gebruik gpt-4o-mini als default
|
||||
2. Korte system prompts
|
||||
3. Beperk conversation history
|
||||
4. Caching waar mogelijk
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
- Vercel AI SDK (`ai` package)
|
||||
- Next.js API Routes
|
||||
- OpenAI API / Anthropic API
|
||||
- Cursor
|
||||
- Vitest
|
||||
- React Testing Library
|
||||
- MSW
|
||||
- Playwright
|
||||
- Supabase
|
||||
|
||||
---
|
||||
|
||||
## Lesopdracht (2 uur)
|
||||
|
||||
### Voeg Comprehensive Tests Toe met Cursor + AI
|
||||
### Bouw een AI Chat Component
|
||||
|
||||
### Setup (30 min)
|
||||
- Install dependencies (Vitest, RTL)
|
||||
- Configureer Vitest
|
||||
- Maak test utils
|
||||
- Verifieer met smoke test
|
||||
**Deel 1: Setup (20 min)**
|
||||
1. `npm install ai @ai-sdk/openai`
|
||||
2. Voeg `OPENAI_API_KEY` toe aan `.env.local`
|
||||
3. Maak `app/api/chat/route.ts`
|
||||
|
||||
### Schrijf Tests met Cursor (1 uur)
|
||||
**Deel 2: Basic Chat (40 min)**
|
||||
1. Maak `components/Chat.tsx`
|
||||
2. Implementeer `useChat` hook
|
||||
3. Bouw chat UI met Tailwind
|
||||
4. Test streaming werkt
|
||||
|
||||
| Type | Aantal | Tijd |
|
||||
|------|--------|------|
|
||||
| Unit Tests | 3-4 utility functies | 20 min |
|
||||
| Component Tests | 3-4 components | 30 min |
|
||||
| Integration Tests | 1-2 flows | 10 min |
|
||||
**Deel 3: System Prompt (30 min)**
|
||||
1. Schrijf system prompt voor je eindproject:
|
||||
- Recipe Generator: cooking assistant
|
||||
- Budget Buddy: financial advisor
|
||||
- Travel Planner: travel expert
|
||||
2. Test met relevante vragen
|
||||
|
||||
### Run & Fix (30 min)
|
||||
- Run `npm test`
|
||||
- AI helpt failures fixen
|
||||
- Bereik >70% coverage
|
||||
**Deel 4: Supabase Integratie (30 min)**
|
||||
1. Maak `messages` tabel
|
||||
2. Sla berichten op met `onFinish`
|
||||
3. Laad history bij page load
|
||||
|
||||
### Track
|
||||
- Test schrijf snelheid met AI?
|
||||
### Deliverable
|
||||
- Werkende AI chat met streaming
|
||||
- Custom system prompt
|
||||
- Messages opgeslagen in Supabase
|
||||
|
||||
---
|
||||
|
||||
## Huiswerk (2 uur)
|
||||
|
||||
### Implementeer AI Code Review Workflow
|
||||
### Bouw AI Feature voor Eindproject
|
||||
|
||||
### Deel 1: Maak Agent (1 uur)
|
||||
**Deel 1: Core AI Feature (1 uur)**
|
||||
|
||||
Custom GPT/Claude Project voor code review.
|
||||
Implementeer de AI chat die past bij je eindproject:
|
||||
|
||||
**Instructions moeten checken op:**
|
||||
- TypeScript safety
|
||||
| Project | AI Feature |
|
||||
|---------|-----------|
|
||||
| Recipe Generator | "Wat kan ik maken met kip en rijst?" |
|
||||
| Budget Buddy | "Analyseer mijn uitgaven deze maand" |
|
||||
| Travel Planner | "Plan een weekend Barcelona" |
|
||||
|
||||
- Custom system prompt
|
||||
- Context uit je database meegeven
|
||||
|
||||
**Deel 2: UX Polish (30 min)**
|
||||
|
||||
Voeg toe:
|
||||
- Streaming indicator
|
||||
- Suggested prompts / quick actions
|
||||
- Copy response button
|
||||
- Clear chat button
|
||||
- Error handling
|
||||
- Accessibility
|
||||
- Performance
|
||||
- Security
|
||||
- Best practices
|
||||
|
||||
**Upload "goede" code als knowledge base**
|
||||
**Deel 3: Documentatie (30 min)**
|
||||
|
||||
### Deel 2: Review 3 Components (1 uur)
|
||||
- Review 3 components
|
||||
- Documenteer ALLE issues
|
||||
- Categoriseer severity
|
||||
- Fix in Cursor
|
||||
- Re-review
|
||||
|
||||
### Deel 3: Enhance Template
|
||||
- Add testing setup aan Starter Template
|
||||
- Add Code Review agent
|
||||
Maak `docs/AI-FEATURE.md`:
|
||||
- Welke AI feature heb je gebouwd?
|
||||
- Wat doet de system prompt?
|
||||
- Hoe integreert het met Supabase?
|
||||
- Welke model keuzes heb je gemaakt?
|
||||
|
||||
### Deliverable
|
||||
- Agent (link)
|
||||
- Review rapport (issues/fixes/before-after)
|
||||
- Reflectie over AI-assisted QA
|
||||
- AI feature in eindproject
|
||||
- Deployed preview
|
||||
- AI-FEATURE.md documentatie
|
||||
|
||||
---
|
||||
|
||||
## Leerdoelen
|
||||
Na deze les kan de student:
|
||||
- Verschillende test types begrijpen en implementeren
|
||||
- AI gebruiken om tests te genereren
|
||||
- Testing tools configureren (Vitest, RTL, MSW, Playwright)
|
||||
- Code review agents bouwen
|
||||
- AI gebruiken voor debugging
|
||||
- Code kwaliteit meten met coverage en metrics
|
||||
- Vercel AI SDK installeren en configureren
|
||||
- `useChat` en `useCompletion` hooks gebruiken
|
||||
- Streaming responses implementeren
|
||||
- API routes opzetten voor AI providers
|
||||
- Custom system prompts schrijven
|
||||
- Chat history opslaan in Supabase
|
||||
- Error handling en loading states implementeren
|
||||
- Kostenbewust omgaan met AI APIs
|
||||
|
||||
Reference in New Issue
Block a user