Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e2e0eb4

Browse files
authored
Merge pull request #37 from vdstack/v5
v5: type-safe matchers injection !
2 parents 5bee791 + c1318fd commit e2e0eb4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+3246
-742
lines changed

README.md

Lines changed: 314 additions & 167 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vdstack/mockit",
3-
"version": "4.0.0",
3+
"version": "5.0.0",
44
"description": "Behaviour mocking library for TypeScript",
55
"main": "dist/index.js",
66
"module": "dist/index.mjs",
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { m } from "../..";
2+
import { when } from "../../behaviours";
3+
import { Mock, resetCompletely } from "../../mocks";
4+
5+
describe("behaviour setup: partial", () => {
6+
it("should partially match the arguments", () => {
7+
function toTest(...args: any[]) {
8+
return "hello world";
9+
}
10+
11+
const mock = Mock(toTest);
12+
when(mock).isCalled.thenReturn("default return value");
13+
14+
expect(
15+
mock({
16+
name: "Victor",
17+
age: 20,
18+
identity: {
19+
id: 1,
20+
21+
},
22+
})
23+
).toBe("default return value");
24+
25+
// when(mock)
26+
// .isCalledWith({ identity: { id: 1 } })
27+
// .thenReturn("hello world Victor");
28+
29+
// // Here, we're not passing exactly { identity: { id: 1 } }, so it should not match
30+
// // Hence, the default return value should be returned
31+
// expect(
32+
// mock({ name: "Victor", age: 20, identity: { id: 1, email: "1@1.1" } })
33+
// ).toBe("default return value");
34+
35+
resetCompletely(mock);
36+
when(mock).isCalled.thenReturn("default return value");
37+
38+
// Now, we're using partial to setup the behaviour
39+
when(mock)
40+
.isCalledWith(m.objectContaining({ identity: { id: 1, email: "[email protected]" } }))
41+
.thenReturn("hello world 1");
42+
43+
// This should not match, because we did not pass the email
44+
expect(mock({ name: "Victor", age: 20, identity: { id: 1 } })).toBe(
45+
"default return value"
46+
);
47+
// This should not match, because we did not pass the email as well
48+
expect(mock({ identity: { id: 1 } })).toBe("default return value");
49+
50+
// This should match, becaused we passed the whole identity object
51+
expect(
52+
mock({ name: "Victor", age: 20, identity: { id: 1, email: "[email protected]" } })
53+
).toBe("hello world 1");
54+
55+
// This as well
56+
expect(mock({ identity: { id: 1, email: "[email protected]" } })).toBe("hello world 1");
57+
58+
// Just in case, this should not match (we did not pass the id: 1 in the identity object)
59+
expect(mock({ name: "Victor" })).toBe("default return value");
60+
});
61+
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { m } from "../..";
2+
import { when } from "../../behaviours";
3+
import { Mock, resetCompletely } from "../../mocks";
4+
5+
describe("behaviour setup: partial", () => {
6+
it("should partially match the arguments", () => {
7+
function toTest(...args: any[]) {
8+
return "hello world";
9+
}
10+
11+
const mock = Mock(toTest);
12+
when(mock).isCalled.thenReturn("default return value");
13+
14+
expect(
15+
mock({
16+
name: "Victor",
17+
age: 20,
18+
identity: {
19+
id: 1,
20+
21+
},
22+
})
23+
).toBe("default return value");
24+
25+
when(mock)
26+
.isCalledWith({ identity: { id: 1 } })
27+
.thenReturn("hello world Victor");
28+
29+
// Here, we're not passing an object containing { identity: { id: 1 } }, so it should not match
30+
// Hence, the default return value should be returned
31+
expect(
32+
mock({ name: "Victor", age: 20, identity: { id: 1, email: "[email protected]" } })
33+
).toBe("default return value");
34+
35+
resetCompletely(mock);
36+
when(mock).isCalled.thenReturn("default return value");
37+
38+
// Now, we're using partialDeep to setup the behaviour
39+
when(mock)
40+
.isCalledWith(m.objectContainingDeep({ identity: { id: 1 } }))
41+
.thenReturn("hello world 1");
42+
43+
expect(
44+
mock({ name: "Victor", age: 20, identity: { id: 1, email: "[email protected]" } })
45+
).toBe("hello world 1");
46+
expect(mock({ identity: { id: 1 } })).toBe("hello world 1");
47+
48+
// Just in case, this should not match (we did not pass the id: 1 in the identity object)
49+
expect(mock({ name: "Victor" })).toBe("default return value");
50+
});
51+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { z } from "zod";
2+
import { when } from "../../behaviours";
3+
import { Mock } from "../../mocks";
4+
import { randomUUID } from "crypto";
5+
import { m } from "../..";
6+
7+
describe("behaviour setup: schema in partial", () => {
8+
function toTest(...args: any[]) {
9+
return "hello world";
10+
}
11+
12+
it("should match schema when placed deep in a partial", () => {
13+
const mock = Mock(toTest);
14+
when(mock).isCalled.thenReturn("default return value");
15+
16+
when(mock)
17+
.isCalledWith(
18+
m.objectContaining({
19+
identity: {
20+
id: 1,
21+
uuid: m.validates(z.string().uuid()),
22+
},
23+
})
24+
)
25+
.thenReturn("ding ding ding");
26+
27+
expect(
28+
mock({
29+
identity: {
30+
id: 1,
31+
uuid: randomUUID(),
32+
},
33+
})
34+
).toBe("ding ding ding");
35+
36+
expect(
37+
mock({
38+
identity: {
39+
id: 1,
40+
uuid: "not a uuid",
41+
},
42+
})
43+
).toBe("default return value");
44+
});
45+
});
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { randomUUID } from "crypto";
2+
import { z } from "zod";
3+
4+
import { unsafe } from "../../behaviours/matchers";
5+
import { when } from "../../behaviours";
6+
import { Mock, resetCompletely } from "../../mocks";
7+
import { m } from "../..";
8+
9+
test("test new zod comparison", () => {
10+
function toTest(params: any) {}
11+
12+
const mock = Mock(toTest);
13+
expect(mock({ name: -1 })).toBe(undefined);
14+
15+
when(mock)
16+
.isCalledWith({ name: m.validates(z.number().int().negative()) })
17+
.thenReturn(unsafe(999));
18+
19+
expect(mock({ name: -1 })).toBe(999);
20+
21+
resetCompletely(mock);
22+
23+
when(mock)
24+
.isCalledWith({
25+
x: m.validates(z.array(z.number().int().positive())),
26+
y: m.validates(z.array(z.number().int().negative())),
27+
z: 2,
28+
})
29+
.thenReturn(unsafe("ding"));
30+
31+
expect(mock({ x: [1, 2], y: [-1, -2], z: 2 })).toBe("ding");
32+
expect(mock({ x: [1, 2], y: [-1, -2], z: 3 })).toBe(undefined);
33+
expect(mock({ x: ["Victor", "D"], y: [-1, -2], z: 2 })).toBe(undefined);
34+
expect(mock({ x: [1, 2], y: ["Victor", "D"], z: 2 })).toBe(undefined);
35+
36+
resetCompletely(mock);
37+
38+
when(mock)
39+
.isCalledWith({
40+
x: m.validates(z.set(z.number().int().positive())),
41+
y: m.validates(z.set(z.number().int().negative())),
42+
z: 2,
43+
})
44+
.thenReturn(unsafe("ding"));
45+
46+
expect(mock({ x: new Set([1, 2]), y: new Set([-1, -2]), z: 2 })).toBe("ding");
47+
expect(mock({ x: new Set(["V", "D"]), y: new Set([-1, -2]), z: 2 })).toBe(
48+
undefined
49+
);
50+
expect(mock({ x: new Set([1, 2]), y: new Set(["V", "D"]), z: 2 })).toBe(
51+
undefined
52+
);
53+
expect(mock({ x: new Set([1, 2]), y: new Set([-1, -2]), z: 3 })).toBe(
54+
undefined
55+
);
56+
57+
resetCompletely(mock);
58+
59+
when(mock)
60+
.isCalledWith({
61+
x: {
62+
y: {
63+
z: {
64+
a: {
65+
b: {
66+
c: m.validates(z.string().uuid()),
67+
},
68+
},
69+
},
70+
},
71+
},
72+
})
73+
.thenReturn(unsafe("ding"));
74+
75+
expect(mock(1)).toBeUndefined();
76+
expect(mock("v")).toBeUndefined();
77+
expect(mock({})).toBeUndefined();
78+
79+
// this does not work
80+
expect(
81+
mock({
82+
x: {
83+
y: {
84+
z: {
85+
a: {
86+
b: {
87+
c: "not an uuid",
88+
},
89+
},
90+
},
91+
},
92+
},
93+
})
94+
).toBeUndefined();
95+
96+
expect(
97+
mock({
98+
x: {
99+
y: {
100+
z: {
101+
a: {
102+
b: {
103+
c: randomUUID(),
104+
},
105+
},
106+
},
107+
},
108+
},
109+
})
110+
).toEqual("ding");
111+
});

src/__tests__/behaviours/thenPreserve.spec.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Mock, when } from "../..";
2+
import { unsafe } from "../../behaviours/matchers";
23

34
describe("thenPreserve", () => {
45
function hello(...args: any[]) {
@@ -15,9 +16,7 @@ describe("thenPreserve", () => {
1516
it("should combine default and custom behaviours", () => {
1617
const mock = Mock(hello);
1718
when(mock).isCalled.thenPreserve();
18-
when(mock)
19-
.isCalledWith(2)
20-
.unsafe.thenReturn("Victor");
19+
when(mock).isCalledWith(2).thenReturn(unsafe("Victor"));
2120

2221
expect(mock()).toBe("hello world");
2322
expect(mock(2)).toBe("Victor");
Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
import { Mock, when } from "../..";
22

33
describe("thenReject", () => {
4-
it("should reject any value provided", () => {
4+
it("should reject any value provided", async () => {
55
const mock = Mock(async () => {});
66
when(mock).isCalled.thenReject(new Error("yo"));
7-
expect(() => mock()).rejects.toThrow("yo");
7+
expect.assertions(1);
8+
9+
// I'm using bun but it's not iso with jest => no expect().rejects :'(
10+
try {
11+
await mock();
12+
} catch (e) {
13+
expect(e).toEqual(new Error("yo"));
14+
}
815
});
916

10-
it("should combine default and custom behaviours", () => {
17+
it("should combine default and custom behaviours", async () => {
1118
const mock = Mock(async (...args: any[]) => {});
1219
when(mock).isCalled.thenReject(new Error("yo"));
1320
when(mock).isCalledWith(2).thenReject(new Error("Victor"));
1421

15-
expect(() => mock()).rejects.toThrow("yo");
16-
expect(() => mock(2)).rejects.toThrow("Victor");
22+
expect.assertions(2);
23+
try {
24+
await mock();
25+
} catch (e) {
26+
expect(e).toEqual(new Error("yo"));
27+
}
28+
29+
try {
30+
await mock(2);
31+
} catch (e) {
32+
expect(e).toEqual(new Error("Victor"));
33+
}
1734
});
1835
});

src/__tests__/behaviours/thenResolveUnsafe.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import { Mock, when } from "../..";
2+
import { unsafe } from "../../behaviours/matchers";
23

34
function hello(...args: any[]) {
45
return "hello world" as const;
56
}
67

7-
describe("unsafe.thenResolve", () => {
8+
describe("thenResolve unsafe", () => {
89
it("should resolve any value provided", async () => {
910
const mock = Mock(hello);
1011
expect(mock()).toBe(undefined);
11-
when(mock).isCalled.unsafe.thenResolve("999s");
12+
when(mock).isCalled.thenResolve(unsafe("999s"));
1213
expect(await mock()).toBe("999s");
1314
});
1415

1516
it("should combine default and custom behaviours", async () => {
1617
const mock = Mock(hello);
17-
when(mock).isCalled.unsafe.thenResolve("999s");
18-
when(mock).isCalledWith(2).unsafe.thenResolve("777s");
18+
when(mock).isCalled.thenResolve(unsafe("999s"));
19+
when(mock).isCalledWith(2).thenResolve(unsafe("777s"));
1920

2021
expect(await mock()).toBe("999s");
2122
expect(await mock(2)).toBe("777s");

src/__tests__/behaviours/thenReturn.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Mock, when } from "../..";
1+
import { Mock, m, when } from "../..";
22

33
function hello(...args: any[]) {
44
return "hello world" as const;
@@ -21,9 +21,10 @@ describe("thenReturn", () => {
2121
});
2222

2323
it("should combine default and custom behaviours", () => {
24-
const mock = Mock(returnNumber);
25-
when(mock).isCalled.thenReturn(999);
26-
when(mock).isCalledWith(2).thenReturn(777);
24+
const mock = m.Mock(returnNumber);
25+
26+
m.when(mock).isCalled.thenReturn(999);
27+
m.when(mock).isCalledWith(2).thenReturn(777);
2728

2829
expect(mock()).toBe(999);
2930
expect(mock(2)).toBe(777);

0 commit comments

Comments
 (0)