Skip to content

Commit

Permalink
wip: status, eachKey and eachValue matchers
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Jul 13, 2023
1 parent 4636617 commit d5b728b
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/v3/ffi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const setResponseDetails = (
interaction: ConsumerInteraction,
res: V3Response
): void => {
interaction.withStatus(res.status);
interaction.withStatus(MatchersV3.reify(res.status) as number);

forEachObjIndexed((v, k) => {
if (Array.isArray(v)) {
Expand Down
59 changes: 58 additions & 1 deletion src/v3/matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
MaxLikeMatcher,
MinLikeMatcher,
ProviderStateInjectedValue,
RulesMatcher,
HTTPResponseStatusClass,
StatusCodeMatcher,
V3RegexMatcher,
} from './types';

Expand All @@ -33,8 +36,9 @@ export const like = <T>(template: T): Matcher<T> => ({
});

/**
* Object where the key itself is ignored, but the value template must match.
* Object where the values are ignored, but the key template must match.
*
* @deprecated use eachKeyMatches or eachValueMatches
* @param keyTemplate Example key to use
* @param template Example value template to base the comparison on
*/
Expand All @@ -48,6 +52,59 @@ export const eachKeyLike = <T>(
},
});

/**
* Object where the _keys_ must match the supplied matchers.
* The values for each key are ignored. That is, there can be 0 or more keys
* with any valid JSON identifier, so long as the names of the keys match the constraints.
*
* @param example Example object with key/values e.g. `{ foo: 'bar', baz: 'qux'}`
* @param matchers Matchers to apply to each key
*/
export const eachKeyMatches = (
example: Record<string, unknown>,
matchers: Matcher<string> | Matcher<string>[] = like('key')
): RulesMatcher<unknown> => ({
'pact:matcher:type': 'eachKey',
rules: Array.isArray(matchers) ? matchers : [matchers],
value: example,
});

/**
* Object where the _values_ must match the supplied matchers.
* The names of the keys are ignored. That is, there can be 0 or more keys
* with any valid JSON identifier, so long as the values match the constraints.
*
* @param example Example object with key/values e.g. `{ foo: 'bar', baz: 'qux'}`
* @param matchers Matchers to apply to each value
*/
export const eachValueMatches = <T>(
example: Record<string, T>,
matchers: Matcher<T> | Matcher<T>[]
): RulesMatcher<T> => ({
'pact:matcher:type': 'eachValue',
rules: Array.isArray(matchers) ? matchers : [matchers],
value: example,
// Unsure if the full object is provided, or just a template k/v pair
// value: {
// [keyTemplate]: template,
// },
});

/**
* Matches HTTP status codes by their range description, or by a list of specific codes.
*
* @param example Example status code to use
* @param range Allowed status codes
*/
export const matchStatus = (
example: number,
range: HTTPResponseStatusClass | number[]
): StatusCodeMatcher<number> => ({
value: example,
'pact:matcher:type': 'statusCode',
status: range,
});

/**
* Array where each element must match the given template
* @param template Template to base the comparison on
Expand Down
27 changes: 26 additions & 1 deletion src/v3/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ export interface ProviderStateInjectedValue<T> extends Matcher<T> {
expression: string;
}

export interface StatusCodeMatcher<T> extends Matcher<T> {
status: string | number[];
}

export interface RulesMatcher<T> extends Matcher<T> {
rules: Matcher<T>[];
}

/**
* Options for the mock server
*/
Expand Down Expand Up @@ -143,7 +151,7 @@ export interface V3Request {
}

export interface V3Response {
status: number;
status: number | Matcher<number>;
headers?: TemplateHeaders;
body?: unknown;
contentType?: string;
Expand All @@ -154,3 +162,20 @@ export interface V3MockServer {
url: string;
id: string;
}

export enum HTTPResponseStatusClass {
// Informational responses (100–199)
Information = 'information',
// Successful responses (200–299)
Success = 'success',
// Redirects (300–399)
Redirect = 'redirect',
// Client errors (400–499)
ClientError = 'clientError',
// Server errors (500–599)
ServerError = 'serverError',
// Non-error response(< 400)
NonError = 'nonError',
// Any error response (>= 400)
Error = 'error',
}

0 comments on commit d5b728b

Please sign in to comment.