diff --git a/packages/type-safe-api/docs/developer_guides/type-safe-api/lambda_handlers.md b/packages/type-safe-api/docs/developer_guides/type-safe-api/lambda_handlers.md index 03bb67dee..e440aa178 100644 --- a/packages/type-safe-api/docs/developer_guides/type-safe-api/lambda_handlers.md +++ b/packages/type-safe-api/docs/developer_guides/type-safe-api/lambda_handlers.md @@ -253,6 +253,8 @@ This will give you generated lambda handler stubs which look like the following: You can implement your lambda handlers in any of the supported languages, or mix and match languages for different operations if you prefer. +An example unit test will also be generated for each handler. These unit tests are only generated when the corresponding handler is initially generated, so you can safely delete the generated test if you do not want it. + ## Function CDK Constructs As well as generating lambda handler stubs, when you use the `@handler` Smithy trait or `x-handler` OpenAPI vendor extension, your generated CDK infrastructure project will include lambda function CDK constructs with preconfigured paths to your handler distributables. This allows you to quickly add lambda integrations to your API: diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/config.yaml b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/config.yaml index 92c13b8e7..b293d79c1 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/config.yaml +++ b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/config.yaml @@ -2,3 +2,6 @@ files: handlers.handlebars: destinationFilename: {{src}}/__all_handlers.ts templateType: SupportingFiles + tests.handlebars: + destinationFilename: {{tst}}/__all_tests.ts + templateType: SupportingFiles diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/handlers.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/handlers.handlebars index 25017db21..2ef379dc3 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/handlers.handlebars +++ b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/handlers.handlebars @@ -7,6 +7,7 @@ {{#startsWith vendorExtensions.x-handler.language 'typescript'}} ###TSAPI_WRITE_FILE### { + "id": "{{nickname}}", "dir": ".", "name": "{{nickname}}", "ext": ".ts", diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/tests.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/tests.handlebars new file mode 100644 index 000000000..eea5b47bb --- /dev/null +++ b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-lambda-handlers/templates/tests.handlebars @@ -0,0 +1,62 @@ +###TSAPI_SPLIT_FILE### +{{#apiInfo ~}} +{{#apis ~}} +{{#operations ~}} +{{#operation ~}} +{{#if vendorExtensions.x-handler}} +{{#startsWith vendorExtensions.x-handler.language 'typescript'}} +###TSAPI_WRITE_FILE### +{ + "id": "{{nickname}}Test", + "dir": ".", + "name": "{{nickname}}", + "ext": ".test.ts", + "overwrite": false, + "kebabCaseFileName": true, + "generateConditionallyId": "{{nickname}}" +} +###/TSAPI_WRITE_FILE###import { + InternalFailureErrorResponseContent, + {{operationIdCamelCase}}ChainedRequestInput, +} from "{{#apiInfo}}{{#apis.0}}{{vendorExtensions.x-runtime-package-name}}{{/apis.0}}{{/apiInfo}}"; +import { + {{nickname}} +} from "../src/###TSAPI_FN###{ "function": "kebabCase", "args": ["{{nickname}}"] }###/TSAPI_FN###"; + +// Common request arguments +const requestArguments = { + chain: undefined as never, + event: {} as any, + context: {} as any, + interceptorContext: { + logger: { + info: jest.fn(), + }, + }, +} satisfies Omit<{{operationIdCamelCase}}ChainedRequestInput, 'input'>; + +describe('{{operationIdCamelCase}}', () => { + + it('should return not implemented error', async () => { + // TODO: Update the test as appropriate when you implement your handler + const response = await {{nickname}}({ + ...requestArguments, + input: { + // TODO: remove the "as any" below and fill in test values for the requestParameters{{#if bodyParam}} and body{{/if}} + requestParameters: {} as any, + body: {} as {{#if bodyParam}}any{{else}}never{{/if}}, + }, + }); + + expect(response.statusCode).toBe(500); + expect((response.body as InternalFailureErrorResponseContent).message).toEqual('Not Implemented!'); + }); + +}); + +{{~/startsWith}} +{{~/if}} +{{~/operation}} +{{~/operations}} +{{~/apis}} +{{~/apiInfo}} \ No newline at end of file diff --git a/packages/type-safe-api/src/project/codegen/handlers/generated-typescript-handlers-project.ts b/packages/type-safe-api/src/project/codegen/handlers/generated-typescript-handlers-project.ts index 4d9280195..724923af0 100644 --- a/packages/type-safe-api/src/project/codegen/handlers/generated-typescript-handlers-project.ts +++ b/packages/type-safe-api/src/project/codegen/handlers/generated-typescript-handlers-project.ts @@ -95,7 +95,8 @@ export class GeneratedTypescriptHandlersProject extends TypeScriptProject { "**/*", "*", // This will be split into a file per targeted handler - `!${this.srcdir}/__all_handlers.ts` + `!${this.srcdir}/__all_handlers.ts`, + `!${this.testdir}/__all_tests.ts` ); // Add OpenAPI Generator cli configuration @@ -169,6 +170,7 @@ export class GeneratedTypescriptHandlersProject extends TypeScriptProject { specPath: this.options.specPath, generatorDirectory: OtherGenerators.TYPESCRIPT_LAMBDA_HANDLERS, srcDir: this.srcdir, + tstDir: this.testdir, normalizers: { KEEP_ONLY_FIRST_TAG_IN_OPERATION: true, }, diff --git a/packages/type-safe-api/test/project/__snapshots__/type-safe-api-project.test.ts.snap b/packages/type-safe-api/test/project/__snapshots__/type-safe-api-project.test.ts.snap index 3c1f99203..89194696c 100644 --- a/packages/type-safe-api/test/project/__snapshots__/type-safe-api-project.test.ts.snap +++ b/packages/type-safe-api/test/project/__snapshots__/type-safe-api-project.test.ts.snap @@ -25871,6 +25871,7 @@ junit.xml **/* * !src/__all_handlers.ts +!test/__all_tests.ts ", "handlers/typescript/.projen/deps.json": { "//": "~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".", diff --git a/packages/type-safe-api/test/project/codegen/handlers/__snapshots__/generated-typescript-handlers-project.test.ts.snap b/packages/type-safe-api/test/project/codegen/handlers/__snapshots__/generated-typescript-handlers-project.test.ts.snap index 108f08d2d..9cc879424 100644 --- a/packages/type-safe-api/test/project/codegen/handlers/__snapshots__/generated-typescript-handlers-project.test.ts.snap +++ b/packages/type-safe-api/test/project/codegen/handlers/__snapshots__/generated-typescript-handlers-project.test.ts.snap @@ -615,6 +615,7 @@ pull_request_rules: **/* * !src/__all_handlers.ts +!test/__all_tests.ts ", ".projen/deps.json": { "//": "~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen".", diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-lambda-handlers.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-lambda-handlers.test.ts.snap index 74c313ff9..778c0dd3c 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-lambda-handlers.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-lambda-handlers.test.ts.snap @@ -61,3 +61,87 @@ export const typescriptTwo: TypescriptTwoChainedHandlerFunction = async (request */ export const handler = typescriptTwoHandler(...INTERCEPTORS, typescriptTwo);" `; + +exports[`Typescript Handlers Code Generation Script Unit Tests Generates With handlers.yaml 3`] = ` +"import { + InternalFailureErrorResponseContent, + TypescriptOneChainedRequestInput, +} from "test-client"; +import { + typescriptOne +} from "../src/typescript-one"; + +// Common request arguments +const requestArguments = { + chain: undefined as never, + event: {} as any, + context: {} as any, + interceptorContext: { + logger: { + info: jest.fn(), + }, + }, +} satisfies Omit; + +describe('TypescriptOne', () => { + + it('should return not implemented error', async () => { + // TODO: Update the test as appropriate when you implement your handler + const response = await typescriptOne({ + ...requestArguments, + input: { + // TODO: remove the "as any" below and fill in test values for the requestParameters + requestParameters: {} as any, + body: {} as never, + }, + }); + + expect(response.statusCode).toBe(500); + expect((response.body as InternalFailureErrorResponseContent).message).toEqual('Not Implemented!'); + }); + +}); + +" +`; + +exports[`Typescript Handlers Code Generation Script Unit Tests Generates With handlers.yaml 4`] = ` +"import { + InternalFailureErrorResponseContent, + TypescriptTwoChainedRequestInput, +} from "test-client"; +import { + typescriptTwo +} from "../src/typescript-two"; + +// Common request arguments +const requestArguments = { + chain: undefined as never, + event: {} as any, + context: {} as any, + interceptorContext: { + logger: { + info: jest.fn(), + }, + }, +} satisfies Omit; + +describe('TypescriptTwo', () => { + + it('should return not implemented error', async () => { + // TODO: Update the test as appropriate when you implement your handler + const response = await typescriptTwo({ + ...requestArguments, + input: { + // TODO: remove the "as any" below and fill in test values for the requestParameters + requestParameters: {} as any, + body: {} as never, + }, + }); + + expect(response.statusCode).toBe(500); + expect((response.body as InternalFailureErrorResponseContent).message).toEqual('Not Implemented!'); + }); + +});" +`; diff --git a/packages/type-safe-api/test/scripts/generators/typescript-lambda-handlers.test.ts b/packages/type-safe-api/test/scripts/generators/typescript-lambda-handlers.test.ts index 960c55971..b4ea83702 100644 --- a/packages/type-safe-api/test/scripts/generators/typescript-lambda-handlers.test.ts +++ b/packages/type-safe-api/test/scripts/generators/typescript-lambda-handlers.test.ts @@ -44,6 +44,8 @@ describe("Typescript Handlers Code Generation Script Unit Tests", () => { expect(snapshot["handlers/src/typescript-one.ts"]).toMatchSnapshot(); expect(snapshot["handlers/src/typescript-two.ts"]).toMatchSnapshot(); + expect(snapshot["handlers/test/typescript-one.test.ts"]).toMatchSnapshot(); + expect(snapshot["handlers/test/typescript-two.test.ts"]).toMatchSnapshot(); // Other language handlers should be skipped expect(