mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
chore: add tests
This commit is contained in:
parent
75ab459c0a
commit
128ee0c9bb
5 changed files with 128 additions and 11 deletions
|
@ -6,6 +6,7 @@ import {
|
|||
type OrganizationWithFeatured,
|
||||
type OrganizationScope,
|
||||
type OrganizationEmailDomain,
|
||||
type CreateOrganization,
|
||||
} from '@logto/schemas';
|
||||
|
||||
import { authedAdminApi } from './api.js';
|
||||
|
@ -17,10 +18,7 @@ type Query = {
|
|||
page_size?: number;
|
||||
};
|
||||
|
||||
export class OrganizationApi extends ApiFactory<
|
||||
Organization,
|
||||
{ name: string; description?: string }
|
||||
> {
|
||||
export class OrganizationApi extends ApiFactory<Organization, Omit<CreateOrganization, 'id'>> {
|
||||
constructor() {
|
||||
super('organizations');
|
||||
}
|
||||
|
|
|
@ -152,6 +152,14 @@ export default class MockClient {
|
|||
return this.logto.getAccessTokenClaims(resource);
|
||||
}
|
||||
|
||||
public async getOrganizationTokenClaims(organizationId: string) {
|
||||
return this.logto.getOrganizationTokenClaims(organizationId);
|
||||
}
|
||||
|
||||
public async clearAccessToken() {
|
||||
return this.logto.clearAccessToken();
|
||||
}
|
||||
|
||||
public async getRefreshToken(): Promise<Nullable<string>> {
|
||||
return this.logto.getRefreshToken();
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
type Organization,
|
||||
type OrganizationRoleWithScopes,
|
||||
type OrganizationInvitationEntity,
|
||||
type JsonObject,
|
||||
type CreateOrganization,
|
||||
} from '@logto/schemas';
|
||||
import { trySafe } from '@silverhand/essentials';
|
||||
|
||||
|
@ -123,11 +123,7 @@ export class OrganizationApiTest extends OrganizationApi {
|
|||
return this.#organizations;
|
||||
}
|
||||
|
||||
override async create(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
customData?: JsonObject;
|
||||
}): Promise<Organization> {
|
||||
override async create(data: Omit<CreateOrganization, 'id'>): Promise<Organization> {
|
||||
const created = await super.create(data);
|
||||
this.organizations.push(created);
|
||||
return created;
|
||||
|
|
|
@ -152,7 +152,7 @@ describe('get access token', () => {
|
|||
).resolves.toBeTruthy();
|
||||
});
|
||||
|
||||
it('can sign in and get multiple Access Tokens by the same Refresh Token within refreshTokenReuseInterval', async () => {
|
||||
it('can sign in and get multiple access tokens by the same refresh token within `refreshTokenReuseInterval`', async () => {
|
||||
const client = new MockClient({ resources: [testApiResourceInfo.indicator] });
|
||||
|
||||
await client.initSession();
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import { UserScope, buildOrganizationUrn } from '@logto/core-kit';
|
||||
import { InteractionEvent, MfaFactor } from '@logto/schemas';
|
||||
|
||||
import { createUserMfaVerification, deleteUser } from '#src/api/admin-user.js';
|
||||
import { putInteraction } from '#src/api/index.js';
|
||||
import MockClient from '#src/client/index.js';
|
||||
import { processSession } from '#src/helpers/client.js';
|
||||
import { createUserByAdmin } from '#src/helpers/index.js';
|
||||
import { OrganizationApiTest } from '#src/helpers/organization.js';
|
||||
import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js';
|
||||
import { generatePassword, generateUsername, randomString } from '#src/utils.js';
|
||||
|
||||
describe('get access token for organization', () => {
|
||||
const username = generateUsername();
|
||||
const password = generatePassword();
|
||||
const scopeName = `read:${randomString()}`;
|
||||
const scopeName2 = `read:other:${randomString()}`;
|
||||
const client = new MockClient({
|
||||
scopes: [scopeName, scopeName2, UserScope.Organizations],
|
||||
});
|
||||
|
||||
/* eslint-disable @silverhand/fp/no-let */
|
||||
let testApiScopeId: string;
|
||||
let testApiScopeId2: string;
|
||||
let testUserId: string;
|
||||
let testOrganizationId: string;
|
||||
let testOrganizationId2: string;
|
||||
/* eslint-enable @silverhand/fp/no-let */
|
||||
|
||||
const organizationApi = new OrganizationApiTest();
|
||||
|
||||
/* eslint-disable @silverhand/fp/no-mutation */
|
||||
beforeAll(async () => {
|
||||
const user = await createUserByAdmin({ username, password });
|
||||
testUserId = user.id;
|
||||
|
||||
const organization = await organizationApi.create({ name: 'org1' });
|
||||
testOrganizationId = organization.id;
|
||||
await organizationApi.addUsers(testOrganizationId, [user.id]);
|
||||
|
||||
const scope = await organizationApi.scopeApi.create({ name: scopeName });
|
||||
testApiScopeId = scope.id;
|
||||
const scope2 = await organizationApi.scopeApi.create({ name: scopeName2 });
|
||||
testApiScopeId2 = scope2.id;
|
||||
|
||||
const role = await organizationApi.roleApi.create({ name: `role1:${randomString()}` });
|
||||
await organizationApi.roleApi.addScopes(role.id, [scope.id]);
|
||||
await organizationApi.addUserRoles(testOrganizationId, user.id, [role.id]);
|
||||
|
||||
const organization2 = await organizationApi.create({ name: 'org2' });
|
||||
testOrganizationId2 = organization2.id;
|
||||
await organizationApi.addUsers(testOrganizationId2, [user.id]);
|
||||
const role2 = await organizationApi.roleApi.create({ name: `role2:${randomString()}` });
|
||||
await organizationApi.roleApi.addScopes(role2.id, [scope2.id]);
|
||||
await organizationApi.addUserRoles(testOrganizationId2, user.id, [role2.id]);
|
||||
|
||||
await enableAllPasswordSignInMethods();
|
||||
|
||||
// Prepare client
|
||||
await client.initSession();
|
||||
await client.successSend(putInteraction, {
|
||||
event: InteractionEvent.SignIn,
|
||||
identifier: { username, password },
|
||||
});
|
||||
const { redirectTo } = await client.submitInteraction();
|
||||
await processSession(client, redirectTo);
|
||||
});
|
||||
/* eslint-enable @silverhand/fp/no-mutation */
|
||||
|
||||
afterAll(async () => {
|
||||
await Promise.all([organizationApi.cleanUp(), deleteUser(testUserId)]);
|
||||
});
|
||||
|
||||
it('should be able to get access token for organization with correct scopes', async () => {
|
||||
await expect(client.getOrganizationTokenClaims(testOrganizationId)).resolves.toMatchObject({
|
||||
aud: buildOrganizationUrn(testOrganizationId),
|
||||
scope: scopeName,
|
||||
});
|
||||
await expect(client.getOrganizationTokenClaims(testOrganizationId2)).resolves.toMatchObject({
|
||||
aud: buildOrganizationUrn(testOrganizationId2),
|
||||
scope: scopeName2,
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to dynamically get access token according to the status quo', async () => {
|
||||
const newOrganization = await organizationApi.create({ name: 'foo' });
|
||||
|
||||
await organizationApi.addUsers(newOrganization.id, [testUserId]);
|
||||
await expect(client.getOrganizationTokenClaims(newOrganization.id)).resolves.toMatchObject({
|
||||
aud: buildOrganizationUrn(newOrganization.id),
|
||||
});
|
||||
|
||||
await organizationApi.deleteUser(newOrganization.id, testUserId);
|
||||
await client.clearAccessToken();
|
||||
await expect(
|
||||
client.getOrganizationTokenClaims(newOrganization.id)
|
||||
).rejects.toMatchInlineSnapshot('[Error: Access denied.]');
|
||||
});
|
||||
|
||||
it('should throw when organization requires mfa but user has not configured', async () => {
|
||||
await organizationApi.update(testOrganizationId, { isMfaRequired: true });
|
||||
await client.clearAccessToken();
|
||||
|
||||
await expect(
|
||||
client.getOrganizationTokenClaims(testOrganizationId)
|
||||
).rejects.toMatchInlineSnapshot('[Error: Access denied.]');
|
||||
});
|
||||
|
||||
it('should be able to get access token for organization when user has mfa configured', async () => {
|
||||
await createUserMfaVerification(testUserId, MfaFactor.TOTP);
|
||||
await expect(client.getOrganizationTokenClaims(testOrganizationId)).resolves.toMatchObject({
|
||||
aud: buildOrganizationUrn(testOrganizationId),
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue