diff --git a/test/management/organizations.test.ts b/test/management/organizations.test.ts index 1ad799bce..a17674cc4 100644 --- a/test/management/organizations.test.ts +++ b/test/management/organizations.test.ts @@ -9,21 +9,23 @@ import { GetOrganizationClientGrantsRequest, GetOrganizationClientGrants200Response, ApiResponse, + DeleteClientGrantsByGrantIdRequest, + GetOrganizationClientGrants200ResponseOneOfInner, } from '../../src/index.js'; +import { checkMethod } from '../utils/index.js'; + describe('OrganizationsManager', () => { let organizations: OrganizationsManager; let request: nock.Scope; const token = 'TOKEN'; - beforeAll(() => { - const client = new ManagementClient({ - domain: 'tenant.auth0.com', - token: token, - }); - organizations = client.organizations; + const client = new ManagementClient({ + domain: 'tenant.auth0.com', + token: token, }); + organizations = client.organizations; describe('#constructor', () => { it('should throw an error when no base URL is provided', () => { @@ -1474,4 +1476,35 @@ describe('OrganizationsManager', () => { }); }); }); + + describe('#deleteClientGrantsById', () => { + const requestParameters: DeleteClientGrantsByGrantIdRequest = { + id: 'org_123', + grant_id: 'grant_id', + }; + const operation = organizations.deleteClientGrantsByGrantId(requestParameters); + const expectedResponse = undefined; + const uri = `/organizations/{id}/client-grants/{grant_id}` + .replace('{id}', encodeURIComponent(String(requestParameters.id))) + .replace('{grant_id}', encodeURIComponent(String(requestParameters.grant_id))); + const method = 'delete'; + + checkMethod({ operation, expectedResponse, uri, method }); + }); + + describe('#postOrganizationClientGrants', () => { + const requestParameters = { id: 'org_123' }; + const requestBody = { grant_id: 'grant_id' }; + const operation = organizations.postOrganizationClientGrants(requestParameters, requestBody); + const expectedResponse: GetOrganizationClientGrants200ResponseOneOfInner = < + GetOrganizationClientGrants200ResponseOneOfInner + >{}; + const uri = `/organizations/{id}/client-grants`.replace( + '{id}', + encodeURIComponent(String(requestParameters.id)) + ); + const method = 'post'; + + checkMethod({ operation, expectedResponse, uri, method, requestBody }); + }); }); diff --git a/test/utils/index.ts b/test/utils/index.ts index fa9c9f608..13c37728b 100644 --- a/test/utils/index.ts +++ b/test/utils/index.ts @@ -1,2 +1,3 @@ export * from './extractParts.js'; export * from './withIdToken.js'; +export * from './wrapperTestUtils.js'; diff --git a/test/utils/wrapperTestUtils.ts b/test/utils/wrapperTestUtils.ts new file mode 100644 index 000000000..2ba06fbf1 --- /dev/null +++ b/test/utils/wrapperTestUtils.ts @@ -0,0 +1,125 @@ +// tests.util.ts +// this file contains commmon test functions that are used to test sdk endpoints +// since the management api managers are essentially wrappers around the REST endpoints, +// these functions end up being repeated for all the managers, this file aims to reduce repetition +// it performs basic sanity checks, input output checks and error handling checks + +import nock, { RequestBodyMatcher } from 'nock'; +import { ApiResponse } from '../../src/lib/models.js'; + +const DOMAIN = `tenant.auth0.com`; +const API_URL = `https://${DOMAIN}/api/v2`; + +// this is not technically not required as type checking will automatically check fot this +// but including it for the sake of completeness +/** + * Checks if the given operation returns a promise when no callback is provided. + * + * @template T - The type of the response expected from the promise. + * @param {any | Promise>} operation - The operation to check, which can be either a promise or any other type. + * @returns {void} + */ +export function checkForPromise(operation: any | Promise>): void { + it('should return a promise if no callback is given', (done) => { + expect(operation instanceof Promise).toBeTruthy(); + operation.then(done.bind(null, null)).catch(done.bind(null, null)); + }); +} + +/** + * Utility function to test if an operation correctly handles errors. + * + * @template T - The type of the response expected from the operation. + * @param {Promise>} operation - The promise representing the operation to be tested. + * @returns {void} - This function does not return anything. + * + * @example + * ```typescript + * checkErrorHandler(someApiOperation); + * ``` + */ +export function checkErrorHandler(operation: Promise>): void { + it('should pass any errors to the promise catch handler', () => { + nock.cleanAll(); + + return operation.catch((err) => { + expect(err).toBeDefined(); + }); + }); +} + +/** + * Verifies that a given operation makes a request to the specified endpoint. + * + * @template T - The type of the result of the operation. + * @param operation - A promise representing the operation to be checked. + * @param request - The nock scope representing the expected request. + */ +export function checkRequestInterceptor(operation: Promise, request: nock.Scope): void { + it(`should make a request to the endpoint`, async () => { + await operation; + expect(request.isDone()).toBeTruthy(); + }); +} + +/** + * Tests an asynchronous operation by comparing its result to an expected response. + * + * @template T - The type of the expected response data. + * @param {Promise>} operation - The asynchronous operation to be tested. + * @param {T} expectedResponse - The expected response data to compare against the operation's result. + */ +export function checkOperation(operation: Promise>, expectedResponse: T): void { + it('should test the method', async () => { + const result = await operation; + expect(result.data).toEqual(expectedResponse); + }); +} + +export type CheckMethodParams = { + operation: Promise>; + expectedResponse: any; + uri: string | RegExp | { (uri: string): boolean }; + method: string; + requestBody?: RequestBodyMatcher | any; +}; + +// this function combines the above functions to check an SDK manager method. +/** + * Checks the given manager method by intercepting the request and validating the response. + * + * Following checks are performed: + * 1. The operation is a promise. + * 2. The operation is rejected in case of an error. + * 3. The request is made to the specified endpoint in the given method. + * 4. The response from the operation is as expected. + * + * @template T - The type of the expected response. + * @param {Object} params - The parameters for the checkMethod function. + * @param {Promise>} params.operation - The operation to be tested. + * @param {any} params.expectedResponse - The expected response from the operation. + * @param {string | RegExp | ((uri: string) => boolean)} params.uri - The URI to intercept. + * @param {string} params.method - The HTTP method to intercept (e.g., 'GET', 'POST'). + * @param {RequestBodyMatcher | any} [params.requestBody] - The optional request body to match. + */ +export const checkMethod = ({ + operation, + expectedResponse, + uri, + method, + requestBody, +}: CheckMethodParams): void => { + // nock the API with success scenario + let request: nock.Scope = nock(API_URL) + .intercept(uri, method, requestBody) + .reply(200, expectedResponse); + + // check for various success checks + checkForPromise(operation); + checkRequestInterceptor(operation, request); + checkOperation(operation, expectedResponse); + + // nock the API with error scenario + request = nock(API_URL).intercept(uri, method, requestBody).reply(500); + checkErrorHandler(operation); +};