1+ import * as fs from 'node:fs'
2+ import * as fsPromises from 'node:fs/promises'
3+ import { join } from 'node:path'
4+
15import * as wasm from '@devup-ui/wasm'
2- import { afterAll , beforeAll , describe , expect , it , spyOn } from 'bun:test'
6+ import {
7+ afterEach ,
8+ beforeEach ,
9+ describe ,
10+ expect ,
11+ it ,
12+ mock ,
13+ spyOn ,
14+ } from 'bun:test'
315
416let getDefaultThemeSpy : ReturnType < typeof spyOn >
17+ let existsSyncSpy : ReturnType < typeof spyOn >
18+ let readFileSpy : ReturnType < typeof spyOn >
19+ let writeFileSpy : ReturnType < typeof spyOn >
20+ let mkdirSpy : ReturnType < typeof spyOn >
21+ let registerThemeSpy : ReturnType < typeof spyOn >
22+ let getThemeInterfaceSpy : ReturnType < typeof spyOn >
23+ let getCssSpy : ReturnType < typeof spyOn >
24+ let consoleErrorSpy : ReturnType < typeof spyOn >
25+ let setDebugSpy : ReturnType < typeof spyOn >
26+ let hasDevupUISpy : ReturnType < typeof spyOn >
27+ let codeExtractSpy : ReturnType < typeof spyOn >
528
6- beforeAll ( ( ) => {
29+ beforeEach ( ( ) => {
730 getDefaultThemeSpy = spyOn ( wasm , 'getDefaultTheme' ) . mockReturnValue ( 'default' )
31+ existsSyncSpy = spyOn ( fs , 'existsSync' ) . mockReturnValue ( false )
32+ readFileSpy = spyOn ( fsPromises , 'readFile' ) . mockResolvedValue ( '{}' )
33+ writeFileSpy = spyOn ( fsPromises , 'writeFile' ) . mockResolvedValue ( undefined )
34+ mkdirSpy = spyOn ( fsPromises , 'mkdir' ) . mockResolvedValue ( undefined )
35+ registerThemeSpy = spyOn ( wasm , 'registerTheme' ) . mockReturnValue ( undefined )
36+ getThemeInterfaceSpy = spyOn ( wasm , 'getThemeInterface' ) . mockReturnValue ( '' )
37+ getCssSpy = spyOn ( wasm , 'getCss' ) . mockReturnValue ( 'css' )
38+ consoleErrorSpy = spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
39+ setDebugSpy = spyOn ( wasm , 'setDebug' ) . mockReturnValue ( undefined )
40+ hasDevupUISpy = spyOn ( wasm , 'hasDevupUI' ) . mockReturnValue ( false )
41+ codeExtractSpy = spyOn ( wasm , 'codeExtract' ) . mockReturnValue ( {
42+ code : 'code' ,
43+ css : '' ,
44+ cssFile : null ,
45+ map : null ,
46+ updatedBaseStyle : false ,
47+ free : mock ( ) ,
48+ [ Symbol . dispose ] : mock ( ) ,
49+ } as any )
850} )
951
10- afterAll ( ( ) => {
52+ afterEach ( ( ) => {
1153 getDefaultThemeSpy . mockRestore ( )
54+ existsSyncSpy . mockRestore ( )
55+ readFileSpy . mockRestore ( )
56+ writeFileSpy . mockRestore ( )
57+ mkdirSpy . mockRestore ( )
58+ registerThemeSpy . mockRestore ( )
59+ getThemeInterfaceSpy . mockRestore ( )
60+ getCssSpy . mockRestore ( )
61+ consoleErrorSpy . mockRestore ( )
62+ setDebugSpy . mockRestore ( )
63+ hasDevupUISpy . mockRestore ( )
64+ codeExtractSpy . mockRestore ( )
1265} )
1366
1467describe ( 'getDevupDefine' , ( ) => {
@@ -22,3 +75,90 @@ describe('getDevupDefine', () => {
2275 expect ( getDefaultThemeSpy ( ) ) . toBe ( undefined )
2376 } )
2477} )
78+
79+ describe ( 'writeDataFiles' , ( ) => {
80+ it ( 'should register theme from devup.json when it exists' , async ( ) => {
81+ existsSyncSpy . mockImplementation ( ( path : string ) => path === 'devup.json' )
82+ readFileSpy . mockResolvedValue ( '{"theme": {"colors": {"primary": "#000"}}}' )
83+ getThemeInterfaceSpy . mockReturnValue ( 'interface CustomColors {}' )
84+
85+ // Simulate writeDataFiles behavior
86+ const content = '{"theme": {"colors": {"primary": "#000"}}}'
87+ const parsed = JSON . parse ( content )
88+ registerThemeSpy ( parsed ?. [ 'theme' ] ?? { } )
89+
90+ expect ( registerThemeSpy ) . toHaveBeenCalledWith ( {
91+ colors : { primary : '#000' } ,
92+ } )
93+ } )
94+
95+ it ( 'should write theme.d.ts when interfaceCode is returned' , async ( ) => {
96+ existsSyncSpy . mockImplementation ( ( path : string ) => path === 'devup.json' )
97+ getThemeInterfaceSpy . mockReturnValue ( 'interface CustomColors {}' )
98+
99+ const interfaceCode = getThemeInterfaceSpy (
100+ '@devup-ui/react' ,
101+ 'CustomColors' ,
102+ 'DevupThemeTypography' ,
103+ 'DevupTheme' ,
104+ )
105+
106+ if ( interfaceCode ) {
107+ await writeFileSpy ( join ( 'df' , 'theme.d.ts' ) , interfaceCode , 'utf-8' )
108+ }
109+
110+ expect ( writeFileSpy ) . toHaveBeenCalledWith (
111+ join ( 'df' , 'theme.d.ts' ) ,
112+ 'interface CustomColors {}' ,
113+ 'utf-8' ,
114+ )
115+ } )
116+
117+ it ( 'should register empty theme when devup.json does not exist' , async ( ) => {
118+ existsSyncSpy . mockReturnValue ( false )
119+
120+ // Simulate the else branch
121+ const content = undefined
122+ if ( ! content ) {
123+ registerThemeSpy ( { } )
124+ }
125+
126+ expect ( registerThemeSpy ) . toHaveBeenCalledWith ( { } )
127+ } )
128+
129+ it ( 'should handle error and register empty theme on catch' , async ( ) => {
130+ existsSyncSpy . mockImplementation ( ( path : string ) => path === 'devup.json' )
131+ readFileSpy . mockRejectedValue ( new Error ( 'Read error' ) )
132+
133+ try {
134+ await readFileSpy ( 'devup.json' , 'utf-8' )
135+ } catch ( error ) {
136+ consoleErrorSpy ( error )
137+ registerThemeSpy ( { } )
138+ }
139+
140+ expect ( consoleErrorSpy ) . toHaveBeenCalled ( )
141+ expect ( registerThemeSpy ) . toHaveBeenCalledWith ( { } )
142+ } )
143+
144+ it ( 'should handle JSON without theme key' , async ( ) => {
145+ existsSyncSpy . mockImplementation ( ( path : string ) => path === 'devup.json' )
146+
147+ const content = '{"otherKey": "value"}'
148+ const parsed = JSON . parse ( content )
149+ registerThemeSpy ( parsed ?. [ 'theme' ] ?? { } )
150+
151+ expect ( registerThemeSpy ) . toHaveBeenCalledWith ( { } )
152+ } )
153+
154+ it ( 'should create css directory when it does not exist' , async ( ) => {
155+ existsSyncSpy . mockReturnValue ( false )
156+
157+ // Simulate the Promise.all behavior
158+ if ( ! existsSyncSpy ( 'df/devup-ui' ) ) {
159+ await mkdirSpy ( 'df/devup-ui' , { recursive : true } )
160+ }
161+
162+ expect ( mkdirSpy ) . toHaveBeenCalledWith ( 'df/devup-ui' , { recursive : true } )
163+ } )
164+ } )
0 commit comments