Files
2026-10-27 17:39:27 +07:00

87 lines
5.8 KiB
JavaScript

// Read-only business smoke checks; POSTs only establish a guest or validate empty login input.
// Cookies stay in memory and are never printed or written to disk.
import assert from "node:assert/strict";
const base = process.env.PREVIEW_URL || "http://127.0.0.1:21021";
const publicOnly = process.env.SMOKE_PUBLIC_ONLY === "1";
const cookies = new Map();
const cookieHeader=()=>[...cookies].map(([key,value])=>`${key}=${value}`).join('; ');
async function request(path, body) {
const response = await fetch(`${base}/api/${path}`, {
method: body === undefined ? "GET" : "POST",
headers: {Cookie: cookieHeader(), ...(body === undefined ? {} : {"Content-Type":"application/json"})},
body: body === undefined ? undefined : JSON.stringify(body),
});
for (const item of response.headers.getSetCookie()) {
const [pair] = item.split(";"); const index = pair.indexOf("=");
cookies.set(pair.slice(0,index), pair.slice(index+1));
}
const envelope = await response.json();
assert.equal(response.status,200,`${path}: HTTP ${response.status}`);
assert.equal(envelope.code,200,`${path}: ${envelope.msg || envelope.tip}`);
return envelope.data;
}
const home = await request("playlet/home");
const response = await fetch(base);
const html = await response.text();
assert.equal(response.status,200);
assert.ok(!html.includes("data-must-watch-sort"),"首页筛选项应保持移除");
if (!publicOnly) {
const guest = await request("auth/guest",{});
assert.ok(guest.userId,"游客登录应返回用户 ID");
assert.equal(guest.token,undefined,"token 不应暴露给浏览器脚本");
assert.ok(cookies.has("drama_session"),"应通过 Cookie 保持会话");
console.log("PASS: HttpOnly guest session");
}
console.log("PASS: SSR homepage");
const checks = ["config/info", "config/footer/info", "navigation/header", "translation/category/list", "theme/list", "playlet/tag/options", "playlet/all/list?sortType=1&pageNum=1&pageSize=4", "playlet/hot/list?pageNum=1&pageSize=4", ...[1,2,3].map(rank=>`playlet/hot/rank/list?rankType=${rank}&pageNum=1&pageSize=4`), "playlet/topic/list?pageNum=1&pageSize=4", "applist/list?categoryId=0", "playlet/hot-like", ...(!publicOnly?["auth/getInfo", "user/center/data", "playlet/history/list?pageNum=1&pageSize=4", "playlet/collect/list?pageNum=1&pageSize=4&watchStatus=0", "playlet/bought/list?pageNum=1&pageSize=4", "coin/trans/list?page=1&pageSize=10&type=0"]:[])];
const dataByPath=new Map();
for(let offset=0;offset<checks.length;offset+=4)await Promise.all(checks.slice(offset,offset+4).map(async path=>{const data=await request(path);assert.ok(data,`${path}: missing data`);dataByPath.set(path.split('?')[0],data);console.log(`PASS: ${path.split("?")[0]}`);}));
const pages=['/shorts/','/shorts/page/2/','/rank/hot/','/rank/new/','/rank/follow/','/topics/','/apps/','/home-road/','/navigation/','/info/about-us/','/info/user-agreement/','/info/privacy-policy/','/info/help-center/','/info/2257/','/info/dmca/'];
const topic=dataByPath.get('playlet/topic/list')?.list?.[0];
if(topic){
const detail=await request(`playlet/topic/detail?id=${topic.id}&pageNum=1&pageSize=4`);
assert.equal(detail.id,topic.id);assert.equal(typeof detail.name,'string');assert.ok(Array.isArray(detail.list));
pages.push(`/topics/${topic.id}/`,`/theme/${topic.id}/`);
}
const tag=dataByPath.get('playlet/tag/options')?.list?.[0];
if(tag)pages.push(`/tag/${tag.id}/`);
const block=home.homeConfigData?.find(item=>item.status&&!item.moreUrl);
if(block)pages.push(`/config/${block.id}/`);
const first = home.homeBannerData?.[0] || home.homeConfigData?.find(block=>block.list?.length)?.list[0];
if (first) {
const search=await request("playlet/search?"+new URLSearchParams({keyword:first.playName||first.title,pageNum:"1",pageSize:"4"}));
assert.ok(Array.isArray(search.list));
pages.push('/search/'+encodeURIComponent(first.playName||first.title)+'/');
const suggestions=await request('playlet/search/suggest?'+new URLSearchParams({keyword:first.playName||first.title}));assert.ok(Array.isArray(suggestions.list));
if (!publicOnly) {
const detail=await request(`playlet/detail?id=${first.id}`);
assert.equal(detail.id,first.id);
const chapters=await request(`playlet/chapter/list?playletId=${first.id}`);
const related=await request(`playlet/guess-like/list?playletId=${first.id}&pageNum=1&pageSize=6`);assert.ok(Array.isArray(related.list));
pages.push(`/detail/${first.id}/`);
if (chapters.list?.length) {
const chapter=await request(`playlet/chapter/detail?playletId=${first.id}&chapterId=${chapters.list[0].id}`);
assert.equal(chapter.id,chapters.list[0].id);
assert.equal(typeof chapter.canWatch,"boolean");
pages.push(`/play/${first.id}/${chapter.id}/`);
}
console.log("PASS: drama detail and chapter permissions");
}
console.log("PASS: search");
}
for(let offset=0;offset<pages.length;offset+=3)await Promise.all(pages.slice(offset,offset+3).map(async path=>{
const response=await fetch(base+path,{headers:{Cookie:cookieHeader()},redirect:'manual'}),html=await response.text();
assert.equal(response.status,200,path);assert.equal(response.headers.get('location'),null,path);assert.ok(!html.includes('内容暂不可用,请稍后重试'),path);assert.ok(!html.includes('class="api-loading"'),path);
const marker=path==='/home-road/'?'return-home-directory':path.startsWith('/search/')?'data-search-results':'';
if(marker)assert.ok(html.includes(marker),path+' must contain the complete server-rendered page');
console.log(`PASS: page ${path}`);
}));
const rejected=await fetch(`${base}/api/not-allowed`);
assert.equal(rejected.status,404);
const removedLogin=await fetch(`${base}/api/auth/login`,{method:"POST",headers:{Origin:new URL(base).origin,"Sec-Fetch-Site":"same-origin","Content-Type":"application/json"},body:"{}"});
assert.equal(removedLogin.status,404);
console.log("PASS: proxy endpoint allowlist rejects removed account routes");