Files
memind/scripts/verify-template-catalog-portal.mjs
T

133 lines
4.7 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* Local smoke test for Portal template catalog API (Memind 8081).
* Usage: node scripts/verify-template-catalog-portal.mjs
*/
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadH5Environment } from './load-env.mjs';
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const root = path.join(scriptDir, '..');
function loadEnvFile(filePath) {
if (!fs.existsSync(filePath)) return;
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const eq = trimmed.indexOf('=');
if (eq <= 0) continue;
const key = trimmed.slice(0, eq).trim();
let value = trimmed.slice(eq + 1).trim();
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
if (!(key in process.env)) process.env[key] = value;
}
}
loadH5Environment(scriptDir);
loadEnvFile(path.join(root, '../memind_adm/.env'));
const base = process.env.PORTAL_API_BASE ?? `http://127.0.0.1:${process.env.H5_PORT ?? 8081}`;
const username =
process.env.VERIFY_PORTAL_USERNAME?.trim() ||
process.env.H5_TEST_USERNAME?.trim() ||
process.env.MEMIND_E2E_USERNAME?.trim() ||
process.env.H5_ADMIN_USERNAME?.trim() ||
'admin';
const password =
process.env.VERIFY_PORTAL_PASSWORD?.trim() ||
process.env.H5_TEST_PASSWORD?.trim() ||
process.env.MEMIND_E2E_PASSWORD?.trim() ||
process.env.JOHN_PASSWORD?.trim() ||
process.env.VERIFY_PASSWORD?.trim() ||
process.env.H5_ADMIN_PASSWORD?.trim() ||
process.env.ADMIN_PASSWORD?.trim() ||
'';
async function request(method, urlPath, { body, cookie } = {}) {
const res = await fetch(`${base}${urlPath}`, {
method,
headers: {
...(body ? { 'Content-Type': 'application/json' } : {}),
...(cookie ? { Cookie: cookie } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const text = await res.text();
let json = null;
try {
json = text ? JSON.parse(text) : null;
} catch {
json = { raw: text.slice(0, 300) };
}
return { status: res.status, json, text, setCookie: res.headers.getSetCookie?.() ?? [] };
}
function cookieFromSetCookie(setCookie) {
return setCookie.map((c) => c.split(';')[0]).join('; ');
}
function assertOk(cond, msg) {
if (!cond) throw new Error(msg);
}
async function main() {
console.log(`==> Portal API base: ${base}`);
if (!password) {
console.error('缺少 Portal 登录密码(VERIFY_PORTAL_PASSWORD / H5_ADMIN_PASSWORD / memind_adm/.env)');
process.exit(1);
}
const login = await request('POST', '/auth/login', {
body: { username, password },
});
assertOk(login.status === 200, `登录失败 HTTP ${login.status}: ${JSON.stringify(login.json)}`);
const cookie = cookieFromSetCookie(login.setCookie);
assertOk(cookie, '登录未返回 session cookie');
console.log(`✓ Portal 登录 (${username})`);
const catalog = await request('GET', '/api/mindspace/v1/template-catalog', { cookie });
assertOk(catalog.status === 200, `catalog HTTP ${catalog.status}: ${JSON.stringify(catalog.json)}`);
const items = catalog.json?.data?.items ?? catalog.json?.items ?? [];
assertOk(Array.isArray(items), 'catalog items 应为数组');
assertOk(items.length >= 13, `应至少 13 个模板,实际 ${items.length}`);
const travel = items.find((item) => item.skillName === 'page-template-travel');
assertOk(travel, '缺少 page-template-travel');
console.log(
`✓ GET template-catalog (${items.length} 项,travel owned=${Boolean(travel.owned)} price=${travel.priceCents})`,
);
const preview = await request('GET', '/api/mindspace/v1/template-catalog/page-template-travel/preview', {
cookie,
});
assertOk(preview.status === 200, `preview HTTP ${preview.status}`);
assertOk(String(preview.text).includes('周末去哪玩'), '预览 HTML 应含示例文案');
console.log('✓ GET template preview HTML');
if (travel.owned) {
console.log('• travel 已拥有,跳过余额购买测试');
} else if (travel.priceCents > 0) {
const purchase = await request('POST', '/api/mindspace/v1/template-catalog/page-template-travel/purchase', {
cookie,
});
if (purchase.status === 402) {
console.log('• 余额不足 (402),purchase 路由正常');
} else {
assertOk(purchase.status === 200, `purchase HTTP ${purchase.status}: ${JSON.stringify(purchase.json)}`);
console.log('✓ POST balance purchase 成功');
}
}
console.log('\n全部 Portal template-catalog API 联调通过。');
}
main().catch((err) => {
console.error('\n联调失败:', err.message);
process.exit(1);
});