diff --git a/tests/unit/utils/actions/action-parameter-descriptor.spec.ts b/tests/unit/utils/actions/action-parameter-descriptor.spec.ts new file mode 100644 index 0000000..87b306b --- /dev/null +++ b/tests/unit/utils/actions/action-parameter-descriptor.spec.ts @@ -0,0 +1,177 @@ +import { ActionMetadata } from "@/utils/actions/action-metadata"; +import { ActionParameterPathParser } from "@/utils/actions/action-parameter-path-parser"; +import { getActionParameterDescriptor, getActionParameterDescriptors } from "@/utils/actions/action-parameter-descriptor"; + +const METADATA = Object.freeze({ + name: "test-metadata", + description: "Test description", + runs: { main: "index.js", using: "node16" }, + + inputs: { + "foo": { + description: "Foo description", + default: 3, + type: "number", + deprecationMessage: "Foo is deprecated", + }, + + "bar": { + description: "Bar description", + default: true, + type: "boolean", + required: false, + redirect: "bar-bar", + }, + + "baz-path": { + description: "Baz description", + type: "utils.io.FileInfo[]:{findFiles}?processSeparately=false", + required: true, + }, + }, + + outputs: { + "foo": { + description: "Foo description", + type: "number", + }, + + "bar": { + description: "Bar description", + type: "boolean", + redirect: "bar-bar", + }, + + "baz-path": { + description: "Baz description", + type: "platforms.UploadedFile[]", + }, + }, +} as ActionMetadata); + +describe("getActionParameterDescriptor", () => { + test("returns a parameter descriptor by its name", () => { + for (const name of Object.keys(METADATA.inputs)) { + const descriptorInstance = {}; + const factory = jest.fn().mockReturnValueOnce(descriptorInstance); + + const descriptor = getActionParameterDescriptor(METADATA, name, factory, METADATA.inputs); + + expect(factory).toHaveBeenCalledTimes(1); + expect(factory).toHaveBeenCalledWith(METADATA.inputs[name], name, [name]); + expect(descriptor).toBe(descriptorInstance); + } + + for (const name of Object.keys(METADATA.outputs)) { + const descriptorInstance = {}; + const factory = jest.fn().mockReturnValueOnce(descriptorInstance); + + const descriptor = getActionParameterDescriptor(METADATA, name, factory, METADATA.outputs); + + expect(factory).toHaveBeenCalledTimes(1); + expect(factory).toHaveBeenCalledWith(METADATA.outputs[name], name, [name]); + expect(descriptor).toBe(descriptorInstance); + } + }); + + test("uses custom path parser", () => { + const pathParser: ActionParameterPathParser = name => name.split("-"); + + for (const name of Object.keys(METADATA.inputs)) { + const descriptorInstance = {}; + const factory = jest.fn().mockReturnValueOnce(descriptorInstance); + + const descriptor = getActionParameterDescriptor(METADATA, name, factory, METADATA.inputs, { pathParser }); + + expect(factory).toHaveBeenCalledTimes(1); + expect(factory).toHaveBeenCalledWith(METADATA.inputs[name], name, pathParser(name)); + expect(descriptor).toBe(descriptorInstance); + } + + for (const name of Object.keys(METADATA.outputs)) { + const descriptorInstance = {}; + const factory = jest.fn().mockReturnValueOnce(descriptorInstance); + + const descriptor = getActionParameterDescriptor(METADATA, name, factory, METADATA.outputs, { pathParser }); + + expect(factory).toHaveBeenCalledTimes(1); + expect(factory).toHaveBeenCalledWith(METADATA.outputs[name], name, pathParser(name)); + expect(descriptor).toBe(descriptorInstance); + } + }); + + test("returns undefined if a parameter with the specified name doesn't exist", () => { + const factory = jest.fn().mockReturnValue({}); + + const inputDescriptor = getActionParameterDescriptor(METADATA, "input-that-does-not-exist", factory, METADATA.inputs); + const outputDescriptor = getActionParameterDescriptor(METADATA, "output-that-does-not-exist", factory, METADATA.outputs); + + expect(factory).not.toHaveBeenCalled(); + expect(inputDescriptor).toBeUndefined(); + expect(outputDescriptor).toBeUndefined(); + }); +}); + +describe("getActionParameterDescriptors", () => { + test("returns all parameter descriptors", () => { + const descriptorInstance = {}; + + const inputFactory = jest.fn().mockReturnValue(descriptorInstance); + const inputNames = Object.keys(METADATA.inputs); + + const outputFactory = jest.fn().mockReturnValue(descriptorInstance); + const outputNames = Object.keys(METADATA.outputs); + + const inputDescriptors = getActionParameterDescriptors(METADATA, inputFactory, METADATA.inputs); + const outputDescriptors = getActionParameterDescriptors(METADATA, outputFactory, METADATA.outputs); + + expect(inputFactory).toHaveBeenCalledTimes(inputNames.length); + expect(outputFactory).toHaveBeenCalledTimes(outputNames.length); + + expect(inputDescriptors).toHaveLength(inputNames.length); + expect(outputDescriptors).toHaveLength(outputNames.length); + + expect(inputDescriptors.every(x => x === descriptorInstance)).toBe(true); + expect(outputDescriptors.every(x => x === descriptorInstance)).toBe(true); + + inputNames.forEach(name => expect(inputFactory).toHaveBeenCalledWith(METADATA.inputs[name], name, [name])); + outputNames.forEach(name => expect(outputFactory).toHaveBeenCalledWith(METADATA.outputs[name], name, [name])); + }); + + test("uses custom path parser", () => { + const descriptorInstance = {}; + const pathParser: ActionParameterPathParser = name => name.split("-"); + + const inputFactory = jest.fn().mockReturnValue(descriptorInstance); + const inputNames = Object.keys(METADATA.inputs); + + const outputFactory = jest.fn().mockReturnValue(descriptorInstance); + const outputNames = Object.keys(METADATA.outputs); + + const inputDescriptors = getActionParameterDescriptors(METADATA, inputFactory, METADATA.inputs, { pathParser }); + const outputDescriptors = getActionParameterDescriptors(METADATA, outputFactory, METADATA.outputs, { pathParser }); + + expect(inputFactory).toHaveBeenCalledTimes(inputNames.length); + expect(outputFactory).toHaveBeenCalledTimes(outputNames.length); + + expect(inputDescriptors).toHaveLength(inputNames.length); + expect(outputDescriptors).toHaveLength(outputNames.length); + + expect(inputDescriptors.every(x => x === descriptorInstance)).toBe(true); + expect(outputDescriptors.every(x => x === descriptorInstance)).toBe(true); + + inputNames.forEach(name => expect(inputFactory).toHaveBeenCalledWith(METADATA.inputs[name], name, pathParser(name))); + outputNames.forEach(name => expect(outputFactory).toHaveBeenCalledWith(METADATA.outputs[name], name, pathParser(name))); + }); + + test("returns an empty array if the metadata doesn't specify any parameters", () => { + const factory = jest.fn().mockReturnValue({}); + + const inputDescriptors = getActionParameterDescriptors({} as ActionMetadata, factory, undefined); + const outputDescriptors = getActionParameterDescriptors({} as ActionMetadata, factory, {}); + + expect(factory).not.toHaveBeenCalled(); + expect(inputDescriptors).toEqual([]); + expect(outputDescriptors).toEqual([]); + }); +});