import type { LoggerFriendly, LoggerFriendlyOptions } from "#Source/log/index.ts" import { Logger } from "#Source/log/index.ts" import type { AnyApiSchema } from "./api-schema.ts" export interface BeforeApiTestHandlerContext { apiSchema: ApiSchema } export type BeforeApiTestHandler = ( context: BeforeApiTestHandlerContext, ) => Promise export interface ApiTestHandlerContext { apiSchema: ApiSchema beforeApiTestResult: BeforeApiTestHandlerResult } export type ApiTestHandler = ( context: ApiTestHandlerContext, ) => Promise export interface AfterApiTestContext< ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, > { apiSchema: ApiSchema beforeApiTestResult: BeforeApiTestResult apiTestResult: ApiTestResult } export type AfterApiTestHandler< ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, > = ( context: AfterApiTestContext, ) => Promise export interface ApiTestOptions< ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, > extends LoggerFriendlyOptions { apiSchema: ApiSchema beforeApiTestHandler: BeforeApiTestHandler apiTestHandler: ApiTestHandler afterApiTestHandler: AfterApiTestHandler< ApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult > } export class ApiTest< ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, > implements LoggerFriendly { readonly logger: Logger protected __ApiSchemaPhantomType__?: ApiSchema protected __BeforeApiTestResultPhantomType__?: BeforeApiTestResult protected __ApiTestResultPhantomType__?: ApiTestResult protected __AfterApiTestResultPhantomType__?: AfterApiTestResult private apiSchema: ApiSchema private beforeApiTestHandler: BeforeApiTestHandler private apiTestHandler: ApiTestHandler private afterApiTestHandler: AfterApiTestHandler< ApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult > constructor( options: ApiTestOptions, ) { this.logger = Logger.fromOptions(options).setDefaultName("ApiTest") this.apiSchema = options.apiSchema this.beforeApiTestHandler = options.beforeApiTestHandler this.apiTestHandler = options.apiTestHandler this.afterApiTestHandler = options.afterApiTestHandler } getApiSchema(): ApiSchema { return this.apiSchema } getBeforeApiTestHandler(): BeforeApiTestHandler { return this.beforeApiTestHandler } getApiTestHandler(): ApiTestHandler { return this.apiTestHandler } getAfterApiTestHandler(): AfterApiTestHandler< ApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult > { return this.afterApiTestHandler } } export const createApiTest = < ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, >( options: ApiTestOptions, ): ApiTest => { return new ApiTest(options) } // oxlint-disable-next-line typescript/no-explicit-any export type AnyApiTest = ApiTest export interface TestApiOptions< ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, > { apiTest: ApiTest } export const testApi = async < ApiSchema extends AnyApiSchema, BeforeApiTestResult, ApiTestResult, AfterApiTestResult, >( options: TestApiOptions, ): Promise => { const { apiTest } = options const apiSchema = apiTest.getApiSchema() const beforeApiTestHandler = apiTest.getBeforeApiTestHandler() const beforeApiTestResult = await beforeApiTestHandler({ apiSchema }) const apiTestHandler = apiTest.getApiTestHandler() const apiTestResult = await apiTestHandler({ apiSchema, beforeApiTestResult }) const afterApiTestHandler = apiTest.getAfterApiTestHandler() const afterApiTestResult = await afterApiTestHandler({ apiSchema, beforeApiTestResult, apiTestResult, }) return afterApiTestResult }