/
interaction.ts
128 lines (109 loc) · 3.65 KB
/
interaction.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* An Interaction is where you define the state of your interaction with a Provider.
* @module Interaction
*/
import { isNil, keys, omitBy } from "lodash";
import { HTTPMethod, methods } from "../common/request";
import { MatcherResult } from "./matchers";
export type Query = string | { [name: string]: string | MatcherResult };
export interface RequestOptions {
method: HTTPMethod | methods;
path: string | MatcherResult;
query?: Query;
headers?: { [name: string]: string | MatcherResult };
body?: any;
}
export interface ResponseOptions {
status: number | MatcherResult;
headers?: { [name: string]: string | MatcherResult };
body?: any;
}
export interface InteractionObject {
state: string | undefined;
uponReceiving: string;
withRequest: RequestOptions;
willRespondWith: ResponseOptions;
}
export interface InteractionState {
providerState?: string;
description?: string;
request?: RequestOptions;
response?: ResponseOptions;
}
export class Interaction {
protected state: InteractionState = {};
/**
* Gives a state the provider should be in for this interaction.
* @param {string} providerState - The state of the provider.
* @returns {Interaction} interaction
*/
public given(providerState: string) {
if (providerState) {
this.state.providerState = providerState;
}
return this;
}
/**
* A free style description of the interaction.
* @param {string} description - A description of the interaction.
* @returns {Interaction} interaction
*/
public uponReceiving(description: string) {
if (isNil(description)) {
throw new Error("You must provide a description for the interaction.");
}
this.state.description = description;
return this;
}
/**
* The request that represents this interaction triggered by the consumer.
* @param {Object} requestOpts
* @param {string} requestOpts.method - The HTTP method
* @param {string} requestOpts.path - The path of the URL
* @param {string} requestOpts.query - Any query string in the interaction
* @param {Object} requestOpts.headers - A key-value pair oject of headers
* @param {Object} requestOpts.body - The body, in {@link String} format or {@link Object} format
* @returns {Interaction} interaction
*/
public withRequest(requestOpts: RequestOptions) {
if (isNil(requestOpts.method)) {
throw new Error("You must provide an HTTP method.");
}
if (keys(HTTPMethod).indexOf(requestOpts.method.toString()) < 0) {
throw new Error(`You must provide a valid HTTP method: ${keys(HTTPMethod).join(", ")}.`);
}
if (isNil(requestOpts.path)) {
throw new Error("You must provide a path.");
}
this.state.request = omitBy(requestOpts, isNil) as RequestOptions;
return this;
}
/**
* The response expected by the consumer.
* @param {Object} responseOpts
* @param {string} responseOpts.status - The HTTP status
* @param {string} responseOpts.headers
* @param {Object} responseOpts.body
*/
public willRespondWith(responseOpts: ResponseOptions) {
if (isNil(responseOpts.status) || responseOpts.status.toString().trim().length === 0) {
throw new Error("You must provide a status code.");
}
this.state.response = omitBy({
body: responseOpts.body,
headers: responseOpts.headers || undefined,
status: responseOpts.status,
}, isNil) as ResponseOptions;
return this;
}
/**
* Returns the interaction object created.
* @returns {Object}
*/
public json(): InteractionState {
if (isNil(this.state.description)) {
throw new Error("You must provide a description for the Interaction");
}
return this.state;
}
}