From 3e8e71a6d7a5aa890e6accc2d910b4222ffa3610 Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Wed, 2 Oct 2024 19:06:18 -0700 Subject: [PATCH 1/7] Improve types for mocking --- CHANGELOG.md | 4 ++++ dist/testing/execution.d.ts | 6 +++++ dist/testing/execution.js | 17 +++++++++++++- dist/testing/mocks.d.ts | 12 ++++++---- dist/testing/mocks.js | 4 +++- .../testing.MockExecutionContext.md | 6 ++--- .../testing.MockSyncExecutionContext.md | 8 +++---- test/compile_test.ts | 10 ++++++--- test/execution_test.ts | 8 +++---- testing/execution.ts | 20 +++++++++++++++++ testing/mocks.ts | 22 ++++++++++++++----- 11 files changed, 92 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dda106104f..4becc3c630 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This changelog keeps track of all changes to the Packs SDK. We follow convention - Add continuation for get permissions request and response +### Changed + +- Improve types for testing + ## [1.7.19] - 2024-09-27 ### Changed diff --git a/dist/testing/execution.d.ts b/dist/testing/execution.d.ts index 1d3b5d22be..4faf97aad0 100644 --- a/dist/testing/execution.d.ts +++ b/dist/testing/execution.d.ts @@ -77,6 +77,12 @@ export declare function executeSyncFormulaFromPackDef(pa * including the continuation, for inspection. */ export declare function executeSyncFormulaFromPackDefSingleIteration(packDef: BasicPackDefinition, syncFormulaName: string, params: ParamValues, context?: SyncExecutionContext, options?: ExecuteOptions, { useRealFetcher, manifestPath }?: ContextOptions): Promise; +/** + * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. + * + * @hidden + */ +export declare function transformSyncFormulaResultToGetPermissionsRequest(packDef: BasicPackDefinition, syncFormulaName: string, result: GenericSyncFormulaResult): GenericExecuteGetPermissionsRequest; /** * Executes an executeGetPermissions request and returns the result. * diff --git a/dist/testing/execution.js b/dist/testing/execution.js index 186ca16c4e..7b1456d00b 100644 --- a/dist/testing/execution.js +++ b/dist/testing/execution.js @@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.newRealFetcherSyncExecutionContext = exports.newRealFetcherExecutionContext = exports.executeMetadataFormula = exports.executeUpdateFormulaFromPackDef = exports.executeGetPermissionsFormulaFromPackDef = exports.executeSyncFormulaFromPackDefSingleIteration = exports.executeSyncFormulaFromPackDef = exports.executeFormulaOrSyncWithRawParams = exports.VMError = exports.executeFormulaOrSyncWithVM = exports.makeFormulaSpec = exports.executeFormulaOrSyncFromCLI = exports.executeFormulaFromPackDef = exports.DEFAULT_MAX_ROWS = void 0; +exports.newRealFetcherSyncExecutionContext = exports.newRealFetcherExecutionContext = exports.executeMetadataFormula = exports.executeUpdateFormulaFromPackDef = exports.executeGetPermissionsFormulaFromPackDef = exports.transformSyncFormulaResultToGetPermissionsRequest = exports.executeSyncFormulaFromPackDefSingleIteration = exports.executeSyncFormulaFromPackDef = exports.executeFormulaOrSyncWithRawParams = exports.VMError = exports.executeFormulaOrSyncWithVM = exports.makeFormulaSpec = exports.executeFormulaOrSyncFromCLI = exports.executeFormulaFromPackDef = exports.DEFAULT_MAX_ROWS = void 0; const types_1 = require("../runtime/types"); const types_2 = require("../runtime/types"); const buffer_1 = require("buffer/"); @@ -52,6 +52,7 @@ const thunk = __importStar(require("../runtime/thunk/thunk")); const handler_templates_1 = require("../handler_templates"); const helpers_7 = require("../runtime/common/helpers"); const helpers_8 = require("../runtime/common/helpers"); +const handler_templates_2 = require("../handler_templates"); const util_1 = __importDefault(require("util")); const validation_1 = require("./validation"); const validation_2 = require("./validation"); @@ -471,6 +472,20 @@ async function executeSyncFormulaFromPackDefSingleIteration(packDef, syncFormula return findAndExecutePackFunction(params, { formulaName: syncFormulaName, type: types_1.FormulaType.Sync }, packDef, executionContext || (0, mocks_2.newMockSyncExecutionContext)(), undefined, undefined, options); } exports.executeSyncFormulaFromPackDefSingleIteration = executeSyncFormulaFromPackDefSingleIteration; +/** + * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. + * + * @hidden + */ +function transformSyncFormulaResultToGetPermissionsRequest(packDef, syncFormulaName, result) { + const formula = (0, helpers_2.findSyncFormula)(packDef, syncFormulaName); + const itemSchema = (0, ensure_1.ensureExists)(formula.schema).items; + const rows = result.result.map(r => ({ + row: (0, handler_templates_2.untransformBody)(r, itemSchema), + })); + return { rows }; +} +exports.transformSyncFormulaResultToGetPermissionsRequest = transformSyncFormulaResultToGetPermissionsRequest; /** * Executes an executeGetPermissions request and returns the result. * diff --git a/dist/testing/mocks.d.ts b/dist/testing/mocks.d.ts index 9f97dfd9e8..bc409b06dd 100644 --- a/dist/testing/mocks.d.ts +++ b/dist/testing/mocks.d.ts @@ -1,18 +1,22 @@ import type { ExecutionContext } from '../api_types'; +import type { FetchRequest } from '../api_types'; import type { FetchResponse } from '../api_types'; import type { Sync } from '../api_types'; +import type { TemporaryBlobStorage } from '../api_types'; import sinon from 'sinon'; +export type SinonFunctionSpy any> = T extends (...args: infer ArgsT) => infer RetT ? sinon.SinonSpy : never; +export type SinonFunctionStub any> = T extends (...args: infer ArgsT) => infer RetT ? sinon.SinonStub : never; export interface MockExecutionContext extends ExecutionContext { fetcher: { - fetch: sinon.SinonStub; + fetch: sinon.SinonStub<[request: FetchRequest], Promise>>; }; temporaryBlobStorage: { - storeUrl: sinon.SinonStub; - storeBlob: sinon.SinonStub; + storeUrl: SinonFunctionStub; + storeBlob: SinonFunctionStub; }; } export interface MockSyncExecutionContext extends MockExecutionContext { - readonly sync: Sync; + sync: Sync; } export declare function newMockSyncExecutionContext(overrides?: Partial): MockSyncExecutionContext; export declare function newMockExecutionContext(overrides?: Partial): MockExecutionContext; diff --git a/dist/testing/mocks.js b/dist/testing/mocks.js index 7cee65cf6c..f3f6ed6e02 100644 --- a/dist/testing/mocks.js +++ b/dist/testing/mocks.js @@ -18,7 +18,9 @@ function newMockExecutionContext(overrides) { timezone: 'America/Los_Angeles', invocationToken: (0, uuid_1.v4)(), fetcher: { - fetch: sinon_1.default.stub(), + fetch: sinon_1.default.stub().callsFake(async (r) => { + throw new Error(`Unhandled fetch: ${r.method} ${r.url}`); + }), }, temporaryBlobStorage: { storeUrl: sinon_1.default.stub(), diff --git a/docs/reference/sdk/interfaces/testing.MockExecutionContext.md b/docs/reference/sdk/interfaces/testing.MockExecutionContext.md index 9d629f3dcb..4c56ad7e11 100644 --- a/docs/reference/sdk/interfaces/testing.MockExecutionContext.md +++ b/docs/reference/sdk/interfaces/testing.MockExecutionContext.md @@ -49,7 +49,7 @@ The [Fetcher](core.Fetcher.md) used for making HTTP requests. | Name | Type | | :------ | :------ | -| `fetch` | `SinonStub`<`any`[], `any`\> | +| `fetch` | `SinonStub`<[request: FetchRequest], `Promise`<[`FetchResponse`](core.FetchResponse.md)<`any`\>\>\> | #### Overrides @@ -108,8 +108,8 @@ or are too large to return inline. See [TemporaryBlobStorage](core.TemporaryBlob | Name | Type | | :------ | :------ | -| `storeBlob` | `SinonStub`<`any`[], `any`\> | -| `storeUrl` | `SinonStub`<`any`[], `any`\> | +| `storeBlob` | `SinonStub`<[blobData: Buffer, contentType: string, opts?: Object], `Promise`<`string`\>\> | +| `storeUrl` | `SinonStub`<[url: string, opts?: Object, fetchOpts?: Pick], `Promise`<`string`\>\> | #### Overrides diff --git a/docs/reference/sdk/interfaces/testing.MockSyncExecutionContext.md b/docs/reference/sdk/interfaces/testing.MockSyncExecutionContext.md index fbb23610c4..4d8e504a4f 100644 --- a/docs/reference/sdk/interfaces/testing.MockSyncExecutionContext.md +++ b/docs/reference/sdk/interfaces/testing.MockSyncExecutionContext.md @@ -47,7 +47,7 @@ The [Fetcher](core.Fetcher.md) used for making HTTP requests. | Name | Type | | :------ | :------ | -| `fetch` | `SinonStub`<`any`[], `any`\> | +| `fetch` | `SinonStub`<[request: FetchRequest], `Promise`<[`FetchResponse`](core.FetchResponse.md)<`any`\>\>\> | #### Inherited from @@ -85,7 +85,7 @@ ___ ### sync -• `Readonly` **sync**: [`Sync`](core.Sync.md) +• **sync**: [`Sync`](core.Sync.md) Information about state of the current sync. Only populated if this is a sync table formula. @@ -106,8 +106,8 @@ or are too large to return inline. See [TemporaryBlobStorage](core.TemporaryBlob | Name | Type | | :------ | :------ | -| `storeBlob` | `SinonStub`<`any`[], `any`\> | -| `storeUrl` | `SinonStub`<`any`[], `any`\> | +| `storeBlob` | `SinonStub`<[blobData: Buffer, contentType: string, opts?: Object], `Promise`<`string`\>\> | +| `storeUrl` | `SinonStub`<[url: string, opts?: Object, fetchOpts?: Pick], `Promise`<`string`\>\> | #### Inherited from diff --git a/test/compile_test.ts b/test/compile_test.ts index 1ee1e8f9e5..c146110fc1 100644 --- a/test/compile_test.ts +++ b/test/compile_test.ts @@ -2,6 +2,7 @@ import {compilePackBundle} from '../testing/compile'; import {executeFormulaOrSyncWithVM} from '../testing/execution'; import {newMockSyncExecutionContext} from '../testing/mocks'; import path from 'path'; +import sinon from 'sinon'; import {translateErrorStackFromVM} from '../runtime/common/source_map'; describe('compile', () => { @@ -79,9 +80,12 @@ describe('compile', () => { }); assert.equal(response, 'okay'); assert.isTrue( - executionContext.temporaryBlobStorage.storeBlob.calledWithMatch((buffer: any) => { - return Buffer.isBuffer(buffer); - }, 'text/html'), + executionContext.temporaryBlobStorage.storeBlob.calledWithMatch( + sinon.match((buffer: any) => { + return Buffer.isBuffer(buffer); + }), + 'text/html', + ), ); }); }); diff --git a/test/execution_test.ts b/test/execution_test.ts index 2da141f163..f96ad29bdd 100644 --- a/test/execution_test.ts +++ b/test/execution_test.ts @@ -149,7 +149,7 @@ describe('Execution', () => { describe('fetcher mocks', () => { it('fetch calls are mocked', async () => { const context = newMockExecutionContext(); - context.fetcher.fetch.returns(newJsonFetchResponse({result: 'hello'})); + context.fetcher.fetch.resolves(newJsonFetchResponse({result: 'hello'})); const result = await executeFormulaFromPackDef(fakePack, 'Lookup', ['foo'], context); assert.equal(result, 'hello'); @@ -177,8 +177,8 @@ describe('Execution', () => { }); const context = newMockExecutionContext(); - context.temporaryBlobStorage.storeBlob.returns('blob-url-1'); - context.temporaryBlobStorage.storeUrl.returns('blob-url-2'); + context.temporaryBlobStorage.storeBlob.resolves('blob-url-1'); + context.temporaryBlobStorage.storeUrl.resolves('blob-url-2'); const result = await executeFormulaFromPackDef(fakeBlobPack, 'Blobs', [], context); assert.equal(result, 'blob-url-1,blob-url-2'); @@ -391,7 +391,7 @@ describe('Execution', () => { it('executes getConnectionName formula', async () => { assertCondition(fakePackWithMetadata.defaultAuthentication?.type === AuthenticationType.HeaderBearerToken); const context = newMockExecutionContext(); - context.fetcher.fetch.returns(newJsonFetchResponse({username: 'some-user'})); + context.fetcher.fetch.resolves(newJsonFetchResponse({username: 'some-user'})); const result = await executeMetadataFormula( fakePackWithMetadata.defaultAuthentication.getConnectionName!, diff --git a/testing/execution.ts b/testing/execution.ts index ed533b9558..e74d9f0f01 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -1,5 +1,6 @@ import type {BasicPackDefinition} from '../types'; import type {Credentials} from './auth_types'; +import type {ExecuteGetPermissionsRequestRow} from '../api'; import type {ExecutionContext} from '../api_types'; import type {FormulaSpecification} from '../runtime/types'; import {FormulaType} from '../runtime/types'; @@ -47,6 +48,7 @@ import * as thunk from '../runtime/thunk/thunk'; import {transformBody} from '../handler_templates'; import {tryFindFormula} from '../runtime/common/helpers'; import {tryFindSyncFormula} from '../runtime/common/helpers'; +import {untransformBody} from '../handler_templates'; import util from 'util'; import {validateParams} from './validation'; import {validateResult} from './validation'; @@ -677,6 +679,24 @@ export async function executeSyncFormulaFromPackDefSingleIteration( ) as Promise; } +/** + * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. + * + * @hidden + */ +export function transformSyncFormulaResultToGetPermissionsRequest( + packDef: BasicPackDefinition, + syncFormulaName: string, + result: GenericSyncFormulaResult, +): GenericExecuteGetPermissionsRequest { + const formula = findSyncFormula(packDef, syncFormulaName); + const itemSchema = ensureExists(formula.schema).items; + const rows = result.result.map>(r => ({ + row: untransformBody(r, itemSchema), + })); + return {rows}; +} + /** * Executes an executeGetPermissions request and returns the result. * diff --git a/testing/mocks.ts b/testing/mocks.ts index e3301040ae..e32cbde329 100644 --- a/testing/mocks.ts +++ b/testing/mocks.ts @@ -1,21 +1,31 @@ import type {ExecutionContext} from '../api_types'; +import type {FetchRequest} from '../api_types'; import type {FetchResponse} from '../api_types'; import type {Sync} from '../api_types'; +import type {TemporaryBlobStorage} from '../api_types'; import sinon from 'sinon'; import {v4} from 'uuid'; +export type SinonFunctionSpy any> = T extends (...args: infer ArgsT) => infer RetT + ? sinon.SinonSpy + : never; + +export type SinonFunctionStub any> = T extends (...args: infer ArgsT) => infer RetT + ? sinon.SinonStub + : never; + export interface MockExecutionContext extends ExecutionContext { fetcher: { - fetch: sinon.SinonStub; + fetch: sinon.SinonStub<[request: FetchRequest], Promise>>; }; temporaryBlobStorage: { - storeUrl: sinon.SinonStub; - storeBlob: sinon.SinonStub; + storeUrl: SinonFunctionStub; + storeBlob: SinonFunctionStub; }; } export interface MockSyncExecutionContext extends MockExecutionContext { - readonly sync: Sync; + sync: Sync; } export function newMockSyncExecutionContext(overrides?: Partial): MockSyncExecutionContext { @@ -30,7 +40,9 @@ export function newMockExecutionContext(overrides?: Partial>().callsFake(async r => { + throw new Error(`Unhandled fetch: ${r.method} ${r.url}`); + }), }, temporaryBlobStorage: { storeUrl: sinon.stub(), From 1fc04a28857bc7d9e129cf40e418ecc2382571ca Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Sun, 6 Oct 2024 21:37:29 -0700 Subject: [PATCH 2/7] Fix untransformBody for arrays --- handler_templates.ts | 8 ++-- test/handler_templates_test.ts | 68 ++++++++++++++++++++++------------ testing/execution.ts | 9 ++++- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/handler_templates.ts b/handler_templates.ts index 337fcef43d..4a797765d2 100644 --- a/handler_templates.ts +++ b/handler_templates.ts @@ -306,7 +306,7 @@ function mapKeys(obj: {[key: string]: any}, schema?: Schema): object { continue; } remappedObject[newKey] = mappedKeys.length > 1 ? deepCopy(obj[key]) : obj[key]; - const keySchema: Schema & ObjectSchemaProperty | undefined = schema.properties[newKey]; + const keySchema: (Schema & ObjectSchemaProperty) | undefined = schema.properties[newKey]; const currentValue = remappedObject[newKey]; if (Array.isArray(currentValue) && isArray(keySchema) && isObject(keySchema.items)) { remappedObject[newKey] = currentValue.map(val => mapKeys(val, keySchema.items)); @@ -367,7 +367,7 @@ function unmapKeys(obj: {[key: string]: any}, schema?: Schema): object { continue; } remappedObject[newKey] = deepCopy(obj[key]); - const keySchema: Schema & ObjectSchemaProperty | undefined = schema.properties[key]; + const keySchema: (Schema & ObjectSchemaProperty) | undefined = schema.properties[key]; const currentValue = remappedObject[newKey]; if (Array.isArray(currentValue) && isArray(keySchema) && isObject(keySchema.items)) { remappedObject[newKey] = currentValue.map(val => unmapKeys(val, keySchema.items)); @@ -380,8 +380,8 @@ function unmapKeys(obj: {[key: string]: any}, schema?: Schema): object { export function untransformBody(body: any, schema: Schema | undefined): any { if (isArray(schema) && isObject(schema.items)) { - const objectBody = body as Record; - const mappedObjs = unmapKeys(objectBody, schema.items); + const objects = body as Array>; + const mappedObjs = objects.map(obj => unmapKeys(obj, schema.items)); return mappedObjs; } diff --git a/test/handler_templates_test.ts b/test/handler_templates_test.ts index 699d4b405f..3cc4c8595d 100644 --- a/test/handler_templates_test.ts +++ b/test/handler_templates_test.ts @@ -107,7 +107,7 @@ describe('handler templates', () => { }); it('array schema', () => { - const inputBody = {Foo: 'bar', Baz: 2}; + const inputBody = [{Foo: 'bar', Baz: 2}]; const body = untransformBody(inputBody, { type: ValueType.Array, items: { @@ -118,10 +118,12 @@ describe('handler templates', () => { }, }, }); - assert.deepEqual(body, { - foo: 'bar', - baz: 2, - }); + assert.deepEqual(body, [ + { + foo: 'bar', + baz: 2, + }, + ]); }); it('object schema', () => { @@ -146,20 +148,26 @@ describe('handler templates', () => { properties: { Foo: {type: ValueType.String, fromKey: 'foo'}, Baz: {type: ValueType.Number, fromKey: 'baz'}, - Biz: {type: ValueType.Array, fromKey: 'biz', items: { - type: ValueType.Object, - properties: { - Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + Biz: { + type: ValueType.Array, + fromKey: 'biz', + items: { + type: ValueType.Object, + properties: { + Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + }, }, - }}, + }, }, }); assert.deepEqual(body, { foo: 'bar', baz: 2, - biz: [{ - buzz: false, - }], + biz: [ + { + buzz: false, + }, + ], }); }); @@ -170,9 +178,13 @@ describe('handler templates', () => { properties: { Foo: {type: ValueType.String, fromKey: 'foo'}, Baz: {type: ValueType.Number, fromKey: 'baz'}, - Biz: {type: ValueType.Object, fromKey: 'biz', properties: { - Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, - }}, + Biz: { + type: ValueType.Object, + fromKey: 'biz', + properties: { + Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + }, + }, }, }); assert.deepEqual(body, { @@ -226,12 +238,16 @@ describe('handler templates', () => { properties: { Foo: {type: ValueType.String, fromKey: 'foo'}, Baz: {type: ValueType.Number, fromKey: 'baz'}, - Biz: {type: ValueType.Array, fromKey: 'biz', items: { - type: ValueType.Object, - properties: { - Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + Biz: { + type: ValueType.Array, + fromKey: 'biz', + items: { + type: ValueType.Object, + properties: { + Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + }, }, - }}, + }, }, }); assert.deepEqual(body, ['foo', 'baz', 'biz']); @@ -244,9 +260,13 @@ describe('handler templates', () => { properties: { Foo: {type: ValueType.String, fromKey: 'foo'}, Baz: {type: ValueType.Number, fromKey: 'baz'}, - Biz: {type: ValueType.Object, fromKey: 'biz', properties: { - Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, - }}, + Biz: { + type: ValueType.Object, + fromKey: 'biz', + properties: { + Buzz: {type: ValueType.Boolean, fromKey: 'buzz'}, + }, + }, }, }); assert.deepEqual(body, ['foo', 'baz', 'biz']); diff --git a/testing/execution.ts b/testing/execution.ts index e74d9f0f01..f63c4ff26c 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -131,7 +131,7 @@ async function findAndExecutePackFunction( return result; } - if (useDeprecatedResultNormalization && formula) { + if (formula) { const resultToNormalize = formulaSpec.type === FormulaType.Sync ? (result as GenericSyncFormulaResult).result : result; @@ -139,7 +139,12 @@ async function findAndExecutePackFunction( // called transform body on non-object responses. if (typeof resultToNormalize === 'object') { const schema = executionContext?.sync?.schema ?? formula.schema; - const normalizedResult = transformBody(resultToNormalize, schema); + let normalizedResult = transformBody(resultToNormalize, schema); + + if (!useDeprecatedResultNormalization) { + normalizedResult = untransformBody(normalizedResult, schema); + } + if (formulaSpec.type === FormulaType.Sync) { (result as GenericSyncFormulaResult).result = normalizedResult; } else { From 5c3745f36a5e6ba7f6276f9a8866e7c623c4b2a9 Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Sun, 6 Oct 2024 21:38:17 -0700 Subject: [PATCH 3/7] Remove executeGetPermissionsFormulaFromPackDef --- testing/execution.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/testing/execution.ts b/testing/execution.ts index f63c4ff26c..3c5fa20ea5 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -684,24 +684,6 @@ export async function executeSyncFormulaFromPackDefSingleIteration( ) as Promise; } -/** - * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. - * - * @hidden - */ -export function transformSyncFormulaResultToGetPermissionsRequest( - packDef: BasicPackDefinition, - syncFormulaName: string, - result: GenericSyncFormulaResult, -): GenericExecuteGetPermissionsRequest { - const formula = findSyncFormula(packDef, syncFormulaName); - const itemSchema = ensureExists(formula.schema).items; - const rows = result.result.map>(r => ({ - row: untransformBody(r, itemSchema), - })); - return {rows}; -} - /** * Executes an executeGetPermissions request and returns the result. * From fef07138ca9043057e7e235bc76eb0cf1c1526f8 Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Sun, 6 Oct 2024 21:38:50 -0700 Subject: [PATCH 4/7] Update changelog --- CHANGELOG.md | 1 + testing/execution.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4becc3c630..281f2a607e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This changelog keeps track of all changes to the Packs SDK. We follow convention ### Changed - Improve types for testing +- Fix `untransformBody` helper for array inputs ## [1.7.19] - 2024-09-27 diff --git a/testing/execution.ts b/testing/execution.ts index 3c5fa20ea5..2f19cce776 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -1,6 +1,5 @@ import type {BasicPackDefinition} from '../types'; import type {Credentials} from './auth_types'; -import type {ExecuteGetPermissionsRequestRow} from '../api'; import type {ExecutionContext} from '../api_types'; import type {FormulaSpecification} from '../runtime/types'; import {FormulaType} from '../runtime/types'; From 3bcf351e3a8897ad79204b420101feef3e2c7cf0 Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Sun, 6 Oct 2024 21:44:55 -0700 Subject: [PATCH 5/7] Rebuild --- dist/handler_templates.js | 4 ++-- dist/testing/execution.d.ts | 6 ------ dist/testing/execution.js | 30 +++++++++--------------------- testing/execution.ts | 11 ++++------- 4 files changed, 15 insertions(+), 36 deletions(-) diff --git a/dist/handler_templates.js b/dist/handler_templates.js index a99ddffe30..a3d5b0b91a 100644 --- a/dist/handler_templates.js +++ b/dist/handler_templates.js @@ -207,8 +207,8 @@ function unmapKeys(obj, schema) { } function untransformBody(body, schema) { if ((0, schema_1.isArray)(schema) && (0, schema_2.isObject)(schema.items)) { - const objectBody = body; - const mappedObjs = unmapKeys(objectBody, schema.items); + const objects = body; + const mappedObjs = objects.map(obj => unmapKeys(obj, schema.items)); return mappedObjs; } if ((0, schema_2.isObject)(schema)) { diff --git a/dist/testing/execution.d.ts b/dist/testing/execution.d.ts index 4faf97aad0..1d3b5d22be 100644 --- a/dist/testing/execution.d.ts +++ b/dist/testing/execution.d.ts @@ -77,12 +77,6 @@ export declare function executeSyncFormulaFromPackDef(pa * including the continuation, for inspection. */ export declare function executeSyncFormulaFromPackDefSingleIteration(packDef: BasicPackDefinition, syncFormulaName: string, params: ParamValues, context?: SyncExecutionContext, options?: ExecuteOptions, { useRealFetcher, manifestPath }?: ContextOptions): Promise; -/** - * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. - * - * @hidden - */ -export declare function transformSyncFormulaResultToGetPermissionsRequest(packDef: BasicPackDefinition, syncFormulaName: string, result: GenericSyncFormulaResult): GenericExecuteGetPermissionsRequest; /** * Executes an executeGetPermissions request and returns the result. * diff --git a/dist/testing/execution.js b/dist/testing/execution.js index 7b1456d00b..483806d3f2 100644 --- a/dist/testing/execution.js +++ b/dist/testing/execution.js @@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.newRealFetcherSyncExecutionContext = exports.newRealFetcherExecutionContext = exports.executeMetadataFormula = exports.executeUpdateFormulaFromPackDef = exports.executeGetPermissionsFormulaFromPackDef = exports.transformSyncFormulaResultToGetPermissionsRequest = exports.executeSyncFormulaFromPackDefSingleIteration = exports.executeSyncFormulaFromPackDef = exports.executeFormulaOrSyncWithRawParams = exports.VMError = exports.executeFormulaOrSyncWithVM = exports.makeFormulaSpec = exports.executeFormulaOrSyncFromCLI = exports.executeFormulaFromPackDef = exports.DEFAULT_MAX_ROWS = void 0; +exports.newRealFetcherSyncExecutionContext = exports.newRealFetcherExecutionContext = exports.executeMetadataFormula = exports.executeUpdateFormulaFromPackDef = exports.executeGetPermissionsFormulaFromPackDef = exports.executeSyncFormulaFromPackDefSingleIteration = exports.executeSyncFormulaFromPackDef = exports.executeFormulaOrSyncWithRawParams = exports.VMError = exports.executeFormulaOrSyncWithVM = exports.makeFormulaSpec = exports.executeFormulaOrSyncFromCLI = exports.executeFormulaFromPackDef = exports.DEFAULT_MAX_ROWS = void 0; const types_1 = require("../runtime/types"); const types_2 = require("../runtime/types"); const buffer_1 = require("buffer/"); @@ -102,13 +102,19 @@ useDeprecatedResultNormalization = true, } = {}) { if (formulaSpec.type === types_1.FormulaType.GetPermissions) { return result; } - if (useDeprecatedResultNormalization && formula) { + if (formula) { const resultToNormalize = formulaSpec.type === types_1.FormulaType.Sync ? result.result : result; // Matches legacy behavior within handler_templates:generateObjectResponseHandler where we never // called transform body on non-object responses. if (typeof resultToNormalize === 'object') { const schema = (_b = (_a = executionContext === null || executionContext === void 0 ? void 0 : executionContext.sync) === null || _a === void 0 ? void 0 : _a.schema) !== null && _b !== void 0 ? _b : formula.schema; - const normalizedResult = (0, handler_templates_1.transformBody)(resultToNormalize, schema); + let normalizedResult = (0, handler_templates_1.transformBody)(resultToNormalize, schema); + if (shouldValidateResult) { + (0, validation_2.validateResult)(formula, normalizedResult); + } + if (!useDeprecatedResultNormalization) { + normalizedResult = (0, handler_templates_2.untransformBody)(normalizedResult, schema); + } if (formulaSpec.type === types_1.FormulaType.Sync) { result.result = normalizedResult; } @@ -117,10 +123,6 @@ useDeprecatedResultNormalization = true, } = {}) { } } } - if (shouldValidateResult && formula) { - const resultToValidate = formulaSpec.type === types_1.FormulaType.Sync ? result.result : result; - (0, validation_2.validateResult)(formula, resultToValidate); - } return result; } async function executeFormulaFromPackDef(packDef, formulaNameWithNamespace, params, context, options, { useRealFetcher, manifestPath } = {}) { @@ -472,20 +474,6 @@ async function executeSyncFormulaFromPackDefSingleIteration(packDef, syncFormula return findAndExecutePackFunction(params, { formulaName: syncFormulaName, type: types_1.FormulaType.Sync }, packDef, executionContext || (0, mocks_2.newMockSyncExecutionContext)(), undefined, undefined, options); } exports.executeSyncFormulaFromPackDefSingleIteration = executeSyncFormulaFromPackDefSingleIteration; -/** - * Transforms a result from a sync formula execution to one that can be passed to executeGetPermissions. - * - * @hidden - */ -function transformSyncFormulaResultToGetPermissionsRequest(packDef, syncFormulaName, result) { - const formula = (0, helpers_2.findSyncFormula)(packDef, syncFormulaName); - const itemSchema = (0, ensure_1.ensureExists)(formula.schema).items; - const rows = result.result.map(r => ({ - row: (0, handler_templates_2.untransformBody)(r, itemSchema), - })); - return { rows }; -} -exports.transformSyncFormulaResultToGetPermissionsRequest = transformSyncFormulaResultToGetPermissionsRequest; /** * Executes an executeGetPermissions request and returns the result. * diff --git a/testing/execution.ts b/testing/execution.ts index 2f19cce776..61e8cff61f 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -140,6 +140,10 @@ async function findAndExecutePackFunction( const schema = executionContext?.sync?.schema ?? formula.schema; let normalizedResult = transformBody(resultToNormalize, schema); + if (shouldValidateResult) { + validateResult(formula, normalizedResult); + } + if (!useDeprecatedResultNormalization) { normalizedResult = untransformBody(normalizedResult, schema); } @@ -152,13 +156,6 @@ async function findAndExecutePackFunction( } } - if (shouldValidateResult && formula) { - const resultToValidate = - formulaSpec.type === FormulaType.Sync ? (result as GenericSyncFormulaResult).result : result; - - validateResult(formula, resultToValidate); - } - return result; } From 96ccb7b5e19c25bf9cd3dbac32df35889c2ab660 Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Sun, 6 Oct 2024 22:05:09 -0700 Subject: [PATCH 6/7] Fix validation for non object types --- dist/testing/execution.js | 8 +++++--- testing/execution.ts | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/dist/testing/execution.js b/dist/testing/execution.js index 483806d3f2..4fefc85664 100644 --- a/dist/testing/execution.js +++ b/dist/testing/execution.js @@ -104,14 +104,13 @@ useDeprecatedResultNormalization = true, } = {}) { } if (formula) { const resultToNormalize = formulaSpec.type === types_1.FormulaType.Sync ? result.result : result; + let resultToValidate = resultToNormalize; // Matches legacy behavior within handler_templates:generateObjectResponseHandler where we never // called transform body on non-object responses. if (typeof resultToNormalize === 'object') { const schema = (_b = (_a = executionContext === null || executionContext === void 0 ? void 0 : executionContext.sync) === null || _a === void 0 ? void 0 : _a.schema) !== null && _b !== void 0 ? _b : formula.schema; let normalizedResult = (0, handler_templates_1.transformBody)(resultToNormalize, schema); - if (shouldValidateResult) { - (0, validation_2.validateResult)(formula, normalizedResult); - } + resultToValidate = normalizedResult; if (!useDeprecatedResultNormalization) { normalizedResult = (0, handler_templates_2.untransformBody)(normalizedResult, schema); } @@ -122,6 +121,9 @@ useDeprecatedResultNormalization = true, } = {}) { result = normalizedResult; } } + if (shouldValidateResult) { + (0, validation_2.validateResult)(formula, resultToValidate); + } } return result; } diff --git a/testing/execution.ts b/testing/execution.ts index 61e8cff61f..e207d8f362 100644 --- a/testing/execution.ts +++ b/testing/execution.ts @@ -133,16 +133,14 @@ async function findAndExecutePackFunction( if (formula) { const resultToNormalize = formulaSpec.type === FormulaType.Sync ? (result as GenericSyncFormulaResult).result : result; + let resultToValidate = resultToNormalize; // Matches legacy behavior within handler_templates:generateObjectResponseHandler where we never // called transform body on non-object responses. if (typeof resultToNormalize === 'object') { const schema = executionContext?.sync?.schema ?? formula.schema; let normalizedResult = transformBody(resultToNormalize, schema); - - if (shouldValidateResult) { - validateResult(formula, normalizedResult); - } + resultToValidate = normalizedResult; if (!useDeprecatedResultNormalization) { normalizedResult = untransformBody(normalizedResult, schema); @@ -154,6 +152,10 @@ async function findAndExecutePackFunction( result = normalizedResult; } } + + if (shouldValidateResult) { + validateResult(formula, resultToValidate); + } } return result; From 728a745de288f98469d8110d1da75445311086bd Mon Sep 17 00:00:00 2001 From: Oleg Vaskevich Date: Mon, 7 Oct 2024 16:09:06 -0700 Subject: [PATCH 7/7] Improve changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 281f2a607e..641dee5baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ This changelog keeps track of all changes to the Packs SDK. We follow convention ### Changed -- Improve types for testing +- Improve types used for testing, specifically on `MockExecutionContext` returned by `newMockExecutionContext()`. + `fetcher.fetch`, `temporaryBlobStorage.storeUrl`, and `temporaryBlobStorage.storeBlob` should be stubbed using + `resolves()` and `rejects()` since the underlying methods return promises - Fix `untransformBody` helper for array inputs ## [1.7.19] - 2024-09-27