From 59a6ad3b7db0a2efbda87334bebefa3a0f776d6e Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Fri, 12 May 2023 17:17:51 +0800 Subject: [PATCH] test(core): add api response guard and error case tests for verification code (#3825) --- packages/core/src/routes/verification-code.ts | 2 + .../src/api/verification-code.ts | 4 +- .../src/tests/api/verification-code.test.ts | 89 ++++++++++++++++++- 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/packages/core/src/routes/verification-code.ts b/packages/core/src/routes/verification-code.ts index 966b4006a..01bfd8bc0 100644 --- a/packages/core/src/routes/verification-code.ts +++ b/packages/core/src/routes/verification-code.ts @@ -21,6 +21,7 @@ export default function verificationCodeRoutes( '/verification-codes', koaGuard({ body: requestVerificationCodePayloadGuard, + status: [204, 400], }), async (ctx, next) => { const code = await createPasscode(undefined, codeType, ctx.guard.body); @@ -36,6 +37,7 @@ export default function verificationCodeRoutes( '/verification-codes/verify', koaGuard({ body: verifyVerificationCodePayloadGuard, + status: [204, 400], }), async (ctx, next) => { const { verificationCode, ...identifier } = ctx.guard.body; diff --git a/packages/integration-tests/src/api/verification-code.ts b/packages/integration-tests/src/api/verification-code.ts index 0bc9155f9..322e558aa 100644 --- a/packages/integration-tests/src/api/verification-code.ts +++ b/packages/integration-tests/src/api/verification-code.ts @@ -1,8 +1,8 @@ -import type { RequestVerificationCodePayload, VerifyVerificationCodePayload } from '@logto/schemas'; +import type { VerifyVerificationCodePayload } from '@logto/schemas'; import { authedAdminApi } from './api.js'; -export const requestVerificationCode = async (payload: RequestVerificationCodePayload) => +export const requestVerificationCode = async (payload: unknown) => authedAdminApi.post('verification-codes', { json: payload }); export const verifyVerificationCode = async (payload: VerifyVerificationCodePayload) => diff --git a/packages/integration-tests/src/tests/api/verification-code.test.ts b/packages/integration-tests/src/tests/api/verification-code.test.ts index 9947d2911..b4cc9c48e 100644 --- a/packages/integration-tests/src/tests/api/verification-code.test.ts +++ b/packages/integration-tests/src/tests/api/verification-code.test.ts @@ -1,7 +1,8 @@ import { VerificationCodeType } from '@logto/connector-kit'; -import { ConnectorType } from '@logto/schemas'; +import { ConnectorType, type RequestVerificationCodePayload } from '@logto/schemas'; import { requestVerificationCode, verifyVerificationCode } from '#src/api/verification-code.js'; +import { createResponseWithCode } from '#src/helpers/admin-tenant.js'; import { clearConnectorsByTypes, setEmailConnector, @@ -30,7 +31,9 @@ describe('Generic verification code through management API', () => { }); it('should create an email verification code on server side', async () => { - await requestVerificationCode({ email: mockEmail }); + const payload: RequestVerificationCodePayload = { email: mockEmail }; + const response = await requestVerificationCode(payload); + expect(response.statusCode).toBe(204); const { code, type, address } = await readVerificationCode(); @@ -40,7 +43,9 @@ describe('Generic verification code through management API', () => { }); it('should create an SMS verification code on server side', async () => { - await requestVerificationCode({ phone: mockPhone }); + const payload: RequestVerificationCodePayload = { phone: mockPhone }; + const response = await requestVerificationCode(payload); + expect(response.statusCode).toBe(204); const { code, type, phone } = await readVerificationCode(); @@ -49,6 +54,60 @@ describe('Generic verification code through management API', () => { expect(code).not.toBeNull(); }); + it('should fail to create a verification code on server side when the email and phone are not provided', async () => { + await expect(requestVerificationCode({ username: 'any_string' })).rejects.toMatchObject( + createResponseWithCode(400) + ); + + await expect(readVerificationCode()).rejects.toThrow(); + }); + + it('should fail to send a verification code on server side when no email connector has been set', async () => { + const emailForTestSendCode = 'test_send@email.com'; + await clearConnectorsByTypes([ConnectorType.Email]); + await expect(requestVerificationCode({ email: emailForTestSendCode })).rejects.toMatchObject( + createResponseWithCode(400) + ); + + await expect( + verifyVerificationCode({ email: emailForTestSendCode, verificationCode: 'any_string' }) + ).rejects.toMatchObject({ + response: { + statusCode: 400, + body: JSON.stringify({ + message: 'Invalid verification code.', + code: 'verification_code.code_mismatch', + }), + }, + }); + + // Restore the email connector + await setEmailConnector(); + }); + + it('should fail to send a verification code on server side when no SMS connector has not been set', async () => { + const phoneForTestSendCode = '1233212321'; + await clearConnectorsByTypes([ConnectorType.Sms]); + await expect(requestVerificationCode({ phone: phoneForTestSendCode })).rejects.toMatchObject( + createResponseWithCode(400) + ); + + await expect( + verifyVerificationCode({ phone: phoneForTestSendCode, verificationCode: 'any_string' }) + ).rejects.toMatchObject({ + response: { + statusCode: 400, + body: JSON.stringify({ + message: 'Invalid verification code.', + code: 'verification_code.code_mismatch', + }), + }, + }); + + // Restore the SMS connector + await setSmsConnector(); + }); + it('should be able to verify the email verification code', async () => { await requestVerificationCode({ email: mockEmail }); @@ -74,6 +133,28 @@ describe('Generic verification code through management API', () => { await readVerificationCode(); await expect( verifyVerificationCode({ phone: mockPhone, verificationCode: '666' }) - ).rejects.toThrow(); + ).rejects.toMatchObject(createResponseWithCode(400)); + }); + + it('should throw when the phone number is not matched', async () => { + const phoneToVerify = '666'; + const phoneToGetCode = mockPhone; + await requestVerificationCode({ phone: phoneToGetCode }); + const { code, phone } = await readVerificationCode(); + expect(phoneToGetCode).toEqual(phone); + await expect( + verifyVerificationCode({ phone: phoneToVerify, verificationCode: code }) + ).rejects.toMatchObject(createResponseWithCode(400)); + }); + + it('should throw when the email is not matched', async () => { + const emailToVerify = 'verify_email@mail.com'; + const emailToGetCode = mockEmail; + await requestVerificationCode({ email: emailToGetCode }); + const { code, address } = await readVerificationCode(); + expect(emailToGetCode).toEqual(address); + await expect( + verifyVerificationCode({ email: emailToVerify, verificationCode: code }) + ).rejects.toMatchObject(createResponseWithCode(400)); }); });