0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-20 21:32:31 -05:00

refactor(test): refactor expectRejects helper method to support status code checking (#4292)

* refactor(test): refactor `expectRejects` helper method to support status code checking

* refactor(test): replace `createResponseWithCode` with `expectRejects`
This commit is contained in:
Xiao Yijun 2023-08-07 13:16:09 +08:00 committed by GitHub
parent 65803deaf4
commit ae0322621f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 318 additions and 176 deletions

View file

@ -27,10 +27,6 @@ import { generatePassword, generateUsername } from '#src/utils.js';
export const resourceDefault = getManagementApiResourceIndicator(defaultTenantId);
export const resourceMe = getManagementApiResourceIndicator(adminTenantId, 'me');
export const createResponseWithCode = (statusCode: number) => ({
response: { statusCode },
});
const createUserWithRoles = async (roleNames: string[]) => {
const username = generateUsername();
const password = generatePassword();

View file

@ -52,15 +52,17 @@ export const removeVerificationCode = async (): Promise<void> => {
}
};
export const expectRejects = async (
promise: Promise<unknown>,
code: string,
messageIncludes?: string
) => {
type ExpectedErrorInfo = {
code: string;
statusCode: number;
messageIncludes?: string;
};
export const expectRejects = async (promise: Promise<unknown>, expected: ExpectedErrorInfo) => {
try {
await promise;
} catch (error: unknown) {
expectRequestError(error, code, messageIncludes);
expectRequestError(error, expected);
return;
}
@ -68,7 +70,9 @@ export const expectRejects = async (
fail();
};
export const expectRequestError = (error: unknown, code: string, messageIncludes?: string) => {
export const expectRequestError = (error: unknown, expected: ExpectedErrorInfo) => {
const { code, statusCode, messageIncludes } = expected;
if (!(error instanceof RequestError)) {
fail('Error should be an instance of RequestError');
}
@ -82,6 +86,8 @@ export const expectRequestError = (error: unknown, code: string, messageIncludes
expect(body.code).toEqual(code);
expect(error.response?.statusCode).toEqual(statusCode);
if (messageIncludes) {
expect(body.message.includes(messageIncludes)).toBeTruthy();
}

View file

@ -78,7 +78,10 @@ export const createNewSocialUserWithUsernameAndPassword = async (connectorId: st
connectorData: { state, redirectUri, code, userId: socialUserId },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(patchInteractionIdentifiers, { username, password });
await client.successSend(putInteractionProfile, { connectorId });

View file

@ -2,8 +2,7 @@ import { HTTPError } from 'got';
import { assignRolesToUser, getUserRoles, deleteRoleFromUser } from '#src/api/index.js';
import { createRole } from '#src/api/role.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { createUserByAdmin } from '#src/helpers/index.js';
import { createUserByAdmin, expectRejects } from '#src/helpers/index.js';
describe('admin console user management (roles)', () => {
it('should get empty list successfully', async () => {
@ -27,9 +26,10 @@ describe('admin console user management (roles)', () => {
const role = await createRole();
await assignRolesToUser(user.id, [role.id]);
await expect(assignRolesToUser(user.id, [role.id])).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(assignRolesToUser(user.id, [role.id]), {
code: 'user.role_exists',
statusCode: 422,
});
});
it('should delete role from user successfully', async () => {

View file

@ -178,8 +178,7 @@ describe('admin console user search params', () => {
['search.primaryEmail', 'jerry_swift_jr_2@geek.best'],
['search.primaryEmail', 'jerry_swift_jr_jr@gmail.com'],
]),
'request.invalid_input',
'`exact`'
{ code: 'request.invalid_input', statusCode: 400, messageIncludes: '`exact`' }
);
});
@ -189,8 +188,11 @@ describe('admin console user search params', () => {
['search.primaryEmail', ''],
['search', 'tom'],
]),
'request.invalid_input',
'cannot be empty'
{
code: 'request.invalid_input',
statusCode: 400,
messageIncludes: 'cannot be empty',
}
);
});
@ -200,8 +202,11 @@ describe('admin console user search params', () => {
['search.primaryEmail', '%gmail%'],
['mode.primaryEmail', 'similar_to'],
]),
'request.invalid_input',
'case-insensitive'
{
code: 'request.invalid_input',
statusCode: 400,
messageIncludes: 'case-insensitive',
}
);
});
@ -212,21 +217,27 @@ describe('admin console user search params', () => {
['search.primaryEmail', '%gmail%'],
['mode.primaryEmail', 'similar to'],
]),
'request.invalid_input',
'is not valid'
),
expectRejects(
getUsers<User[]>([['search.email', '%gmail%']]),
'request.invalid_input',
'is not valid'
{
code: 'request.invalid_input',
statusCode: 400,
messageIncludes: 'is not valid',
}
),
expectRejects(getUsers<User[]>([['search.email', '%gmail%']]), {
code: 'request.invalid_input',
statusCode: 400,
messageIncludes: 'is not valid',
}),
expectRejects(
getUsers<User[]>([
['search.primaryEmail', '%gmail%'],
['joint', 'and1'],
]),
'request.invalid_input',
'is not valid'
{
code: 'request.invalid_input',
statusCode: 400,
messageIncludes: 'is not valid',
}
),
]);
});

View file

@ -17,8 +17,7 @@ import {
postUserIdentity,
verifyUserPassword,
} from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { createUserByAdmin } from '#src/helpers/index.js';
import { createUserByAdmin, expectRejects } from '#src/helpers/index.js';
import { createNewSocialUserWithUsernameAndPassword } from '#src/helpers/interactions.js';
import { generateUsername, generateEmail, generatePhone, generatePassword } from '#src/utils.js';
@ -38,19 +37,25 @@ describe('admin console user management', () => {
generatePhone(),
];
await createUserByAdmin(username, password, email, phone);
await expect(createUserByAdmin(username, password)).rejects.toMatchObject(
createResponseWithCode(422)
);
await expect(createUserByAdmin(undefined, undefined, email)).rejects.toMatchObject(
createResponseWithCode(422)
);
await expect(createUserByAdmin(undefined, undefined, undefined, phone)).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(createUserByAdmin(username, password), {
code: 'user.username_already_in_use',
statusCode: 422,
});
await expectRejects(createUserByAdmin(undefined, undefined, email), {
code: 'user.email_already_in_use',
statusCode: 422,
});
await expectRejects(createUserByAdmin(undefined, undefined, undefined, phone), {
code: 'user.phone_already_in_use',
statusCode: 422,
});
});
it('should fail when get user by invalid id', async () => {
await expect(getUser('invalid-user-id')).rejects.toMatchObject(createResponseWithCode(404));
await expectRejects(getUser('invalid-user-id'), {
code: 'entity.not_found',
statusCode: 404,
});
});
it('should update userinfo successfully', async () => {
@ -74,7 +79,10 @@ describe('admin console user management', () => {
it('should respond 422 when no update data provided', async () => {
const user = await createUserByAdmin();
await expect(updateUser(user.id, {})).rejects.toMatchObject(createResponseWithCode(422));
await expectRejects(updateUser(user.id, {}), {
code: 'entity.invalid_input',
statusCode: 422,
});
});
it('should fail when update userinfo with conflict identifiers', async () => {
@ -82,15 +90,20 @@ describe('admin console user management', () => {
await createUserByAdmin(username, undefined, email, phone);
const anotherUser = await createUserByAdmin();
await expect(updateUser(anotherUser.id, { username })).rejects.toMatchObject(
createResponseWithCode(422)
);
await expect(updateUser(anotherUser.id, { primaryEmail: email })).rejects.toMatchObject(
createResponseWithCode(422)
);
await expect(updateUser(anotherUser.id, { primaryPhone: phone })).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(updateUser(anotherUser.id, { username }), {
code: 'user.username_already_in_use',
statusCode: 422,
});
await expectRejects(updateUser(anotherUser.id, { primaryEmail: email }), {
code: 'user.email_already_in_use',
statusCode: 422,
});
await expectRejects(updateUser(anotherUser.id, { primaryPhone: phone }), {
code: 'user.phone_already_in_use',
statusCode: 422,
});
});
it('should delete user successfully', async () => {
@ -171,22 +184,23 @@ describe('admin console user management', () => {
it('should return 204 if password is correct', async () => {
const user = await createUserByAdmin(undefined, 'new_password');
expect(await verifyUserPassword(user.id, 'new_password')).toHaveProperty('statusCode', 204);
void deleteUser(user.id);
await deleteUser(user.id);
});
it('should return 422 if password is incorrect', async () => {
const user = await createUserByAdmin(undefined, 'new_password');
await expect(verifyUserPassword(user.id, 'wrong_password')).rejects.toMatchObject(
createResponseWithCode(422)
);
void deleteUser(user.id);
await expectRejects(verifyUserPassword(user.id, 'wrong_password'), {
code: 'session.invalid_credentials',
statusCode: 422,
});
await deleteUser(user.id);
});
it('should return 400 if password is empty', async () => {
const user = await createUserByAdmin();
await expect(verifyUserPassword(user.id, '')).rejects.toMatchObject(
createResponseWithCode(400)
);
void deleteUser(user.id);
await expectRejects(verifyUserPassword(user.id, ''), {
code: 'guard.invalid_input',
statusCode: 400,
});
});
});

View file

@ -22,7 +22,7 @@ import {
listConnectorFactories,
getConnectorFactory,
} from '#src/api/connector.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { expectRejects } from '#src/helpers/index.js';
const connectorIdMap = new Map<string, string>();
@ -158,32 +158,39 @@ test('connector set-up flow', async () => {
test('create connector with non-exist connectorId', async () => {
await cleanUpConnectorTable();
await expect(postConnector({ connectorId: 'non-exist-id' })).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(postConnector({ connectorId: 'non-exist-id' }), {
code: 'connector.not_found_with_connector_id',
statusCode: 422,
});
});
test('create non standard social connector with target', async () => {
await cleanUpConnectorTable();
await expect(
postConnector({ connectorId: mockSocialConnectorId, metadata: { target: 'target' } })
).rejects.toMatchObject(createResponseWithCode(400));
await expectRejects(
postConnector({ connectorId: mockSocialConnectorId, metadata: { target: 'target' } }),
{
code: 'connector.cannot_overwrite_metadata_for_non_standard_connector',
statusCode: 400,
}
);
});
test('create duplicated social connector', async () => {
await cleanUpConnectorTable();
await postConnector({ connectorId: mockSocialConnectorId });
await expect(postConnector({ connectorId: mockSocialConnectorId })).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(postConnector({ connectorId: mockSocialConnectorId }), {
code: 'connector.multiple_instances_not_supported',
statusCode: 422,
});
});
test('override metadata for non-standard social connector', async () => {
await cleanUpConnectorTable();
const { id } = await postConnector({ connectorId: mockSocialConnectorId });
await expect(updateConnectorConfig(id, {}, { target: 'target' })).rejects.toMatchObject(
createResponseWithCode(400)
);
await expectRejects(updateConnectorConfig(id, {}, { target: 'target' }), {
code: 'connector.cannot_overwrite_metadata_for_non_standard_connector',
statusCode: 400,
});
});
test('send SMS/email test message', async () => {

View file

@ -2,8 +2,7 @@ import { SignInIdentifier } from '@logto/schemas';
import type { StatisticsData } from '#src/api/index.js';
import { api, getTotalUsersCount, getNewUsersData, getActiveUsersData } from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { createUserByAdmin } from '#src/helpers/index.js';
import { createUserByAdmin, expectRejects } from '#src/helpers/index.js';
import { registerNewUser, signInWithPassword } from '#src/helpers/interactions.js';
import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js';
import { generateUsername, generatePassword } from '#src/utils.js';
@ -18,13 +17,18 @@ describe('admin console dashboard', () => {
});
it('non authorized request should return 401', async () => {
await expect(api.get('dashboard/users/total')).rejects.toMatchObject(
createResponseWithCode(401)
);
await expect(api.get('dashboard/users/new')).rejects.toMatchObject(createResponseWithCode(401));
await expect(api.get('dashboard/users/active')).rejects.toMatchObject(
createResponseWithCode(401)
);
await expectRejects(api.get('dashboard/users/total'), {
code: 'auth.authorization_header_missing',
statusCode: 401,
});
await expectRejects(api.get('dashboard/users/new'), {
code: 'auth.authorization_header_missing',
statusCode: 401,
});
await expectRejects(api.get('dashboard/users/active'), {
code: 'auth.authorization_header_missing',
statusCode: 401,
});
});
it('should get total user count successfully', async () => {

View file

@ -2,8 +2,8 @@ import type { Hook } from '@logto/schemas';
import { HookEvent } from '@logto/schemas';
import { authedAdminApi } from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { getHookCreationPayload } from '#src/helpers/hook.js';
import { expectRejects } from '#src/helpers/index.js';
describe('hooks', () => {
it('should be able to create, query, update, and delete a hook', async () => {
@ -20,10 +20,10 @@ describe('hooks', () => {
.json<Hook>()
).toMatchObject({ ...created, events: [HookEvent.PostSignIn] });
expect(await authedAdminApi.delete(`hooks/${created.id}`)).toHaveProperty('statusCode', 204);
await expect(authedAdminApi.get(`hooks/${created.id}`)).rejects.toHaveProperty(
'response.statusCode',
404
);
await expectRejects(authedAdminApi.get(`hooks/${created.id}`), {
code: 'entity.not_exists_with_id',
statusCode: 404,
});
});
it('should be able to create, query, update, and delete a hook by the original API', async () => {
@ -49,10 +49,10 @@ describe('hooks', () => {
event: HookEvent.PostSignIn,
});
expect(await authedAdminApi.delete(`hooks/${created.id}`)).toHaveProperty('statusCode', 204);
await expect(authedAdminApi.get(`hooks/${created.id}`)).rejects.toHaveProperty(
'response.statusCode',
404
);
await expectRejects(authedAdminApi.get(`hooks/${created.id}`), {
code: 'entity.not_exists_with_id',
statusCode: 404,
});
});
it('should return hooks with pagination if pagination-related query params are provided', async () => {
@ -76,9 +76,10 @@ describe('hooks', () => {
url: 'not_work_url',
},
};
await expect(authedAdminApi.post('hooks', { json: payload })).rejects.toMatchObject(
createResponseWithCode(400)
);
await expectRejects(authedAdminApi.post('hooks', { json: payload }), {
code: 'guard.invalid_input',
statusCode: 400,
});
});
it('should throw error when no event is provided when creating a hook', async () => {
@ -88,9 +89,10 @@ describe('hooks', () => {
url: 'not_work_url',
},
};
await expect(authedAdminApi.post('hooks', { json: payload })).rejects.toMatchObject(
createResponseWithCode(400)
);
await expectRejects(authedAdminApi.post('hooks', { json: payload }), {
code: 'hook.missing_events',
statusCode: 400,
});
});
it('should throw error if update a hook with a invalid hook id', async () => {
@ -98,14 +100,16 @@ describe('hooks', () => {
name: 'new_hook_name',
};
await expect(authedAdminApi.patch('hooks/invalid_id', { json: payload })).rejects.toMatchObject(
createResponseWithCode(404)
);
await expectRejects(authedAdminApi.patch('hooks/invalid_id', { json: payload }), {
code: 'entity.not_exists',
statusCode: 404,
});
});
it('should throw error if regenerate a hook signing key with a invalid hook id', async () => {
await expect(authedAdminApi.patch('hooks/invalid_id/signing-key')).rejects.toMatchObject(
createResponseWithCode(404)
);
await expectRejects(authedAdminApi.patch('hooks/invalid_id/signing-key'), {
code: 'entity.not_exists',
statusCode: 404,
});
});
});

View file

@ -1,9 +1,8 @@
import { HookEvent, type Hook } from '@logto/schemas';
import { authedAdminApi } from '#src/api/api.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { getHookCreationPayload } from '#src/helpers/hook.js';
import { createMockServer } from '#src/helpers/index.js';
import { createMockServer, expectRejects } from '#src/helpers/index.js';
const responseSuccessPort = 9999;
const responseSuccessEndpoint = `http://localhost:${responseSuccessPort}`;
@ -46,21 +45,29 @@ describe('hook testing', () => {
it('should return 404 if the hook to test does not exist', async () => {
const invalidHookId = 'invalid_id';
await expect(
await expectRejects(
authedAdminApi.post(`hooks/${invalidHookId}/test`, {
json: { events: [HookEvent.PostSignIn], config: { url: responseSuccessEndpoint } },
})
).rejects.toMatchObject(createResponseWithCode(404));
}),
{
code: 'entity.not_exists_with_id',
statusCode: 404,
}
);
});
it('should return 422 if the hook endpoint is not working', async () => {
const payload = getHookCreationPayload(HookEvent.PostRegister);
const created = await authedAdminApi.post('hooks', { json: payload }).json<Hook>();
await expect(
await expectRejects(
authedAdminApi.post(`hooks/${created.id}/test`, {
json: { events: [HookEvent.PostSignIn], config: { url: 'not_work_url' } },
})
).rejects.toMatchObject(createResponseWithCode(422));
}),
{
code: 'hook.send_test_payload_failed',
statusCode: 422,
}
);
// Clean Up
await authedAdminApi.delete(`hooks/${created.id}`);

View file

@ -62,11 +62,17 @@ describe('reset password', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.new_password_required_in_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.new_password_required_in_profile',
statusCode: 422,
});
await client.successSend(putInteractionProfile, { password: userProfile.password });
await expectRejects(client.submitInteraction(), 'user.same_password');
await expectRejects(client.submitInteraction(), {
code: 'user.same_password',
statusCode: 422,
});
const newPasswordRecord = generatePassword();
@ -115,11 +121,17 @@ describe('reset password', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.new_password_required_in_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.new_password_required_in_profile',
statusCode: 422,
});
await client.successSend(putInteractionProfile, { password: userProfile.password });
await expectRejects(client.submitInteraction(), 'user.same_password');
await expectRejects(client.submitInteraction(), {
code: 'user.same_password',
statusCode: 422,
});
const newPasswordRecord = generatePassword();

View file

@ -138,7 +138,10 @@ describe('Register with passwordless identifier', () => {
email: primaryEmail,
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
await client.successSend(patchInteractionProfile, {
password,
@ -240,7 +243,10 @@ describe('Register with passwordless identifier', () => {
phone: primaryPhone,
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
await client.successSend(patchInteractionProfile, {
password,
@ -308,7 +314,10 @@ describe('Register with passwordless identifier', () => {
email: primaryEmail,
});
await expectRejects(client.submitInteraction(), 'user.email_already_in_use');
await expectRejects(client.submitInteraction(), {
code: 'user.email_already_in_use',
statusCode: 422,
});
await client.successSend(deleteInteractionProfile);
await client.successSend(putInteractionEvent, { event: InteractionEvent.SignIn });
@ -360,7 +369,10 @@ describe('Register with passwordless identifier', () => {
phone: primaryPhone,
});
await expectRejects(client.submitInteraction(), 'user.phone_already_in_use');
await expectRejects(client.submitInteraction(), {
code: 'user.phone_already_in_use',
statusCode: 422,
});
await client.successSend(deleteInteractionProfile);
await client.successSend(putInteractionEvent, { event: InteractionEvent.SignIn });

View file

@ -124,7 +124,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.user_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.user_not_exist',
statusCode: 404,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { email: newEmail });
@ -163,7 +166,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.user_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.user_not_exist',
statusCode: 404,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { phone: newPhone });
@ -205,7 +211,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
// Fulfill user profile
await client.successSend(putInteractionProfile, {
@ -264,7 +273,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
// Fulfill user profile with existing password
await client.successSend(putInteractionProfile, {
@ -272,7 +284,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
password,
});
await expectRejects(client.submitInteraction(), 'user.password_exists_in_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.password_exists_in_profile',
statusCode: 400,
});
await client.successSend(putInteractionProfile, {
username,
@ -315,7 +330,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
verificationCode: code,
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
// Fulfill user profile with existing password
await client.successSend(putInteractionProfile, {
@ -323,7 +341,10 @@ describe('Sign-In flow using verification-code identifiers', () => {
password,
});
await expectRejects(client.submitInteraction(), 'user.username_already_in_use');
await expectRejects(client.submitInteraction(), {
code: 'user.username_already_in_use',
statusCode: 422,
});
await client.successSend(putInteractionProfile, {
username,

View file

@ -112,7 +112,10 @@ describe('Sign-In flow using password identifiers', () => {
},
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
await client.successSend(sendVerificationCode, {
email: primaryEmail,
@ -171,7 +174,10 @@ describe('Sign-In flow using password identifiers', () => {
},
});
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
await client.successSend(sendVerificationCode, {
phone: primaryPhone,

View file

@ -63,7 +63,10 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });
@ -116,7 +119,10 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId, email: socialEmail },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });
@ -149,7 +155,10 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId, phone: socialPhone },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });
@ -192,7 +201,10 @@ describe('Social Identifier Interactions', () => {
},
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(patchInteractionIdentifiers, {
connectorId,
@ -253,12 +265,18 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });
await expectRejects(client.submitInteraction(), 'user.missing_profile');
await expectRejects(client.submitInteraction(), {
code: 'user.missing_profile',
statusCode: 422,
});
await client.successSend(patchInteractionProfile, { username: generateUsername() });
@ -291,7 +309,10 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId, email: generateEmail() },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });
@ -325,7 +346,10 @@ describe('Social Identifier Interactions', () => {
connectorData: { state, redirectUri, code, userId: socialUserId, phone: generatePhone() },
});
await expectRejects(client.submitInteraction(), 'user.identity_not_exist');
await expectRejects(client.submitInteraction(), {
code: 'user.identity_not_exist',
statusCode: 422,
});
await client.successSend(putInteractionEvent, { event: InteractionEvent.Register });
await client.successSend(putInteractionProfile, { connectorId });

View file

@ -1,5 +1,5 @@
import { getLog, getAuditLogs } from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { expectRejects } from '#src/helpers/index.js';
describe('logs', () => {
it('should get logs successfully', async () => {
@ -20,6 +20,9 @@ describe('logs', () => {
});
it('should throw on getting non-exist log detail', async () => {
await expect(getLog('non-exist-log-id')).rejects.toMatchObject(createResponseWithCode(404));
await expectRejects(getLog('non-exist-log-id'), {
code: 'entity.not_exists_with_id',
statusCode: 404,
});
});
});

View file

@ -2,18 +2,19 @@ import { got } from 'got';
import { logtoConsoleUrl, logtoUrl } from '#src/constants.js';
import {
createResponseWithCode,
createUserWithAllRolesAndSignInToClient,
deleteUser,
resourceDefault,
resourceMe,
} from '#src/helpers/admin-tenant.js';
import { expectRejects } from '#src/helpers/index.js';
describe('me', () => {
it('should only be available in admin tenant', async () => {
await expect(got.get(new URL('/me/custom-data', logtoConsoleUrl))).rejects.toMatchObject(
createResponseWithCode(401)
);
await expectRejects(got.get(new URL('/me/custom-data', logtoConsoleUrl)), {
code: 'auth.authorization_header_missing',
statusCode: 401,
});
// Redirect to UI
const response = await got.get(new URL('/me/custom-data', logtoUrl));
@ -24,11 +25,15 @@ describe('me', () => {
it('should only recognize the access token with correct resource and scope', async () => {
const { id, client } = await createUserWithAllRolesAndSignInToClient();
await expect(
await expectRejects(
got.get(logtoConsoleUrl + '/me/custom-data', {
headers: { authorization: `Bearer ${await client.getAccessToken(resourceDefault)}` },
})
).rejects.toMatchObject(createResponseWithCode(401));
}),
{
code: 'auth.unauthorized',
statusCode: 401,
}
);
await expect(
got.get(logtoConsoleUrl + '/me/custom-data', {

View file

@ -9,7 +9,7 @@ import {
deleteResource,
setDefaultResource,
} from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { expectRejects } from '#src/helpers/index.js';
import { generateResourceIndicator, generateResourceName } from '#src/utils.js';
describe('admin console api resources', () => {
@ -47,9 +47,10 @@ describe('admin console api resources', () => {
// Create second resource with same indicator should throw
const resourceName2 = generateResourceName();
await expect(createResource(resourceName2, resourceIndicator)).rejects.toMatchObject(
createResponseWithCode(422)
);
await expectRejects(createResource(resourceName2, resourceIndicator), {
code: 'resource.resource_identifier_in_use',
statusCode: 422,
});
});
it('should get resource list successfully', async () => {

View file

@ -1,7 +1,7 @@
import { SignInIdentifier } from '@logto/schemas';
import { getSignInExperience, updateSignInExperience } from '#src/api/index.js';
import { createResponseWithCode } from '#src/helpers/admin-tenant.js';
import { expectRejects } from '#src/helpers/index.js';
describe('admin console sign-in experience', () => {
it('should get sign-in experience successfully', async () => {
@ -38,8 +38,9 @@ describe('admin console sign-in experience', () => {
},
};
await expect(updateSignInExperience(newSignInExperience)).rejects.toMatchObject(
createResponseWithCode(400)
);
await expectRejects(updateSignInExperience(newSignInExperience), {
code: 'sign_in_experiences.username_requires_password',
statusCode: 400,
});
});
});

View file

@ -2,13 +2,12 @@ import { VerificationCodeType } from '@logto/connector-kit';
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,
setSmsConnector,
} from '#src/helpers/connector.js';
import { readVerificationCode, removeVerificationCode } from '#src/helpers/index.js';
import { expectRejects, readVerificationCode, removeVerificationCode } from '#src/helpers/index.js';
import { enableAllVerificationCodeSignInMethods } from '#src/helpers/sign-in-experience.js';
describe('Generic verification code through management API', () => {
@ -55,9 +54,10 @@ describe('Generic verification code through management API', () => {
});
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 expectRejects(requestVerificationCode({ username: 'any_string' }), {
code: 'guard.invalid_input',
statusCode: 400,
});
await expect(readVerificationCode()).rejects.toThrow();
});
@ -65,9 +65,10 @@ describe('Generic verification code through management API', () => {
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 expectRejects(requestVerificationCode({ email: emailForTestSendCode }), {
code: 'connector.not_found',
statusCode: 400,
});
await expect(
verifyVerificationCode({ email: emailForTestSendCode, verificationCode: 'any_string' })
@ -88,9 +89,10 @@ describe('Generic verification code through management API', () => {
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 expectRejects(requestVerificationCode({ phone: phoneForTestSendCode }), {
code: 'connector.not_found',
statusCode: 400,
});
await expect(
verifyVerificationCode({ phone: phoneForTestSendCode, verificationCode: 'any_string' })
@ -131,9 +133,10 @@ describe('Generic verification code through management API', () => {
it('should throw when the code is not valid', async () => {
await requestVerificationCode({ phone: mockPhone });
await readVerificationCode();
await expect(
verifyVerificationCode({ phone: mockPhone, verificationCode: '666' })
).rejects.toMatchObject(createResponseWithCode(400));
await expectRejects(verifyVerificationCode({ phone: mockPhone, verificationCode: '666' }), {
code: 'verification_code.code_mismatch',
statusCode: 400,
});
});
it('should throw when the phone number is not matched', async () => {
@ -142,9 +145,10 @@ describe('Generic verification code through management API', () => {
await requestVerificationCode({ phone: phoneToGetCode });
const { code, phone } = await readVerificationCode();
expect(phoneToGetCode).toEqual(phone);
await expect(
verifyVerificationCode({ phone: phoneToVerify, verificationCode: code })
).rejects.toMatchObject(createResponseWithCode(400));
await expectRejects(verifyVerificationCode({ phone: phoneToVerify, verificationCode: code }), {
code: 'verification_code.not_found',
statusCode: 400,
});
});
it('should throw when the email is not matched', async () => {
@ -153,8 +157,9 @@ describe('Generic verification code through management API', () => {
await requestVerificationCode({ email: emailToGetCode });
const { code, address } = await readVerificationCode();
expect(emailToGetCode).toEqual(address);
await expect(
verifyVerificationCode({ email: emailToVerify, verificationCode: code })
).rejects.toMatchObject(createResponseWithCode(400));
await expectRejects(verifyVerificationCode({ email: emailToVerify, verificationCode: code }), {
code: 'verification_code.not_found',
statusCode: 400,
});
});
});