glam/apps/archief-assistent/e2e/cache.spec.ts
kempersc ea35da02dc test(archief-assistent): add Playwright E2E test suite
- Add chat.spec.ts for RAG query testing
- Add count-queries.spec.ts for aggregation validation
- Add map-panel.spec.ts for geographic feature testing
- Add cache.spec.ts for response caching verification
- Add auth.setup.ts for authentication handling
- Configure playwright.config.ts for multi-browser testing
- Tests run against production archief.support
2026-01-09 21:09:56 +01:00

194 lines
6.3 KiB
TypeScript

import { test, expect } from '@playwright/test'
import { loginAndNavigate, waitForChatReady } from './auth.setup'
/**
* Cache behavior tests for ArchiefAssistent
*
* Tests verify that:
* - Repeat queries show cache hit indicator
* - Cached responses are faster than initial queries
* - Cache works correctly across the session
*/
test.describe('Cache Behavior', () => {
test.beforeEach(async ({ page }) => {
await loginAndNavigate(page)
await waitForChatReady(page)
})
/**
* Helper to submit a query and measure response time
*/
async function askQuestionTimed(page: any, question: string): Promise<{ response: string; timeMs: number }> {
const chatInput = page.getByTestId('chat-input')
const sendButton = page.getByTestId('send-button')
const startTime = Date.now()
await chatInput.fill(question)
await sendButton.click()
// Wait for assistant response
const assistantMessage = page.getByTestId('assistant-message').last()
await assistantMessage.waitFor({ timeout: 45000 })
const endTime = Date.now()
const response = await assistantMessage.textContent() || ''
return {
response,
timeMs: endTime - startTime
}
}
test('should show cache indicator on repeat query', async ({ page }) => {
const query = 'Hoeveel archieven zijn er in Utrecht?'
// First query
await askQuestionTimed(page, query)
// Wait a moment
await page.waitForTimeout(1000)
// Same query again
await askQuestionTimed(page, query)
// Look for cache indicator in the UI
// This depends on implementation - common patterns:
// - Text like "cached", "uit cache", "cache hit"
// - An icon or badge
// - A tooltip
const cacheIndicators = [
page.getByText(/cache/i),
page.getByText(/cached/i),
page.getByText(/uit cache/i),
page.locator('[class*="cache"]'),
page.locator('[data-testid*="cache"]'),
]
let cacheIndicatorFound = false
for (const indicator of cacheIndicators) {
if (await indicator.isVisible().catch(() => false)) {
cacheIndicatorFound = true
break
}
}
// Log whether cache indicator was found (not a hard failure if not found)
if (!cacheIndicatorFound) {
console.log('Note: No visible cache indicator found. May be implemented differently or not at all.')
}
})
test('cached response should be faster than initial query', async ({ page }) => {
const query = 'Hoeveel musea zijn er in Noord-Holland?'
// First query (should hit the RAG pipeline)
const first = await askQuestionTimed(page, query)
console.log(`First query time: ${first.timeMs}ms`)
// Wait a moment
await page.waitForTimeout(500)
// Same query again (should be cached)
const second = await askQuestionTimed(page, query)
console.log(`Second query time: ${second.timeMs}ms`)
// Cached response should be significantly faster
// We use a generous threshold since network variability exists
// Cache hit should be at least 50% faster or under 2 seconds
const isFaster = second.timeMs < first.timeMs * 0.75 || second.timeMs < 2000
// Soft assertion - log the result but don't fail if not met
// (caching behavior may vary based on server state)
if (isFaster) {
console.log('Cache appears to be working - second query was faster')
} else {
console.log('Warning: Second query was not significantly faster. Cache may not be active.')
}
// Both queries should return the same response
expect(second.response).toBe(first.response)
})
test('different queries should not share cache', async ({ page }) => {
const query1 = 'Hoeveel archieven zijn er in Gelderland?'
const query2 = 'Hoeveel musea zijn er in Gelderland?'
// First query
const result1 = await askQuestionTimed(page, query1)
// Different query
const result2 = await askQuestionTimed(page, query2)
// Responses should be different (different institution types)
expect(result2.response).not.toBe(result1.response)
})
test('slight variations should not hit cache', async ({ page }) => {
// Two queries that mean the same thing but are phrased differently
const query1 = 'Hoeveel archieven zijn er in Utrecht?'
const query2 = 'Wat is het aantal archieven in Utrecht?'
// First query
const result1 = await askQuestionTimed(page, query1)
// Wait
await page.waitForTimeout(500)
// Similar query with different phrasing
const result2 = await askQuestionTimed(page, query2)
// Both should return similar counts (within reason)
// Extract numbers from responses
const num1Match = result1.response.match(/\d+/)
const num2Match = result2.response.match(/\d+/)
if (num1Match && num2Match) {
const num1 = parseInt(num1Match[0])
const num2 = parseInt(num2Match[0])
// Should be the same count
expect(num2).toBe(num1)
}
})
})
test.describe('Cache with Session', () => {
test('cache should persist within same session', async ({ page }) => {
await loginAndNavigate(page)
await waitForChatReady(page)
const query = 'Hoeveel bibliotheken zijn er in Zuid-Holland?'
// First query
const chatInput = page.getByTestId('chat-input')
const sendButton = page.getByTestId('send-button')
await chatInput.fill(query)
await sendButton.click()
const firstResponse = page.getByTestId('assistant-message').last()
await firstResponse.waitFor({ timeout: 45000 })
const firstText = await firstResponse.textContent()
// Navigate away (if there are other pages) and back
// For now, just reload and re-query
// Note: Full cache persistence across page loads depends on implementation
// Ask a different question
await chatInput.fill('Wat is een archief?')
await sendButton.click()
await page.getByTestId('assistant-message').last().waitFor({ timeout: 45000 })
// Ask the original question again
await chatInput.fill(query)
await sendButton.click()
const repeatResponse = page.getByTestId('assistant-message').last()
await repeatResponse.waitFor({ timeout: 45000 })
const repeatText = await repeatResponse.textContent()
// Should get the same answer
expect(repeatText).toBe(firstText)
})
})