11import { expect } from 'chai' ;
22import { ValidationService } from '../../../src/domains/services/validation.service' ;
33import { Specification } from '../../../src/domains/models/SpecificationFile' ;
4+ import { ConfigService } from '../../../src/domains/services/config.service' ;
5+ import { promises as fs } from 'fs' ;
6+ import path from 'path' ;
7+ import os from 'os' ;
48
59const validAsyncAPI = `{
610 "asyncapi": "2.6.0",
@@ -24,6 +28,45 @@ const completelyInvalidDocument = `{
2428 "document": true
2529}` ;
2630
31+ // Test AsyncAPI documents with external references
32+ const asyncAPIWithPrivateGitHubRef = `{
33+ "asyncapi": "2.6.0",
34+ "info": {
35+ "title": "Test Service with Private GitHub Ref",
36+ "version": "1.0.0"
37+ },
38+ "channels": {
39+ "user/private": {
40+ "publish": {
41+ "message": {
42+ "payload": {
43+ "$ref": "https://github.com/private-org/private-repo/blob/main/schema.yaml#/payload"
44+ }
45+ }
46+ }
47+ }
48+ }
49+ }` ;
50+
51+ const asyncAPIWithPublicHTTPRef = `{
52+ "asyncapi": "2.6.0",
53+ "info": {
54+ "title": "Test Service with Public HTTP Ref",
55+ "version": "1.0.0"
56+ },
57+ "channels": {
58+ "user/event": {
59+ "publish": {
60+ "message": {
61+ "payload": {
62+ "$ref": "https://raw.githubusercontent.com/asyncapi/spec/master/examples/streetlights.yml#/channels/light/measured/message/payload"
63+ }
64+ }
65+ }
66+ }
67+ }
68+ }` ;
69+
2770describe ( 'ValidationService' , ( ) => {
2871 let validationService : ValidationService ;
2972
@@ -129,4 +172,81 @@ describe('ValidationService', () => {
129172 }
130173 } ) ;
131174 } ) ;
132- } ) ;
175+
176+ describe ( 'validateDocument() with external URLs' , ( ) => {
177+ let originalConfig : any ;
178+ const CONFIG_DIR = path . join ( os . homedir ( ) , '.asyncapi' ) ;
179+ const CONFIG_FILE = path . join ( CONFIG_DIR , 'config.json' ) ;
180+
181+ beforeEach ( async ( ) => {
182+ // Backup original config
183+ try {
184+ const content = await fs . readFile ( CONFIG_FILE , 'utf8' ) ;
185+ originalConfig = JSON . parse ( content ) ;
186+ } catch ( err ) {
187+ originalConfig = null ;
188+ }
189+ } ) ;
190+
191+ afterEach ( async ( ) => {
192+ // Restore original config
193+ if ( originalConfig ) {
194+ await fs . writeFile ( CONFIG_FILE , JSON . stringify ( originalConfig , null , 2 ) , 'utf8' ) ;
195+ } else {
196+ try {
197+ await fs . unlink ( CONFIG_FILE ) ;
198+ } catch ( err ) {
199+ // File doesn't exist, ignore
200+ }
201+ }
202+ } ) ;
203+
204+ it ( 'should fail to validate document with private GitHub reference when not properly configured' , async ( ) => {
205+ // Ensure no auth config exists for private GitHub repository
206+ try {
207+ await fs . unlink ( CONFIG_FILE ) ;
208+ } catch ( err ) {
209+ // File doesn't exist, ignore
210+ }
211+
212+ const specFile = new Specification ( asyncAPIWithPrivateGitHubRef ) ;
213+ const options = {
214+ 'diagnostics-format' : 'stylish' as const
215+ } ;
216+
217+ const result = await validationService . validateDocument ( specFile , options ) ;
218+
219+ // The validation succeeds but the document is invalid due to unresolved ref
220+ expect ( result . success ) . to . equal ( true ) ;
221+ if ( result . success ) {
222+ expect ( result . data ) . to . have . property ( 'status' ) ;
223+ expect ( result . data ?. status ) . to . equal ( 'invalid' ) ;
224+ expect ( result . data ) . to . have . property ( 'diagnostics' ) ;
225+ expect ( result . data ?. diagnostics ) . to . be . an ( 'array' ) ;
226+
227+ // Should have an invalid-ref diagnostic for the private GitHub URL
228+ const invalidRefDiagnostic = result . data ?. diagnostics ?. find ( ( d : any ) => d . code === 'invalid-ref' ) ;
229+ // eslint-disable-next-line no-unused-expressions
230+ expect ( invalidRefDiagnostic ) . to . exist ;
231+ expect ( invalidRefDiagnostic ?. message ) . to . include ( 'Page not found' ) ;
232+ expect ( invalidRefDiagnostic ?. message ) . to . include ( 'https://github.com/private-org/private-repo/blob/main/schema.yaml' ) ;
233+ }
234+ } ) ;
235+
236+ it ( 'should validate document with public HTTP reference' , async ( ) => {
237+ const specFile = new Specification ( asyncAPIWithPublicHTTPRef ) ;
238+ const options = {
239+ 'diagnostics-format' : 'stylish' as const
240+ } ;
241+
242+ const result = await validationService . validateDocument ( specFile , options ) ;
243+
244+ expect ( result . success ) . to . equal ( true ) ;
245+ if ( result . success ) {
246+ expect ( result . data ) . to . have . property ( 'status' ) ;
247+ expect ( result . data ) . to . have . property ( 'diagnostics' ) ;
248+ expect ( result . data ?. diagnostics ) . to . be . an ( 'array' ) ;
249+ }
250+ } ) ;
251+ } ) ;
252+ } ) ;
0 commit comments