Repository: wheresrhys/fetch-mock (js)

Issue:
new `contains:` string matcher
For super concise serving of fixtures without having to include lots of generic bits of the url or having to resort to regex

`match:` might be a better choice of keyword, simply because it contains 3 fewer characters

Pull request description:
Rhys/contains
Fixes #544 

Patch:
diff --git a/docs/docs/API/route/matcher.md b/docs/docs/API/route/matcher.md
index f640fb7..6165678 100644
--- a/docs/docs/API/route/matcher.md
+++ b/docs/docs/API/route/matcher.md
@@ -50,6 +50,12 @@ Match a url beginning with a string, e.g. `"begin:http://www.site.com"`
 
 Match a url ending with a string, e.g. `"end:.jpg"`
 
+### include:...
+
+`{String}`
+
+Match a url including a string, e.g. `"include:site.com/api"`
+
 ### path:...
 
 `{String}`
diff --git a/packages/fetch-mock/src/Matchers.ts b/packages/fetch-mock/src/Matchers.ts
index 0f9ced1..d71d8e0 100644
--- a/packages/fetch-mock/src/Matchers.ts
+++ b/packages/fetch-mock/src/Matchers.ts
@@ -9,6 +9,7 @@ import { normalizeHeaders, getPath, normalizeUrl } from './RequestUtils.js';
 export type URLMatcherObject = {
 	begin?: string;
 	end?: string;
+	include?: string;
 	glob?: string;
 	express?: string;
 	path?: string;
@@ -41,11 +42,15 @@ const stringMatchers: { [key: string]: UrlMatcherGenerator } = {
 	begin:
 		(targetString) =>
 		({ url }) =>
-			url.indexOf(targetString) === 0,
+			url.startsWith(targetString),
 	end:
 		(targetString) =>
 		({ url }) =>
-			url.substr(-targetString.length) === targetString,
+			url.endsWith(targetString),
+	include:
+		(targetString) =>
+		({ url }) =>
+			url.includes(targetString),
 
 	glob: (targetString) => {
 		const urlRX = glob(targetString);


Test patch:
diff --git a/packages/fetch-mock/src/__tests__/Matchers/url.test.js b/packages/fetch-mock/src/__tests__/Matchers/url.test.js
index cd814e5..9088613 100644
--- a/packages/fetch-mock/src/__tests__/Matchers/url.test.js
+++ b/packages/fetch-mock/src/__tests__/Matchers/url.test.js
@@ -47,6 +47,19 @@ describe('url matching', () => {
 		expect(route.matcher({ url: 'http://b.com/path' })).toBe(true);
 	});
 
+	it('match include: keyword', () => {
+		const route = new Route({
+			url: 'include:m/p',
+			response: 200,
+		});
+
+		expect(route.matcher({ url: 'http://a.com/path' })).toBe(true);
+		expect(route.matcher({ url: 'http://a.com/ram/path' })).toBe(true);
+		expect(route.matcher({ url: 'http://a.com/p' })).toBe(true);
+		expect(route.matcher({ url: 'http://a.com/P' })).toBe(false);
+		expect(route.matcher({ url: 'http://a.com/ramp' })).toBe(false);
+	});
+
 	it('match glob: keyword', () => {
 		const route = new Route({ url: 'glob:/its/*/*', response: 200 });
 		expect(route.matcher({ url: '/its/alive' })).toBe(false);