11import { describe , expect , it } from "bun:test" ;
22import type { SyntaxTree } from "@wdprlib/ast" ;
3- import { renderToHtml } from "@wdprlib/render" ;
3+ import { renderToHtml , type ResolvedUser , type RenderOptions } from "@wdprlib/render" ;
44import * as fs from "fs" ;
55import * as path from "path" ;
66
77const FIXTURES_DIR = path . join ( import . meta. dir , "../fixtures" ) ;
88
9+ /**
10+ * Mock user database for testing
11+ * Simulates Wikidot's user resolution behavior
12+ */
13+ const MOCK_USERS : Record < string , { id : number ; name : string } > = {
14+ alice : { id : 1 , name : "Alice" } ,
15+ bob : { id : 2 , name : "Bob" } ,
16+ system : { id : 3 , name : "system" } ,
17+ } ;
18+
19+ /**
20+ * Create a mock user resolver that mimics Wikidot's behavior
21+ */
22+ function createMockUserResolver ( ) : ( username : string ) => ResolvedUser | null {
23+ return ( username : string ) : ResolvedUser | null => {
24+ const normalized = username . toLowerCase ( ) . trim ( ) ;
25+
26+ // "anonymous" is special - returns null to render as "Anonymous" text
27+ if ( normalized === "anonymous" ) {
28+ return null ;
29+ }
30+
31+ const user = MOCK_USERS [ normalized ] ;
32+ if ( ! user ) {
33+ return null ;
34+ }
35+
36+ // Generate Wikidot-style URLs
37+ const baseUrl = "http://www.wikidot.com" ;
38+ return {
39+ name : user . name ,
40+ url : `${ baseUrl } /user:info/${ normalized } ` ,
41+ avatarUrl : `${ baseUrl } /avatar.php?userid=${ user . id } &size=small×tamp=0` ,
42+ karmaUrl : `${ baseUrl } /userkarma.php?u=${ user . id } ` ,
43+ } ;
44+ } ;
45+ }
46+
947/**
1048 * renderテストから除外するfixture
1149 * 除外する場合は理由をコメントで記載すること
1250 */
1351const EXCLUDED_FIXTURES = new Set < string > ( [
1452 // "include/wikidot", // includeは外部ページ展開後のHTMLのため比較不可
15- "module/listpages" , // ListPagesは動的コンテンツのため比較不可
16- "module/listpages-misc" , // 同上
17- "module/backlinks/basic" , // Backlinksは動的コンテンツ
18- "module/listusers/basic" , // ListUsersは動的コンテンツ
19- "module/listusers/fail" , // 同上
20- "module/pagetree" , // PageTreeは動的コンテンツ(resolver未実装)
53+ // "module/listpages", // ListPagesは動的コンテンツのため比較不可
54+ // "module/listpages-misc", // 同上
55+ // "module/backlinks/basic", // Backlinksは動的コンテンツ
56+ // "module/listusers/basic", // ListUsersは動的コンテンツ
57+ // "module/listusers/fail", // 同上
58+ // "module/pagetree", // PageTreeは動的コンテンツ(resolver未実装)
2159 // "table/fail-paragraph", // リンク解釈・段落内改行処理の問題(別issueで対応)
2260 // "expr/edge-cases", // エラーメッセージがWikidotと異なる(スタックベース vs 再帰下降)
23- "misc/bibliography" , // bibliography機能(bibcite/bibitems)が未実装
61+ // "misc/bibliography", // bibliography機能(bibcite/bibitems)が未実装
2462 // "image/basic", // アライメント付き画像の段落エスケープが未実装
2563 // "image/fail", // 同上
2664] ) ;
@@ -143,11 +181,15 @@ describe("Render Fixture Tests", () => {
143181 const syntaxTree : SyntaxTree = JSON . parse ( expectedJson ) ;
144182 const expectedHtml = fs . readFileSync ( testCase . outputPath ! , "utf-8" ) ;
145183
146- const rendered = renderToHtml ( syntaxTree , {
184+ const options : RenderOptions = {
147185 page : {
148186 pageName : "some-page" ,
149187 } ,
150- } ) ;
188+ resolvers : {
189+ user : createMockUserResolver ( ) ,
190+ } ,
191+ } ;
192+ const rendered = renderToHtml ( syntaxTree , options ) ;
151193 expect ( normalizeHtml ( rendered ) ) . toBe ( normalizeHtml ( expectedHtml ) ) ;
152194 } ) ;
153195 }
@@ -159,7 +201,7 @@ describe("Render Fixture Tests", () => {
159201 const missing = casesRequiringOutput . map ( ( c ) => c . category ) ;
160202 throw new Error (
161203 `Missing output.html for ${ missing . length } fixture(s):\n - ${ missing . join ( "\n - " ) } \n\n` +
162- `Add output.html or add to NO_OUTPUT_REQUIRED/EXCLUDED_FIXTURES with justification.` ,
204+ `Add output.html or add to NO_OUTPUT_REQUIRED/EXCLUDED_FIXTURES with justification.` ,
163205 ) ;
164206 }
165207 } ) ;
0 commit comments