// 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", "recharge/package/list", "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{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/','/info/feedback/']; 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"); } if(!publicOnly)pages.push('/member/center/','/member/favorites/','/member/history/','/member/purchased/','/member/settings/','/info/deposit/','/info/deposit/vip/'); for(let offset=0;offset{ 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.startsWith('/member/settings/')?'member-settings':path.startsWith('/member/')?'member-center':path.startsWith('/info/deposit/')?'wallet-page':path==='/info/feedback/'?'id="feedback-form"':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 invalidLogin=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(invalidLogin.status,400); assert.equal((await invalidLogin.json()).code,400); console.log("PASS: proxy endpoint allowlist and browser login input validation");