0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

refactor(core): fix tests

This commit is contained in:
Gao Sun 2023-11-12 00:27:01 +08:00
parent 35e44a54d3
commit 49aabe0290
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
4 changed files with 55 additions and 26 deletions

View file

@ -8,7 +8,8 @@ import koaGuard from '#src/middleware/koa-guard.js';
import koaPagination from '#src/middleware/koa-pagination.js';
import type { AnonymousRouter } from '#src/routes/types.js';
const { default: swaggerRoutes, paginationParameters } = await import('./index.js');
const { default: swaggerRoutes } = await import('./index.js');
const { paginationParameters } = await import('./utils/parameters.js');
const createSwaggerRequest = (
allRouters: Router[],
@ -79,7 +80,7 @@ describe('GET /swagger.json', () => {
get: { tags: ['Mock'] },
},
'/api/.well-known': {
put: { tags: ['.well-known'] },
put: { tags: ['Well known'] },
},
});
});
@ -101,22 +102,18 @@ describe('GET /swagger.json', () => {
const response = await swaggerRequest.get('/swagger.json');
expect(response.body.paths).toMatchObject({
'/api/mock/:id/:field': {
get: {
parameters: [
{
name: 'id',
in: 'path',
required: true,
schema: { type: 'number' },
},
{
name: 'field',
in: 'path',
required: true,
schema: { type: 'string' },
},
],
},
parameters: [
{
$ref: '#/components/parameters/mocId:root',
},
{
name: 'field',
in: 'path',
required: true,
schema: { type: 'string' },
},
],
get: {},
},
});
});

View file

@ -17,7 +17,7 @@ import { translationSchemas, zodTypeToSwagger } from '#src/utils/zod.js';
import type { AnonymousRouter } from '../types.js';
import { buildTag, findSupplementFiles } from './utils/general.js';
import { buildTag, findSupplementFiles, normalizePath } from './utils/general.js';
import {
type ParameterArray,
buildParameters,
@ -103,6 +103,20 @@ const isManagementApiRouter = ({ stack }: Router) =>
.filter(({ path }) => !path.includes('.*'))
.some(({ stack }) => stack.some((function_) => isKoaAuthMiddleware(function_)));
// Add more components here to cover more ID parameters in paths. For example, if there is a
// path `/foo/:barBazId`, then add `bar-baz` to the array.
const identifiableEntityNames = [
'application',
'connector',
'resource',
'user',
'log',
'role',
'scope',
'hook',
'domain',
];
/**
* Attach the `/swagger.json` route which returns the generated OpenAPI document for the
* management APIs.
@ -123,14 +137,14 @@ export default function swaggerRoutes<T extends AnonymousRouter, R extends Route
return (
router.stack
// Filter out universal routes (mostly like a proxy route to withtyped)
.filter(({ path }) => !path.includes('.*') && path.startsWith('/organization'))
.filter(({ path }) => !path.includes('.*'))
.flatMap<RouteObject>(({ path: routerPath, stack, methods }) =>
methods
.map((method) => method.toLowerCase())
// There is no need to show the HEAD method.
.filter((method): method is OpenAPIV3.HttpMethods => method !== 'head')
.map((httpMethod) => {
const path = `/api${routerPath}`;
const path = normalizePath(routerPath);
const { pathParameters, ...operation } = buildOperation(
stack,
routerPath,
@ -180,7 +194,7 @@ export default function swaggerRoutes<T extends AnonymousRouter, R extends Route
paths: Object.fromEntries(pathMap),
components: {
schemas: translationSchemas,
parameters: ['organization', 'organization-role', 'organization-scope', 'user'].reduce(
parameters: identifiableEntityNames.reduce(
(previous, entityName) => ({ ...previous, ...buildPathIdParameters(entityName) }),
{}
),

View file

@ -14,8 +14,12 @@ export const getRootComponent = (path?: string) => path?.split('/')[1];
* component name.
* @example '/organization-roles' -> 'Organization roles'
*/
export const buildTag = (path: string) =>
capitalize((getRootComponent(path) ?? 'General').replaceAll('-', ' '));
export const buildTag = (path: string) => {
const rootComponent = (getRootComponent(path) ?? 'General').replaceAll('-', ' ');
return rootComponent.startsWith('.')
? capitalize(rootComponent.slice(1))
: capitalize(rootComponent);
};
/**
* Recursively find all supplement files (files end with `.openapi.json`) for the given
@ -37,3 +41,16 @@ export const findSupplementFiles = async (directory: string) => {
return result;
};
/* eslint-enable @silverhand/fp/no-mutating-methods, no-await-in-loop */
/**
* Normalize the path to the OpenAPI path by adding `/api` prefix and replacing the path parameters
* with OpenAPI path parameters.
*
* @example
* normalizePath('/organization/:id') -> '/api/organization/{id}'
*/
export const normalizePath = (path: string) =>
`/api${path}`
.split('/')
.map((part) => (part.startsWith(':') ? `{${part.slice(1)}}` : part))
.join('/');

View file

@ -336,8 +336,7 @@ export default class SchemaRouter<
`/:id/${pathname}/:${camelCaseSchemaId(relationSchema)}`,
koaGuard({
params: z.object({ id: z.string().min(1), [relationSchemaId]: z.string().min(1) }),
// Should be 422 if the relation doesn't exist, update until we change the error handling
status: [204, 404],
status: [204, 422],
}),
async (ctx, next) => {
const {
@ -345,7 +344,9 @@ export default class SchemaRouter<
} = ctx.guard;
await relationQueries.delete({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- `koaGuard()` ensures the value is not `undefined`
[columns.schemaId]: id!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- `koaGuard()` ensures the value is not `undefined`
[columns.relationSchemaId]: relationId!,
});