Files
Charon/tests/fixtures/token-refresh-validation.spec.ts
2026-02-10 00:18:05 +00:00

102 lines
3.2 KiB
TypeScript

import { test, expect, refreshTokenIfNeeded } from './auth-fixtures';
/**
* Token Refresh Validation Tests
*
* Validates that the token refresh mechanism works correctly for long-running E2E sessions.
* These tests verify:
* - Token cache creation and reading
* - JWT expiry extraction
* - Token refresh endpoint integration
* - Concurrent access safety (file locking)
*/
test.describe('Token Refresh for Long-Running Sessions', () => {
test('New token should be cached with expiry', async ({ adminUser, page }) => {
const baseURL = page.context().baseURL || 'http://localhost:8080';
// Get initial token
let token = adminUser.token;
// refresh should either return the same token or a new one
const refreshedToken = await refreshTokenIfNeeded(baseURL, token);
expect(refreshedToken).toBeTruthy();
expect(refreshedToken).toMatch(/^[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_.]+\.[A-Za-z0-9\-_=]*$/);
});
test('Token refresh should work for 60-minute session simulation', async ({
adminUser,
page,
}) => {
const baseURL = page.context().baseURL || 'http://localhost:8080';
let token = adminUser.token;
let refreshCount = 0;
// Simulate 6 checkpoints over 60 minutes (10-min intervals in test)
// In production, these would be actual 10-minute intervals
for (let i = 0; i < 6; i++) {
const oldToken = token;
// Attempt refresh (should be no-op if not expired)
token = await refreshTokenIfNeeded(baseURL, token);
if (token !== oldToken) {
refreshCount++;
}
// Verify token is still valid by making a request
const response = await page.request.get('/api/v1/auth/status', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
expect(response.status()).toBeLessThan(400);
// In a real 60-min test, this would wait 10 minutes
// For validation, we skip the wait
// await page.waitForTimeout(10*60*1000);
}
// Token should be valid after the session
expect(token).toBeTruthy();
expect(token).toMatch(/^[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_.]+\.[A-Za-z0-9\-_=]*$/);
});
test('Token should remain valid across page navigation', async ({ adminUser, page }) => {
const baseURL = page.context().baseURL || 'http://localhost:8080';
let token = adminUser.token;
// Refresh token
token = await refreshTokenIfNeeded(baseURL, token);
// Set header for next request
await page.setExtraHTTPHeaders({
'Authorization': `Bearer ${token}`,
});
// Navigate to dashboard
const response = await page.goto('/');
expect(response?.status()).toBeLessThan(400);
});
test('Concurrent token access should not corrupt cache', async ({ adminUser }) => {
const baseURL = 'http://localhost:8080';
const token = adminUser.token;
// Simulate concurrent refresh calls (would happen in parallel tests)
const promises = Array.from({ length: 5 }, () =>
refreshTokenIfNeeded(baseURL, token)
);
const results = await Promise.all(promises);
// All should return valid tokens
results.forEach((result) => {
expect(result).toBeTruthy();
expect(result).toMatch(/^[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_.]+\.[A-Za-z0-9\-_=]*$/);
});
});
});