From ccd95bb66f541efc339eedb0baf630a9f82f1f35 Mon Sep 17 00:00:00 2001 From: mefellows Date: Thu, 1 Dec 2022 11:10:43 +1100 Subject: [PATCH] fix: support multiple header values with matchers Fixes #964 --- src/v3/ffi.ts | 14 +++++++++++--- src/v3/types.ts | 7 +++++-- src/v4/http/index.ts | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/v3/ffi.ts b/src/v3/ffi.ts index 1225e2461..1d045a797 100644 --- a/src/v3/ffi.ts +++ b/src/v3/ffi.ts @@ -1,22 +1,29 @@ /* eslint-disable import/first */ import { forEachObjIndexed } from 'ramda'; import { ConsumerInteraction } from '@pact-foundation/pact-core/src/consumer/index'; -import { isArray } from 'util'; import { TemplateHeaders, V3Request, V3Response } from './types'; import { matcherValueOrString } from './matchers'; import { MatchersV3 } from '../v3'; +type TemplateHeaderArrayValue = string[] | MatchersV3.Matcher[]; + export const setRequestDetails = ( interaction: ConsumerInteraction, req: V3Request ): void => { interaction.withRequest(req.method, matcherValueOrString(req.path)); forEachObjIndexed((v, k) => { - interaction.withRequestHeader(k, 0, matcherValueOrString(v)); + if (Array.isArray(v)) { + (v as TemplateHeaderArrayValue).forEach((header, index) => { + interaction.withRequestHeader(k, index, matcherValueOrString(header)); + }); + } else { + interaction.withRequestHeader(k, 0, matcherValueOrString(v)); + } }, req.headers); forEachObjIndexed((v, k) => { - if (isArray(v)) { + if (Array.isArray(v)) { (v as unknown[]).forEach((vv, i) => { interaction.withQuery(k, i, matcherValueOrString(vv)); }); @@ -37,6 +44,7 @@ export const setResponseDetails = ( }, res.headers); }; +// TODO: this might need to consider an array of values export const contentTypeFromHeaders = ( headers: TemplateHeaders | undefined, defaultContentType: string diff --git a/src/v3/types.ts b/src/v3/types.ts index 737dd9fd2..de8f997b1 100644 --- a/src/v3/types.ts +++ b/src/v3/types.ts @@ -55,8 +55,11 @@ export interface V3ProviderState { parameters?: JsonMap; } -export type TemplateHeaders = { - [header: string]: string | MatchersV3.Matcher; +export declare type TemplateHeaders = { + [header: string]: + | string + | MatchersV3.Matcher + | (MatchersV3.Matcher | string)[]; }; export type TemplateQuery = Record< diff --git a/src/v4/http/index.ts b/src/v4/http/index.ts index c5de71b77..6e6c9ba08 100644 --- a/src/v4/http/index.ts +++ b/src/v4/http/index.ts @@ -3,7 +3,7 @@ import { ConsumerInteraction, ConsumerPact } from '@pact-foundation/pact-core'; import { JsonMap } from '../../common/jsonTypes'; import { forEachObjIndexed } from 'ramda'; import { Path, TemplateHeaders, TemplateQuery, V3MockServer } from '../../v3'; -import { AnyTemplate, matcherValueOrString } from '../../v3/matchers'; +import { AnyTemplate, Matcher, matcherValueOrString } from '../../v3/matchers'; import { PactV4Options, PluginConfig, @@ -34,6 +34,8 @@ import { } from '../../v3/display'; import logger from '../../common/logger'; +type TemplateHeaderArrayValue = string[] | Matcher[]; + export class UnconfiguredInteraction implements V4UnconfiguredInteraction { // tslint:disable:no-empty-function constructor( @@ -138,7 +140,19 @@ export class RequestBuilder implements V4RequestBuilder { headers(headers: TemplateHeaders) { forEachObjIndexed((v, k) => { - this.interaction.withRequestHeader(`${k}`, 0, matcherValueOrString(v)); + if (Array.isArray(v)) { + (v as TemplateHeaderArrayValue).forEach( + (header: string | Matcher, index: number) => { + this.interaction.withRequestHeader( + `${k}`, + index, + matcherValueOrString(header) + ); + } + ); + } else { + this.interaction.withRequestHeader(`${k}`, 0, matcherValueOrString(v)); + } }, headers); return this;