11// Mock better-auth ESM-only modules so Jest (CJS) can import AppModule's transitive AuthModule.
22// These must appear before any imports so that Jest hoists them before module evaluation.
33
4- // Stub the auth instance so auth.server.ts never runs its top-level side effects
5- // (validateSecurityConfig, betterAuth(), Redis connection, etc.)
64jest . mock ( './auth/auth.server' , ( ) => ( {
75 auth : {
86 api : { } ,
@@ -14,20 +12,23 @@ jest.mock('./auth/auth.server', () => ({
1412 isStaticTrustedOrigin : ( ) => false ,
1513} ) ) ;
1614
17- // Stub the NestJS better-auth integration module
1815jest . mock ( '@thallesp/nestjs-better-auth' , ( ) => {
1916 // eslint-disable-next-line @typescript-eslint/no-var-requires
2017 const { Module } = require ( '@nestjs/common' ) ;
2118 @Module ( { } )
2219 class AuthModuleStub {
2320 static forRoot ( ) {
24- return { module : AuthModuleStub , imports : [ ] , providers : [ ] , exports : [ ] } ;
21+ return {
22+ module : AuthModuleStub ,
23+ imports : [ ] ,
24+ providers : [ ] ,
25+ exports : [ ] ,
26+ } ;
2527 }
2628 }
2729 return { AuthModule : AuthModuleStub } ;
2830} ) ;
2931
30- // Stub better-auth ESM-only packages (loaded by @trycompai/auth package)
3132jest . mock ( 'better-auth/plugins/access' , ( ) => ( {
3233 createAccessControl : ( ) => ( {
3334 newRole : ( ) => ( { } ) ,
@@ -76,6 +77,7 @@ jest.mock('@db', () => {
7677 organization : { findFirst : jest . fn ( ) , findMany : jest . fn ( ) } ,
7778 auditLog : { create : jest . fn ( ) } ,
7879 trust : { findMany : jest . fn ( ) . mockResolvedValue ( [ ] ) } ,
80+ dynamicIntegration : { findMany : jest . fn ( ) . mockResolvedValue ( [ ] ) } ,
7981 apiKey : { findFirst : jest . fn ( ) } ,
8082 session : { findFirst : jest . fn ( ) } ,
8183 member : { findFirst : jest . fn ( ) } ,
@@ -101,9 +103,20 @@ process.env.APP_AWS_BUCKET_NAME = 'test-bucket';
101103process . env . APP_AWS_REGION = 'us-east-1' ;
102104
103105import { Test } from '@nestjs/testing' ;
104- import { DocumentBuilder , SwaggerModule , type OpenAPIObject } from '@nestjs/swagger' ;
106+ import {
107+ DocumentBuilder ,
108+ SwaggerModule ,
109+ type OpenAPIObject ,
110+ } from '@nestjs/swagger' ;
105111import { INestApplication , VersioningType } from '@nestjs/common' ;
106112import { AppModule } from './app.module' ;
113+ import {
114+ applyPublicOpenApiMetadata ,
115+ PUBLIC_OPENAPI_DESCRIPTION ,
116+ PUBLIC_OPENAPI_TITLE ,
117+ PUBLIC_SERVER_URL ,
118+ } from './openapi/public-docs-metadata' ;
119+ import { collectPublicOpenApiIssues } from './openapi/public-docs-quality' ;
107120
108121describe ( 'OpenAPI document' , ( ) => {
109122 let app : INestApplication ;
@@ -119,37 +132,73 @@ describe('OpenAPI document', () => {
119132 await app . init ( ) ;
120133
121134 const config = new DocumentBuilder ( )
122- . setTitle ( 'Test' )
135+ . setTitle ( PUBLIC_OPENAPI_TITLE )
136+ . setDescription ( PUBLIC_OPENAPI_DESCRIPTION )
123137 . setVersion ( '1.0' )
124138 . build ( ) ;
125139 document = SwaggerModule . createDocument ( app , config ) ;
140+ applyPublicOpenApiMetadata ( document ) ;
126141 } ) ;
127142
128143 afterAll ( async ( ) => {
129144 if ( app ) await app . close ( ) ;
130145 } ) ;
131146
132- const hiddenPrefixes = [ '/v1/auth' , '/v1/admin' , '/v1/internal' ] ;
147+ describe ( 'public metadata' , ( ) => {
148+ it ( 'uses production API servers in the generated Mintlify spec' , ( ) => {
149+ expect ( document . info . title ) . toBe ( PUBLIC_OPENAPI_TITLE ) ;
150+ expect ( document . info . description ) . toBe ( PUBLIC_OPENAPI_DESCRIPTION ) ;
151+ expect ( document . servers ) . toEqual ( [
152+ {
153+ url : PUBLIC_SERVER_URL ,
154+ description : 'Production API Server' ,
155+ } ,
156+ ] ) ;
157+ } ) ;
158+
159+ it ( 'keeps the public spec complete, SEO-ready, and free of private surfaces' , ( ) => {
160+ const issues = collectPublicOpenApiIssues ( document ) ;
133161
134- for ( const prefix of hiddenPrefixes ) {
135- it ( `does not expose any path starting with ${ prefix } ` , ( ) => {
136- const exposed = Object . keys ( document . paths ) . filter ( ( p ) => p . startsWith ( prefix ) ) ;
137- expect ( exposed ) . toEqual ( [ ] ) ;
162+ expect ( issues . excludedPaths ) . toEqual ( [ ] ) ;
163+ expect ( issues . exposedTags ) . toEqual ( [ ] ) ;
164+ expect ( issues . invalidSeo ) . toEqual ( [ ] ) ;
165+ expect ( issues . missingMetadata ) . toEqual ( [ ] ) ;
166+ expect ( issues . missingSummaries ) . toEqual ( [ ] ) ;
167+ expect ( issues . sensitiveSchemaDetails ) . toEqual ( [ ] ) ;
138168 } ) ;
139- }
140169
141- describe ( 'summaries' , ( ) => {
142- it ( 'every public operation declares a non-empty summary' , ( ) => {
143- const missing : string [ ] = [ ] ;
144- for ( const [ routePath , methods ] of Object . entries ( document . paths ) ) {
145- for ( const [ method , op ] of Object . entries ( methods as Record < string , { summary ?: string } > ) ) {
146- if ( typeof op !== 'object' || ! op ) continue ;
147- if ( ! op . summary || op . summary . trim ( ) === '' ) {
148- missing . push ( `${ method . toUpperCase ( ) } ${ routePath } ` ) ;
170+ it ( 'curates high-value API pages with operation-specific SEO copy' , ( ) => {
171+ expect (
172+ document . paths [ '/v1/questionnaire/parse/upload/token' ] ,
173+ ) . toBeUndefined ( ) ;
174+
175+ const upload = document . paths [ '/v1/questionnaire/parse/upload' ] ?. post as
176+ | {
177+ summary ?: string ;
178+ description ?: string ;
179+ 'x-mint' ?: { href ?: string ; metadata ?: { title ?: string } } ;
180+ }
181+ | undefined ;
182+
183+ expect ( upload ?. summary ) . toBe ( 'Auto-answer uploaded questionnaire' ) ;
184+ expect ( upload ?. description ) . toContain ( 'approved organization evidence' ) ;
185+ expect ( upload ?. [ 'x-mint' ] ?. href ) . toBe (
186+ '/api-reference/questionnaire/upload-a-questionnaire-file-and-auto-answer-with-export' ,
187+ ) ;
188+
189+ const policies = document . paths [ '/v1/policies' ] ?. get as
190+ | {
191+ summary ?: string ;
192+ description ?: string ;
193+ 'x-mint' ?: { metadata ?: { title ?: string } } ;
149194 }
150- }
151- }
152- expect ( missing ) . toEqual ( [ ] ) ;
195+ | undefined ;
196+
197+ expect ( policies ?. summary ) . toBe ( 'List compliance policies' ) ;
198+ expect ( policies ?. description ) . toContain ( 'SOC 2' ) ;
199+ expect ( policies ?. [ 'x-mint' ] ?. metadata ?. title ) . toBe (
200+ 'List compliance policies | Comp AI API' ,
201+ ) ;
153202 } ) ;
154203 } ) ;
155204} ) ;
0 commit comments