mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
test: add integration tests for roles (#2900)
This commit is contained in:
parent
375a8f4842
commit
175516a711
8 changed files with 259 additions and 9 deletions
|
@ -132,7 +132,7 @@ describe('role routes', () => {
|
|||
const response = await roleRequester
|
||||
.patch(`/roles/${mockRole.id}`)
|
||||
.send({ name: mockRole.name });
|
||||
expect(response.status).toEqual(400);
|
||||
expect(response.status).toEqual(422);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -158,11 +158,12 @@ describe('role routes', () => {
|
|||
|
||||
it('POST /roles/:id/scopes', async () => {
|
||||
findRoleById.mockResolvedValueOnce(mockRole);
|
||||
findRolesScopesByRoleId.mockResolvedValueOnce([]);
|
||||
findRolesScopesByRoleId.mockResolvedValue([]);
|
||||
findScopesByIds.mockResolvedValueOnce([]);
|
||||
const response = await roleRequester.post(`/roles/${mockRole.id}/scopes`).send({
|
||||
scopeIds: [mockScope.id],
|
||||
});
|
||||
expect(response.status).toEqual(201);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(insertRolesScopes).toHaveBeenCalledWith([
|
||||
{ roleId: mockRole.id, scopeId: mockScope.id },
|
||||
]);
|
||||
|
@ -181,7 +182,7 @@ describe('role routes', () => {
|
|||
findUsersByIds.mockResolvedValueOnce([mockUser]);
|
||||
const response = await roleRequester.get(`/roles/${mockRole.id}/users`);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual([mockUser]);
|
||||
expect(response.body[0]).toHaveProperty('id', mockUser.id);
|
||||
});
|
||||
|
||||
it('POST /roles/:id/users', async () => {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { buildIdGenerator } from '@logto/core-kit';
|
||||
import type { RoleResponse, ScopeResponse } from '@logto/schemas';
|
||||
import { Roles } from '@logto/schemas';
|
||||
import { userInfoSelectFields, Roles } from '@logto/schemas';
|
||||
import { tryThat } from '@logto/shared';
|
||||
import { pick } from '@silverhand/essentials';
|
||||
import { object, string, z } from 'zod';
|
||||
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
|
@ -107,6 +108,7 @@ export default function roleRoutes<T extends AuthedRouter>(...[router]: RouterIn
|
|||
new RequestError({
|
||||
code: 'role.name_in_use',
|
||||
name: roleBody.name,
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -156,7 +158,14 @@ export default function roleRoutes<T extends AuthedRouter>(...[router]: RouterIn
|
|||
} = ctx.guard;
|
||||
|
||||
await findRoleById(id);
|
||||
assertThat(!name || !(await findRoleByRoleName(name, id)), 'role.name_in_use');
|
||||
assertThat(
|
||||
!name || !(await findRoleByRoleName(name, id)),
|
||||
new RequestError({
|
||||
code: 'role.name_in_use',
|
||||
name,
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
ctx.body = await updateRoleById(id, body);
|
||||
|
||||
return next();
|
||||
|
@ -238,7 +247,10 @@ export default function roleRoutes<T extends AuthedRouter>(...[router]: RouterIn
|
|||
|
||||
await Promise.all(scopeIds.map(async (scopeId) => findScopeById(scopeId)));
|
||||
await insertRolesScopes(scopeIds.map((scopeId) => ({ roleId: id, scopeId })));
|
||||
ctx.status = 201;
|
||||
|
||||
const newRolesScopes = await findRolesScopesByRoleId(id);
|
||||
const scopes = await findScopesByIds(newRolesScopes.map(({ scopeId }) => scopeId));
|
||||
ctx.body = scopes;
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -272,7 +284,8 @@ export default function roleRoutes<T extends AuthedRouter>(...[router]: RouterIn
|
|||
|
||||
await findRoleById(id);
|
||||
const usersRoles = await findUsersRolesByRoleId(id);
|
||||
ctx.body = await findUsersByIds(usersRoles.map(({ userId }) => userId));
|
||||
const users = await findUsersByIds(usersRoles.map(({ userId }) => userId));
|
||||
ctx.body = users.map((user) => pick(user, ...userInfoSelectFields));
|
||||
|
||||
return next();
|
||||
}
|
||||
|
|
55
packages/integration-tests/src/api/role.ts
Normal file
55
packages/integration-tests/src/api/role.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import type { CreateRole, Role, Scope, User } from '@logto/schemas';
|
||||
|
||||
import { generateRoleName } from '#src/utils.js';
|
||||
|
||||
import { authedAdminApi } from './api.js';
|
||||
|
||||
export const createRole = (name?: string, description?: string, scopeIds?: string[]) =>
|
||||
authedAdminApi
|
||||
.post('roles', {
|
||||
json: {
|
||||
name: name ?? generateRoleName(),
|
||||
description: description ?? generateRoleName(),
|
||||
scopeIds,
|
||||
},
|
||||
})
|
||||
.json<Role>();
|
||||
|
||||
export const getRoles = () => authedAdminApi.get('roles').json<Role[]>();
|
||||
|
||||
export const getRole = (roleId: string) => authedAdminApi.get(`roles/${roleId}`).json<Role>();
|
||||
|
||||
export const updateRole = (roleId: string, payload: Partial<Omit<CreateRole, 'id'>>) =>
|
||||
authedAdminApi
|
||||
.patch(`roles/${roleId}`, {
|
||||
json: {
|
||||
...payload,
|
||||
},
|
||||
})
|
||||
.json<Role>();
|
||||
|
||||
export const deleteRole = (roleId: string) => authedAdminApi.delete(`roles/${roleId}`);
|
||||
|
||||
export const getRoleScopes = (roleId: string) =>
|
||||
authedAdminApi.get(`roles/${roleId}/scopes`).json<Scope[]>();
|
||||
|
||||
export const assignScopesToRole = (scopeIds: string[], roleId: string) =>
|
||||
authedAdminApi
|
||||
.post(`roles/${roleId}/scopes`, {
|
||||
json: { scopeIds },
|
||||
})
|
||||
.json<Scope[]>();
|
||||
|
||||
export const deleteScopeFromRole = (scopeId: string, roleId: string) =>
|
||||
authedAdminApi.delete(`roles/${roleId}/scopes/${scopeId}`);
|
||||
|
||||
export const getRoleUsers = (roleId: string) =>
|
||||
authedAdminApi.get(`roles/${roleId}/users`).json<User[]>();
|
||||
|
||||
export const assignUsersToRole = (userIds: string[], roleId: string) =>
|
||||
authedAdminApi.post(`roles/${roleId}/users`, {
|
||||
json: { userIds },
|
||||
});
|
||||
|
||||
export const deleteUserFromRole = (userId: string, roleId: string) =>
|
||||
authedAdminApi.delete(`roles/${roleId}/users/${userId}`);
|
|
@ -5,7 +5,7 @@ import { createResource } from '#src/api/index.js';
|
|||
import { createScope, deleteScope, getScopes, updateScope } from '#src/api/scope.js';
|
||||
import { generateScopeName } from '#src/utils.js';
|
||||
|
||||
describe('admin console api resources', () => {
|
||||
describe('scopes', () => {
|
||||
it('should get management api resource scopes successfully', async () => {
|
||||
const scopes = await getScopes(managementResource.id);
|
||||
|
||||
|
|
46
packages/integration-tests/src/tests/api/role.scope.test.ts
Normal file
46
packages/integration-tests/src/tests/api/role.scope.test.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { createResource } from '#src/api/index.js';
|
||||
import {
|
||||
assignScopesToRole,
|
||||
createRole,
|
||||
deleteScopeFromRole,
|
||||
getRoleScopes,
|
||||
} from '#src/api/role.js';
|
||||
import { createScope } from '#src/api/scope.js';
|
||||
|
||||
describe('roles scopes', () => {
|
||||
it('should get role scopes successfully', async () => {
|
||||
const role = await createRole();
|
||||
const resource = await createResource();
|
||||
const scope = await createScope(resource.id);
|
||||
await assignScopesToRole([scope.id], role.id);
|
||||
const scopes = await getRoleScopes(role.id);
|
||||
|
||||
expect(scopes.length).toBe(1);
|
||||
expect(scopes[0]).toHaveProperty('id', scope.id);
|
||||
expect(scopes[0]).toHaveProperty('resource.id', resource.id);
|
||||
});
|
||||
|
||||
it('should assign scopes to role successfully', async () => {
|
||||
const role = await createRole();
|
||||
const resource = await createResource();
|
||||
const scope1 = await createScope(resource.id);
|
||||
const scope2 = await createScope(resource.id);
|
||||
const scopes = await assignScopesToRole([scope1.id, scope2.id], role.id);
|
||||
|
||||
expect(scopes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove scope from role successfully', async () => {
|
||||
const role = await createRole();
|
||||
const resource = await createResource();
|
||||
const scope = await createScope(resource.id);
|
||||
await assignScopesToRole([scope.id], role.id);
|
||||
const scopes = await getRoleScopes(role.id);
|
||||
expect(scopes.length).toBe(1);
|
||||
|
||||
await deleteScopeFromRole(scope.id, role.id);
|
||||
|
||||
const newScopes = await getRoleScopes(role.id);
|
||||
expect(newScopes.length).toBe(0);
|
||||
});
|
||||
});
|
96
packages/integration-tests/src/tests/api/role.test.ts
Normal file
96
packages/integration-tests/src/tests/api/role.test.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { HTTPError } from 'got';
|
||||
|
||||
import { createResource } from '#src/api/resource.js';
|
||||
import {
|
||||
createRole,
|
||||
deleteRole,
|
||||
getRole,
|
||||
getRoles,
|
||||
getRoleScopes,
|
||||
updateRole,
|
||||
} from '#src/api/role.js';
|
||||
import { createScope } from '#src/api/scope.js';
|
||||
import { generateRoleName } from '#src/utils.js';
|
||||
|
||||
describe('roles', () => {
|
||||
it('should get roles list successfully', async () => {
|
||||
await createRole();
|
||||
const roles = await getRoles();
|
||||
|
||||
expect(roles.length > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should create role successfully', async () => {
|
||||
const roleName = generateRoleName();
|
||||
const description = roleName;
|
||||
|
||||
const role = await createRole(roleName, description);
|
||||
|
||||
expect(role.name).toBe(roleName);
|
||||
expect(role.description).toBe(description);
|
||||
});
|
||||
|
||||
it('should create role with scopeIds successfully', async () => {
|
||||
const roleName = generateRoleName();
|
||||
const description = roleName;
|
||||
const resource = await createResource();
|
||||
const scope = await createScope(resource.id);
|
||||
|
||||
const role = await createRole(roleName, description, [scope.id]);
|
||||
const scopes = await getRoleScopes(role.id);
|
||||
|
||||
expect(role.name).toBe(roleName);
|
||||
expect(role.description).toBe(description);
|
||||
expect(scopes[0]).toHaveProperty('id', scope.id);
|
||||
});
|
||||
|
||||
it('should fail when create role with conflict name', async () => {
|
||||
const createdRole = await createRole();
|
||||
|
||||
const response = await createRole(createdRole.name).catch((error: unknown) => error);
|
||||
expect(response instanceof HTTPError && response.response.statusCode === 422).toBe(true);
|
||||
});
|
||||
|
||||
it('should get role detail successfully', async () => {
|
||||
const createdRole = await createRole();
|
||||
const role = await getRole(createdRole.id);
|
||||
|
||||
expect(role.name).toBe(createdRole.name);
|
||||
expect(role.description).toBe(createdRole.description);
|
||||
});
|
||||
|
||||
it('should update role details successfully', async () => {
|
||||
const role = await createRole();
|
||||
|
||||
const newName = `new_${role.name}`;
|
||||
const newDescription = `new_${role.description}`;
|
||||
|
||||
await updateRole(role.id, {
|
||||
name: newName,
|
||||
description: newDescription,
|
||||
});
|
||||
|
||||
const updatedRole = await getRole(role.id);
|
||||
|
||||
expect(updatedRole.name).toBe(newName);
|
||||
expect(updatedRole.description).toBe(newDescription);
|
||||
});
|
||||
|
||||
it('should fail when update role with conflict name', async () => {
|
||||
const role1 = await createRole();
|
||||
const role2 = await createRole();
|
||||
const response = await updateRole(role2.id, {
|
||||
name: role1.name,
|
||||
}).catch((error: unknown) => error);
|
||||
expect(response instanceof HTTPError && response.response.statusCode === 422).toBe(true);
|
||||
});
|
||||
|
||||
it('should delete role successfully', async () => {
|
||||
const role = await createRole();
|
||||
|
||||
await deleteRole(role.id);
|
||||
|
||||
const response = await getRole(role.id).catch((error: unknown) => error);
|
||||
expect(response instanceof HTTPError && response.response.statusCode === 404).toBe(true);
|
||||
});
|
||||
});
|
38
packages/integration-tests/src/tests/api/role.user.test.ts
Normal file
38
packages/integration-tests/src/tests/api/role.user.test.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { createUser } from '#src/api/index.js';
|
||||
import { assignUsersToRole, createRole, deleteUserFromRole, getRoleUsers } from '#src/api/role.js';
|
||||
import { generateNewUserProfile } from '#src/helpers/user.js';
|
||||
|
||||
describe('roles users', () => {
|
||||
it('should get role users successfully', async () => {
|
||||
const role = await createRole();
|
||||
const user = await createUser(generateNewUserProfile({}));
|
||||
await assignUsersToRole([user.id], role.id);
|
||||
const users = await getRoleUsers(role.id);
|
||||
|
||||
expect(users.length).toBe(1);
|
||||
expect(users[0]).toHaveProperty('id', user.id);
|
||||
});
|
||||
|
||||
it('should assign users to role successfully', async () => {
|
||||
const role = await createRole();
|
||||
const user1 = await createUser(generateNewUserProfile({}));
|
||||
const user2 = await createUser(generateNewUserProfile({}));
|
||||
await assignUsersToRole([user1.id, user2.id], role.id);
|
||||
const users = await getRoleUsers(role.id);
|
||||
|
||||
expect(users.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove user from role successfully', async () => {
|
||||
const role = await createRole();
|
||||
const user = await createUser(generateNewUserProfile({}));
|
||||
await assignUsersToRole([user.id], role.id);
|
||||
const users = await getRoleUsers(role.id);
|
||||
expect(users.length).toBe(1);
|
||||
|
||||
await deleteUserFromRole(user.id, role.id);
|
||||
|
||||
const newUsers = await getRoleUsers(role.id);
|
||||
expect(newUsers.length).toBe(0);
|
||||
});
|
||||
});
|
|
@ -7,6 +7,7 @@ export const generateResourceName = () => `res_${crypto.randomUUID()}`;
|
|||
export const generateResourceIndicator = () => `https://${crypto.randomUUID()}.logto.io`;
|
||||
export const generateEmail = () => `${crypto.randomUUID().toLowerCase()}@logto.io`;
|
||||
export const generateScopeName = () => `sc:${crypto.randomUUID()}`;
|
||||
export const generateRoleName = () => `role_${crypto.randomUUID()}`;
|
||||
|
||||
export const generatePhone = () => {
|
||||
const array = new Uint32Array(1);
|
||||
|
|
Loading…
Reference in a new issue