Skip to content

Commit

Permalink
updated flows intial tests with new unit test template
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharpandey13 committed Oct 27, 2024
1 parent 863eaf0 commit 23af401
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 64 deletions.
91 changes: 36 additions & 55 deletions test/management/flows.test.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,57 @@
import nock from 'nock';
import { FlowsManager } from '../../src/index.js';
import { ManagementClient } from '../../src/index.js';
import {
checkForPromise,
checkErrorHandler,
checkRequestInterceptor,
checkOperation,
} from './tests.util.js';
import { GetFlows200Response } from '../../src/index.js';
import { checkMethod } from './tests.util.js';
import { GetFlows200Response, PostFlows201Response } from '../../src/index.js';

const DOMAIN = `tenant.auth0.com`;
const API_URL = `https://${DOMAIN}/api/v2`;
const token = 'TOKEN';

describe('FlowsManager', () => {
const flowsManager: FlowsManager = new ManagementClient({ domain: DOMAIN, token }).flows;

// this is the test for the method getFlows()
// it calls a GET endpoint and does not take any input parameters or body
describe('getFlows', () => {
// expected response from the API
const expectedResponse: GetFlows200Response = [
{
id: 'flw_123',
name: 'test',
created_at: '2024-10-23T09:29:24.286Z',
updated_at: '2024-10-23T09:29:24.286Z',
executed_at: '2024-10-23T09:29:24.286Z',
},
];

// getFlows method
const operation = flowsManager.getFlows();
const expectedResponse: GetFlows200Response = <GetFlows200Response>{};
const uri = `/flows`;
const method = 'get';

// clean all previous nocks
nock.cleanAll();
checkMethod({ operation, expectedResponse, uri, method });
});

// nock the API with success scenario
let request: nock.Scope = nock(API_URL).get('/flows').reply(200, expectedResponse);
checkForPromise(operation);
checkRequestInterceptor(operation, request, '/flows');
checkOperation(operation, expectedResponse);
// this is the test for the method getFlowsById()
// it calls a GET endpoint and takes input parameters but no input body
describe('getFlowsById', () => {
const operation = flowsManager.getFlowsById({ id: 'flowId' });
const expectedResponse: PostFlows201Response = <PostFlows201Response>{};
const uri = `/flows/flowId`;
const method = 'get';

// nock the API with error scenario
request = nock(API_URL).get('/flows').reply(500);
checkErrorHandler(operation);
checkMethod({ operation, expectedResponse, uri, method });
});

describe('getFlows', () => {
// expected response from the API
const expectedResponse: GetFlows200Response = [
{
id: 'flw_123',
name: 'test',
created_at: '2024-10-23T09:29:24.286Z',
updated_at: '2024-10-23T09:29:24.286Z',
executed_at: '2024-10-23T09:29:24.286Z',
},
];

// getFlows method
const operation = flowsManager.getFlows();
// this is the test for the method patchFlowsById()
// it calls a PATCH endpoint and takes input parameters and body
describe('patchFlowsById', () => {
const requestBody: { name: string } = { name: 'flowName' };
const operation = flowsManager.patchFlowsById({ id: 'flowId' }, requestBody);
const expectedResponse: PostFlows201Response = <PostFlows201Response>{};
const uri = `/flows/flowId`;
const method = 'patch';

// clean all previous nocks
nock.cleanAll();
checkMethod({ operation, expectedResponse, uri, method, requestBody });
});

// nock the API with success scenario
let request: nock.Scope = nock(API_URL).get('/flows').reply(200, expectedResponse);
checkForPromise(operation);
checkRequestInterceptor(operation, request, '/flows');
checkOperation(operation, expectedResponse);
// this is the test for the method postFlows()
// it calls a POST endpoint and takes only a body
describe('postFlows', () => {
const requestBody: { name: string } = { name: 'flowName' };
const operation = flowsManager.postFlows(requestBody);
const expectedResponse: PostFlows201Response = <PostFlows201Response>{};
const uri = `/flows`;
const method = 'post';

// nock the API with error scenario
request = nock(API_URL).get('/flows').reply(500);
checkErrorHandler(operation);
checkMethod({ operation, expectedResponse, uri, method, requestBody });
});
});
102 changes: 93 additions & 9 deletions test/management/tests.util.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
import nock from 'nock';
// 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<ApiResponse<T>>} operation - The operation to check, which can be either a promise or any other type.
* @returns {void}
*/
export function checkForPromise<T>(operation: any | Promise<ApiResponse<T>>): 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<ApiResponse<T>>} operation - The promise representing the operation to be tested.
* @returns {void} - This function does not return anything.
*
* @example
* ```typescript
* checkErrorHandler(someApiOperation);
* ```
*/
export function checkErrorHandler<T>(operation: Promise<ApiResponse<T>>): void {
it('should pass any errors to the promise catch handler', () => {
nock.cleanAll();
Expand All @@ -20,22 +48,78 @@ export function checkErrorHandler<T>(operation: Promise<ApiResponse<T>>): void {
});
}

// this function checks if a request is made to the specified endpoint in a given method.
// it is used to check if the correct endpoint is being called in the tests
export function checkRequestInterceptor<T>(
operation: Promise<T>,
request: nock.Scope,
endpoint: string
): void {
it(`should make a request to ${endpoint}`, async () => {
/**
* 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<T>(operation: Promise<T>, 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<ApiResponse<T>>} operation - The asynchronous operation to be tested.
* @param {T} expectedResponse - The expected response data to compare against the operation's result.
*/
export function checkOperation<T>(operation: Promise<ApiResponse<T>>, expectedResponse: T): void {
it('should test the method', async () => {
const result = await operation;
expect(result.data).toEqual(expectedResponse);
});
}

export type CheckMethodParams<T> = {
operation: Promise<ApiResponse<T>>;
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<ApiResponse<T>>} 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 = <T>({
operation,
expectedResponse,
uri,
method,
requestBody,
}: CheckMethodParams<T>): 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);
};

0 comments on commit 23af401

Please sign in to comment.