2023-03-14 11:10:55 +01:00
'use strict' ;
const fse = require ( 'fs-extra' ) ;
const SwaggerParser = require ( '@apidevtools/swagger-parser' ) ;
const { api , plugins , components , contentTypes } = require ( '../__mocks__/mock-strapi-data' ) ;
const documentation = require ( '../documentation' ) ;
2023-03-17 10:28:31 +01:00
const override = require ( '../override' ) ;
2023-03-14 11:10:55 +01:00
const defaultConfig = require ( '../../config/default-plugin-config' ) ;
const mockStrapiInstance = {
dirs : {
app : {
api : './' ,
extensions : './' ,
} ,
} ,
contentTypes ,
components ,
api ,
plugins ,
config : {
2023-03-17 10:28:31 +01:00
get : ( ) => defaultConfig ,
2023-03-14 11:10:55 +01:00
} ,
2023-03-14 17:52:14 +01:00
log : {
info : jest . fn ( ) ,
warn : jest . fn ( ) ,
} ,
2023-03-14 11:10:55 +01:00
} ;
jest . mock ( 'fs-extra' , ( ) => ( {
... jest . requireActual ( 'fs-extra' ) ,
writeJson : jest . fn ( ) ,
ensureFile : jest . fn ( ) ,
} ) ) ;
describe ( 'Documentation service' , ( ) => {
beforeAll ( ( ) => {
global . strapi = mockStrapiInstance ;
global . strapi . contentType = jest . fn ( ( uid ) => {
// Only deal with mocked data, return empty attributes for unmocked relations
if ( ! global . strapi . contentTypes [ uid ] ) return { attributes : { } } ;
return global . strapi . contentTypes [ uid ] ;
} ) ;
global . strapi . plugin = jest . fn ( ( name ) => global . strapi . plugins [ name ] ) ;
2023-03-17 10:28:31 +01:00
global . strapi . plugins . documentation = {
service : jest . fn ( ( name ) => {
const mockServices = {
override : override ( { strapi : global . strapi } ) ,
} ;
return mockServices [ name ] ;
} ) ,
} ;
2023-03-14 11:10:55 +01:00
} ) ;
afterAll ( ( ) => {
// Teardown the mocked strapi instance
global . strapi = { } ;
} ) ;
2023-03-17 10:28:31 +01:00
afterEach ( ( ) => {
// Reset the mocked strapi config
global . strapi . config . get = ( ) => defaultConfig ;
} ) ;
2023-03-14 11:10:55 +01:00
it ( 'generates a valid openapi schema' , async ( ) => {
const docService = documentation ( { strapi : global . strapi } ) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
const validatePromise = SwaggerParser . validate ( mockFinalDoc ) ;
await expect ( validatePromise ) . resolves . not . toThrow ( ) ;
} ) ;
2023-03-14 17:52:14 +01:00
describe ( 'Determines the plugins that need documentation' , ( ) => {
it ( 'generates documentation for the default plugins if the user provided nothing in the config' , async ( ) => {
const docService = documentation ( { strapi : global . strapi } ) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
2023-03-15 11:01:09 +01:00
expect ( mockFinalDoc [ 'x-strapi-config' ] . plugins ) . toEqual ( [ 'upload' , 'users-permissions' ] ) ;
2023-03-14 17:52:14 +01:00
} ) ;
it ( "generates documentation only for plugins in the user's config" , async ( ) => {
2023-03-17 10:28:31 +01:00
global . strapi . config . get = ( ) => ( {
2023-03-14 17:52:14 +01:00
... defaultConfig ,
2023-03-14 18:11:26 +01:00
'x-strapi-config' : { ... defaultConfig [ 'x-strapi-config' ] , plugins : [ 'upload' ] } ,
2023-03-14 17:52:14 +01:00
} ) ;
2023-03-15 11:01:09 +01:00
const docService = documentation ( { strapi : global . strapi } ) ;
2023-03-14 17:52:14 +01:00
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
2023-03-14 18:11:26 +01:00
expect ( mockFinalDoc [ 'x-strapi-config' ] . plugins ) . toEqual ( [ 'upload' ] ) ;
2023-03-14 17:52:14 +01:00
} ) ;
it ( 'does not generate documentation for any plugins' , async ( ) => {
2023-03-17 10:28:31 +01:00
global . strapi . config . get = ( ) => ( {
2023-03-14 17:52:14 +01:00
... defaultConfig ,
'x-strapi-config' : { ... defaultConfig [ 'x-strapi-config' ] , plugins : [ ] } ,
} ) ;
2023-03-15 11:01:09 +01:00
const docService = documentation ( { strapi : global . strapi } ) ;
2023-03-14 17:52:14 +01:00
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
expect ( mockFinalDoc [ 'x-strapi-config' ] . plugins ) . toEqual ( [ ] ) ;
} ) ;
} ) ;
2023-03-15 11:01:09 +01:00
describe ( 'Handles user config and overrides' , ( ) => {
it ( 'replaces default config with the user config' , async ( ) => {
const userConfig = {
info : {
version : '4.0.0' ,
title : 'custom-documentation' ,
description : 'custom description' ,
termsOfService : 'custom terms of service' ,
contact : {
name : 'custom-team' ,
email : 'custom-contact-email@something.io' ,
url : 'custom-mywebsite.io' ,
} ,
license : {
name : 'custom Apache 2.0' ,
url : 'custom https://www.apache.org/licenses/LICENSE-2.0.html' ,
} ,
} ,
'x-strapi-config' : {
path : 'custom-documentation' ,
showGeneratedFiles : false ,
generateDefaultResponse : false ,
plugins : [ ] ,
} ,
servers : [ ] , // Servers is generated based on the config.servers so it shouldn't be overridden
externalDocs : {
description : 'custom Find out more' ,
url : 'custom-doc-url' ,
} ,
webhooks : {
test : { } ,
} ,
security : [
{
bearerAuth : [ 'custom' ] ,
} ,
] ,
} ;
2023-03-17 10:28:31 +01:00
global . strapi . config . get = ( ) => ( { ... userConfig } ) ;
2023-03-15 11:01:09 +01:00
const docService = documentation ( { strapi : global . strapi } ) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
expect ( mockFinalDoc . info ) . toEqual ( userConfig . info ) ;
expect ( mockFinalDoc [ 'x-strapi-config' ] ) . toEqual ( userConfig [ 'x-strapi-config' ] ) ;
expect ( mockFinalDoc . externalDocs ) . toEqual ( userConfig . externalDocs ) ;
expect ( mockFinalDoc . security ) . toEqual ( userConfig . security ) ;
expect ( mockFinalDoc . webhooks ) . toEqual ( userConfig . webhooks ) ;
} ) ;
2023-03-17 10:28:31 +01:00
2023-03-14 17:52:14 +01:00
it ( "does not apply an override if the plugin providing the override isn't specified in the x-strapi-config.plugins" , async ( ) => {
2023-03-17 10:28:31 +01:00
global . strapi . config . get = ( ) => ( {
2023-03-14 17:52:14 +01:00
... defaultConfig ,
'x-strapi-config' : { ... defaultConfig [ 'x-strapi-config' ] , plugins : [ ] } ,
} ) ;
const docService = documentation ( { strapi : global . strapi } ) ;
docService . registerDoc (
{
2023-03-15 09:42:51 +01:00
paths : {
'/test' : {
get : {
tags : [ 'Users-Permissions - Users & Roles' ] ,
summary : 'Get list of users' ,
responses : { } ,
} ,
2023-03-14 17:52:14 +01:00
} ,
} ,
} ,
'users-permissions'
) ;
expect ( global . strapi . log . info ) . toHaveBeenCalledWith (
` @strapi/documentation will not use the override provided by users-permissions since the plugin was not specified in the x-strapi-config.plugins array `
) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
expect ( mockFinalDoc . paths [ '/test' ] ) . toBeUndefined ( ) ;
} ) ;
2023-03-15 11:01:09 +01:00
it ( 'overrides (extends) Tags' , async ( ) => {
const docService = documentation ( { strapi : global . strapi } ) ;
// Simulate override from users-permissions plugin
docService . registerDoc (
{
tags : [ 'users-permissions-tag' ] ,
} ,
'users-permissions'
) ;
// Simulate override from upload plugin
docService . registerDoc (
{
tags : [ 'upload-tag' ] ,
} ,
'upload'
) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
expect ( mockFinalDoc . tags ) . toEqual ( [ 'users-permissions-tag' , 'upload-tag' ] ) ;
} ) ;
it ( 'overrides (replaces existing or adds new) Paths' , async ( ) => {
const docService = documentation ( { strapi : global . strapi } ) ;
// Simulate override from upload plugin
docService . registerDoc (
{
paths : {
// This path exists after generating with mock data, replace it
'/upload/files' : {
get : {
responses : [ 'existing-path-test' ] ,
} ,
} ,
// This path does not exist after generating with mock data, add it
'/upload/new-path' : {
get : {
responses : [ 'new-path-test' ] ,
} ,
} ,
} ,
} ,
'upload'
) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
console . log ( mockFinalDoc ) ;
expect ( mockFinalDoc . paths [ '/upload/files' ] . get . responses ) . toEqual ( [ 'existing-path-test' ] ) ;
expect ( Object . keys ( mockFinalDoc . paths [ '/upload/files' ] . get ) ) . toEqual ( [ 'responses' ] ) ;
expect ( mockFinalDoc . paths [ '/upload/new-path' ] . get . responses ) . toEqual ( [ 'new-path-test' ] ) ;
} ) ;
it ( 'overrides (replaces existing or adds new) Components' , async ( ) => {
const docService = documentation ( { strapi : global . strapi } ) ;
// Simulate override from upload plugin
docService . registerDoc (
{
components : {
schemas : {
// This component schema exists after generating with mock data, replace it
UploadFileResponse : {
properties : {
data : { $ref : 'test-existing-component' } ,
meta : { type : 'object' } ,
} ,
} ,
// This component schema does not exist after generating with mock data, add it
UploadFileMockCompo : {
properties : {
data : { $ref : 'test-new-component' } ,
meta : { type : 'object' } ,
} ,
} ,
} ,
} ,
} ,
'upload'
) ;
await docService . generateFullDoc ( ) ;
const lastMockCall = fse . writeJson . mock . calls [ fse . writeJson . mock . calls . length - 1 ] ;
const mockFinalDoc = lastMockCall [ 1 ] ;
expect ( mockFinalDoc . components . schemas . UploadFileResponse . properties . data . $ref ) . toEqual (
'test-existing-component'
) ;
expect ( mockFinalDoc . components . schemas . UploadFileMockCompo . properties . data . $ref ) . toEqual (
'test-new-component'
) ;
} ) ;
2023-03-14 17:52:14 +01:00
} ) ;
2023-03-14 11:10:55 +01:00
} ) ;