From aa3635aae9b244e0fd36899b92bd9eaadab40cff Mon Sep 17 00:00:00 2001 From: David de Kloet Date: Thu, 4 Jun 2026 13:12:38 +0200 Subject: [PATCH 1/2] Add generate unit test for generated customBg transport --- .../generator-adapter/generators/app/index.ts | 21 +- .../templates/src/transport/custombg.ts.ejs | 90 ++++-- .../test/integration/adapter.test.ts.ejs | 12 +- .../test/integration/fixtures.ts.ejs | 25 +- .../templates/test/unit/custombg.test.ts.ejs | 278 ++++++++++++++++++ 5 files changed, 400 insertions(+), 26 deletions(-) create mode 100644 scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs diff --git a/scripts/generator-adapter/generators/app/index.ts b/scripts/generator-adapter/generators/app/index.ts index a55cf907..237d9c49 100644 --- a/scripts/generator-adapter/generators/app/index.ts +++ b/scripts/generator-adapter/generators/app/index.ts @@ -221,7 +221,7 @@ export default class extends Generator.default { this.fs.copyTpl( this.templatePath(`test/integration/adapter.test.ts.ejs`), this.destinationPath(`${this.args[0]}/${this.props.adapterName}/test/integration/adapter.test.ts`), - { endpoints: httpEndpoints, transportName: 'rest', setBgExecuteMsEnv: false }, + { endpoints: httpEndpoints, transportName: 'rest', setBgExecuteMsEnv: false, mockPostResponse: false }, ) // Create http unit test files @@ -270,9 +270,11 @@ export default class extends Generator.default { this.fs.copyTpl( this.templatePath(`test/integration/adapter.test.ts.ejs`), this.destinationPath(`${this.args[0]}/${this.props.adapterName}/test/integration/${fileName}`), - { endpoints: customFgEndpoints, transportName: 'customfg', setBgExecuteMsEnv: false }, + { endpoints: customFgEndpoints, transportName: 'customfg', setBgExecuteMsEnv: false, mockPostResponse: false }, ) } + + // Create adapter.test.ts or adapter-custombg.test.ts if there is at least one endpoint with customBgTransport if (customBgEndpoints.length) { let fileName = 'adapter.test.ts' if (httpEndpoints.length || wsEndpoints.length || customFgEndpoints.length) { @@ -281,8 +283,18 @@ export default class extends Generator.default { this.fs.copyTpl( this.templatePath(`test/integration/adapter.test.ts.ejs`), this.destinationPath(`${this.args[0]}/${this.props.adapterName}/test/integration/${fileName}`), - { endpoints: customBgEndpoints, transportName: 'custombg', setBgExecuteMsEnv: true }, + { endpoints: customBgEndpoints, transportName: 'custombg', setBgExecuteMsEnv: true, mockPostResponse: true }, ) + + // Create customBg unit test files + for (const { inputEndpointName, normalizedEndpointNameCap, inputTransports } of customBgEndpoints) { + const transportFileBaseName = inputTransports.length > 1 ? `${inputEndpointName}-custombg` : inputEndpointName + this.fs.copyTpl( + this.templatePath(`test/unit/custombg.test.ts.ejs`), + this.destinationPath(`${this.args[0]}/${this.props.adapterName}/test/unit/${transportFileBaseName}.test.ts`), + { inputEndpointName, normalizedEndpointNameCap, transportFileBaseName }, + ) + } } // Copy test fixtures @@ -291,7 +303,8 @@ export default class extends Generator.default { this.destinationPath(`${this.args[0]}/${this.props.adapterName}/test/integration/fixtures.ts`), { includeWsFixtures: wsEndpoints.length > 0, - includeHttpFixtures: httpEndpoints.length > 0 || customBgEndpoints.length > 0 || customFgEndpoints.length > 0, + includeHttpFixtures: httpEndpoints.length > 0 || customFgEndpoints.length > 0, + includeCustomBgFixtures: customBgEndpoints.length > 0 }, ) diff --git a/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs b/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs index d7a622e1..5e2cb079 100644 --- a/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs @@ -1,4 +1,5 @@ import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { calculateHttpRequestKey } from '@chainlink/external-adapter-framework/cache' import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' import { Requester } from '@chainlink/external-adapter-framework/util/requester' import { @@ -9,34 +10,48 @@ import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' import { BaseEndpointTypes, inputParameters } from '../endpoint/<%= inputEndpointName %>' import { AdapterError } from '@chainlink/external-adapter-framework/validation/error' -const logger = makeLogger('CustomTransport') +const logger = makeLogger('<%= normalizedEndpointNameCap %>Transport') type RequestParams = typeof inputParameters.validated +type PriceResponse = { + [symbol: string]: { + price: number + } +} + <% if (includeComments) { -%> -// CustomTransport extends base types from endpoint and adds additional, Provider-specific types (if needed). +// <%= normalizedEndpointNameCap %>Transport extends base types from endpoint and adds additional, Provider-specific types (if needed). <% } -%> -export type CustomTransportTypes = BaseEndpointTypes & { +export type <%= normalizedEndpointNameCap %>TransportTypes = BaseEndpointTypes & { Provider: { RequestBody: never ResponseBody: any } } <% if (includeComments) { -%> -// CustomTransport is used to perform custom data fetching and processing from a Provider. The framework provides built-in transports to -// fetch data from a Provider using several protocols, including `http`, `websocket`, and `sse`. Use CustomTransport when the Provider uses +// <%= normalizedEndpointNameCap %>Transport is used to perform custom data fetching and processing from a Provider. The framework provides built-in transports to +// fetch data from a Provider using several protocols, including `http`, `websocket`, and `sse`. Use <%= normalizedEndpointNameCap %>Transport when the Provider uses // different protocol, or you need custom functionality that built-in transports don't support. For example, custom, multistep authentication // for requests, paginated requests, on-chain data retrieval using third party libraries, and so on. <% } -%> -export class CustomTransport extends SubscriptionTransport { +export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTransport<<%= normalizedEndpointNameCap %>TransportTypes> { <% if (includeComments) { -%> // name of the transport, used for logging <% } -%> name!: string +<% if (includeComments) { -%> + // name of the endpoint, used to calculate the request key +<% } -%> + endpointName!: string +<% if (includeComments) { -%> + // instance of adapter config +<% } -%> + config!: BaseEndpointTypes['Settings'] <% if (includeComments) { -%> // cache instance for caching responses from provider <% } -%> - responseCache!: ResponseCache + responseCache!: ResponseCache<<%= normalizedEndpointNameCap %>TransportTypes> <% if (includeComments) { -%> // instance of Requester to be used for data fetching. Use this instance to perform http calls <% } -%> @@ -46,8 +61,10 @@ export class CustomTransport extends SubscriptionTransport // REQUIRED. Transport will be automatically initialized by the framework using this method. It will be called with transport // dependencies, adapter settings, endpoint name, and transport name as arguments. Use this method to initialize transport state <% } -%> - async initialize(dependencies: TransportDependencies, adapterSettings: CustomTransportTypes['Settings'], endpointName: string, transportName: string): Promise { + async initialize(dependencies: TransportDependencies<<%= normalizedEndpointNameCap %>TransportTypes>, adapterSettings: <%= normalizedEndpointNameCap %>TransportTypes['Settings'], endpointName: string, transportName: string): Promise { await super.initialize(dependencies, adapterSettings, endpointName, transportName) + this.config = adapterSettings + this.endpointName = endpointName this.requester = dependencies.requester } <% if (includeComments) { -%> @@ -55,13 +72,13 @@ export class CustomTransport extends SubscriptionTransport // and an array of all the entries in the subscription set as second argument. Use this method to handle the incoming // request, process it and save it in the cache. <% } -%> - async backgroundHandler(context: EndpointContext, entries: RequestParams[]) { + async backgroundHandler(context: EndpointContext<<%= normalizedEndpointNameCap %>TransportTypes>, entries: RequestParams[]) { await Promise.all(entries.map(async (param) => this.handleRequest(param))) await sleep(context.adapterSettings.BACKGROUND_EXECUTE_MS) } async handleRequest(param: RequestParams) { - let response: AdapterResponse + let response: AdapterResponse<<%= normalizedEndpointNameCap %>TransportTypes['Response']> try { response = await this._handleRequest(param) } catch (e) { @@ -81,19 +98,56 @@ export class CustomTransport extends SubscriptionTransport } async _handleRequest( - _: RequestParams, - ): Promise> { + params: RequestParams, + ): PromiseTransportTypes['Response']>> { - const providerDataRequestedUnixMs = Date.now() + const providerDataRequestedUnixMs = Date.now() - // custom transport logic + // custom transport logic + + const requestConfig = { + method: 'POST', + baseURL: this.config.API_ENDPOINT, + url: '/cryptocurrency/price', + headers: { + 'X_API_KEY': this.config.API_KEY, + }, + data: { + symbol: params.base.toUpperCase(), + convert: params.quote.toUpperCase(), + }, + } + + const response = await this.requester.request( + calculateHttpRequestKey({ + context: { + adapterSettings: this.config, + inputParameters, + endpointName: this.endpointName, + }, + data: requestConfig.data, + transportName: this.name, + }), + requestConfig, + ) + + const data = response.response.data + const baseSymbol = params.base.toUpperCase() + const result = data[baseSymbol]?.price + + if (result === undefined) { + throw new AdapterError({ + statusCode: 502, + message: `The data provider didn't return any value for ${params.base}/${params.quote}`, + }) + } return { data: { - result: 2000, + result, }, statusCode: 200, - result: 2000, + result, timestamps: { providerDataRequestedUnixMs, providerDataReceivedUnixMs: Date.now(), @@ -102,9 +156,9 @@ export class CustomTransport extends SubscriptionTransport } } - getSubscriptionTtlFromConfig(adapterSettings: CustomTransportTypes['Settings']): number { + getSubscriptionTtlFromConfig(adapterSettings: <%= normalizedEndpointNameCap %>TransportTypes['Settings']): number { return adapterSettings.WARMUP_SUBSCRIPTION_TTL } } -export const customSubscriptionTransport = new CustomTransport() \ No newline at end of file +export const customSubscriptionTransport = new <%= normalizedEndpointNameCap %>Transport() diff --git a/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs b/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs index f86ed0c5..8478994a 100644 --- a/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs @@ -3,7 +3,11 @@ import { setEnvVariables, } from '@chainlink/external-adapter-framework/util/testing-utils' import * as nock from 'nock' +<% if (mockPostResponse) { %> +import { mockPostResponseSuccess } from './fixtures' +<% } else { %> import { mockResponseSuccess } from './fixtures' +<% } %> describe('execute', () => { let spy: jest.SpyInstance @@ -41,11 +45,15 @@ describe('execute', () => { endpoint: '<%= endpoints[i].inputEndpointName %>', transport: '<%= transportName %>' } +<% if (mockPostResponse) { %> + mockPostResponseSuccess() +<% } else { %> mockResponseSuccess() +<% } %> const response = await testAdapter.request(data) - expect(response.statusCode).toBe(200) expect(response.json()).toMatchSnapshot() + expect(response.statusCode).toBe(200) }) }) - <% } %> +<% } %> }) diff --git a/scripts/generator-adapter/generators/app/templates/test/integration/fixtures.ts.ejs b/scripts/generator-adapter/generators/app/templates/test/integration/fixtures.ts.ejs index 7d1fed78..4daef21b 100644 --- a/scripts/generator-adapter/generators/app/templates/test/integration/fixtures.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/test/integration/fixtures.ts.ejs @@ -1,4 +1,4 @@ -<% if (includeHttpFixtures) { %>import nock from 'nock'<% } %> +<% if (includeHttpFixtures || includeCustomBgFixtures) { %>import nock from 'nock'<% } %> <% if (includeWsFixtures) { %>import { MockWebsocketServer } from '@chainlink/external-adapter-framework/util/testing-utils'<% } %> <% if (includeHttpFixtures) { %> export const mockResponseSuccess = (): nock.Scope => @@ -22,6 +22,27 @@ export const mockResponseSuccess = (): nock.Scope => ]) .persist() <% } %> +<% if (includeCustomBgFixtures) { %> +export const mockPostResponseSuccess = (): nock.Scope => + nock('https://dataproviderapi.com', { + encodedQueryParams: true, + }) + .post('/cryptocurrency/price', { + symbol: 'ETH', + convert: 'USD', + }) + .reply(200, () => ({ ETH: { price: 10000 } }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + .persist() +<% } %> <% if (includeWsFixtures) { %> export const mockWebsocketServer = (URL: string): MockWebsocketServer => { const mockWsServer = new MockWebsocketServer(URL, { mock: false }) @@ -41,4 +62,4 @@ export const mockWebsocketServer = (URL: string): MockWebsocketServer => { return mockWsServer } -<% } %> \ No newline at end of file +<% } %> diff --git a/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs b/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs new file mode 100644 index 00000000..6706cb3a --- /dev/null +++ b/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs @@ -0,0 +1,278 @@ +import { EndpointContext } from '@chainlink/external-adapter-framework/adapter' +import { calculateHttpRequestKey } from '@chainlink/external-adapter-framework/cache' +import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' +import { deferredPromise, LoggerFactoryProvider } from '@chainlink/external-adapter-framework/util' +import { makeStub } from '@chainlink/external-adapter-framework/util/testing-utils' +import { BaseEndpointTypes, inputParameters } from '../../src/endpoint/<%= inputEndpointName %>' +import { <%= normalizedEndpointNameCap %>Transport } from '../../src/transport/<%= transportFileBaseName %>' + +const log = jest.fn() +const debugLog = jest.fn() +const logger = { + fatal: log, + error: log, + warn: log, + info: log, + debug: debugLog, + trace: debugLog, + msgPrefix: 'mock-logger', +} + +const loggerFactory = { child: () => logger } + +LoggerFactoryProvider.set(loggerFactory) + +describe('<%= normalizedEndpointNameCap %>Transport', () => { + const transportName = 'default_single_transport' + const endpointName = '<%= inputEndpointName %>' + const API_ENDPOINT = 'http://api.example.com' + const API_KEY = 'test-api-key' + const BACKGROUND_EXECUTE_MS = 10_000 + + const adapterSettings = makeStub('adapterSettings', { + API_ENDPOINT, + API_KEY, + WARMUP_SUBSCRIPTION_TTL: 10_000, + BACKGROUND_EXECUTE_MS, + MAX_COMMON_KEY_SIZE: 300, + } as unknown as BaseEndpointTypes['Settings']) + + const context = makeStub('context', { + adapterSettings, + } as EndpointContext) + + const requester = makeStub('requester', { + request: jest.fn(), + }) + + const responseCache = { + write: jest.fn(), + } + + const dependencies = makeStub('dependencies', { + requester, + responseCache, + subscriptionSetFactory: { + buildSet: jest.fn(), + }, + } as unknown as TransportDependencies) + + let transport: <%= normalizedEndpointNameCap %>Transport + + type RequestConfig = { + baseURL: string + method: 'POST' + data: { + method: 'account_info' + params: [ + { + account: string + ledger_index: 'validated' + }, + ] + } + } + + const requestConfigForParams = ({ + base, + quote, + }: { + base: string + quote: string + }): RequestConfig => ({ + method: 'POST', + baseURL: adapterSettings.API_ENDPOINT, + url: '/cryptocurrency/price', + headers: { + 'X_API_KEY': adapterSettings.API_KEY, + }, + data: { + symbol: base.toUpperCase(), + convert: quote.toUpperCase(), + }, + }) + + const requestKeyForConfig = (requestConfig: RequestConfig) => { + const requestKey = calculateHttpRequestKey({ + context: { + adapterSettings, + inputParameters, + endpointName, + }, + data: requestConfig.data, + transportName, + }) + /* + expect(log).toBeCalledWith(`Generated HTTP request queue key: "${requestKey}"`) + expect(log).toBeCalledTimes(1) + log.mockClear() + */ + return requestKey + } + + const mockPriceResponse = (symbol: string, price: number | Promise) => { + requester.request.mockImplementationOnce(async () => { + return { + response: { + data: { + [symbol.toUpperCase()]: { + price: await price, + } + }, + }, + } + }) + } + + beforeEach(async () => { + jest.resetAllMocks() + jest.useFakeTimers() + + transport = new <%= normalizedEndpointNameCap %>Transport() + + await transport.initialize(dependencies, adapterSettings, endpointName, transportName) + }) + + afterEach(() => { + expect(log).not.toBeCalled() + }) + + describe('backgroundHandler', () => { + it('should sleep after handleRequest', async () => { + const t0 = Date.now() + let t1 = 0 + transport.backgroundHandler(context, []).then(() => { + t1 = Date.now() + }) + await jest.runAllTimersAsync() + expect(t1 - t0).toBe(BACKGROUND_EXECUTE_MS) + }) + }) + + describe('handleRequest', () => { + it('should cache response', async () => { + const from = 'ETH' + const to = 'USD' + const price = 2100 + + const params = makeStub('params', { + base: from, + quote: to, + }) + + mockPriceResponse(from, price) + + await transport.handleRequest(params) + + const expectedResult = price + + const expectedResponse = { + statusCode: 200, + result: expectedResult, + data: { + result: expectedResult, + }, + timestamps: { + providerDataRequestedUnixMs: Date.now(), + providerDataReceivedUnixMs: Date.now(), + providerIndicatedTimeUnixMs: undefined, + }, + } + + expect(responseCache.write).toBeCalledWith(transportName, [ + { + params, + response: expectedResponse, + }, + ]) + expect(responseCache.write).toBeCalledTimes(1) + }) + }) + + describe('_handleRequest', () => { + it('should return price response', async () => { + const from = 'ETH' + const to = 'USD' + const price = 2100 + + const params = makeStub('params', { + base: from, + quote: to, + }) + + mockPriceResponse(from, price) + const response = await transport._handleRequest(params) + + const expectedResult = price + + expect(response).toEqual({ + statusCode: 200, + result: expectedResult, + data: { + result: expectedResult, + }, + timestamps: { + providerDataRequestedUnixMs: Date.now(), + providerDataReceivedUnixMs: Date.now(), + providerIndicatedTimeUnixMs: undefined, + }, + }) + + const expectedRequestConfig = requestConfigForParams(params) + const expectedRequestKey = requestKeyForConfig(expectedRequestConfig) + + expect(requester.request).toHaveBeenCalledWith(expectedRequestKey, expectedRequestConfig) + expect(requester.request).toHaveBeenCalledTimes(1) + }) + + it('should throw if response does not include price', async () => { + const from = 'ETH' + const to = 'USD' + const price = undefined + + const params = makeStub('params', { + base: from, + quote: to, + }) + + mockPriceResponse(from, price) + expect(() => transport._handleRequest(params)).rejects.toThrow(`The data provider didn't return any value for ${params.base}/${params.quote}`) + }) + + it('should record received timestamp separate from requested timestamp', async () => { + const from = 'ETH' + const to = 'USD' + const price = 2100 + + const params = makeStub('params', { + base: from, + quote: to, + }) + + const [pricePromise, resolvePrice] = deferredPromise() + mockPriceResponse(from, pricePromise) + + const requestTimestamp = Date.now() + const responsePromise = transport._handleRequest(params) + jest.advanceTimersByTime(1234) + const responseTimestamp = Date.now() + expect(responseTimestamp).toBeGreaterThan(requestTimestamp) + + resolvePrice(price) + + const expectedResult = price + expect(await responsePromise).toEqual({ + statusCode: 200, + result: expectedResult, + data: { + result: expectedResult, + }, + timestamps: { + providerDataRequestedUnixMs: requestTimestamp, + providerDataReceivedUnixMs: responseTimestamp, + providerIndicatedTimeUnixMs: undefined, + }, + }) + }) + }) +}) From 0ddb09b1d329bd66aa0b04cd4140c89b1399da17 Mon Sep 17 00:00:00 2001 From: David de Kloet Date: Fri, 5 Jun 2026 11:41:58 +0200 Subject: [PATCH 2/2] Fix compilation issues --- .../templates/src/transport/custombg.ts.ejs | 35 ++++++------------- .../test/integration/adapter.test.ts.ejs | 6 +--- .../templates/test/unit/custombg.test.ts.ejs | 18 +++------- 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs b/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs index 5e2cb079..75c724c1 100644 --- a/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/src/transport/custombg.ts.ejs @@ -1,6 +1,5 @@ import { TransportDependencies } from '@chainlink/external-adapter-framework/transports' import { calculateHttpRequestKey } from '@chainlink/external-adapter-framework/cache' -import { ResponseCache } from '@chainlink/external-adapter-framework/cache/response' import { Requester } from '@chainlink/external-adapter-framework/util/requester' import { AdapterResponse, sleep, makeLogger @@ -20,26 +19,13 @@ type PriceResponse = { } } -<% if (includeComments) { -%> -// <%= normalizedEndpointNameCap %>Transport extends base types from endpoint and adds additional, Provider-specific types (if needed). -<% } -%> -export type <%= normalizedEndpointNameCap %>TransportTypes = BaseEndpointTypes & { - Provider: { - RequestBody: never - ResponseBody: any - } -} <% if (includeComments) { -%> // <%= normalizedEndpointNameCap %>Transport is used to perform custom data fetching and processing from a Provider. The framework provides built-in transports to // fetch data from a Provider using several protocols, including `http`, `websocket`, and `sse`. Use <%= normalizedEndpointNameCap %>Transport when the Provider uses // different protocol, or you need custom functionality that built-in transports don't support. For example, custom, multistep authentication // for requests, paginated requests, on-chain data retrieval using third party libraries, and so on. <% } -%> -export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTransport<<%= normalizedEndpointNameCap %>TransportTypes> { -<% if (includeComments) { -%> - // name of the transport, used for logging -<% } -%> - name!: string +export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTransport { <% if (includeComments) { -%> // name of the endpoint, used to calculate the request key <% } -%> @@ -48,10 +34,6 @@ export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTrans // instance of adapter config <% } -%> config!: BaseEndpointTypes['Settings'] -<% if (includeComments) { -%> - // cache instance for caching responses from provider -<% } -%> - responseCache!: ResponseCache<<%= normalizedEndpointNameCap %>TransportTypes> <% if (includeComments) { -%> // instance of Requester to be used for data fetching. Use this instance to perform http calls <% } -%> @@ -61,7 +43,12 @@ export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTrans // REQUIRED. Transport will be automatically initialized by the framework using this method. It will be called with transport // dependencies, adapter settings, endpoint name, and transport name as arguments. Use this method to initialize transport state <% } -%> - async initialize(dependencies: TransportDependencies<<%= normalizedEndpointNameCap %>TransportTypes>, adapterSettings: <%= normalizedEndpointNameCap %>TransportTypes['Settings'], endpointName: string, transportName: string): Promise { + async initialize( + dependencies: TransportDependencies, + adapterSettings: BaseEndpointTypes['Settings'], + endpointName: string, + transportName: string + ): Promise { await super.initialize(dependencies, adapterSettings, endpointName, transportName) this.config = adapterSettings this.endpointName = endpointName @@ -72,13 +59,13 @@ export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTrans // and an array of all the entries in the subscription set as second argument. Use this method to handle the incoming // request, process it and save it in the cache. <% } -%> - async backgroundHandler(context: EndpointContext<<%= normalizedEndpointNameCap %>TransportTypes>, entries: RequestParams[]) { + async backgroundHandler(context: EndpointContext, entries: RequestParams[]) { await Promise.all(entries.map(async (param) => this.handleRequest(param))) await sleep(context.adapterSettings.BACKGROUND_EXECUTE_MS) } async handleRequest(param: RequestParams) { - let response: AdapterResponse<<%= normalizedEndpointNameCap %>TransportTypes['Response']> + let response: AdapterResponse try { response = await this._handleRequest(param) } catch (e) { @@ -99,7 +86,7 @@ export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTrans async _handleRequest( params: RequestParams, - ): PromiseTransportTypes['Response']>> { + ): Promise> { const providerDataRequestedUnixMs = Date.now() @@ -156,7 +143,7 @@ export class <%= normalizedEndpointNameCap %>Transport extends SubscriptionTrans } } - getSubscriptionTtlFromConfig(adapterSettings: <%= normalizedEndpointNameCap %>TransportTypes['Settings']): number { + getSubscriptionTtlFromConfig(adapterSettings: BaseEndpointTypes['Settings']): number { return adapterSettings.WARMUP_SUBSCRIPTION_TTL } } diff --git a/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs b/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs index 8478994a..55e294e3 100644 --- a/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/test/integration/adapter.test.ts.ejs @@ -3,11 +3,7 @@ import { setEnvVariables, } from '@chainlink/external-adapter-framework/util/testing-utils' import * as nock from 'nock' -<% if (mockPostResponse) { %> -import { mockPostResponseSuccess } from './fixtures' -<% } else { %> -import { mockResponseSuccess } from './fixtures' -<% } %> +import { <% if (mockPostResponse) { %>mockPostResponseSuccess<% } else { %>mockResponseSuccess<% } %> } from './fixtures' describe('execute', () => { let spy: jest.SpyInstance diff --git a/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs b/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs index 6706cb3a..405f5e9f 100644 --- a/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs +++ b/scripts/generator-adapter/generators/app/templates/test/unit/custombg.test.ts.ejs @@ -61,15 +61,12 @@ describe('<%= normalizedEndpointNameCap %>Transport', () => { type RequestConfig = { baseURL: string + url: string method: 'POST' + headers: Record data: { - method: 'account_info' - params: [ - { - account: string - ledger_index: 'validated' - }, - ] + symbol: string + convert: string } } @@ -102,11 +99,6 @@ describe('<%= normalizedEndpointNameCap %>Transport', () => { data: requestConfig.data, transportName, }) - /* - expect(log).toBeCalledWith(`Generated HTTP request queue key: "${requestKey}"`) - expect(log).toBeCalledTimes(1) - log.mockClear() - */ return requestKey } @@ -228,7 +220,7 @@ describe('<%= normalizedEndpointNameCap %>Transport', () => { it('should throw if response does not include price', async () => { const from = 'ETH' const to = 'USD' - const price = undefined + const price = undefined as unknown as number const params = makeStub('params', { base: from,