PHP Classes

File: tests/playwright/api-smoke.test.js

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   tests/playwright/api-smoke.test.js   Download  
File: tests/playwright/api-smoke.test.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 5,940 bytes
 

Contents

Class file image Download
/** * API smoke tests: verify key endpoints return expected structure. * All requests use the saved auth session. */ const { test, expect } = require('@playwright/test'); const path = require('path'); test.use({ storageState: path.join(__dirname, '.auth-state.json') }); // Unauthenticated endpoints const PUBLIC_API = [ '/api/verify', '/api/i18n/catalog?ns=common&locale=en', '/api/i18n/catalog?ns=errors&locale=en', '/api/i18n/catalog?ns=common&locale=es', '/api/i18n/catalog?ns=errors&locale=es', ]; // Auth-required GET endpoints (expect 200 + JSON) const AUTH_API_GET = [ '/api/messages/netmail', '/api/messages/netmail/stats', '/api/messages/echomail', '/api/messages/echomail/stats', '/api/echoareas', '/api/address-book', '/api/nodelist/search?q=test', '/api/polls', '/api/files/areas', '/api/users/online', '/api/admin/users', '/api/admin/stats', '/api/admin/economy', '/api/admin/chat-rooms', '/api/admin/polls', ]; test.describe('Public API endpoints', () => { for (const endpoint of PUBLIC_API) { test(`GET ${endpoint} returns 200 JSON`, async ({ request }) => { const response = await request.get(endpoint); expect(response.status(), `${endpoint} status`).toBe(200); const ct = response.headers()['content-type'] || ''; expect(ct, `${endpoint} content-type`).toContain('application/json'); }); } }); /** * The catalog API returns: { success, locale, default_locale, catalogs: { <ns>: { key: value, ... } } } */ function extractCatalog(json, ns) { return (json.catalogs && json.catalogs[ns]) ? json.catalogs[ns] : {}; } test.describe('i18n catalog structure', () => { test('en/common catalog has keys and no raw PHP values', async ({ request }) => { const response = await request.get('/api/i18n/catalog?ns=common&locale=en'); expect(response.ok()).toBe(true); const json = await response.json(); expect(json.success).toBe(true); const catalog = extractCatalog(json, 'common'); const keys = Object.keys(catalog); expect(keys.length).toBeGreaterThan(50); // Spot-check known keys expect(catalog['ui.common.loading']).toBeTruthy(); expect(catalog['ui.common.error']).toBeTruthy(); }); test('es/common catalog has same keys as en', async ({ request }) => { const [enResp, esResp] = await Promise.all([ request.get('/api/i18n/catalog?ns=common&locale=en'), request.get('/api/i18n/catalog?ns=common&locale=es'), ]); const en = extractCatalog(await enResp.json(), 'common'); const es = extractCatalog(await esResp.json(), 'common'); const enKeys = Object.keys(en).sort(); const esKeys = Object.keys(es).sort(); const missingInEs = enKeys.filter(k => !(k in es)); const missingInEn = esKeys.filter(k => !(k in en)); expect(missingInEs, `Keys in en but missing in es: ${missingInEs.join(', ')}`).toHaveLength(0); expect(missingInEn, `Keys in es but missing in en: ${missingInEn.join(', ')}`).toHaveLength(0); }); test('es/errors catalog has same keys as en/errors', async ({ request }) => { const [enResp, esResp] = await Promise.all([ request.get('/api/i18n/catalog?ns=errors&locale=en'), request.get('/api/i18n/catalog?ns=errors&locale=es'), ]); const en = extractCatalog(await enResp.json(), 'errors'); const es = extractCatalog(await esResp.json(), 'errors'); const enKeys = Object.keys(en).sort(); const esKeys = Object.keys(es).sort(); const missingInEs = enKeys.filter(k => !(k in es)); const missingInEn = esKeys.filter(k => !(k in en)); expect(missingInEs, `Error keys in en but missing in es: ${missingInEs.join(', ')}`).toHaveLength(0); expect(missingInEn, `Error keys in es but missing in en: ${missingInEn.join(', ')}`).toHaveLength(0); }); }); test.describe('Authenticated API endpoints', () => { for (const endpoint of AUTH_API_GET) { test(`GET ${endpoint} returns JSON (not a redirect or error page)`, async ({ request }) => { const response = await request.get(endpoint); // Allow 200 or 404 (feature may be disabled), but not 302 (not logged in) or 500 expect( [200, 404].includes(response.status()), `${endpoint} returned ${response.status()}` ).toBe(true); if (response.status() === 200) { const ct = response.headers()['content-type'] || ''; expect(ct, `${endpoint} should return JSON`).toContain('application/json'); } }); } }); test.describe('Error response structure', () => { test('unauthenticated API requests return error_code', async ({ request }) => { // Make a request without auth to an auth-required endpoint const response = await request.get('/api/messages/netmail', { headers: { 'Cookie': '' }, }); if (response.status() === 401) { const json = await response.json(); expect(json.error_code, 'error_code should be present').toBeTruthy(); expect(json.error_code.startsWith('errors.'), 'error_code should use errors.* namespace').toBe(true); } // If server returns 302 redirect instead of 401 JSON, that's also acceptable }); test('login with missing fields returns error_code', async ({ request }) => { const response = await request.post('/api/auth/login', { data: { username: '', password: '' }, }); expect(response.status()).toBe(400); const json = await response.json(); expect(json.error_code).toBeTruthy(); expect(json.error_code.startsWith('errors.')).toBe(true); }); });