156 lines
5.8 KiB
JavaScript
156 lines
5.8 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
/**
|
|||
|
|
* 验证 john4 客户下单系统 Page Data 链路(insert + admin read)。
|
|||
|
|
*/
|
|||
|
|
import { loadH5Environment } from './load-env.mjs';
|
|||
|
|
import {
|
|||
|
|
createReporter,
|
|||
|
|
loginViaApi,
|
|||
|
|
resolvePortalBase,
|
|||
|
|
} from './scenario-test-lib.mjs';
|
|||
|
|
import path from 'node:path';
|
|||
|
|
import { fileURLToPath } from 'node:url';
|
|||
|
|
import { PUBLISH_ROOT_DIR } from '../user-publish.mjs';
|
|||
|
|
import fs from 'node:fs/promises';
|
|||
|
|
|
|||
|
|
const repoRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|||
|
|
const USER_ID = process.env.CUSTOMER_ORDER_USER_ID ?? '32035858-9a20-425b-89da-c118ef0779aa';
|
|||
|
|
const DATASET = 'customer_orders';
|
|||
|
|
const FORM_PAGE = 'customer-order-form.html';
|
|||
|
|
const ADMIN_PAGE = 'customer-order-admin.html';
|
|||
|
|
|
|||
|
|
loadH5Environment(import.meta.dirname);
|
|||
|
|
|
|||
|
|
async function findPageIdFromPolicy(publishKey) {
|
|||
|
|
const policyDir = path.join(repoRoot, PUBLISH_ROOT_DIR, publishKey, '.mindspace', 'page-data-policies');
|
|||
|
|
const entries = await fs.readdir(policyDir);
|
|||
|
|
for (const name of entries.filter((item) => item.endsWith('.json'))) {
|
|||
|
|
const raw = await fs.readFile(path.join(policyDir, name), 'utf8');
|
|||
|
|
const policy = JSON.parse(raw);
|
|||
|
|
if (policy?.datasets?.[DATASET]?.insert) {
|
|||
|
|
return { pageId: policy.pageId, fileName: name };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
const port = Number(process.env.H5_PORT ?? 8081);
|
|||
|
|
const baseUrl = resolvePortalBase(port);
|
|||
|
|
const reporter = createReporter();
|
|||
|
|
|
|||
|
|
console.log('==> 客户下单系统 Page Data 验证');
|
|||
|
|
console.log(` Portal: ${baseUrl}`);
|
|||
|
|
console.log(` 用户: ${USER_ID}\n`);
|
|||
|
|
|
|||
|
|
const auth = await loginViaApi(baseUrl, { username: 'john4', password: '888888' }, reporter);
|
|||
|
|
const publishKey = auth.user?.id ?? USER_ID;
|
|||
|
|
|
|||
|
|
const formUrl = `${baseUrl}/MindSpace/${publishKey}/public/${FORM_PAGE}`;
|
|||
|
|
const adminUrl = `${baseUrl}/MindSpace/${publishKey}/public/${ADMIN_PAGE}`;
|
|||
|
|
|
|||
|
|
for (const [label, url] of [['下单页', formUrl], ['后台页', adminUrl]]) {
|
|||
|
|
const res = await fetch(url, { headers: { Cookie: auth.cookie } });
|
|||
|
|
const html = await res.text();
|
|||
|
|
if (res.status !== 200) {
|
|||
|
|
reporter.fail(`${label} HTTP`, `${res.status}`);
|
|||
|
|
} else {
|
|||
|
|
reporter.pass(`${label} HTTP 200`, url);
|
|||
|
|
}
|
|||
|
|
if (!html.includes('page-data-client.js')) {
|
|||
|
|
reporter.fail(`${label} 脚本`, '缺少 page-data-client.js');
|
|||
|
|
} else {
|
|||
|
|
reporter.pass(`${label} Page Data 客户端`, '已引用');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const formMeta = await findPageIdFromPolicy(publishKey);
|
|||
|
|
if (!formMeta?.pageId) {
|
|||
|
|
reporter.fail('Page Data policy', '未找到 customer_orders insert policy');
|
|||
|
|
process.exit(reporter.summary());
|
|||
|
|
}
|
|||
|
|
reporter.pass('Page Data policy', `${formMeta.fileName} pageId=${formMeta.pageId}`);
|
|||
|
|
|
|||
|
|
const insertPayload = {
|
|||
|
|
customer_name: '测试客户',
|
|||
|
|
phone: '13800138000',
|
|||
|
|
product_name: '演示商品A',
|
|||
|
|
quantity: '2',
|
|||
|
|
address: '上海市浦东新区测试路 1 号',
|
|||
|
|
remark: '自动化验证',
|
|||
|
|
status: '待处理',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const insertRes = await fetch(
|
|||
|
|
`${baseUrl}/api/public/pages/${formMeta.pageId}/data/${DATASET}/rows`,
|
|||
|
|
{
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Content-Type': 'application/json', Cookie: auth.cookie },
|
|||
|
|
body: JSON.stringify(insertPayload),
|
|||
|
|
},
|
|||
|
|
);
|
|||
|
|
const insertBody = await insertRes.json().catch(() => ({}));
|
|||
|
|
if (!insertRes.ok) {
|
|||
|
|
reporter.fail('下单 insert', `${insertRes.status} ${JSON.stringify(insertBody)}`);
|
|||
|
|
} else {
|
|||
|
|
reporter.pass('下单 insert', `row id=${insertBody?.data?.id ?? insertBody?.id ?? 'ok'}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const adminMeta = await (async () => {
|
|||
|
|
const policyDir = path.join(repoRoot, PUBLISH_ROOT_DIR, publishKey, '.mindspace', 'page-data-policies');
|
|||
|
|
const entries = await fs.readdir(policyDir);
|
|||
|
|
for (const name of entries.filter((item) => item.endsWith('.json'))) {
|
|||
|
|
const policy = JSON.parse(await fs.readFile(path.join(policyDir, name), 'utf8'));
|
|||
|
|
if (policy?.datasets?.[DATASET]?.read) return policy.pageId;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
})();
|
|||
|
|
|
|||
|
|
if (!adminMeta) {
|
|||
|
|
reporter.fail('后台 policy', '未找到 read policy');
|
|||
|
|
} else {
|
|||
|
|
const tokenRes = await fetch(`${baseUrl}/api/public/pages/${adminMeta}/data-auth`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Content-Type': 'application/json', Cookie: auth.cookie },
|
|||
|
|
body: JSON.stringify({ password: '88888888' }),
|
|||
|
|
});
|
|||
|
|
const tokenBody = await tokenRes.json().catch(() => ({}));
|
|||
|
|
const token = tokenBody?.data?.token ?? tokenBody?.token;
|
|||
|
|
if (!tokenRes.ok || !token) {
|
|||
|
|
reporter.fail('后台口令认证', `${tokenRes.status}`);
|
|||
|
|
} else {
|
|||
|
|
const listRes = await fetch(
|
|||
|
|
`${baseUrl}/api/public/pages/${adminMeta}/data/${DATASET}?limit=20`,
|
|||
|
|
{ headers: { 'x-page-data-token': token, Cookie: auth.cookie } },
|
|||
|
|
);
|
|||
|
|
const listBody = await listRes.json().catch(() => ({}));
|
|||
|
|
const rows = listBody?.data?.rows ?? listBody?.rows ?? [];
|
|||
|
|
const hit = rows.some((row) => row.customer_name === insertPayload.customer_name && row.product_name === insertPayload.product_name);
|
|||
|
|
if (!listRes.ok || !hit) {
|
|||
|
|
reporter.fail('后台读订单', `rows=${rows.length}, 未找到测试订单`);
|
|||
|
|
} else {
|
|||
|
|
reporter.pass('后台读订单', `共 ${rows.length} 条,含测试订单`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const sqlitePath = path.join(repoRoot, PUBLISH_ROOT_DIR, publishKey, '.mindspace', 'private-data.sqlite');
|
|||
|
|
try {
|
|||
|
|
await fs.stat(sqlitePath);
|
|||
|
|
reporter.pass('用户数据空间', 'private-data.sqlite 存在');
|
|||
|
|
} catch {
|
|||
|
|
reporter.pass('用户数据空间', 'PostgreSQL 模式(无本地 sqlite 文件)');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('\n--- 访问入口 ---');
|
|||
|
|
console.log(`下单页: ${formUrl}`);
|
|||
|
|
console.log(`后台页: ${adminUrl} (口令 88888888)`);
|
|||
|
|
|
|||
|
|
process.exit(reporter.summary());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main().catch((err) => {
|
|||
|
|
console.error(err instanceof Error ? err.stack ?? err.message : err);
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|