Skip to content

Commit ede2052

Browse files
author
Olof Dahlbom
committed
Initial commit
1 parent 8d1835e commit ede2052

12 files changed

+1348
-30
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ tsconfig.tsbuildinfo
1111
tmp/
1212
dist/
1313
.vscode/
14+
.yarn/cache

package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@
217217
"@babel/register": "^7.24.6",
218218
"@changesets/cli": "^2.27.8",
219219
"@chiragrupani/karma-chromium-edge-launcher": "^2.4.1",
220+
"@types/diff": "^5.2.2",
220221
"@types/jest": "^29.5.12",
221222
"@types/karma": "^6.3.8",
222223
"@types/node": "^22.5.4",
@@ -267,5 +268,9 @@
267268
"webpack": "^5.94.0",
268269
"whatwg-fetch": "^3.6.20"
269270
},
270-
"packageManager": "yarn@4.4.1"
271+
"packageManager": "yarn@4.4.1",
272+
"dependencies": {
273+
"diff": "^7.0.0",
274+
"tty-table": "^4.2.3"
275+
}
271276
}

src/mocks/mock-request.js

+96-22
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,29 @@ import MockAssert from './mock-assert'
22
import Response from '../response'
33
import { isPlainObject } from '../utils/index'
44
import { clone } from '../utils/clone'
5-
import { sortedUrl, toSortedQueryString, isSubset } from './mock-utils'
5+
import { sortedUrl, toSortedQueryString, filterKeys } from './mock-utils'
66

77
/**
88
* @param {number} id
99
* @param {object} props
1010
* @param {string} props.method
1111
* @param {string|function} props.url
1212
* @param {string|function} props.body - request body
13+
* @param {string} props.mockName
1314
* @param {object} props.response
1415
* @param {string} props.response.body
1516
* @param {object} props.response.headers
1617
* @param {integer} props.response.status
1718
*/
19+
20+
const MATCHED_AS_UNDEFINED_IN_MOCK = 'MATCHED_AS_UNDEFINED_IN_MOCK'
21+
const MATCHED_BY_FUNCTION = 'MATCHED_BY_FUNCTION'
22+
const MISMATCH_BY_FUNCTION = 'MISMATCHED_BY_FUNCTION'
23+
1824
function MockRequest(id, props) {
1925
this.id = id
2026

27+
this.mockName = props.mockName ? props.mockName : this.id
2128
this.method = props.method || 'get'
2229
this.urlFunction = typeof props.url === 'function'
2330
this.url = props.url
@@ -80,33 +87,100 @@ MockRequest.prototype = {
8087
return new MockAssert(this.calls)
8188
},
8289

83-
/**
84-
* Checks if the request matches with the mock HTTP method, URL, headers and body
85-
*
86-
* @return {boolean}
87-
*/
88-
isExactMatch(request) {
89-
const bodyMatch = () => {
90-
if (this.body === undefined) {
91-
return true
90+
bodyMatchRequest(request) {
91+
if (this.body === undefined) {
92+
return {
93+
match: true,
94+
mockValue: MATCHED_AS_UNDEFINED_IN_MOCK,
95+
value: MATCHED_AS_UNDEFINED_IN_MOCK,
9296
}
97+
}
98+
if (this.bodyFunction) {
99+
const match = this.body(request.body())
100+
const value = match ? MATCHED_BY_FUNCTION : MISMATCH_BY_FUNCTION
101+
return { match, mockValue: value, requestValue: value }
102+
}
103+
const requestBodyAsString = toSortedQueryString(request.body())
104+
const match = this.body === requestBodyAsString
105+
return {
106+
match,
107+
mockValue: decodeURIComponent(this.body),
108+
requestValue: decodeURIComponent(requestBodyAsString),
109+
}
110+
},
93111

94-
return this.bodyFunction
95-
? this.body(request.body())
96-
: this.body === toSortedQueryString(request.body())
112+
urlMatchRequest(request) {
113+
if (this.urlFunction) {
114+
const match = Boolean(this.url(request.url(), request.params()))
115+
const value = match ? MATCHED_BY_FUNCTION : MISMATCH_BY_FUNCTION
116+
return { match, mockValue: value, requestValue: value }
117+
}
118+
const requestUrlAsSortedString = sortedUrl(request.url())
119+
const mockRequestUrlAsSortedString = sortedUrl(this.url)
120+
const match = mockRequestUrlAsSortedString === requestUrlAsSortedString
121+
return {
122+
match,
123+
mockValue: decodeURIComponent(mockRequestUrlAsSortedString),
124+
requestValue: decodeURIComponent(requestUrlAsSortedString),
97125
}
126+
},
98127

99-
const urlMatch = this.urlFunction
100-
? this.url(request.url(), request.params())
101-
: sortedUrl(this.url) === sortedUrl(request.url())
128+
headersMatchRequest(request) {
129+
if (!this.headers)
130+
return {
131+
match: true,
132+
mockValue: MATCHED_AS_UNDEFINED_IN_MOCK,
133+
value: MATCHED_AS_UNDEFINED_IN_MOCK,
134+
}
135+
if (this.headersFunction) {
136+
const match = this.headers(request.headers())
137+
const value = match ? MATCHED_BY_FUNCTION : MISMATCH_BY_FUNCTION
138+
return { match, mockValue: value, requestValue: value }
139+
}
140+
const filteredRequestHeaders = filterKeys(this.headersObject, request.headers())
141+
const requestHeadersAsSortedString = toSortedQueryString(filteredRequestHeaders)
142+
const mockRequestHeadersAsSortedString = toSortedQueryString(this.headersObject)
143+
const match = requestHeadersAsSortedString === mockRequestHeadersAsSortedString
144+
145+
return {
146+
match,
147+
mockValue: mockRequestHeadersAsSortedString,
148+
requestValue: requestHeadersAsSortedString,
149+
}
150+
},
102151

103-
const headerMatch =
104-
!this.headers ||
105-
(this.headersFunction
106-
? this.headers(request.headers())
107-
: isSubset(this.headersObject, request.headers()))
152+
methodMatchRequest(request) {
153+
const requestMethod = request.method()
154+
const match = this.method === requestMethod
155+
return {
156+
match,
157+
mockValue: this.method,
158+
requestValue: requestMethod,
159+
}
160+
},
108161

109-
return this.method === request.method() && urlMatch && bodyMatch() && headerMatch
162+
getRequestMatching(request) {
163+
const method = this.methodMatchRequest(request)
164+
const url = this.urlMatchRequest(request)
165+
const body = this.bodyMatchRequest(request)
166+
const headers = this.headersMatchRequest(request)
167+
return {
168+
mockName: this.mockName,
169+
isExactMatch: method.match && url.match && body.match && headers.match,
170+
isPartialMatch: this.isPartialMatch(request),
171+
method,
172+
url,
173+
body,
174+
headers,
175+
}
176+
},
177+
/**
178+
* Checks if the request matches with the mock HTTP method, URL, headers and body
179+
*
180+
* @return {boolean}
181+
*/
182+
isExactMatch(request) {
183+
return this.getRequestMatching(request).isExactMatch
110184
},
111185

112186
/**

src/mocks/mock-resource.js

+28
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function MockResource(id, client) {
1616
this.id = id
1717
this.manifest = client._manifest
1818
this.resourceName = null
19+
this.mockName = null
1920
this.methodName = null
2021
this.requestParams = {}
2122
this.responseData = null
@@ -37,6 +38,32 @@ MockResource.prototype = {
3738
return this
3839
},
3940

41+
/**
42+
* Names you mock instance for debugging purposes.
43+
* @return {MockResource}
44+
*/
45+
named(mockName) {
46+
this.mockName = mockName
47+
return this
48+
},
49+
50+
/**
51+
* Creates a name for the mock based on the client id and the resource name.
52+
* @returns {String}
53+
*/
54+
getName() {
55+
const { mockName, manifest, resourceName, id } = this
56+
const { clientId } = manifest || {}
57+
if (mockName) return mockName
58+
59+
const resourcePart = resourceName || id
60+
if (clientId) {
61+
return `${clientId} - ${resourcePart}`
62+
}
63+
64+
return resourceName ? `${resourceName} - ${id}` : id
65+
},
66+
4067
/**
4168
* @return {MockResource}
4269
*/
@@ -115,6 +142,7 @@ MockResource.prototype = {
115142

116143
if (!this.mockRequest) {
117144
this.mockRequest = new MockRequest(this.id, {
145+
mockName: this.getName(),
118146
method: finalRequest.method(),
119147
url: this.generateUrlMatcher(finalRequest),
120148
body: finalRequest.body(),

src/mocks/mock-utils.js

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ export function isSubset(A, B) {
5151
return toSortedQueryString(A) === toSortedQueryString(filteredB)
5252
}
5353

54+
export function filterKeys(A, B) {
55+
// Make B only contain the non-nullish keys it has in in common with A
56+
const keysFromA = validKeys(A)
57+
const filteredB = filterByPredicate(B, (keyFromB) => keysFromA.includes(keyFromB))
58+
return filteredB
59+
}
60+
5461
/**
5562
* Sort the query params on a URL based on the 'key=value' string value.
5663
* E.g. /example?b=2&a=1 will become /example?a=1&b=2

0 commit comments

Comments
 (0)