0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

chore: add response guard and integration tests for application APIs (#3771)

This commit is contained in:
Charles Zhao 2023-05-06 12:05:50 +08:00 committed by GitHub
parent d2e6e1fd5b
commit 0e46ddacca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 16 deletions

View file

@ -169,6 +169,7 @@ describe('application route', () => {
'http://127.0.0.1',
'http://localhost:3002',
],
postLogoutRedirectUris: [],
},
})
).resolves.toHaveProperty('status', 200);
@ -179,6 +180,7 @@ describe('application route', () => {
applicationRequest.patch('/applications/foo').send({
oidcClientMetadata: {
redirectUris: ['www.example.com', 'com.example://callback'],
postLogoutRedirectUris: [],
},
})
).resolves.toHaveProperty('status', 400);
@ -194,6 +196,7 @@ describe('application route', () => {
'com.example://callback',
'io.logto://Abc123',
],
postLogoutRedirectUris: [],
},
})
).resolves.toHaveProperty('status', 200);
@ -205,6 +208,7 @@ describe('application route', () => {
type: ApplicationType.Native,
oidcClientMetadata: {
redirectUris: ['https://www.example.com', 'com.example/callback'],
postLogoutRedirectUris: [],
},
})
).resolves.toHaveProperty('status', 400);

View file

@ -35,7 +35,11 @@ export default function applicationRoutes<T extends AuthedRouter>(
queries.applicationsRoles;
const { findRoleByRoleName } = queries.roles;
router.get('/applications', koaPagination(), async (ctx, next) => {
router.get(
'/applications',
koaPagination(),
koaGuard({ response: z.array(Applications.guard), status: 200 }),
async (ctx, next) => {
const { limit, offset } = ctx.pagination;
const [{ count }, applications] = await Promise.all([
@ -48,7 +52,8 @@ export default function applicationRoutes<T extends AuthedRouter>(
ctx.body = applications;
return next();
});
}
);
router.post(
'/applications',
@ -57,6 +62,8 @@ export default function applicationRoutes<T extends AuthedRouter>(
.omit({ id: true, createdAt: true })
.partial()
.merge(Applications.createGuard.pick({ name: true, type: true })),
response: Applications.guard,
status: [200, 422],
}),
async (ctx, next) => {
const { oidcClientMetadata, ...rest } = ctx.guard.body;
@ -77,6 +84,7 @@ export default function applicationRoutes<T extends AuthedRouter>(
koaGuard({
params: object({ id: string().min(1) }),
response: Applications.guard.merge(z.object({ isAdmin: z.boolean() })),
status: [200, 404],
}),
async (ctx, next) => {
const {
@ -114,6 +122,8 @@ export default function applicationRoutes<T extends AuthedRouter>(
isAdmin: boolean().optional(),
})
),
response: Applications.guard,
status: [200, 404, 500],
}),
async (ctx, next) => {
const {
@ -135,7 +145,11 @@ export default function applicationRoutes<T extends AuthedRouter>(
assertThat(
internalAdminRole,
new RequestError('entity.not_exists', { name: InternalRole.Admin })
new RequestError({
code: 'entity.not_exists',
status: 500,
data: { name: InternalRole.Admin },
})
);
if (isAdmin && !usedToBeAdmin) {
@ -155,7 +169,11 @@ export default function applicationRoutes<T extends AuthedRouter>(
router.delete(
'/applications/:id',
koaGuard({ params: object({ id: string().min(1) }) }),
koaGuard({
params: object({ id: string().min(1) }),
response: z.undefined(),
status: [204, 404],
}),
async (ctx, next) => {
const { id } = ctx.guard.params;
// Note: will need delete cascade when application is joint with other tables

View file

@ -17,6 +17,8 @@ export const createApplication = async (name: string, type: ApplicationType) =>
})
.json<Application>();
export const getApplications = async () => authedAdminApi.get('applications').json<Application[]>();
export const getApplication = async (applicationId: string) =>
authedAdminApi.get(`applications/${applicationId}`).json<Application>();

View file

@ -6,13 +6,13 @@ import {
getApplication,
updateApplication,
deleteApplication,
getApplications,
} from '#src/api/index.js';
describe('admin console application', () => {
it('should create application successfully', async () => {
const applicationName = 'test-create-app';
const applicationType = ApplicationType.SPA;
const application = await createApplication(applicationName, applicationType);
expect(application.name).toBe(applicationName);
@ -25,7 +25,7 @@ describe('admin console application', () => {
});
it('should update application details successfully', async () => {
const application = await createApplication('test-update-app', ApplicationType.SPA);
const application = await createApplication('test-update-app', ApplicationType.Traditional);
const newApplicationDescription = `new_${application.description ?? ''}`;
@ -46,8 +46,15 @@ describe('admin console application', () => {
expect(updatedApplication.oidcClientMetadata.redirectUris).toEqual(newRedirectUris);
});
it('should fetch all applications created above', async () => {
const applications = await getApplications();
const applicationNames = applications.map(({ name }) => name);
expect(applicationNames).toContain('test-create-app');
expect(applicationNames).toContain('test-update-app');
});
it('should delete application successfully', async () => {
const application = await createApplication('test-delete-app', ApplicationType.SPA);
const application = await createApplication('test-delete-app', ApplicationType.Native);
await deleteApplication(application.id);