Files
jiapu/tests/pc-endpoint-coverage.test.js
T
2026-07-11 11:03:47 +08:00

83 lines
5.0 KiB
JavaScript

const assert = require('assert');
const fs = require('fs');
const path = require('path');
const root = path.join(__dirname, '..');
const openApi = fs.readFileSync(path.join(root, 'genealogy-pc-openapi.yaml'), 'utf8');
const apiClient = fs.readFileSync(path.join(root, 'utils', 'ApiClient.js'), 'utf8');
const authPages = fs.readFileSync(path.join(root, 'public', 'js', 'auth-pages.js'), 'utf8');
const captchaPages = fs.readFileSync(path.join(root, 'public', 'js', 'captcha-pages.js'), 'utf8');
const profilePages = fs.readFileSync(path.join(root, 'public', 'js', 'profile-pages.js'), 'utf8');
const securityPages = fs.readFileSync(path.join(root, 'public', 'js', 'security-pages.js'), 'utf8');
const regionPages = fs.readFileSync(path.join(root, 'public', 'js', 'region-pages.js'), 'utf8');
const uploadPages = fs.readFileSync(path.join(root, 'public', 'js', 'upload-pages.js'), 'utf8');
const ENDPOINTS = {
'GET /captcha/require': { source: captchaPages, needle: 'api.captchaRequire', status: 'complete' },
'POST /captcha/challenge': { source: captchaPages, needle: "api.buildApiUrl('/captcha/challenge')", status: 'complete' },
'POST /captcha/verify': { source: captchaPages, needle: "api.buildApiUrl('/captcha/verify')", status: 'complete' },
'GET /auth/code': { status: 'blocked', reason: 'legacy captcha has no PC request field' },
'POST /genealogy/pc/auth/register': { source: authPages, needle: 'api.register', status: 'complete' },
'POST /genealogy/pc/auth/login': { source: authPages, needle: 'api.login', status: 'complete' },
'POST /genealogy/pc/auth/login/sms': { source: authPages, needle: 'api.loginBySms', status: 'complete' },
'POST /genealogy/pc/auth/sms/code': { source: authPages, needle: 'api.sendSmsCode', status: 'complete' },
'GET /genealogy/pc/auth/profile': { source: profilePages, needle: 'api.currentProfile', status: 'complete' },
'PUT /genealogy/pc/auth/profile': { source: profilePages, needle: 'api.updateProfile', status: 'complete' },
'PUT /genealogy/pc/auth/password': { source: securityPages, needle: 'api.changePassword', status: 'complete' },
'PUT /genealogy/pc/auth/password/reset': { source: authPages, needle: 'api.resetPassword', status: 'complete' },
'PUT /genealogy/pc/auth/phone': { status: 'blocked', reason: 'PC/H5 phone SMS scene is not documented' },
'POST /genealogy/pc/auth/account/deactivate': { source: securityPages, needle: 'api.deactivateAccount', status: 'complete' },
'DELETE /genealogy/pc/auth/logout': { source: securityPages, needle: 'api.logout', status: 'complete' },
'POST /genealogy/pc/files/upload': { source: uploadPages, needle: 'api.uploadFile', status: 'complete' },
'POST /genealogy/pc/files/resumable/init': { source: uploadPages, needle: 'api.initResumableUpload', status: 'complete' },
'POST /genealogy/pc/files/resumable/chunk': { source: uploadPages, needle: 'api.uploadChunk', status: 'complete' },
'POST /genealogy/pc/files/resumable/complete': { source: uploadPages, needle: 'api.completeResumableUpload', status: 'complete' },
'POST /genealogy/pc/files/reference': { status: 'blocked', reason: 'PC business table and ID contract is not documented' },
'DELETE /genealogy/pc/files/reference': { status: 'blocked', reason: 'PC business table and ID contract is not documented' },
'GET /genealogy/region/children': { source: regionPages, needle: 'api.regionChildren', status: 'complete' },
'GET /genealogy/region/path/{regionCode}': { source: regionPages, needle: 'api.regionPath', apiNeedle: '/genealogy/region/path/', status: 'complete' },
'GET /genealogy/region/search': { source: regionPages, needle: 'api.regionSearch', status: 'complete' },
'GET /genealogy/region/{regionCode}': { source: regionPages, needle: 'api.regionDetail', apiNeedle: '/genealogy/region/', status: 'complete' }
};
function getDocumentOperations(documentText) {
let currentPath = '';
const operations = [];
documentText.split(/\r?\n/).forEach((line) => {
const pathMatch = line.match(/^ (\/[^:]+):$/);
const methodMatch = line.match(/^ (get|post|put|delete):$/);
if (pathMatch) currentPath = pathMatch[1];
if (methodMatch && currentPath) operations.push(`${methodMatch[1].toUpperCase()} ${currentPath}`);
});
return operations;
}
function run() {
const operations = getDocumentOperations(openApi);
assert.strictEqual(operations.length, 25);
assert.deepStrictEqual(Object.keys(ENDPOINTS).sort(), operations.slice().sort());
operations.forEach((operation) => {
const descriptor = ENDPOINTS[operation];
const route = operation.slice(operation.indexOf(' ') + 1);
assert.match(apiClient, new RegExp((descriptor.apiNeedle || route).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
assert.ok(descriptor, `${operation} must have an owner`);
if (descriptor.status === 'blocked') {
assert.ok(descriptor.reason, `${operation} must name its backend block`);
return;
}
assert.ok(descriptor.source.includes(descriptor.needle), `${operation} must be used by its page module`);
});
console.log('pc-endpoint-coverage tests passed');
}
run();