From e75a0cf1f1cf96d55559810811c3c3d18978bd69 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Thu, 12 Oct 2023 16:31:16 +0800 Subject: [PATCH] refactor(test): add ApiFactory for integration tests --- packages/integration-tests/src/api/factory.ts | 29 +++++++++++ .../src/api/organization-scope.ts | 46 +++++------------ .../integration-tests/src/api/organization.ts | 41 +++------------- .../src/tests/api/organization-scope.test.ts | 45 ++++++++--------- .../src/tests/api/organization.test.ts | 49 +++++++++---------- 5 files changed, 92 insertions(+), 118 deletions(-) create mode 100644 packages/integration-tests/src/api/factory.ts diff --git a/packages/integration-tests/src/api/factory.ts b/packages/integration-tests/src/api/factory.ts new file mode 100644 index 000000000..e2761d66c --- /dev/null +++ b/packages/integration-tests/src/api/factory.ts @@ -0,0 +1,29 @@ +import { authedAdminApi } from './api.js'; + +export class ApiFactory< + Schema extends Record, + PostData extends Record, + PatchData extends Record = Partial, +> { + constructor(public readonly path: string) {} + + async create(data: PostData): Promise { + return authedAdminApi.post(this.path, { json: data }).json(); + } + + async getList(params?: URLSearchParams): Promise { + return authedAdminApi.get(this.path + '?' + (params?.toString() ?? '')).json(); + } + + async get(id: string): Promise { + return authedAdminApi.get(this.path + '/' + id).json(); + } + + async update(id: string, data: PatchData): Promise { + return authedAdminApi.patch(this.path + '/' + id, { json: data }).json(); + } + + async delete(id: string): Promise { + await authedAdminApi.delete(this.path + '/' + id); + } +} diff --git a/packages/integration-tests/src/api/organization-scope.ts b/packages/integration-tests/src/api/organization-scope.ts index f754a1298..99d6256b2 100644 --- a/packages/integration-tests/src/api/organization-scope.ts +++ b/packages/integration-tests/src/api/organization-scope.ts @@ -1,39 +1,15 @@ import { type OrganizationScope } from '@logto/schemas'; -import { authedAdminApi } from './api.js'; +import { ApiFactory } from './factory.js'; -export const createOrganizationScope = async (name: string, description?: string) => { - return authedAdminApi - .post('organization-scopes', { - json: { - name, - description, - }, - }) - .json(); -}; +class OrganizationScopeApi extends ApiFactory< + OrganizationScope, + { name: string; description?: string } +> { + constructor() { + super('organization-scopes'); + } +} -export const getOrganizationScopes = async (params?: URLSearchParams) => { - return authedAdminApi - .get('organization-scopes?' + (params?.toString() ?? '')) - .json(); -}; - -export const getOrganizationScope = async (id: string) => { - return authedAdminApi.get('organization-scopes/' + id).json(); -}; - -export const updateOrganizationScope = async (id: string, name: string, description?: string) => { - return authedAdminApi - .patch('organization-scopes/' + id, { - json: { - name, - description, - }, - }) - .json(); -}; - -export const deleteOrganizationScope = async (id: string) => { - return authedAdminApi.delete('organization-scopes/' + id); -}; +/** API methods for operating organization template scopes. */ +export const scopeApi = new OrganizationScopeApi(); diff --git a/packages/integration-tests/src/api/organization.ts b/packages/integration-tests/src/api/organization.ts index f039b6b0f..f145de82b 100644 --- a/packages/integration-tests/src/api/organization.ts +++ b/packages/integration-tests/src/api/organization.ts @@ -1,37 +1,12 @@ import { type Organization } from '@logto/schemas'; -import { authedAdminApi } from './api.js'; +import { ApiFactory } from './factory.js'; -export const createOrganization = async (name: string, description?: string) => { - return authedAdminApi - .post('organizations', { - json: { - name, - description, - }, - }) - .json(); -}; +class OrganizationApi extends ApiFactory { + constructor() { + super('organizations'); + } +} -export const getOrganizations = async (params?: URLSearchParams) => { - return authedAdminApi.get('organizations?' + (params?.toString() ?? '')).json(); -}; - -export const getOrganization = async (id: string) => { - return authedAdminApi.get('organizations/' + id).json(); -}; - -export const updateOrganization = async (id: string, name: string, description?: string) => { - return authedAdminApi - .patch('organizations/' + id, { - json: { - name, - description, - }, - }) - .json(); -}; - -export const deleteOrganization = async (id: string) => { - return authedAdminApi.delete('organizations/' + id); -}; +/** API methods for operating organizations. */ +export const organizationApi = new OrganizationApi(); diff --git a/packages/integration-tests/src/tests/api/organization-scope.test.ts b/packages/integration-tests/src/tests/api/organization-scope.test.ts index ac46ab0d2..afcca541f 100644 --- a/packages/integration-tests/src/tests/api/organization-scope.test.ts +++ b/packages/integration-tests/src/tests/api/organization-scope.test.ts @@ -4,21 +4,15 @@ import { generateStandardId } from '@logto/shared'; import { isKeyInObject } from '@silverhand/essentials'; import { HTTPError } from 'got'; -import { - createOrganizationScope, - getOrganizationScopes, - getOrganizationScope, - updateOrganizationScope, - deleteOrganizationScope, -} from '#src/api/organization-scope.js'; +import { scopeApi } from '#src/api/organization-scope.js'; const randomId = () => generateStandardId(4); describe('organization scopes', () => { it('should fail if the name of the new organization scope already exists', async () => { const name = 'test' + randomId(); - await createOrganizationScope(name); - const response = await createOrganizationScope(name).catch((error: unknown) => error); + await scopeApi.create({ name }); + const response = await scopeApi.create({ name }).catch((error: unknown) => error); assert(response instanceof HTTPError); @@ -30,9 +24,9 @@ describe('organization scopes', () => { it('should get organization scopes successfully', async () => { const [name1, name2] = ['test' + randomId(), 'test' + randomId()]; - await createOrganizationScope(name1, 'A test organization scope.'); - await createOrganizationScope(name2); - const scopes = await getOrganizationScopes(); + await scopeApi.create({ name: name1, description: 'A test organization scope.' }); + await scopeApi.create({ name: name2 }); + const scopes = await scopeApi.getList(); expect(scopes).toContainEqual( expect.objectContaining({ name: name1, description: 'A test organization scope.' }) @@ -43,13 +37,13 @@ describe('organization scopes', () => { it('should get organization scopes with pagination', async () => { // Add 20 scopes to exceed the default page size await Promise.all( - Array.from({ length: 30 }).map(async () => createOrganizationScope('test' + randomId())) + Array.from({ length: 30 }).map(async () => scopeApi.create({ name: 'test' + randomId() })) ); - const scopes = await getOrganizationScopes(); + const scopes = await scopeApi.getList(); expect(scopes).toHaveLength(20); - const scopes2 = await getOrganizationScopes( + const scopes2 = await scopeApi.getList( new URLSearchParams({ page: '2', page_size: '10', @@ -61,22 +55,25 @@ describe('organization scopes', () => { }); it('should be able to create and get organization scopes by id', async () => { - const createdScope = await createOrganizationScope('test' + randomId()); - const scope = await getOrganizationScope(createdScope.id); + const createdScope = await scopeApi.create({ name: 'test' + randomId() }); + const scope = await scopeApi.get(createdScope.id); expect(scope).toStrictEqual(createdScope); }); it('should fail when try to get an organization scope that does not exist', async () => { - const response = await getOrganizationScope('0').catch((error: unknown) => error); + const response = await scopeApi.get('0').catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); it('should be able to update organization scope', async () => { - const createdScope = await createOrganizationScope('test' + randomId()); + const createdScope = await scopeApi.create({ name: 'test' + randomId() }); const newName = 'test' + randomId(); - const scope = await updateOrganizationScope(createdScope.id, newName, 'test description.'); + const scope = await scopeApi.update(createdScope.id, { + name: newName, + description: 'test description.', + }); expect(scope).toStrictEqual({ ...createdScope, name: newName, @@ -85,14 +82,14 @@ describe('organization scopes', () => { }); it('should be able to delete organization scope', async () => { - const createdScope = await createOrganizationScope('test' + randomId()); - await deleteOrganizationScope(createdScope.id); - const response = await getOrganizationScope(createdScope.id).catch((error: unknown) => error); + const createdScope = await scopeApi.create({ name: 'test' + randomId() }); + await scopeApi.delete(createdScope.id); + const response = await scopeApi.get(createdScope.id).catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); it('should fail when try to delete an organization scope that does not exist', async () => { - const response = await deleteOrganizationScope('0').catch((error: unknown) => error); + const response = await scopeApi.delete('0').catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); }); diff --git a/packages/integration-tests/src/tests/api/organization.test.ts b/packages/integration-tests/src/tests/api/organization.test.ts index 4f19b0b70..6c95c9221 100644 --- a/packages/integration-tests/src/tests/api/organization.test.ts +++ b/packages/integration-tests/src/tests/api/organization.test.ts @@ -1,18 +1,12 @@ import { HTTPError } from 'got'; -import { - createOrganization, - deleteOrganization, - getOrganization, - getOrganizations, - updateOrganization, -} from '#src/api/organization.js'; +import { organizationApi } from '#src/api/organization.js'; describe('organizations', () => { it('should get organizations successfully', async () => { - await createOrganization('test', 'A test organization.'); - await createOrganization('test2'); - const organizations = await getOrganizations(); + await organizationApi.create({ name: 'test', description: 'A test organization.' }); + await organizationApi.create({ name: 'test2' }); + const organizations = await organizationApi.getList(); expect(organizations).toContainEqual( expect.objectContaining({ name: 'test', description: 'A test organization.' }) @@ -24,12 +18,14 @@ describe('organizations', () => { it('should get organizations with pagination', async () => { // Add 20 organizations to exceed the default page size - await Promise.all(Array.from({ length: 30 }).map(async () => createOrganization('test'))); + await Promise.all( + Array.from({ length: 30 }).map(async () => organizationApi.create({ name: 'test' })) + ); - const organizations = await getOrganizations(); + const organizations = await organizationApi.getList(); expect(organizations).toHaveLength(20); - const organizations2 = await getOrganizations( + const organizations2 = await organizationApi.getList( new URLSearchParams({ page: '2', page_size: '10', @@ -41,25 +37,24 @@ describe('organizations', () => { }); it('should be able to create and get organizations by id', async () => { - const createdOrganization = await createOrganization('test'); - const organization = await getOrganization(createdOrganization.id); + const createdOrganization = await organizationApi.create({ name: 'test' }); + const organization = await organizationApi.get(createdOrganization.id); expect(organization).toStrictEqual(createdOrganization); }); it('should fail when try to get an organization that does not exist', async () => { - const response = await getOrganization('0').catch((error: unknown) => error); + const response = await organizationApi.get('0').catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); it('should be able to update organization', async () => { - const createdOrganization = await createOrganization('test'); - const organization = await updateOrganization( - createdOrganization.id, - 'test2', - 'test description.' - ); + const createdOrganization = await organizationApi.create({ name: 'test' }); + const organization = await organizationApi.update(createdOrganization.id, { + name: 'test2', + description: 'test description.', + }); expect(organization).toStrictEqual({ ...createdOrganization, name: 'test2', @@ -68,14 +63,16 @@ describe('organizations', () => { }); it('should be able to delete organization', async () => { - const createdOrganization = await createOrganization('test'); - await deleteOrganization(createdOrganization.id); - const response = await getOrganization(createdOrganization.id).catch((error: unknown) => error); + const createdOrganization = await organizationApi.create({ name: 'test' }); + await organizationApi.delete(createdOrganization.id); + const response = await organizationApi + .get(createdOrganization.id) + .catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); it('should fail when try to delete an organization that does not exist', async () => { - const response = await deleteOrganization('0').catch((error: unknown) => error); + const response = await organizationApi.delete('0').catch((error: unknown) => error); expect(response instanceof HTTPError && response.response.statusCode).toBe(404); }); });