57 lines
4.1 KiB
JavaScript
57 lines
4.1 KiB
JavaScript
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFile} from 'node:fs/promises';
|
|
import ts from 'typescript';
|
|
|
|
const source=await readFile(new URL('../src/app/robots.ts',import.meta.url),'utf8');
|
|
const originUrl='data:text/javascript;base64,'+Buffer.from('export let calls=0;let origin="";export function setOrigin(value){origin=value;calls=0;}export async function getSeoOrigin(){calls++;return origin;}').toString('base64');
|
|
const originStub=await import(originUrl);
|
|
const code=ts.transpileModule(source,{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.ESNext}}).outputText.replace("'@/lib/seo-server'",JSON.stringify(originUrl));
|
|
const {default:robots}=await import('data:text/javascript;base64,'+Buffer.from(code).toString('base64'));
|
|
|
|
async function policy(environment,nodeEnvironment='production',origin='https://permanent.drama.test') {
|
|
const previous={APP_ENV:process.env.APP_ENV,NODE_ENV:process.env.NODE_ENV};
|
|
try{
|
|
if(environment===undefined)delete process.env.APP_ENV;else process.env.APP_ENV=environment;
|
|
process.env.NODE_ENV=nodeEnvironment;
|
|
originStub.setOrigin(origin);
|
|
return await robots();
|
|
}finally{
|
|
for(const [key,value] of Object.entries(previous))if(value===undefined)delete process.env[key];else process.env[key]=value;
|
|
}
|
|
}
|
|
|
|
// These rules contain literal prefixes; use the longest matching prefix, with Allow winning ties.
|
|
function crawlable(document,path) {
|
|
const groups=Array.isArray(document.rules)?document.rules:[document.rules];
|
|
const rules=groups.filter(group=>group.userAgent==='*').flatMap(group=>['allow','disallow'].flatMap(type=>(Array.isArray(group[type])?group[type]:[group[type]]).filter(Boolean).map(prefix=>({prefix,allow:type==='allow'}))));
|
|
return rules.filter(rule=>path.startsWith(rule.prefix)).sort((a,b)=>b.prefix.length-a.prefix.length||Number(b.allow)-Number(a.allow))[0]?.allow??true;
|
|
}
|
|
|
|
test('production permits public pages, valid pagination and resources needed to render or play them',async()=>{
|
|
const document=await policy('production');
|
|
for(const path of ['/','/shorts/','/shorts/page/2/','/rank/new/','/topics/urban/','/tag/urban/','/config/editors-choice/','/detail/city-story/','/play/city-story/90001/','/info/about-us/','/_next/static/chunks/site.js','/_next/static/css/site.css','/scripts/site-runtime.js','/assets/poster.webp','/h5/m3u8/demo.m3u8','/enkey?token=test','/sitemap.xml'])assert.equal(crawlable(document,path),true,path);
|
|
for(const path of ['/api/app/playlet/home','/api/app/auth/guest','/healthz','/healthz/'])assert.equal(crawlable(document,path),false,path);
|
|
});
|
|
|
|
test('noindex pages and duplicate variants remain crawlable so their head directives are visible',async()=>{
|
|
const document=await policy('production');
|
|
for(const path of ['/search/','/search/都市/','/search/都市/page/2/','/member/center/','/member/favorites/','/member/history/','/member/purchased/','/member/settings/','/info/deposit/','/info/deposit/vip/','/info/settings/','/info/user-center/','/info/feedback/','/navigation/','/apps/','/home-road/','/detail/city-story/page/2/','/shorts/?sort=2','/play/city-story/90001/?commentSort=1'])assert.equal(crawlable(document,path),true,path);
|
|
assert.equal(document.sitemap,'https://permanent.drama.test/sitemap.xml');
|
|
});
|
|
|
|
test('development and test are closed to crawling while the standalone production default stays open',async()=>{
|
|
for(const environment of ['development','test']){
|
|
const document=await policy(environment);
|
|
for(const path of ['/','/shorts/','/detail/city-story/','/_next/static/site.js'])assert.equal(crawlable(document,path),false,environment+' '+path);
|
|
assert.equal(document.sitemap,undefined);assert.equal(originStub.calls,0);
|
|
}
|
|
assert.equal(crawlable(await policy(undefined,'development'),'/'),false);
|
|
assert.equal(crawlable(await policy(undefined,'production'),'/'),true);
|
|
});
|
|
|
|
test('missing site configuration omits only the Sitemap directive and leaves production crawl rules available',async()=>{
|
|
const document=await policy('production','production','');
|
|
assert.equal(document.sitemap,undefined);assert.equal(crawlable(document,'/shorts/'),true);
|
|
});
|