@dr.pogodin/react-utils 1.43.5 → 1.43.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/development/shared/utils/jest/index.js +12 -6
- package/build/development/shared/utils/jest/index.js.map +1 -1
- package/build/production/shared/utils/jest/index.js +7 -3
- package/build/production/shared/utils/jest/index.js.map +1 -1
- package/package.json +1 -1
- package/src/shared/utils/jest/index.ts +12 -6
|
@@ -168,12 +168,18 @@ function snapshot(element, options) {
|
|
|
168
168
|
});
|
|
169
169
|
if (res === undefined) throw Error('Render failed');
|
|
170
170
|
if (options?.await) {
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
// BEWARE: Although `promise` is thenable (i.e. it has .then() method),
|
|
172
|
+
// it is not an instance of proper Promise class, and returning it directly
|
|
173
|
+
// breaks some async logic in Jest test or React test functions... thus, we
|
|
174
|
+
// wrap it into Promise instance here.
|
|
175
|
+
return new Promise(resolve => {
|
|
176
|
+
void promise.then(() => {
|
|
177
|
+
// TODO: These lines are the same as the lines below for sync variant of
|
|
178
|
+
// the function. We should split and reuse them in both places.
|
|
179
|
+
const nodes = res.asFragment().childNodes;
|
|
180
|
+
expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();
|
|
181
|
+
resolve(res);
|
|
182
|
+
});
|
|
177
183
|
});
|
|
178
184
|
}
|
|
179
185
|
const nodes = res.asFragment().childNodes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_mockdate","_interopRequireDefault","require","_react","_client","_react2","_global","global","IS_REACT_ACT_ENVIRONMENT","originalProcessVersions","process","versions","mockClientSide","Object","defineProperty","value","undefined","unmockClientSide","writable","getMockUuid","seed","x","toString","padStart","slice","mockAxios","handlers","axios","jest","requireActual","defaults","adapter","config","handler","res","data","headers","status","statusText","console","warn","JSON","stringify","e","mockTimer","time","mockdate","set","Date","now","advanceTimersByTimeAsync","mount","scene","root","element","document","createElement","body","appendChild","destroy","act","unmount","remove","snapshot","expect","toMatchSnapshot","createRoot","render","options","promise","await","Error","then","nodes","asFragment","childNodes","length"],"sources":["../../../../../src/shared/utils/jest/index.ts"],"sourcesContent":["/* global jest, document */\n/* eslint-disable import/no-extraneous-dependencies */\n\nimport type {\n AxiosRequestConfig,\n AxiosResponse,\n AxiosStatic,\n InternalAxiosRequestConfig,\n} from 'axios';\n\nimport mockdate from 'mockdate';\nimport { type ReactElement, type ReactNode, act } from 'react';\nimport { type Root, createRoot } from 'react-dom/client';\n\nimport { type RenderResult, render } from '@testing-library/react';\n\n/**\n * An alias for [act(..)](https://reactjs.org/docs/test-utils.html#act)\n * from `react`.\n */\nexport { act };\n\nexport { default as getGlobal } from './global';\n\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\nconst originalProcessVersions = process.versions;\n\n/**\n * Tricks **react-utils** into thinking the test is running within client-side\n * (browser) environment.\n */\nexport function mockClientSide(): void {\n Object.defineProperty(process, 'versions', { value: undefined });\n}\n\n/**\n * Reverts the effect of {@link module:JU.mockClientSide mockClientSide(..)}.\n */\nexport function unmockClientSide(): void {\n Object.defineProperty(process, 'versions', {\n value: originalProcessVersions,\n writable: false,\n });\n}\n\n/**\n * Generates a mock UUID, or better said it determenistically transforms given\n * `seed` number into a UUID-formatted string.\n * @param {number} seed\n * @return {string}\n */\nexport function getMockUuid(seed = 0): string {\n const x = seed.toString(16).padStart(32, '0');\n return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20)}`;\n}\n\nexport type AxiosRequestHandlerT =\n (config: AxiosRequestConfig) => Partial<AxiosResponse> | null | undefined;\n\nexport function mockAxios(handlers: AxiosRequestHandlerT[]): AxiosStatic {\n const axios: AxiosStatic = jest.requireActual('axios');\n\n axios.defaults.adapter = async (\n config: AxiosRequestConfig,\n ): Promise<AxiosResponse> => {\n for (const handler of handlers) {\n const res = handler(config);\n if (res) {\n return {\n config: config as InternalAxiosRequestConfig,\n data: null,\n headers: {},\n status: 200,\n statusText: 'OK',\n ...res,\n };\n }\n }\n\n // Fallback to the regular network request.\n let res: AxiosResponse;\n try {\n res = await axios({ ...config, adapter: ['xhr', 'http', 'fetch'] });\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test.\\n\\nConfig:\\n',\n config,\n '\\n\\nResult:\\n',\n JSON.stringify(res, null, 2),\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test, and failed.\\n\\nConfig:\\n',\n config,\n '\\n\\nError\\n',\n JSON.stringify(e, null, 2),\n );\n throw e;\n }\n\n return res;\n };\n\n return axios;\n}\n\n/**\n * Advances mock timers, and mock date by the specified time.\n * @param {number} time Time step [ms].\n * @returns {Promise} Wait for this to \"jump after\" any async code which should\n * be executed because of the mock time movement.\n */\nexport async function mockTimer(time: number): Promise<void> {\n mockdate.set(time + Date.now());\n await jest.advanceTimersByTimeAsync(time);\n}\n\nexport type MountedSceneT = HTMLElement & {\n destroy: () => void;\n snapshot: () => void;\n};\n\n/**\n * Mounts `scene` to the DOM, and returns the root scene element.\n * @param scene\n * @return Created container DOM element with destroy() function\n * attached.\n */\nexport function mount(scene: ReactNode): MountedSceneT {\n let root: Root;\n const element = document.createElement('div');\n document.body.appendChild(element);\n\n const res: MountedSceneT = (element as unknown) as MountedSceneT;\n res.destroy = () => {\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root.unmount();\n });\n res.remove();\n };\n\n res.snapshot = () => {\n expect(res).toMatchSnapshot();\n };\n\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root = createRoot(res);\n root.render(scene);\n });\n return res;\n}\n\n// NOTE: If in future we have additional options here, they should be distributed\n// across two objects, depending whether they are applicable to the sync, or async\n// versions of snapshot(), or both.\ntype AsyncSnapshotOptionsT = {\n await?: Promise<void>;\n};\n\nexport function snapshot(element: ReactElement): RenderResult;\n\nexport async function snapshot(\n element: ReactElement,\n options: AsyncSnapshotOptionsT,\n): Promise<RenderResult>;\n\nexport function snapshot(\n element: React.ReactElement,\n options?: AsyncSnapshotOptionsT,\n): Promise<RenderResult> | RenderResult {\n let res: RenderResult | undefined;\n\n // TODO: Just adding async to the actor function breaks stuff, as it makes\n // act() asynchronous no matter the `options.await` value, thus breaking all\n // calls that do not await for snapshot() result... thus... perhaps we need\n // to have a more complex typing to ensure it all works as intended in all\n // cases, and while being correctly enforced by TypeScript.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const promise = act(() => {\n res = render(element);\n return options?.await;\n });\n\n if (res === undefined) throw Error('Render failed');\n if (options?.await) {\n // TODO: Then body of .then() is the same as the last three lines in this\n // function, executed for the non-async variant. We should re-use that.\n return promise.then(() => {\n const nodes = res!.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res!;\n });\n }\n\n const nodes = res.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_mockdate","_interopRequireDefault","require","_react","_client","_react2","_global","global","IS_REACT_ACT_ENVIRONMENT","originalProcessVersions","process","versions","mockClientSide","Object","defineProperty","value","undefined","unmockClientSide","writable","getMockUuid","seed","x","toString","padStart","slice","mockAxios","handlers","axios","jest","requireActual","defaults","adapter","config","handler","res","data","headers","status","statusText","console","warn","JSON","stringify","e","mockTimer","time","mockdate","set","Date","now","advanceTimersByTimeAsync","mount","scene","root","element","document","createElement","body","appendChild","destroy","act","unmount","remove","snapshot","expect","toMatchSnapshot","createRoot","render","options","promise","await","Error","Promise","resolve","then","nodes","asFragment","childNodes","length"],"sources":["../../../../../src/shared/utils/jest/index.ts"],"sourcesContent":["/* global jest, document */\n/* eslint-disable import/no-extraneous-dependencies */\n\nimport type {\n AxiosRequestConfig,\n AxiosResponse,\n AxiosStatic,\n InternalAxiosRequestConfig,\n} from 'axios';\n\nimport mockdate from 'mockdate';\nimport { type ReactElement, type ReactNode, act } from 'react';\nimport { type Root, createRoot } from 'react-dom/client';\n\nimport { type RenderResult, render } from '@testing-library/react';\n\n/**\n * An alias for [act(..)](https://reactjs.org/docs/test-utils.html#act)\n * from `react`.\n */\nexport { act };\n\nexport { default as getGlobal } from './global';\n\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\nconst originalProcessVersions = process.versions;\n\n/**\n * Tricks **react-utils** into thinking the test is running within client-side\n * (browser) environment.\n */\nexport function mockClientSide(): void {\n Object.defineProperty(process, 'versions', { value: undefined });\n}\n\n/**\n * Reverts the effect of {@link module:JU.mockClientSide mockClientSide(..)}.\n */\nexport function unmockClientSide(): void {\n Object.defineProperty(process, 'versions', {\n value: originalProcessVersions,\n writable: false,\n });\n}\n\n/**\n * Generates a mock UUID, or better said it determenistically transforms given\n * `seed` number into a UUID-formatted string.\n * @param {number} seed\n * @return {string}\n */\nexport function getMockUuid(seed = 0): string {\n const x = seed.toString(16).padStart(32, '0');\n return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20)}`;\n}\n\nexport type AxiosRequestHandlerT =\n (config: AxiosRequestConfig) => Partial<AxiosResponse> | null | undefined;\n\nexport function mockAxios(handlers: AxiosRequestHandlerT[]): AxiosStatic {\n const axios: AxiosStatic = jest.requireActual('axios');\n\n axios.defaults.adapter = async (\n config: AxiosRequestConfig,\n ): Promise<AxiosResponse> => {\n for (const handler of handlers) {\n const res = handler(config);\n if (res) {\n return {\n config: config as InternalAxiosRequestConfig,\n data: null,\n headers: {},\n status: 200,\n statusText: 'OK',\n ...res,\n };\n }\n }\n\n // Fallback to the regular network request.\n let res: AxiosResponse;\n try {\n res = await axios({ ...config, adapter: ['xhr', 'http', 'fetch'] });\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test.\\n\\nConfig:\\n',\n config,\n '\\n\\nResult:\\n',\n JSON.stringify(res, null, 2),\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test, and failed.\\n\\nConfig:\\n',\n config,\n '\\n\\nError\\n',\n JSON.stringify(e, null, 2),\n );\n throw e;\n }\n\n return res;\n };\n\n return axios;\n}\n\n/**\n * Advances mock timers, and mock date by the specified time.\n * @param {number} time Time step [ms].\n * @returns {Promise} Wait for this to \"jump after\" any async code which should\n * be executed because of the mock time movement.\n */\nexport async function mockTimer(time: number): Promise<void> {\n mockdate.set(time + Date.now());\n await jest.advanceTimersByTimeAsync(time);\n}\n\nexport type MountedSceneT = HTMLElement & {\n destroy: () => void;\n snapshot: () => void;\n};\n\n/**\n * Mounts `scene` to the DOM, and returns the root scene element.\n * @param scene\n * @return Created container DOM element with destroy() function\n * attached.\n */\nexport function mount(scene: ReactNode): MountedSceneT {\n let root: Root;\n const element = document.createElement('div');\n document.body.appendChild(element);\n\n const res: MountedSceneT = (element as unknown) as MountedSceneT;\n res.destroy = () => {\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root.unmount();\n });\n res.remove();\n };\n\n res.snapshot = () => {\n expect(res).toMatchSnapshot();\n };\n\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root = createRoot(res);\n root.render(scene);\n });\n return res;\n}\n\n// NOTE: If in future we have additional options here, they should be distributed\n// across two objects, depending whether they are applicable to the sync, or async\n// versions of snapshot(), or both.\ntype AsyncSnapshotOptionsT = {\n await?: Promise<void>;\n};\n\nexport function snapshot(element: ReactElement): RenderResult;\n\nexport async function snapshot(\n element: ReactElement,\n options: AsyncSnapshotOptionsT,\n): Promise<RenderResult>;\n\nexport function snapshot(\n element: React.ReactElement,\n options?: AsyncSnapshotOptionsT,\n): Promise<RenderResult> | RenderResult {\n let res: RenderResult | undefined;\n\n // TODO: Just adding async to the actor function breaks stuff, as it makes\n // act() asynchronous no matter the `options.await` value, thus breaking all\n // calls that do not await for snapshot() result... thus... perhaps we need\n // to have a more complex typing to ensure it all works as intended in all\n // cases, and while being correctly enforced by TypeScript.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const promise = act(() => {\n res = render(element);\n return options?.await;\n });\n\n if (res === undefined) throw Error('Render failed');\n if (options?.await) {\n // BEWARE: Although `promise` is thenable (i.e. it has .then() method),\n // it is not an instance of proper Promise class, and returning it directly\n // breaks some async logic in Jest test or React test functions... thus, we\n // wrap it into Promise instance here.\n return new Promise((resolve) => {\n void promise.then(() => {\n // TODO: These lines are the same as the lines below for sync variant of\n // the function. We should split and reuse them in both places.\n const nodes = res!.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n resolve(res!);\n });\n });\n }\n\n const nodes = res.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -37,7 +37,11 @@ function snapshot(element,options){let res;// TODO: Just adding async to the act
|
|
|
37
37
|
// to have a more complex typing to ensure it all works as intended in all
|
|
38
38
|
// cases, and while being correctly enforced by TypeScript.
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
40
|
-
const promise=(0,_react.act)(()=>{res=(0,_react2.render)(element);return options?.await});if(res===undefined)throw Error("Render failed");if(options?.await){//
|
|
41
|
-
//
|
|
42
|
-
|
|
40
|
+
const promise=(0,_react.act)(()=>{res=(0,_react2.render)(element);return options?.await});if(res===undefined)throw Error("Render failed");if(options?.await){// BEWARE: Although `promise` is thenable (i.e. it has .then() method),
|
|
41
|
+
// it is not an instance of proper Promise class, and returning it directly
|
|
42
|
+
// breaks some async logic in Jest test or React test functions... thus, we
|
|
43
|
+
// wrap it into Promise instance here.
|
|
44
|
+
return new Promise(resolve=>{void promise.then(()=>{// TODO: These lines are the same as the lines below for sync variant of
|
|
45
|
+
// the function. We should split and reuse them in both places.
|
|
46
|
+
const nodes=res.asFragment().childNodes;expect(nodes.length>1?[...nodes]:nodes[0]).toMatchSnapshot();resolve(res)})})}const nodes=res.asFragment().childNodes;expect(nodes.length>1?[...nodes]:nodes[0]).toMatchSnapshot();return res}
|
|
43
47
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_mockdate","_interopRequireDefault","require","_react","_client","_react2","_global","global","IS_REACT_ACT_ENVIRONMENT","originalProcessVersions","process","versions","mockClientSide","Object","defineProperty","value","undefined","unmockClientSide","writable","getMockUuid","seed","x","toString","padStart","slice","mockAxios","handlers","axios","jest","requireActual","defaults","adapter","config","handler","res","data","headers","status","statusText","console","warn","JSON","stringify","e","mockTimer","time","mockdate","set","Date","now","advanceTimersByTimeAsync","mount","scene","root","element","document","createElement","body","appendChild","destroy","act","unmount","remove","snapshot","expect","toMatchSnapshot","createRoot","render","options","promise","await","Error","then","nodes","asFragment","childNodes","length"],"sources":["../../../../../src/shared/utils/jest/index.ts"],"sourcesContent":["/* global jest, document */\n/* eslint-disable import/no-extraneous-dependencies */\n\nimport type {\n AxiosRequestConfig,\n AxiosResponse,\n AxiosStatic,\n InternalAxiosRequestConfig,\n} from 'axios';\n\nimport mockdate from 'mockdate';\nimport { type ReactElement, type ReactNode, act } from 'react';\nimport { type Root, createRoot } from 'react-dom/client';\n\nimport { type RenderResult, render } from '@testing-library/react';\n\n/**\n * An alias for [act(..)](https://reactjs.org/docs/test-utils.html#act)\n * from `react`.\n */\nexport { act };\n\nexport { default as getGlobal } from './global';\n\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\nconst originalProcessVersions = process.versions;\n\n/**\n * Tricks **react-utils** into thinking the test is running within client-side\n * (browser) environment.\n */\nexport function mockClientSide(): void {\n Object.defineProperty(process, 'versions', { value: undefined });\n}\n\n/**\n * Reverts the effect of {@link module:JU.mockClientSide mockClientSide(..)}.\n */\nexport function unmockClientSide(): void {\n Object.defineProperty(process, 'versions', {\n value: originalProcessVersions,\n writable: false,\n });\n}\n\n/**\n * Generates a mock UUID, or better said it determenistically transforms given\n * `seed` number into a UUID-formatted string.\n * @param {number} seed\n * @return {string}\n */\nexport function getMockUuid(seed = 0): string {\n const x = seed.toString(16).padStart(32, '0');\n return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20)}`;\n}\n\nexport type AxiosRequestHandlerT =\n (config: AxiosRequestConfig) => Partial<AxiosResponse> | null | undefined;\n\nexport function mockAxios(handlers: AxiosRequestHandlerT[]): AxiosStatic {\n const axios: AxiosStatic = jest.requireActual('axios');\n\n axios.defaults.adapter = async (\n config: AxiosRequestConfig,\n ): Promise<AxiosResponse> => {\n for (const handler of handlers) {\n const res = handler(config);\n if (res) {\n return {\n config: config as InternalAxiosRequestConfig,\n data: null,\n headers: {},\n status: 200,\n statusText: 'OK',\n ...res,\n };\n }\n }\n\n // Fallback to the regular network request.\n let res: AxiosResponse;\n try {\n res = await axios({ ...config, adapter: ['xhr', 'http', 'fetch'] });\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test.\\n\\nConfig:\\n',\n config,\n '\\n\\nResult:\\n',\n JSON.stringify(res, null, 2),\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test, and failed.\\n\\nConfig:\\n',\n config,\n '\\n\\nError\\n',\n JSON.stringify(e, null, 2),\n );\n throw e;\n }\n\n return res;\n };\n\n return axios;\n}\n\n/**\n * Advances mock timers, and mock date by the specified time.\n * @param {number} time Time step [ms].\n * @returns {Promise} Wait for this to \"jump after\" any async code which should\n * be executed because of the mock time movement.\n */\nexport async function mockTimer(time: number): Promise<void> {\n mockdate.set(time + Date.now());\n await jest.advanceTimersByTimeAsync(time);\n}\n\nexport type MountedSceneT = HTMLElement & {\n destroy: () => void;\n snapshot: () => void;\n};\n\n/**\n * Mounts `scene` to the DOM, and returns the root scene element.\n * @param scene\n * @return Created container DOM element with destroy() function\n * attached.\n */\nexport function mount(scene: ReactNode): MountedSceneT {\n let root: Root;\n const element = document.createElement('div');\n document.body.appendChild(element);\n\n const res: MountedSceneT = (element as unknown) as MountedSceneT;\n res.destroy = () => {\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root.unmount();\n });\n res.remove();\n };\n\n res.snapshot = () => {\n expect(res).toMatchSnapshot();\n };\n\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root = createRoot(res);\n root.render(scene);\n });\n return res;\n}\n\n// NOTE: If in future we have additional options here, they should be distributed\n// across two objects, depending whether they are applicable to the sync, or async\n// versions of snapshot(), or both.\ntype AsyncSnapshotOptionsT = {\n await?: Promise<void>;\n};\n\nexport function snapshot(element: ReactElement): RenderResult;\n\nexport async function snapshot(\n element: ReactElement,\n options: AsyncSnapshotOptionsT,\n): Promise<RenderResult>;\n\nexport function snapshot(\n element: React.ReactElement,\n options?: AsyncSnapshotOptionsT,\n): Promise<RenderResult> | RenderResult {\n let res: RenderResult | undefined;\n\n // TODO: Just adding async to the actor function breaks stuff, as it makes\n // act() asynchronous no matter the `options.await` value, thus breaking all\n // calls that do not await for snapshot() result... thus... perhaps we need\n // to have a more complex typing to ensure it all works as intended in all\n // cases, and while being correctly enforced by TypeScript.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const promise = act(() => {\n res = render(element);\n return options?.await;\n });\n\n if (res === undefined) throw Error('Render failed');\n if (options?.await) {\n // TODO: Then body of .then() is the same as the last three lines in this\n // function, executed for the non-async variant. We should re-use that.\n return promise.then(() => {\n const nodes = res!.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res!;\n });\n }\n\n const nodes = res.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res;\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"index.js","names":["_mockdate","_interopRequireDefault","require","_react","_client","_react2","_global","global","IS_REACT_ACT_ENVIRONMENT","originalProcessVersions","process","versions","mockClientSide","Object","defineProperty","value","undefined","unmockClientSide","writable","getMockUuid","seed","x","toString","padStart","slice","mockAxios","handlers","axios","jest","requireActual","defaults","adapter","config","handler","res","data","headers","status","statusText","console","warn","JSON","stringify","e","mockTimer","time","mockdate","set","Date","now","advanceTimersByTimeAsync","mount","scene","root","element","document","createElement","body","appendChild","destroy","act","unmount","remove","snapshot","expect","toMatchSnapshot","createRoot","render","options","promise","await","Error","Promise","resolve","then","nodes","asFragment","childNodes","length"],"sources":["../../../../../src/shared/utils/jest/index.ts"],"sourcesContent":["/* global jest, document */\n/* eslint-disable import/no-extraneous-dependencies */\n\nimport type {\n AxiosRequestConfig,\n AxiosResponse,\n AxiosStatic,\n InternalAxiosRequestConfig,\n} from 'axios';\n\nimport mockdate from 'mockdate';\nimport { type ReactElement, type ReactNode, act } from 'react';\nimport { type Root, createRoot } from 'react-dom/client';\n\nimport { type RenderResult, render } from '@testing-library/react';\n\n/**\n * An alias for [act(..)](https://reactjs.org/docs/test-utils.html#act)\n * from `react`.\n */\nexport { act };\n\nexport { default as getGlobal } from './global';\n\nglobal.IS_REACT_ACT_ENVIRONMENT = true;\n\nconst originalProcessVersions = process.versions;\n\n/**\n * Tricks **react-utils** into thinking the test is running within client-side\n * (browser) environment.\n */\nexport function mockClientSide(): void {\n Object.defineProperty(process, 'versions', { value: undefined });\n}\n\n/**\n * Reverts the effect of {@link module:JU.mockClientSide mockClientSide(..)}.\n */\nexport function unmockClientSide(): void {\n Object.defineProperty(process, 'versions', {\n value: originalProcessVersions,\n writable: false,\n });\n}\n\n/**\n * Generates a mock UUID, or better said it determenistically transforms given\n * `seed` number into a UUID-formatted string.\n * @param {number} seed\n * @return {string}\n */\nexport function getMockUuid(seed = 0): string {\n const x = seed.toString(16).padStart(32, '0');\n return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20)}`;\n}\n\nexport type AxiosRequestHandlerT =\n (config: AxiosRequestConfig) => Partial<AxiosResponse> | null | undefined;\n\nexport function mockAxios(handlers: AxiosRequestHandlerT[]): AxiosStatic {\n const axios: AxiosStatic = jest.requireActual('axios');\n\n axios.defaults.adapter = async (\n config: AxiosRequestConfig,\n ): Promise<AxiosResponse> => {\n for (const handler of handlers) {\n const res = handler(config);\n if (res) {\n return {\n config: config as InternalAxiosRequestConfig,\n data: null,\n headers: {},\n status: 200,\n statusText: 'OK',\n ...res,\n };\n }\n }\n\n // Fallback to the regular network request.\n let res: AxiosResponse;\n try {\n res = await axios({ ...config, adapter: ['xhr', 'http', 'fetch'] });\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test.\\n\\nConfig:\\n',\n config,\n '\\n\\nResult:\\n',\n JSON.stringify(res, null, 2),\n );\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Network request has not been mocked for a test, and failed.\\n\\nConfig:\\n',\n config,\n '\\n\\nError\\n',\n JSON.stringify(e, null, 2),\n );\n throw e;\n }\n\n return res;\n };\n\n return axios;\n}\n\n/**\n * Advances mock timers, and mock date by the specified time.\n * @param {number} time Time step [ms].\n * @returns {Promise} Wait for this to \"jump after\" any async code which should\n * be executed because of the mock time movement.\n */\nexport async function mockTimer(time: number): Promise<void> {\n mockdate.set(time + Date.now());\n await jest.advanceTimersByTimeAsync(time);\n}\n\nexport type MountedSceneT = HTMLElement & {\n destroy: () => void;\n snapshot: () => void;\n};\n\n/**\n * Mounts `scene` to the DOM, and returns the root scene element.\n * @param scene\n * @return Created container DOM element with destroy() function\n * attached.\n */\nexport function mount(scene: ReactNode): MountedSceneT {\n let root: Root;\n const element = document.createElement('div');\n document.body.appendChild(element);\n\n const res: MountedSceneT = (element as unknown) as MountedSceneT;\n res.destroy = () => {\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root.unmount();\n });\n res.remove();\n };\n\n res.snapshot = () => {\n expect(res).toMatchSnapshot();\n };\n\n // NOTE: As it seems @testing-library may reset this flag to false\n // when it is simulating user events.\n global.IS_REACT_ACT_ENVIRONMENT = true;\n\n act(() => {\n root = createRoot(res);\n root.render(scene);\n });\n return res;\n}\n\n// NOTE: If in future we have additional options here, they should be distributed\n// across two objects, depending whether they are applicable to the sync, or async\n// versions of snapshot(), or both.\ntype AsyncSnapshotOptionsT = {\n await?: Promise<void>;\n};\n\nexport function snapshot(element: ReactElement): RenderResult;\n\nexport async function snapshot(\n element: ReactElement,\n options: AsyncSnapshotOptionsT,\n): Promise<RenderResult>;\n\nexport function snapshot(\n element: React.ReactElement,\n options?: AsyncSnapshotOptionsT,\n): Promise<RenderResult> | RenderResult {\n let res: RenderResult | undefined;\n\n // TODO: Just adding async to the actor function breaks stuff, as it makes\n // act() asynchronous no matter the `options.await` value, thus breaking all\n // calls that do not await for snapshot() result... thus... perhaps we need\n // to have a more complex typing to ensure it all works as intended in all\n // cases, and while being correctly enforced by TypeScript.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n const promise = act(() => {\n res = render(element);\n return options?.await;\n });\n\n if (res === undefined) throw Error('Render failed');\n if (options?.await) {\n // BEWARE: Although `promise` is thenable (i.e. it has .then() method),\n // it is not an instance of proper Promise class, and returning it directly\n // breaks some async logic in Jest test or React test functions... thus, we\n // wrap it into Promise instance here.\n return new Promise((resolve) => {\n void promise.then(() => {\n // TODO: These lines are the same as the lines below for sync variant of\n // the function. We should split and reuse them in both places.\n const nodes = res!.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n resolve(res!);\n });\n });\n }\n\n const nodes = res.asFragment().childNodes;\n expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();\n return res;\n}\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -193,12 +193,18 @@ export function snapshot(
|
|
|
193
193
|
|
|
194
194
|
if (res === undefined) throw Error('Render failed');
|
|
195
195
|
if (options?.await) {
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
// BEWARE: Although `promise` is thenable (i.e. it has .then() method),
|
|
197
|
+
// it is not an instance of proper Promise class, and returning it directly
|
|
198
|
+
// breaks some async logic in Jest test or React test functions... thus, we
|
|
199
|
+
// wrap it into Promise instance here.
|
|
200
|
+
return new Promise((resolve) => {
|
|
201
|
+
void promise.then(() => {
|
|
202
|
+
// TODO: These lines are the same as the lines below for sync variant of
|
|
203
|
+
// the function. We should split and reuse them in both places.
|
|
204
|
+
const nodes = res!.asFragment().childNodes;
|
|
205
|
+
expect(nodes.length > 1 ? [...nodes] : nodes[0]).toMatchSnapshot();
|
|
206
|
+
resolve(res!);
|
|
207
|
+
});
|
|
202
208
|
});
|
|
203
209
|
}
|
|
204
210
|
|