Skip to content

Commit a3ade99

Browse files
committed
Make mocking helpers independent of vscode
1 parent 4429385 commit a3ade99

File tree

3 files changed

+85
-80
lines changed

3 files changed

+85
-80
lines changed

extensions/ql-vscode/src/view/common/SuggestBox/__tests__/useOpenKey.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { KeyboardEvent } from "react";
22
import { renderHook } from "@testing-library/react";
33
import type { FloatingContext } from "@floating-ui/react";
4-
import { mockedObject } from "../../../../../test/vscode-tests/utils/mocking.helpers";
4+
import { mockedObject } from "../../../../../test/mocked-object";
55
import { useOpenKey } from "../useOpenKey";
66

77
describe("useOpenKey", () => {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
export type DeepPartial<T> = T extends object
2+
? {
3+
[P in keyof T]?: DeepPartial<T[P]>;
4+
}
5+
: T;
6+
7+
type DynamicProperties<T extends object> = {
8+
[P in keyof T]?: () => T[P];
9+
};
10+
11+
type MockedObjectOptions<T extends object> = {
12+
/**
13+
* Properties for which the given method should be called when accessed.
14+
* The method should return the value to be returned when the property is accessed.
15+
* Methods which are explicitly defined in `methods` will take precedence over
16+
* dynamic properties.
17+
*/
18+
dynamicProperties?: DynamicProperties<T>;
19+
};
20+
21+
export function mockedObject<T extends object>(
22+
props: DeepPartial<T>,
23+
{ dynamicProperties }: MockedObjectOptions<T> = {},
24+
): T {
25+
return new Proxy<T>({} as unknown as T, {
26+
get: (_target, prop) => {
27+
if (prop in props) {
28+
return (props as any)[prop];
29+
}
30+
if (dynamicProperties && prop in dynamicProperties) {
31+
return (dynamicProperties as any)[prop]();
32+
}
33+
34+
// The `then` method is accessed by `Promise.resolve` to check if the object is a thenable.
35+
// We don't want to throw an error when this happens.
36+
if (prop === "then") {
37+
return undefined;
38+
}
39+
40+
// The `asymmetricMatch` is accessed by jest to check if the object is a matcher.
41+
// We don't want to throw an error when this happens.
42+
if (prop === "asymmetricMatch") {
43+
return undefined;
44+
}
45+
46+
// The `Symbol.iterator` is accessed by jest to check if the object is iterable.
47+
// We don't want to throw an error when this happens.
48+
if (prop === Symbol.iterator) {
49+
return undefined;
50+
}
51+
52+
// The `$$typeof` is accessed by jest to check if the object is a React element.
53+
// We don't want to throw an error when this happens.
54+
if (prop === "$$typeof") {
55+
return undefined;
56+
}
57+
58+
// The `nodeType` and `tagName` are accessed by jest to check if the object is a DOM node.
59+
// We don't want to throw an error when this happens.
60+
if (prop === "nodeType" || prop === "tagName") {
61+
return undefined;
62+
}
63+
64+
// The `@@__IMMUTABLE_ITERABLE__@@` and variants are accessed by jest to check if the object is an
65+
// immutable object (from Immutable.js).
66+
// We don't want to throw an error when this happens.
67+
if (prop.toString().startsWith("@@__IMMUTABLE_")) {
68+
return undefined;
69+
}
70+
71+
// The `Symbol.toStringTag` is accessed by jest.
72+
// We don't want to throw an error when this happens.
73+
if (prop === Symbol.toStringTag) {
74+
return "MockedObject";
75+
}
76+
77+
throw new Error(`Method ${String(prop)} not mocked`);
78+
},
79+
});
80+
}

extensions/ql-vscode/test/vscode-tests/utils/mocking.helpers.ts

Lines changed: 4 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,11 @@ import type { QuickPickItem, window, Uri } from "vscode";
22
import type { DatabaseItem } from "../../../src/databases/local-databases";
33
import type { Octokit } from "@octokit/rest";
44

5-
export type DeepPartial<T> = T extends object
6-
? {
7-
[P in keyof T]?: DeepPartial<T[P]>;
8-
}
9-
: T;
5+
import type { DeepPartial } from "../../mocked-object";
6+
import { mockedObject } from "../../mocked-object";
107

11-
type DynamicProperties<T extends object> = {
12-
[P in keyof T]?: () => T[P];
13-
};
14-
15-
type MockedObjectOptions<T extends object> = {
16-
/**
17-
* Properties for which the given method should be called when accessed.
18-
* The method should return the value to be returned when the property is accessed.
19-
* Methods which are explicitly defined in `methods` will take precedence over
20-
* dynamic properties.
21-
*/
22-
dynamicProperties?: DynamicProperties<T>;
23-
};
24-
25-
export function mockedObject<T extends object>(
26-
props: DeepPartial<T>,
27-
{ dynamicProperties }: MockedObjectOptions<T> = {},
28-
): T {
29-
return new Proxy<T>({} as unknown as T, {
30-
get: (_target, prop) => {
31-
if (prop in props) {
32-
return (props as any)[prop];
33-
}
34-
if (dynamicProperties && prop in dynamicProperties) {
35-
return (dynamicProperties as any)[prop]();
36-
}
37-
38-
// The `then` method is accessed by `Promise.resolve` to check if the object is a thenable.
39-
// We don't want to throw an error when this happens.
40-
if (prop === "then") {
41-
return undefined;
42-
}
43-
44-
// The `asymmetricMatch` is accessed by jest to check if the object is a matcher.
45-
// We don't want to throw an error when this happens.
46-
if (prop === "asymmetricMatch") {
47-
return undefined;
48-
}
49-
50-
// The `Symbol.iterator` is accessed by jest to check if the object is iterable.
51-
// We don't want to throw an error when this happens.
52-
if (prop === Symbol.iterator) {
53-
return undefined;
54-
}
55-
56-
// The `$$typeof` is accessed by jest to check if the object is a React element.
57-
// We don't want to throw an error when this happens.
58-
if (prop === "$$typeof") {
59-
return undefined;
60-
}
61-
62-
// The `nodeType` and `tagName` are accessed by jest to check if the object is a DOM node.
63-
// We don't want to throw an error when this happens.
64-
if (prop === "nodeType" || prop === "tagName") {
65-
return undefined;
66-
}
67-
68-
// The `@@__IMMUTABLE_ITERABLE__@@` and variants are accessed by jest to check if the object is an
69-
// immutable object (from Immutable.js).
70-
// We don't want to throw an error when this happens.
71-
if (prop.toString().startsWith("@@__IMMUTABLE_")) {
72-
return undefined;
73-
}
74-
75-
// The `Symbol.toStringTag` is accessed by jest.
76-
// We don't want to throw an error when this happens.
77-
if (prop === Symbol.toStringTag) {
78-
return "MockedObject";
79-
}
80-
81-
throw new Error(`Method ${String(prop)} not mocked`);
82-
},
83-
});
84-
}
8+
export { mockedObject };
9+
export type { DeepPartial };
8510

8611
export function mockedOctokitFunction<
8712
Namespace extends keyof Octokit["rest"],

0 commit comments

Comments
 (0)