diff --git a/src/core/components/parameter-row.jsx b/src/core/components/parameter-row.jsx index 44690be649f..7234220cce1 100644 --- a/src/core/components/parameter-row.jsx +++ b/src/core/components/parameter-row.jsx @@ -68,8 +68,12 @@ export default class ParameterRow extends Component { let { onChange, rawParam } = this.props let valueForUpstream - // Coerce empty strings and empty Immutable objects to null - if(value === "" || (value && value.size === 0)) { + // Coerce empty strings, empty Immutable objects, and empty arrays to null + if( + value === "" || + (value && value.size === 0) || + (Array.isArray(value) && value.length === 0) + ) { valueForUpstream = null } else { valueForUpstream = value diff --git a/src/core/plugins/spec/actions.js b/src/core/plugins/spec/actions.js index 8ea0c5801b2..7e9b6e68071 100644 --- a/src/core/plugins/spec/actions.js +++ b/src/core/plugins/spec/actions.js @@ -390,8 +390,12 @@ export const executeRequest = (req) => req.parameters = req.parameters || {} const paramValue = paramToValue(param, req.parameters) - // if the value is falsy or an empty Immutable iterable... - if(!paramValue || (paramValue && paramValue.size === 0)) { + // if the value is falsy, an empty Immutable iterable, or an empty array... + if( + !paramValue || + (paramValue && paramValue.size === 0) || + (Array.isArray(paramValue) && paramValue.length === 0) + ) { // set it to empty string, so Swagger Client will treat it as // present but empty. req.parameters[param.get("name")] = "" diff --git a/test/unit/components/parameter-row.jsx b/test/unit/components/parameter-row.jsx index 862a055c4de..402c41967c6 100644 --- a/test/unit/components/parameter-row.jsx +++ b/test/unit/components/parameter-row.jsx @@ -147,6 +147,23 @@ describe("", () => { expect(wrapper.find(".parameter__type").length).toEqual(1) expect(wrapper.find(".parameter__type").text()).toEqual("boolean") }) + + it("coerces empty array parameter values to null", () => { + const param = fromJS({ + name: "status", + in: "query", + value: ["available"], + }) + const props = { + ...createProps({ param, isOAS3: true }), + onChange: jest.fn(), + } + const parameterRow = new ParameterRow(props) + + parameterRow.onChangeWrapper([]) + + expect(props.onChange).toHaveBeenCalledWith(param, null, false) + }) }) describe("bug #5573: zero default and example values", function () { diff --git a/test/unit/core/plugins/spec/actions.js b/test/unit/core/plugins/spec/actions.js index bf2e9b0952f..bedb888b9ba 100644 --- a/test/unit/core/plugins/spec/actions.js +++ b/test/unit/core/plugins/spec/actions.js @@ -142,6 +142,65 @@ describe("spec plugin - actions", function(){ expect(system.specActions.setMutatedRequest.mock.calls.length).toEqual(1) expect(system.specActions.setRequest.mock.calls.length).toEqual(1) }) + + it("should send explicitly included empty array parameters as empty strings", async () => { + // Given + const system = { + fn: { + buildRequest: jest.fn(req => req), + execute: jest.fn().mockImplementation(() => Promise.resolve({})) + }, + specActions: { + setMutatedRequest: jest.fn(), + setRequest: jest.fn(), + setResponse: jest.fn() + }, + specSelectors: { + parameterInclusionSettingFor: () => true, + url: () => "http://example.com/openapi.json", + isOAS3: () => false + }, + getConfigs: () => ({ + requestInterceptor: jest.fn(), + responseInterceptor: jest.fn() + }) + } + // When + let executeFn = executeRequest({ + pathName: "/pets", + method: "GET", + operation: fromJS({ + operationId: "findPets", + parameters: [ + { + name: "status", + in: "query", + allowEmptyValue: true + } + ] + }), + parameters: { + status: [] + } + }) + await executeFn(system) + + // Then + expect(system.fn.buildRequest).toHaveBeenCalledWith( + expect.objectContaining({ + parameters: { + status: "" + } + }) + ) + expect(system.fn.execute).toHaveBeenCalledWith( + expect.objectContaining({ + parameters: { + status: "" + } + }) + ) + }) }) xit("should call specActions.setResponse, when fn.execute resolves", function(){