Exercise publishing permissions and XML over real HTTP integration
waterfall-wiki CI and deployment / verify-and-deploy (pull_request) Has been cancelled
waterfall-wiki CI and deployment / verify-and-deploy (pull_request) Has been cancelled
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {randomUUID} from 'node:crypto';
|
||||
import {newToken,tokenDigest,ACCOUNT_COOKIE} from '../src/lib/account-crypto';
|
||||
import {guidanceXml} from '../src/content/guides/catalog';
|
||||
import {db} from '../src/lib/db';
|
||||
import {publishDocument,resolveDocument,withdrawDocument,discoverDocuments} from '../src/lib/guidance-store';
|
||||
export async function verifyGuidancePublishing(){
|
||||
export async function verifyGuidancePublishing(base:string){
|
||||
const owner=randomUUID(),other=randomUUID(),id='user-'+owner+'-document';
|
||||
for(const uid of [owner,other])await db().query("INSERT INTO account_users(id,email,password_hash,verified_at) VALUES($1,$2,'test',now())",[uid,uid+'@example.com']);
|
||||
const doc={id,revision:1,kind:'context',title:'实际数据库文档',summary:'摘要',applies:'条件',body:'正文',steps:[],checks:[],links:[],tags:[]};
|
||||
@@ -14,4 +16,21 @@ export async function verifyGuidancePublishing(){
|
||||
assert.equal((await resolveDocument(id,1))?.body,'正文');assert.equal(await resolveDocument(id,999),null);
|
||||
await assert.rejects(()=>db().query('UPDATE guidance_revisions SET content=$2 WHERE document_id=$1',[id,{}]),/immutable/);
|
||||
assert.equal(await withdrawDocument(other,id),false);assert.equal(await withdrawDocument(owner,id),true);assert.equal(await resolveDocument(id),null);assert.ok(await resolveDocument(id,1));assert.ok(!(await discoverDocuments()).some(d=>d.id===id));
|
||||
const token=newToken();await db().query("INSERT INTO account_tokens(digest,user_id,kind,expires_at) VALUES($1,$2,'session',now()+interval '1 hour')",[tokenDigest(token),owner]);
|
||||
const headers={'Content-Type':'application/json',origin:process.env.ACCOUNT_PUBLIC_ORIGIN||base,cookie:ACCOUNT_COOKIE+'='+token};
|
||||
const httpDoc={...doc,id:'user-'+owner+'-http',tags:['往返标签']};
|
||||
const request=(path:string,method:string,body?:unknown,extra:Record<string,string>={})=>fetch(base+'/api/documents'+path,{method,headers:{...headers,...extra},...(body?{body:typeof body==='string'?body:JSON.stringify(body)}:{})});
|
||||
assert.equal((await request('','POST',httpDoc,{cookie:''})).status,401);
|
||||
assert.equal((await request('','POST',httpDoc,{origin:'https://untrusted.example'})).status,403);
|
||||
const preview=await request('/preview','POST',httpDoc);assert.equal(preview.status,200,await preview.clone().text());assert.equal(await resolveDocument(httpDoc.id,1),null);
|
||||
const created=await request('','POST',guidanceXml(httpDoc),{'Content-Type':'application/xml'});assert.equal(created.status,201,await created.clone().text());
|
||||
assert.equal((await request('','POST',httpDoc)).status,409);
|
||||
assert.equal((await request('','POST',{...httpDoc,id:'user-'+other+'-http'})).status,400);
|
||||
const xml=await fetch(base+'/api/documents/'+httpDoc.id+'?revision=1&format=xml');assert.equal(xml.status,200);assert.match(await xml.text(),/<tag>往返标签<\/tag>/);
|
||||
const page=await fetch(base+'/documents/'+httpDoc.id+'?revision=1');assert.equal(page.status,200);assert.ok((await page.text()).includes('实际数据库文档'));
|
||||
assert.equal((await request('/'+httpDoc.id,'DELETE',undefined,{cookie:''})).status,401);
|
||||
assert.equal((await request('/'+httpDoc.id,'DELETE')).status,200);
|
||||
assert.equal((await fetch(base+'/api/documents/'+httpDoc.id)).status,404);
|
||||
assert.equal((await fetch(base+'/api/documents/'+httpDoc.id+'?revision=1')).status,200);
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processi
|
||||
let ready=false;for(let i=0;i<60;i++){try{if((await fetch(base+'/api/health')).ok){ready=true;break;}}catch{}await setTimeout(250);}assert.ok(ready);
|
||||
for(const route of ['/','/images','/videos','/audio','/articles','/motion','/library/import','/tools/doodle','/tools/skills','/tools/skills/street-people','/tools/skills/shadow-puppet'])assert.equal((await fetch(base+route)).status,200,route);
|
||||
await verifyEmailAccounts();
|
||||
await verifyGuidancePublishing();
|
||||
await verifyGuidancePublishing(base);
|
||||
await verifyFlatNoteMigration();
|
||||
const root=await request('/api/tags',{name:'线条',slug:'lines'});const child=await request('/api/tags',{name:'白色',slug:'white'});
|
||||
const sameTag=await request('/api/tags',{name:'#线条'});assert.equal(sameTag.id,root.id,'Hashtag creation reuses the globally unique tag');
|
||||
|
||||
Reference in New Issue
Block a user