1+ import { execSync } from 'child_process'
2+ import { existsSync , readFileSync } from 'fs'
3+ import { join } from 'path'
4+ import { describe , expect , it , beforeAll } from 'vitest'
5+
6+ const DIST_DIR = join ( process . cwd ( ) , 'dist' )
7+ const CJS_FILE = join ( DIST_DIR , 'index.cjs' )
8+ const ESM_FILE = join ( DIST_DIR , 'index.js' )
9+ const DTS_FILE = join ( DIST_DIR , 'index.d.ts' )
10+
11+ describe ( 'Build Output Verification' , ( ) => {
12+ beforeAll ( ( ) => {
13+ // Ensure build exists
14+ if ( ! existsSync ( DIST_DIR ) ) {
15+ execSync ( 'pnpm build' , { stdio : 'inherit' } )
16+ }
17+ } )
18+
19+ it ( 'should generate all required build files' , ( ) => {
20+ expect ( existsSync ( CJS_FILE ) ) . toBe ( true )
21+ expect ( existsSync ( ESM_FILE ) ) . toBe ( true )
22+ expect ( existsSync ( DTS_FILE ) ) . toBe ( true )
23+ } )
24+
25+ it ( 'should generate valid CommonJS format' , ( ) => {
26+ const cjsContent = readFileSync ( CJS_FILE , 'utf8' )
27+
28+ // Should start with 'use strict'
29+ expect ( cjsContent ) . toMatch ( / ^ ' u s e s t r i c t ' / )
30+
31+ // Should use require() for dependencies
32+ expect ( cjsContent ) . toMatch ( / r e q u i r e \( [ ' " ] / )
33+
34+ // Should not contain ES6 import statements
35+ expect ( cjsContent ) . not . toMatch ( / ^ i m p o r t \s + / )
36+ } )
37+
38+ it ( 'should generate valid ES module format' , ( ) => {
39+ const esmContent = readFileSync ( ESM_FILE , 'utf8' )
40+
41+ // Should use import statements
42+ expect ( esmContent ) . toMatch ( / ^ i m p o r t \s + / )
43+
44+ // Should not contain require() calls
45+ expect ( esmContent ) . not . toMatch ( / r e q u i r e \( [ ' " ] / )
46+ } )
47+
48+ it ( 'should generate TypeScript definitions' , ( ) => {
49+ const dtsContent = readFileSync ( DTS_FILE , 'utf8' )
50+
51+ // Should contain export declarations
52+ expect ( dtsContent ) . toMatch ( / e x p o r t \s + / )
53+
54+ // Should contain key function types
55+ expect ( dtsContent ) . toMatch ( / p a r s e / )
56+ expect ( dtsContent ) . toMatch ( / r e n d e r / )
57+ } )
58+
59+ it ( 'should load CJS build correctly' , async ( ) => {
60+ // Use dynamic require to avoid bundler issues
61+ const cjsModule = await import ( CJS_FILE )
62+
63+ expect ( typeof cjsModule . parse ) . toBe ( 'function' )
64+ expect ( typeof cjsModule . render ) . toBe ( 'function' )
65+ expect ( typeof cjsModule . createChain ) . toBe ( 'function' )
66+ expect ( cjsModule . CompileError ) . toBeDefined ( )
67+
68+ // Should have all expected exports
69+ const exports = Object . keys ( cjsModule )
70+ expect ( exports ) . toContain ( 'parse' )
71+ expect ( exports ) . toContain ( 'render' )
72+ expect ( exports ) . toContain ( 'CompileError' )
73+ expect ( exports ) . toContain ( 'ContentType' )
74+ expect ( exports ) . toContain ( 'MessageRole' )
75+ } )
76+
77+ it ( 'should load ESM build correctly' , async ( ) => {
78+ const esmModule = await import ( ESM_FILE )
79+
80+ expect ( typeof esmModule . parse ) . toBe ( 'function' )
81+ expect ( typeof esmModule . render ) . toBe ( 'function' )
82+ expect ( typeof esmModule . createChain ) . toBe ( 'function' )
83+ expect ( esmModule . CompileError ) . toBeDefined ( )
84+
85+ // Should have all expected exports
86+ const exports = Object . keys ( esmModule )
87+ expect ( exports ) . toContain ( 'parse' )
88+ expect ( exports ) . toContain ( 'render' )
89+ expect ( exports ) . toContain ( 'CompileError' )
90+ expect ( exports ) . toContain ( 'ContentType' )
91+ expect ( exports ) . toContain ( 'MessageRole' )
92+ } )
93+
94+ it ( 'should have functional parse and render in CJS build' , async ( ) => {
95+ const { parse, render } = await import ( CJS_FILE )
96+
97+ const template = 'Hello {{name}}!'
98+ const parsed = parse ( template )
99+
100+ expect ( parsed ) . toBeDefined ( )
101+ expect ( parsed . type ) . toBe ( 'Fragment' )
102+
103+ const rendered = await render ( {
104+ prompt : template ,
105+ parameters : { name : 'World' }
106+ } )
107+
108+ expect ( rendered ) . toBeDefined ( )
109+ expect ( rendered . messages ) . toBeDefined ( )
110+ expect ( rendered . config ) . toBeDefined ( )
111+ expect ( Array . isArray ( rendered . messages ) ) . toBe ( true )
112+ } )
113+
114+ it ( 'should have functional parse and render in ESM build' , async ( ) => {
115+ const { parse, render } = await import ( ESM_FILE )
116+
117+ const template = 'Hello {{name}}!'
118+ const parsed = parse ( template )
119+
120+ expect ( parsed ) . toBeDefined ( )
121+ expect ( parsed . type ) . toBe ( 'Fragment' )
122+
123+ const rendered = await render ( {
124+ prompt : template ,
125+ parameters : { name : 'World' }
126+ } )
127+
128+ expect ( rendered ) . toBeDefined ( )
129+ expect ( rendered . messages ) . toBeDefined ( )
130+ expect ( rendered . config ) . toBeDefined ( )
131+ expect ( Array . isArray ( rendered . messages ) ) . toBe ( true )
132+ } )
133+
134+ it ( 'should have identical exports between CJS and ESM builds' , async ( ) => {
135+ const cjsModule = await import ( CJS_FILE )
136+ const esmModule = await import ( ESM_FILE )
137+
138+ // Filter out 'default' export which is expected to differ between CJS and ESM
139+ const cjsExports = Object . keys ( cjsModule ) . filter ( key => key !== 'default' ) . sort ( )
140+ const esmExports = Object . keys ( esmModule ) . filter ( key => key !== 'default' ) . sort ( )
141+
142+ expect ( cjsExports ) . toEqual ( esmExports )
143+ expect ( cjsExports . length ) . toBeGreaterThan ( 10 ) // Ensure we have substantial exports
144+ } )
145+ } )
0 commit comments