Flesh out payment stuff

This commit is contained in:
Joey Yakimowich-Payne 2026-01-22 12:21:12 -07:00
commit acfed861ab
No known key found for this signature in database
GPG key ID: 6BFE655FA5ABD1E1
27 changed files with 938 additions and 173 deletions

View file

@ -2159,6 +2159,126 @@ console.log('\n=== Game Session Tests ===');
}
});
await test('GET /api/payments/status returns expected generation limit for access type', async () => {
const { data } = await request('GET', '/api/payments/status');
const status = data as Record<string, unknown>;
const accessType = status.accessType as string;
const limit = status.generationLimit as number | null;
if (accessType === 'group') {
if (limit !== null) throw new Error('Expected null generationLimit for group access');
return;
}
if (accessType === 'subscription') {
if (limit !== 250) throw new Error(`Expected generationLimit 250, got ${limit}`);
return;
}
if (accessType === 'none') {
if (limit !== 5) throw new Error(`Expected free tier generationLimit 5, got ${limit}`);
return;
}
throw new Error(`Unexpected accessType: ${accessType}`);
});
await test('POST /api/generate with two documents blocks free tier users', async () => {
const statusRes = await request('GET', '/api/payments/status');
const status = statusRes.data as Record<string, unknown>;
const accessType = status.accessType as string;
const res = await fetch(`${API_URL}/api/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
body: JSON.stringify({
topic: 'Document content',
documents: [
{ type: 'text', content: 'Doc A' },
{ type: 'text', content: 'Doc B' }
],
questionCount: 2
}),
});
if (accessType === 'none') {
if (res.status !== 403) throw new Error(`Expected 403 for free tier, got ${res.status}`);
const data = await res.json();
if (!data.error || !String(data.error).toLowerCase().includes('document')) {
throw new Error('Expected document limit error message');
}
return;
}
const VALID_STATUSES = [200, 503];
if (!VALID_STATUSES.includes(res.status)) {
throw new Error(`Expected one of ${VALID_STATUSES.join('/')}, got ${res.status}`);
}
});
await test('POST /api/upload with OCR blocks free tier users', async () => {
const statusRes = await request('GET', '/api/payments/status');
const status = statusRes.data as Record<string, unknown>;
const accessType = status.accessType as string;
const formData = new FormData();
const blob = new Blob(['test content'], { type: 'text/plain' });
formData.append('document', blob, 'test.txt');
formData.append('useOcr', 'true');
const res = await fetch(`${API_URL}/api/upload`, {
method: 'POST',
headers: {
Authorization: `Bearer ${TOKEN}`,
},
body: formData,
});
if (accessType === 'none') {
if (res.status !== 403) throw new Error(`Expected 403 for free tier OCR, got ${res.status}`);
const data = await res.json();
if (!data.error || !String(data.error).toLowerCase().includes('ocr')) {
throw new Error('Expected OCR access error message');
}
return;
}
const VALID_STATUSES = [200, 400];
if (!VALID_STATUSES.includes(res.status)) {
throw new Error(`Expected one of ${VALID_STATUSES.join('/')}, got ${res.status}`);
}
});
console.log('\nPayments Refund Tests:');
await test('POST /api/payments/refund without token returns 401', async () => {
const res = await fetch(`${API_URL}/api/payments/refund`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ paymentIntentId: 'pi_test' }),
});
if (res.status !== 401) throw new Error(`Expected 401, got ${res.status}`);
});
await test('POST /api/payments/refund with non-admin returns 403 or 503', async () => {
const res = await fetch(`${API_URL}/api/payments/refund`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
body: JSON.stringify({ paymentIntentId: 'pi_test' }),
});
const VALID_STATUSES = [403, 503];
if (!VALID_STATUSES.includes(res.status)) {
throw new Error(`Expected one of ${VALID_STATUSES.join('/')}, got ${res.status}`);
}
});
console.log('\n=== Quiz Sharing Tests ===');
let shareTestQuizId: string | null = null;