1- import { describe , it , expect , beforeEach , afterEach } from 'vitest' ;
2- import mockFs from 'mock-fs' ;
1+ import { describe , it , expect , beforeEach , afterEach , Mocked , vi } from 'vitest' ;
32import {
43 GitHubActionsParser ,
54 GitHubAction ,
65 GitHubWorkflow ,
76 GitHubActionInput ,
87 GitHubActionOutput ,
98} from './github-actions-parser.js' ;
10- import { RepositoryInfo } from '@ci-dokumentor/core' ;
11- import { RepositoryInfoMockFactory } from '@ci-dokumentor/core/tests' ;
9+ import { ReaderAdapter , RepositoryInfo } from '@ci-dokumentor/core' ;
10+ import { ReaderAdapterMockFactory , RepositoryInfoMockFactory } from '@ci-dokumentor/core/tests' ;
1211
1312describe ( 'GitHubActionsParser' , ( ) => {
14- let repositoryInfo : RepositoryInfo ;
13+ let mockReaderAdapter : Mocked < ReaderAdapter > ;
14+ let mockRepositoryInfo : Mocked < RepositoryInfo > ;
1515 let parser : GitHubActionsParser ;
1616
1717 beforeEach ( ( ) => {
18- repositoryInfo = RepositoryInfoMockFactory . create ( ) ;
18+ vi . resetAllMocks ( ) ;
1919
20- parser = new GitHubActionsParser ( ) ;
20+ mockReaderAdapter = ReaderAdapterMockFactory . create ( ) ;
21+ mockRepositoryInfo = RepositoryInfoMockFactory . create ( ) ;
22+
23+ parser = new GitHubActionsParser ( mockReaderAdapter ) ;
2124 } ) ;
2225
2326 afterEach ( ( ) => {
24- mockFs . restore ( ) ;
27+ vi . resetAllMocks ( ) ;
2528 } ) ;
2629
2730 describe ( 'parseFile' , ( ) => {
2831 describe ( 'GitHub Actions' , ( ) => {
2932 it ( 'should parse an action file' , async ( ) => {
3033 // Arrange
31- mockFs ( {
32- '/test' : {
33- 'action.yml' : `name: Test Action
34+ const filePath = '/test/action.yml' ;
35+ const fileContent = `name: Test Action
3436description: A test GitHub Action
3537author: Test Author
3638branding:
@@ -62,15 +64,13 @@ outputs:
6264 value: \${{ steps.step-id.outputs.value }}
6365runs:
6466 using: composite
65- ` ,
66- } ,
67- } ) ;
67+ ` ;
68+
69+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
70+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
6871
6972 // Act
70- const result = parser . parseFile (
71- '/test/action.yml' ,
72- repositoryInfo
73- ) as GitHubAction ;
73+ const result = await parser . parseFile ( filePath , mockRepositoryInfo ) as GitHubAction ;
7474
7575 // Assert
7676 expect ( result ) . toBeDefined ( ) ;
@@ -117,29 +117,22 @@ runs:
117117 describe ( 'GitHub Workflows' , ( ) => {
118118 it ( 'should parse a complete workflow file' , async ( ) => {
119119 // Arrange
120- mockFs ( {
121- '/test' : {
122- '.github' : {
123- workflows : {
124- 'workflow.yml' : `name: Test Workflow
120+ const filePath = '/test/.github/workflows/workflow.yml' ;
121+ const fileContent = `name: Test Workflow
125122on: push
126123jobs:
127124 build:
128125 runs-on: ubuntu-latest
129126 steps:
130127 - name: Checkout code
131128 uses: actions/checkout@v2
132- ` ,
133- } ,
134- } ,
135- } ,
136- } ) ;
129+ ` ;
130+
131+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
132+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
137133
138134 // Act
139- const result = parser . parseFile (
140- '/test/.github/workflows/workflow.yml' ,
141- repositoryInfo
142- ) as GitHubWorkflow ;
135+ const result = await parser . parseFile ( filePath , mockRepositoryInfo ) as GitHubWorkflow ;
143136
144137 // Assert
145138 expect ( result ) . toBeDefined ( ) ;
@@ -151,28 +144,21 @@ jobs:
151144
152145 it ( 'should parse a workflow without defined name' , async ( ) => {
153146 // Arrange
154- mockFs ( {
155- '/test' : {
156- '.github' : {
157- workflows : {
158- 'workflow-test.yml' : `on: push
147+ const filePath = '/test/.github/workflows/workflow-test.yml' ;
148+ const fileContent = `on: push
159149jobs:
160150 build:
161151 runs-on: ubuntu-latest
162152 steps:
163153 - name: Checkout code
164154 uses: actions/checkout@v2
165- ` ,
166- } ,
167- } ,
168- } ,
169- } ) ;
155+ ` ;
156+
157+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
158+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
170159
171160 // Act
172- const result = parser . parseFile (
173- '/test/.github/workflows/workflow-test.yml' ,
174- repositoryInfo
175- ) as GitHubWorkflow ;
161+ const result = await parser . parseFile ( filePath , mockRepositoryInfo ) as GitHubWorkflow ;
176162
177163 // Assert
178164 expect ( result ) . toBeDefined ( ) ;
@@ -183,101 +169,69 @@ jobs:
183169 describe ( 'Error handling' , ( ) => {
184170 it ( 'should throw error for invalid YAML' , async ( ) => {
185171 // Arrange
186- mockFs ( {
187- '/test' : {
188- '.github' : {
189- workflows : {
190- 'invalid.yml' : `invalid: yaml: content` ,
191- } ,
192- } ,
193- } ,
194- } ) ;
172+ const filePath = '/test/.github/workflows/invalid.yml' ;
173+ const fileContent = `invalid: yaml: content` ;
174+
175+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
176+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
195177
196178 // Act & Assert
197- expect ( ( ) =>
198- parser . parseFile ( '/test/.github/workflows/invalid.yml' , repositoryInfo )
199- ) . toThrow ( 'Nested mappings are not allowed in compact mappings at line 1, column 10' ) ;
179+ await expect ( parser . parseFile ( filePath , mockRepositoryInfo ) ) . rejects . toThrow ( ) ;
200180 } ) ;
201181
202182 it ( 'should throw error for empty file' , async ( ) => {
203183 // Arrange
204- mockFs ( {
205- '/test' : {
206- '.github' : {
207- workflows : {
208- 'empty.yml' : '' ,
209- } ,
210- } ,
211- } ,
212- } ) ;
184+ const filePath = '/test/.github/workflows/empty.yml' ;
185+
186+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
187+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( '' ) ) ;
213188
214189 // Act & Assert
215- expect ( ( ) =>
216- parser . parseFile ( '/test/.github/workflows/empty.yml' , repositoryInfo )
217- ) . toThrow ( 'Unsupported source file' ) ;
190+ await expect ( parser . parseFile ( filePath , mockRepositoryInfo ) ) . rejects . toThrow ( ) ;
218191 } ) ;
219192
220193 it ( 'should throw error for plain text when parseable as YAML' , async ( ) => {
221194 // Arrange
222- mockFs ( {
223- '/test' : {
224- '.github' : {
225- workflows : {
226- 'plain-text.yml' : `This is not a YAML file` ,
227- } ,
228- } ,
229- } ,
230- } ) ;
195+ const filePath = '/test/.github/workflows/plain-text.yml' ;
196+ const fileContent = `This is not a YAML file` ;
197+
198+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
199+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
231200
232201 // Act & Assert
233- expect ( ( ) =>
234- parser . parseFile ( '/test/.github/workflows/plain-text.yml' , repositoryInfo )
235- ) . toThrow (
236- 'Unsupported GitHub Actions file format: /test/.github/workflows/plain-text.yml'
237- ) ;
202+ await expect ( parser . parseFile ( filePath , mockRepositoryInfo ) ) . rejects . toThrow ( ) ;
238203 } ) ;
239204
240205 it ( 'should throw error for valid YAML but unsupported structure' , async ( ) => {
241206 // Arrange
242- mockFs ( {
243- '/test' : {
244- '.github' : {
245- workflows : {
246- 'object-without-required-fields.yml' : `someField: value
207+ const filePath = '/test/.github/workflows/object-without-required-fields.yml' ;
208+ const fileContent = `someField: value
247209anotherField: 123
248- ` ,
249- } ,
250- } ,
251- } ,
252- } ) ;
210+ ` ;
211+
212+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
213+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
253214
254215 // Act & Assert
255- expect ( ( ) =>
256- parser . parseFile (
257- '/test/.github/workflows/object-without-required-fields.yml' ,
258- repositoryInfo
259- )
260- ) . toThrow (
261- 'Unsupported GitHub Actions file format: /test/.github/workflows/object-without-required-fields.yml'
262- ) ;
216+ await expect ( parser . parseFile ( filePath , mockRepositoryInfo ) ) . rejects . toThrow ( ) ;
263217 } ) ;
264218 } ) ;
265219
266220 describe ( 'Type detection' , ( ) => {
267221 it ( 'should detect GitHub Action when it has name but no on/jobs properties' , async ( ) => {
268222 // Arrange
269- mockFs ( {
270- '/test' : {
271- 'action.yml' : `name: Simple Action
223+ const filePath = '/test/action.yml' ;
224+ const fileContent = `name: Simple Action
272225description: A simple GitHub Action
273226runs:
274227 using: node20
275- ` ,
276- } ,
277- } ) ;
228+ ` ;
229+
230+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
231+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
278232
279233 // Act
280- const result = parser . parseFile ( '/test/action.yml' , repositoryInfo ) ;
234+ const result = await parser . parseFile ( filePath , mockRepositoryInfo ) ;
281235
282236 // Assert
283237 expect ( result ) . toBeDefined ( ) ;
@@ -288,29 +242,22 @@ runs:
288242
289243 it ( 'should detect GitHub Workflow when it has on property' , async ( ) => {
290244 // Arrange
291- mockFs ( {
292- '/test' : {
293- '.github' : {
294- workflows : {
295- 'workflow.yml' : `name: Test Workflow
245+ const filePath = '/test/.github/workflows/workflow.yml' ;
246+ const fileContent = `name: Test Workflow
296247on: push
297248jobs:
298249 build:
299250 runs-on: ubuntu-latest
300251 steps:
301252 - name: Checkout code
302253 uses: actions/checkout@v2
303- ` ,
304- } ,
305- } ,
306- } ,
307- } ) ;
254+ ` ;
255+
256+ mockReaderAdapter . resourceExists . mockReturnValue ( true ) ;
257+ mockReaderAdapter . readResource . mockResolvedValue ( Buffer . from ( fileContent ) ) ;
308258
309259 // Act
310- const result = parser . parseFile (
311- '/test/.github/workflows/workflow.yml' ,
312- repositoryInfo
313- ) ;
260+ const result = await parser . parseFile ( filePath , mockRepositoryInfo ) ;
314261
315262 // Assert
316263 expect ( result ) . toBeDefined ( ) ;
0 commit comments