assistant/tools/learning/test-platform-policy.mjs

297 lines
23 KiB
JavaScript

import assert from 'node:assert/strict';
import { beginSearchRequestPolicy, beginNoteOpenRequestPolicy, beginReadonlyRequestPolicy, endPlatformRequestPolicy, matchPlatformRequest, SEARCH_POLICY_VERSION, NOTE_POLICY_VERSION, READONLY_POLICY_VERSION, SEARCH_SCROLL_POLICY_VERSION } from './platform-policy.mjs';
const official = 'https://www.xiaohongshu.com';
const observed = { kind: 'fill', tag: 'input', unique: true, search_input: true, sensitive: false };
const actual = { tag: 'input', search_input: true, sensitive: false, visible: true, in_viewport: true, unobscured: true };
const action = { sessionOrigin: official, pageUrl: `${official}/explore`, kind: 'fill', observed, actual, matchCount: 1 };
const policy = beginSearchRequestPolicy(action);
assert.ok(policy);
const request = { policy, automating: true, sessionOrigin: official, pageUrl: `${official}/search_result_ai?keyword=fixture`, activeMainFrame: true,
method: 'POST', resourceType: 'xhr', url: 'https://so.xiaohongshu.com/api/sns/web/v2/search/notes' };
let assertions = 1;
function check(value, expected = null) { assert.deepEqual(value, expected); assertions += 1; }
for (const [rule, url, resourceType = 'xhr'] of [
['collect', 'https://t2.xiaohongshu.com/api/v2/collect'],
['search_history', 'https://so.xiaohongshu.com/api/sns/web/search/history/sync'],
['search_notes', 'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'],
['search_onebox', 'https://edith.xiaohongshu.com/api/sns/web/v1/search/onebox'],
['search_dqa', 'https://so.xiaohongshu.com/api/sns/web/v1/dqa/instant'],
['apm_data', 'https://apm-fe.xiaohongshu.com/api/data', 'fetch'],
['apm_data_xhr', 'https://apm-fe.xiaohongshu.com/api/data', 'xhr'],
]) check(matchPlatformRequest({ ...request, url, resourceType }), { policy_version: SEARCH_POLICY_VERSION, policy_rule: rule });
const enter = beginSearchRequestPolicy({ ...action, kind: 'press', key: 'Enter' });
check(matchPlatformRequest({ ...request, policy: enter }), { policy_version: SEARCH_POLICY_VERSION, policy_rule: 'search_notes' });
for (const changed of [
{sessionOrigin:'http://127.0.0.1'}, {sessionOrigin:'https://xiaohongshu.com'}, {pageUrl:'https://www.xiaohongshu.com.evil.test/explore'},
{pageUrl:'https://user:password@www.xiaohongshu.com/explore'}, {pageUrl:'http://www.xiaohongshu.com/explore'}, {pageUrl:'invalid'},
{kind:'click'}, {kind:'read'}, {kind:'extract'}, {kind:'wait'}, {kind:'scroll'}, {kind:'press',key:'Tab'},
{matchCount:0}, {matchCount:2}, {observed:{...observed,unique:false}}, {observed:{...observed,search_input:false}},
{observed:{...observed,sensitive:true}}, {observed:{...observed,tag:'button'}}, {observed:null},
{actual:{...actual,sensitive:true}}, {actual:{...actual,search_input:false}}, {actual:{...actual,visible:false}},
{actual:{...actual,in_viewport:false}}, {actual:{...actual,unobscured:false}}, {actual:null},
]) check(beginSearchRequestPolicy({ ...action, ...changed }));
for (const changed of [
{policy:null}, {policy:{version:SEARCH_POLICY_VERSION,expiresAt:Date.now()+15000}}, {automating:false}, {activeMainFrame:false},
{sessionOrigin:'https://xiaohongshu.com'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:password@www.xiaohongshu.com/'},
{method:'GET'}, {method:'PUT'}, {method:'DELETE'}, {resourceType:'fetch'}, {resourceType:'document'}, {resourceType:'other'},
{url:'https://so.xiaohongshu.com.evil.test/api/sns/web/v2/search/notes'}, {url:'http://so.xiaohongshu.com/api/sns/web/v2/search/notes'},
{url:'https://user:password@so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://so.xiaohongshu.com:8443/api/sns/web/v2/search/notes'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/'}, {url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/delete'},
{url:'https://so.xiaohongshu.com/api/sns/web/v1/search/notes'}, {url:'https://edith.xiaohongshu.com/api/sns/web/v2/search/notes'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/comment/post'}, {url:'https://apm.xiaohongshu.com/api/data'}, {url:'invalid'},
{url:'https://apm-fe.xiaohongshu.com/api/data/',resourceType:'xhr'},
{url:'https://apm-fe.xiaohongshu.com.evil.test/api/data',resourceType:'xhr'},
{url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr',method:'GET'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
]) check(matchPlatformRequest({ ...request, ...changed }));
const noteHref = `${official}/search_result/${'a'.repeat(24)}?xsec_token=FIXTURE-SECRET`;
const noteObserved = { kind:'click', tag:'a', unique:true, sensitive:false };
const noteActual = { tag:'a', sensitive:false, visible:true, in_viewport:true, unobscured:true, href:noteHref };
const noteAction = { sessionOrigin:official, pageUrl:`${official}/search_result_ai?keyword=fixture`, kind:'click',
observed:noteObserved, actual:noteActual, matchCount:1, href:noteHref };
const notePolicy = beginNoteOpenRequestPolicy(noteAction);
assert.ok(notePolicy); assertions += 1;
const noteRequest = { ...request, policy:notePolicy, url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed' };
for (const [rule, url, resourceType = 'xhr'] of [
['collect','https://t2.xiaohongshu.com/api/v2/collect'],
['note_share_code','https://edith.xiaohongshu.com/api/sns/web/share/code'],
['note_widgets','https://edith.xiaohongshu.com/api/sns/web/v2/widgets'],
['note_feed','https://edith.xiaohongshu.com/api/sns/web/v1/feed'],
['note_seo','https://edith.xiaohongshu.com/api/sns/web/worldcup/note/seo'],
['note_metrics','https://edith.xiaohongshu.com/api/sns/web/v1/note/metrics_report'],
['note_history_report','https://edith.xiaohongshu.com/api/sns/v1/history/report_web'],
['apm_data','https://apm-fe.xiaohongshu.com/api/data','fetch'],
]) check(matchPlatformRequest({ ...noteRequest, url, resourceType }), { policy_version:NOTE_POLICY_VERSION, policy_rule:rule });
const targetedCollectionPolicy = beginNoteOpenRequestPolicy({...noteAction,observed:{...noteObserved,unique:false},targetResolvedUnique:true});
check(matchPlatformRequest({...noteRequest,policy:targetedCollectionPolicy}), {policy_version:NOTE_POLICY_VERSION,policy_rule:'note_feed'});
check(beginNoteOpenRequestPolicy({...noteAction,observed:{...noteObserved,unique:false},targetResolvedUnique:true,matchCount:2}));
check(matchPlatformRequest({...request,url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'}));
check(matchPlatformRequest({...noteRequest,url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web',resourceType:'fetch'}));
const exploreHref = `${official}/explore/${'b'.repeat(24)}`;
const explorePolicy = beginNoteOpenRequestPolicy({ ...noteAction, href:exploreHref, actual:{...noteActual,href:exploreHref} });
check(matchPlatformRequest({...noteRequest,policy:explorePolicy}), { policy_version:NOTE_POLICY_VERSION,policy_rule:'note_feed' });
for (const changed of [
{kind:'fill'}, {kind:'press'}, {kind:'read'}, {kind:'extract'}, {kind:'scroll'}, {kind:'wait'},
{sessionOrigin:'http://127.0.0.1'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:pass@www.xiaohongshu.com/'},
{matchCount:0}, {matchCount:2}, {observed:{...noteObserved,unique:false}}, {observed:{...noteObserved,sensitive:true}},
{observed:{...noteObserved,tag:'button'}}, {observed:{...noteObserved,kind:'read'}}, {observed:null},
{actual:{...noteActual,tag:'button'}}, {actual:{...noteActual,sensitive:true}}, {actual:{...noteActual,visible:false}},
{actual:{...noteActual,in_viewport:false}}, {actual:{...noteActual,unobscured:false}}, {actual:{...noteActual,href:exploreHref}},
]) check(beginNoteOpenRequestPolicy({...noteAction,...changed}));
for (const href of [
`${official}/explore`, `${official}/explore/${'b'.repeat(23)}`, `${official}/explore/${'g'.repeat(24)}`,
`${official}/Explore/${'b'.repeat(24)}`, `${official}/explore/${'b'.repeat(24)}/`, `${official}/explore/${'b'.repeat(24)}/delete`,
`${official}/user/profile/${'b'.repeat(24)}`, `https://www.xiaohongshu.com.evil.test/explore/${'b'.repeat(24)}`,
`https://user:pass@www.xiaohongshu.com/explore/${'b'.repeat(24)}`, `javascript:alert(1)`,
]) check(beginNoteOpenRequestPolicy({...noteAction,href,actual:{...noteActual,href}}));
for (const changed of [
{automating:false}, {activeMainFrame:false}, {pageUrl:'https://example.com/'}, {sessionOrigin:'https://example.com'},
{method:'GET'}, {method:'DELETE'}, {resourceType:'fetch'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed/delete'}, {url:'https://so.xiaohongshu.com/api/sns/web/v1/feed'},
{url:'https://edith.xiaohongshu.com.evil.test/api/sns/web/v1/feed'},
{url:'https://user:pass@edith.xiaohongshu.com/api/sns/web/v1/feed'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
]) check(matchPlatformRequest({...noteRequest,...changed}));
const expired = beginSearchRequestPolicy({ ...action, now:Date.now()-16000 });
check(matchPlatformRequest({ ...request, policy:expired }));
const expiredNote = beginNoteOpenRequestPolicy({...noteAction,now:Date.now()-16000});
check(matchPlatformRequest({...noteRequest,policy:expiredNote}));
endPlatformRequestPolicy(policy);
endPlatformRequestPolicy(enter);
endPlatformRequestPolicy(notePolicy);
endPlatformRequestPolicy(explorePolicy);
endPlatformRequestPolicy(targetedCollectionPolicy);
check(matchPlatformRequest(request));
check(matchPlatformRequest({ ...request, policy:enter }));
check(matchPlatformRequest(noteRequest));
check(matchPlatformRequest({...noteRequest,policy:explorePolicy}));
const readRoot = {tag:'div',readonly_root:true,sensitive:false,forbidden:false};
const readonlyAction = {sessionOrigin:official,pageUrl:`${official}/explore/${'a'.repeat(24)}`,kind:'scroll',selector:'#comments',selectorObserved:true,actualRoots:[readRoot]};
for (const kind of ['read','extract','scroll','wait']) {
const cap = beginReadonlyRequestPolicy({...readonlyAction,kind});
const readRequest = {...request,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'};
check(matchPlatformRequest(readRequest),{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
check(matchPlatformRequest({...readRequest,url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'fetch'}),{policy_version:READONLY_POLICY_VERSION,policy_rule:'apm_data'});
for (const changed of [
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes'}, {url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
{url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'}, {url:'https://so.xiaohongshu.com/api/sns/web/search/history/sync'},
{url:'https://t2.xiaohongshu.com/api/v2/collect/post'}, {method:'PUT'}, {resourceType:'fetch'}, {activeMainFrame:false}, {automating:false},
{pageUrl:'https://example.com/'}, {url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
]) check(matchPlatformRequest({...readRequest,...changed}));
endPlatformRequestPolicy(cap);
check(matchPlatformRequest(readRequest));
}
for (const changed of [
{kind:'click'}, {kind:'fill'}, {kind:'press'}, {selectorObserved:false}, {selector:''}, {selector:'body'},
{sessionOrigin:'http://127.0.0.1'}, {pageUrl:'https://example.com/'}, {pageUrl:'https://user:pass@www.xiaohongshu.com/'},
{actualRoots:[]}, {actualRoots:null}, {actualRoots:[{...readRoot,readonly_root:false}]},
{actualRoots:[{...readRoot,sensitive:true}]}, {actualRoots:[{...readRoot,forbidden:true}]},
...['input','textarea','select','button','form','script','iframe','body'].map(tag=>({actualRoots:[{...readRoot,tag}]})),
]) check(beginReadonlyRequestPolicy({...readonlyAction,...changed}));
for (const kind of ['scroll','wait']) {
const cap = beginReadonlyRequestPolicy({...readonlyAction,kind,selector:'body',selectorObserved:false,actualRoots:[{...readRoot,tag:'body'}]});
check(matchPlatformRequest({...request,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'}),{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
endPlatformRequestPolicy(cap);
}
for (const kind of ['read','extract']) check(beginReadonlyRequestPolicy({...readonlyAction,kind,selector:'body',actualRoots:[{...readRoot,tag:'body'}]}));
const expiredRead = beginReadonlyRequestPolicy({...readonlyAction,now:Date.now()-16000});
check(matchPlatformRequest({...request,policy:expiredRead,url:'https://t2.xiaohongshu.com/api/v2/collect'}));
// A seek within a known search-results root receives only the pagination rule,
// bound to the exact page and the finite action window. These tests make no
// browser, API, model or network calls.
check(SEARCH_SCROLL_POLICY_VERSION, 'xhs-search-scroll-experimental-v1');
const scrollNow = 10_000;
const scrollPage = `${official}/search_result_ai?keyword=fixture&source=web`;
const scrollObserved = {kind:'read',tag:'div',unique:true,sensitive:false};
const scrollRoot = {...readRoot,visible:true,in_viewport:true};
const untilTarget = {selector:'section.note-item a.title',field:'text',value:'准备开始装修了,主打一个听劝!'};
const scrollAction = {sessionOrigin:official,pageUrl:scrollPage,kind:'scroll',selector:'#search-results',selectorObserved:true,
observed:scrollObserved,actualRoots:[scrollRoot],scrollScope:'viewport',untilTarget,now:scrollNow};
const scrollPolicy = beginReadonlyRequestPolicy(scrollAction);
check(scrollPolicy, {version:SEARCH_SCROLL_POLICY_VERSION,scope:'search_scroll',expiresAt:25_000});
check(Object.isFrozen(scrollPolicy), true);
check(Object.keys(scrollPolicy).sort(), ['expiresAt','scope','version']);
const scrollRequest = {policy:scrollPolicy,automating:true,sessionOrigin:official,pageUrl:scrollPage,activeMainFrame:true,
method:'POST',resourceType:'xhr',url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes',now:scrollNow};
for (const [pagePath,tag] of [['/search_result','section'],['/search_result_ai','div']]) {
const pageUrl = `${official}${pagePath}?keyword=fixture&source=web`;
const cap = beginReadonlyRequestPolicy({...scrollAction,pageUrl,observed:{...scrollObserved,tag},actualRoots:[{...scrollRoot,tag}]});
check(cap?.scope, 'search_scroll');
for (const [rule,url,resourceType] of [
['collect','https://t2.xiaohongshu.com/api/v2/collect','xhr'],
['apm_data','https://apm-fe.xiaohongshu.com/api/data','fetch'],
['search_notes','https://so.xiaohongshu.com/api/sns/web/v2/search/notes','xhr'],
]) check(matchPlatformRequest({...scrollRequest,policy:cap,pageUrl,url,resourceType}),
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:rule});
endPlatformRequestPolicy(cap);
check(matchPlatformRequest({...scrollRequest,policy:cap,pageUrl}));
}
const boundedTextPolicy = beginReadonlyRequestPolicy({...scrollAction,untilTarget:{...untilTarget,value:'文'.repeat(2000)}});
check(boundedTextPolicy?.scope, 'search_scroll');
endPlatformRequestPolicy(boundedTextPolicy);
// Invalid new-scope intent can legitimately retain the old readonly UI policy.
// The invariant is that it cannot authorize search pagination.
function noSearchScroll(changed, {fallback = false} = {}) {
const cap = beginReadonlyRequestPolicy({...scrollAction,...changed});
check(cap?.scope === 'search_scroll', false);
check(matchPlatformRequest({...scrollRequest,policy:cap}));
if (fallback) {
check(cap?.scope, 'readonly_ui');
check(matchPlatformRequest({...scrollRequest,policy:cap,url:'https://t2.xiaohongshu.com/api/v2/collect'}),
{policy_version:READONLY_POLICY_VERSION,policy_rule:'collect'});
}
endPlatformRequestPolicy(cap);
}
for (const changed of [
...['read','extract','wait'].map(kind=>({kind})),
{scrollScope:undefined}, {scrollScope:'container'}, {scrollScope:'Viewport'},
{observed:undefined}, {observed:null}, {observed:{...scrollObserved,kind:'scroll'}},
{observed:{...scrollObserved,kind:'click'}}, {observed:{...scrollObserved,unique:false}},
{observed:{...scrollObserved,unique:undefined}}, {observed:{...scrollObserved,sensitive:true}},
{observed:{...scrollObserved,sensitive:undefined}}, {observed:{...scrollObserved,tag:undefined}},
{observed:{...scrollObserved,tag:''}}, {observed:{...scrollObserved,tag:'DIV'}},
{observed:{...scrollObserved,tag:'section'}},
{actualRoots:[{...scrollRoot,visible:false}]}, {actualRoots:[{...scrollRoot,visible:undefined}]},
{actualRoots:[{...scrollRoot,in_viewport:false}]}, {actualRoots:[{...scrollRoot,in_viewport:undefined}]},
{actualRoots:[scrollRoot,{...scrollRoot}]},
{actualRoots:[{...scrollRoot,tag:'section'}]},
{observed:{...scrollObserved,tag:'a'},actualRoots:[{...scrollRoot,tag:'a'}]},
{untilTarget:undefined}, {untilTarget:null}, {untilTarget:[]}, {untilTarget:'title'},
{untilTarget:{...untilTarget,field:'href'}}, {untilTarget:{...untilTarget,field:'attribute'}},
{untilTarget:{...untilTarget,field:undefined}}, {untilTarget:{...untilTarget,value:''}},
{untilTarget:{...untilTarget,value:' \n\t '}}, {untilTarget:{...untilTarget,value:undefined}},
{untilTarget:{...untilTarget,value:42}}, {untilTarget:{...untilTarget,value:'文'.repeat(2001)}},
{untilTarget:{selector:untilTarget.selector,field:'text',parameter:'note_title'}},
{untilTarget:{...untilTarget,parameter:'note_title'}}, {untilTarget:{...untilTarget,attribute:'title'}},
{untilTarget:{...untilTarget,unexpected:true}},
...['','body','html',':root','body .note','html > section','section, body','xpath=//a','text=title',
'role=link','section >> a','a:has-text("title")','javascript:alert(1)'].map(selector=>({untilTarget:{...untilTarget,selector}})),
...['html',':root','body .note','section, body','xpath=//section','text=results','css=#results',
'#results >> section','section:has-text("results")','javascript:alert(1)'].map(selector=>({selector})),
...['/explore','/explore/'+ 'a'.repeat(24),'/search_result/','/search_result_ai/',
'/search_result/'+ 'a'.repeat(24),'/search_result_ai/more','/Search_result','/user/profile',
'/search_result_other'].map(path=>({pageUrl:`${official}${path}?keyword=fixture`})),
]) noSearchScroll(changed, {fallback:true});
for (const changed of [
...['click','fill','press'].map(kind=>({kind})),
{sessionOrigin:'http://127.0.0.1'}, {sessionOrigin:'https://xiaohongshu.com'},
{sessionOrigin:'https://www.xiaohongshu.com.evil.test'},
{pageUrl:'http://www.xiaohongshu.com/search_result?keyword=fixture'},
{pageUrl:'https://www.xiaohongshu.com.evil.test/search_result?keyword=fixture'},
{pageUrl:'https://user:password@www.xiaohongshu.com/search_result?keyword=fixture'},
{pageUrl:'https://www.xiaohongshu.com:8443/search_result?keyword=fixture'}, {pageUrl:'invalid'},
{selectorObserved:false}, {selectorObserved:undefined}, {selector:''}, {selector:null}, {selector:'x'.repeat(1001)},
{actualRoots:[]}, {actualRoots:null}, {actualRoots:[null]},
{actualRoots:[{...scrollRoot,readonly_root:false}]}, {actualRoots:[{...scrollRoot,sensitive:true}]},
{actualRoots:[{...scrollRoot,forbidden:true}]},
...['input','textarea','select','button','form','script','style','noscript','iframe','body','html'].map(tag=>
({observed:{...scrollObserved,tag},actualRoots:[{...scrollRoot,tag}]})),
{selector:'body',selectorObserved:false,observed:{...scrollObserved,tag:'body'},actualRoots:[{...scrollRoot,tag:'body'}]},
{now:NaN}, {now:Infinity},
]) noSearchScroll(changed);
for (const changed of [
{policy:null}, {policy:{}}, {policy:{...scrollPolicy}},
{policy:Object.freeze({version:SEARCH_SCROLL_POLICY_VERSION,scope:'search_scroll',expiresAt:25_000,pageUrl:scrollPage,startsAt:scrollNow})},
{automating:false}, {automating:undefined}, {activeMainFrame:false}, {activeMainFrame:undefined},
{sessionOrigin:'https://xiaohongshu.com'}, {sessionOrigin:'https://www.xiaohongshu.com.evil.test'},
{pageUrl:`${official}/search_result?keyword=fixture&source=web`},
{pageUrl:`${official}/search_result_ai?keyword=other&source=web`},
{pageUrl:`${official}/search_result_ai?source=web&keyword=fixture`},
{pageUrl:`${scrollPage}#results`}, {pageUrl:`${scrollPage}&page=2`},
{pageUrl:`${official}/explore?keyword=fixture&source=web`},
{pageUrl:'https://www.xiaohongshu.com.evil.test/search_result_ai?keyword=fixture&source=web'},
{pageUrl:'https://user:password@www.xiaohongshu.com/search_result_ai?keyword=fixture&source=web'},
{pageUrl:'http://www.xiaohongshu.com/search_result_ai?keyword=fixture&source=web'},
{pageUrl:'https://www.xiaohongshu.com:8443/search_result_ai?keyword=fixture&source=web'},
{method:'GET'}, {method:'PUT'}, {method:'DELETE'}, {method:'PATCH'}, {method:'post'},
{resourceType:'fetch'}, {resourceType:'document'}, {resourceType:'other'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/search/notes/delete'},
{url:'https://so.xiaohongshu.com/api/sns/web/v1/search/notes'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v2/search/notes'},
{url:'https://so.xiaohongshu.com.evil.test/api/sns/web/v2/search/notes'},
{url:'https://user:password@so.xiaohongshu.com/api/sns/web/v2/search/notes'},
{url:'http://so.xiaohongshu.com/api/sns/web/v2/search/notes'},
{url:'https://so.xiaohongshu.com:8443/api/sns/web/v2/search/notes'},
{url:'https://so.xiaohongshu.com/api/sns/web/search/history/sync'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/search/onebox'},
{url:'https://so.xiaohongshu.com/api/sns/web/v1/dqa/instant'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/feed'},
{url:'https://edith.xiaohongshu.com/api/sns/v1/history/report_web'},
{url:'https://t2.xiaohongshu.com/api/v2/collect/post'},
{url:'https://apm-fe.xiaohongshu.com/api/data',resourceType:'xhr'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/comment/post'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/user/follow'},
{url:'https://edith.xiaohongshu.com/api/sns/web/v1/im/message/send'},
{url:'https://so.xiaohongshu.com/api/sns/web/v2/unknown'},
{url:'https://so.xiaohongshu.com/api/security/verify'},
{url:'javascript:alert(1)'}, {url:'invalid'},
{now:scrollNow-1}, {now:25_000}, {now:25_001}, {now:NaN}, {now:Infinity},
]) check(matchPlatformRequest({...scrollRequest,...changed}));
for (const now of [scrollNow,24_999]) check(matchPlatformRequest({...scrollRequest,now}),
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:'search_notes'});
// Mutating the caller's action after creation cannot move the internal page pin.
const mutableAction = {...scrollAction};
const pinnedPolicy = beginReadonlyRequestPolicy(mutableAction);
mutableAction.pageUrl = `${official}/search_result_ai?keyword=changed`;
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy,pageUrl:mutableAction.pageUrl}));
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy}),
{policy_version:SEARCH_SCROLL_POLICY_VERSION,policy_rule:'search_notes'});
endPlatformRequestPolicy(pinnedPolicy);
check(matchPlatformRequest({...scrollRequest,policy:pinnedPolicy}));
endPlatformRequestPolicy(scrollPolicy);
check(matchPlatformRequest(scrollRequest));
console.log(JSON.stringify({ result:'passed', assertions, search_rules:7, note_rules:8, readonly_rules:2, search_scroll_rules:3,
scoped_page_binding:true, live_requests:0, localhost_exception:false, expiry_and_revocation:true }));