From 56c8436e19037bb4d1edf6f0b62393185e0a0696 Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Thu, 10 Aug 2023 13:24:37 +0800 Subject: [PATCH] test: add sad paths for sign in with password identifier flow (#4294) * test: add sad paths for sign in with password identifier flow * refactor(test): align sie config reset logic for interaction api tests --- .../sad-path.test.ts | 10 +- .../happy-path.test.ts} | 2 +- .../sad-path.test.ts | 201 ++++++++++++++++++ 3 files changed, 208 insertions(+), 5 deletions(-) rename packages/integration-tests/src/tests/api/interaction/{sign-in-with-password-identifier.test.ts => sign-in-with-password-identifier/happy-path.test.ts} (99%) create mode 100644 packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/sad-path.test.ts diff --git a/packages/integration-tests/src/tests/api/interaction/sign-in-with-passcode-identifier/sad-path.test.ts b/packages/integration-tests/src/tests/api/interaction/sign-in-with-passcode-identifier/sad-path.test.ts index 6c0a5b11d..98e384e6c 100644 --- a/packages/integration-tests/src/tests/api/interaction/sign-in-with-passcode-identifier/sad-path.test.ts +++ b/packages/integration-tests/src/tests/api/interaction/sign-in-with-passcode-identifier/sad-path.test.ts @@ -31,10 +31,6 @@ describe('Sign-in flow sad path using verification-code identifiers', () => { await clearConnectorsByTypes([ConnectorType.Email, ConnectorType.Sms]); }); - afterEach(async () => { - await enableAllVerificationCodeSignInMethods(); - }); - it('Should fail to sign in with passcode if sign-in mode is register only', async () => { await updateSignInExperience({ signInMode: SignInMode.Register }); const client = await initClient(); @@ -48,6 +44,9 @@ describe('Sign-in flow sad path using verification-code identifiers', () => { statusCode: 403, } ); + + // Reset + await enableAllVerificationCodeSignInMethods(); }); it('Should fail to sign in if related identifiers are not enabled', async () => { @@ -101,6 +100,9 @@ describe('Sign-in flow sad path using verification-code identifiers', () => { statusCode: 422, } ); + + // Reset + await enableAllVerificationCodeSignInMethods(); }); it('Should fail to update sign in email identifier if verification code is incorrect or mismatch', async () => { diff --git a/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier.test.ts b/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/happy-path.test.ts similarity index 99% rename from packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier.test.ts rename to packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/happy-path.test.ts index c3ae4ddf7..f406925c7 100644 --- a/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier.test.ts +++ b/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/happy-path.test.ts @@ -20,7 +20,7 @@ import { } from '#src/helpers/sign-in-experience.js'; import { generateNewUser, generateNewUserProfile } from '#src/helpers/user.js'; -describe('Sign-In flow using password identifiers', () => { +describe('Sign-in flow using password identifiers', () => { beforeAll(async () => { await enableAllPasswordSignInMethods(); await clearConnectorsByTypes([ConnectorType.Sms, ConnectorType.Email]); diff --git a/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/sad-path.test.ts b/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/sad-path.test.ts new file mode 100644 index 000000000..3c4cd404d --- /dev/null +++ b/packages/integration-tests/src/tests/api/interaction/sign-in-with-password-identifier/sad-path.test.ts @@ -0,0 +1,201 @@ +import { InteractionEvent, SignInMode } from '@logto/schemas'; + +import { suspendUser } from '#src/api/admin-user.js'; +import { putInteraction } from '#src/api/interaction.js'; +import { updateSignInExperience } from '#src/api/sign-in-experience.js'; +import { initClient } from '#src/helpers/client.js'; +import { expectRejects } from '#src/helpers/index.js'; +import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js'; +import { generateNewUser } from '#src/helpers/user.js'; +import { generateName, generatePassword } from '#src/utils.js'; + +describe('Sign-in flow sad path using password identifiers', () => { + beforeAll(async () => { + await enableAllPasswordSignInMethods(); + }); + + it('Should fail to sign-in with password if sign-in mode is register only', async () => { + await updateSignInExperience({ signInMode: SignInMode.Register }); + const client = await initClient(); + + // Username & password + const { + userProfile: { username, password: password1 }, + } = await generateNewUser({ username: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username, password: password1 }, + }), + { + code: 'auth.forbidden', + statusCode: 403, + } + ); + + // Email & password + const { + userProfile: { primaryEmail, password: password2 }, + } = await generateNewUser({ primaryEmail: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { email: primaryEmail, password: password2 }, + }), + { + code: 'auth.forbidden', + statusCode: 403, + } + ); + + // Phone & password + const { + userProfile: { primaryPhone, password: password3 }, + } = await generateNewUser({ primaryPhone: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { phone: primaryPhone, password: password3 }, + }), + { + code: 'auth.forbidden', + statusCode: 403, + } + ); + + // Reset + await enableAllPasswordSignInMethods(); + }); + + it('Should fail to sign-in with password if related identifiers are not enabled', async () => { + await updateSignInExperience({ signIn: { methods: [] } }); + const client = await initClient(); + + // Username & password + const { + userProfile: { username, password: password1 }, + } = await generateNewUser({ username: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username, password: password1 }, + }), + { + code: 'user.sign_in_method_not_enabled', + statusCode: 422, + } + ); + + // Email & password + const { + userProfile: { primaryEmail, password: password2 }, + } = await generateNewUser({ primaryEmail: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { email: primaryEmail, password: password2 }, + }), + { + code: 'user.sign_in_method_not_enabled', + statusCode: 422, + } + ); + + // Phone & password + const { + userProfile: { primaryPhone, password: password3 }, + } = await generateNewUser({ primaryPhone: true, password: true }); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { phone: primaryPhone, password: password3 }, + }), + { + code: 'user.sign_in_method_not_enabled', + statusCode: 422, + } + ); + + // Reset + await enableAllPasswordSignInMethods(); + }); + + it('Should fail to sign-in with username and password if username is not existed', async () => { + const client = await initClient(); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username: generateName(), password: generatePassword() }, + }), + { + code: 'session.invalid_credentials', + statusCode: 422, + } + ); + }); + + it('Should fail to sign-in with username and password if user password is not correct', async () => { + const { + userProfile: { username }, + } = await generateNewUser({ username: true, password: true }); + const client = await initClient(); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username, password: generatePassword() }, + }), + { + code: 'session.invalid_credentials', + statusCode: 422, + } + ); + }); + + it('Should fail to sign-in with username and password if user password is not set', async () => { + const { + userProfile: { username }, + } = await generateNewUser({ username: true, primaryEmail: true }); + const client = await initClient(); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username, password: generatePassword() }, + }), + { + code: 'session.invalid_credentials', + statusCode: 422, + } + ); + }); + + it('Should fail to sign-in with username and password if the user is suspended', async () => { + const { + user, + userProfile: { username, password }, + } = await generateNewUser({ username: true, password: true }); + + await suspendUser(user.id, true); + + const client = await initClient(); + + await expectRejects( + client.send(putInteraction, { + event: InteractionEvent.SignIn, + identifier: { username, password }, + }), + { + code: 'user.suspended', + statusCode: 401, + } + ); + }); +});