- 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
194 lines
6.3 KiB
TypeScript
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)
|
|
})
|
|
})
|