@quilted/react-testing
Advanced tools
Comparing version 0.3.5 to 0.3.6
@@ -9,4 +9,8 @@ "use strict"; | ||
var _react = require("react"); | ||
var _TestRenderer = require("./TestRenderer.js"); | ||
var _HookRunner = require("./HookRunner.js"); | ||
var _print = require("./print.js"); | ||
@@ -20,2 +24,3 @@ | ||
const allMounted = new Set(); | ||
const mount = createMount({}); | ||
return { | ||
@@ -38,5 +43,3 @@ mount, | ||
let context; | ||
const testRenderer = { | ||
current: null | ||
}; | ||
const testRendererRef = /*#__PURE__*/(0, _react.createRef)(); | ||
const rootApi = { | ||
@@ -166,5 +169,3 @@ act, | ||
context = env.mount( /*#__PURE__*/(0, _jsxRuntime.jsx)(_TestRenderer.TestRenderer, { | ||
ref: renderer => { | ||
testRenderer.current = renderer; | ||
}, | ||
ref: testRendererRef, | ||
render: render, | ||
@@ -194,5 +195,5 @@ children: element | ||
act(() => { | ||
var _testRenderer$current; | ||
var _testRendererRef$curr; | ||
(_testRenderer$current = testRenderer.current) === null || _testRenderer$current === void 0 ? void 0 : _testRenderer$current.setProps(props); | ||
(_testRendererRef$curr = testRendererRef.current) === null || _testRendererRef$curr === void 0 ? void 0 : _testRendererRef$curr.setProps(props); | ||
}); | ||
@@ -243,3 +244,3 @@ } | ||
function updateRootNode() { | ||
rootNode = testRenderer.current == null ? null : env.update(testRenderer.current, createNode, context); | ||
rootNode = testRendererRef.current == null ? null : env.update(testRendererRef.current, createNode, context); | ||
rootNode = rootNode && resolveRoot(rootNode); | ||
@@ -270,8 +271,2 @@ } | ||
function mount(element) { | ||
const root = createRoot(element); | ||
root.mount(); | ||
return root; | ||
} | ||
function createMount(createMountOptions) { | ||
@@ -305,2 +300,57 @@ const { | ||
function testHook(useHook, options) { | ||
const hookRunnerRef = /*#__PURE__*/(0, _react.createRef)(); | ||
const rootOrPromise = mount( /*#__PURE__*/(0, _jsxRuntime.jsx)(_HookRunner.HookRunner, { | ||
useHook: useHook, | ||
ref: hookRunnerRef | ||
}), options); | ||
const withRoot = root => { | ||
const getCurrentValue = () => { | ||
if (hookRunnerRef.current == null) { | ||
throw new Error('Attempted to access the hook value while the hook runner was not mounted'); | ||
} | ||
return hookRunnerRef.current.current; | ||
}; | ||
return { | ||
get current() { | ||
return getCurrentValue(); | ||
}, | ||
get value() { | ||
return getCurrentValue(); | ||
}, | ||
get context() { | ||
return root.context; | ||
}, | ||
get actions() { | ||
return root.actions; | ||
}, | ||
act(action) { | ||
return root.act(() => action(getCurrentValue())); | ||
}, | ||
mount() { | ||
root.mount(); | ||
}, | ||
unmount() { | ||
root.unmount(); | ||
} | ||
}; | ||
}; | ||
return 'then' in rootOrPromise ? rootOrPromise.then(root => withRoot(root)) : withRoot(rootOrPromise); | ||
} | ||
Reflect.defineProperty(mount, 'hook', { | ||
writable: false, | ||
value: testHook | ||
}); | ||
Reflect.defineProperty(mount, 'extend', { | ||
@@ -307,0 +357,0 @@ writable: false, |
@@ -10,32 +10,17 @@ "use strict"; | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
const defaultRender = element => element; | ||
class TestRenderer extends _react.Component { | ||
constructor(...args) { | ||
super(...args); | ||
const TestRenderer = /*#__PURE__*/(0, _react.forwardRef)(({ | ||
children, | ||
render = defaultRender | ||
}, ref) => { | ||
const [props, setProps] = (0, _react.useState)(); | ||
(0, _react.useImperativeHandle)(ref, () => ({ | ||
setProps(newProps) { | ||
setProps(newProps); | ||
} | ||
_defineProperty(this, "state", {}); | ||
} | ||
setProps(props) { | ||
this.setState({ | ||
props | ||
}); | ||
} | ||
render() { | ||
const { | ||
props | ||
} = this.state; | ||
const { | ||
children, | ||
render = defaultRender | ||
} = this.props; | ||
return render(props ? /*#__PURE__*/(0, _react.cloneElement)(children, props) : children); | ||
} | ||
} | ||
})); | ||
return render(props ? /*#__PURE__*/(0, _react.cloneElement)(children, props) : children); | ||
}); | ||
exports.TestRenderer = TestRenderer; |
import type { ReactElement } from 'react'; | ||
import type { Node as BaseNode, Root as BaseRoot, RootNode, PlainObject, EmptyObject, EraseIfEmpty, IfEmptyObject } from './types'; | ||
import type { Node as BaseNode, RootNode, PlainObject, EmptyObject, EraseIfEmpty, IfEmptyObject } from './types'; | ||
interface BaseNodeCreationOptions<T, Extensions extends PlainObject> { | ||
@@ -10,3 +10,3 @@ props: T; | ||
declare type NodeCreationOptions<T, Extensions extends PlainObject = EmptyObject> = EmptyObject extends Extensions ? BaseNodeCreationOptions<T, Extensions> : BaseNodeCreationOptions<T, Extensions> & Extensions; | ||
export interface Environment<Context, Extensions extends PlainObject = EmptyObject> { | ||
export interface EnvironmentOptions<Context, Extensions extends PlainObject = EmptyObject> { | ||
act<T>(action: () => T): T extends Promise<any> ? Promise<void> : void; | ||
@@ -46,12 +46,23 @@ mount(element: ReactElement<any>): Context; | ||
extend<AdditionalMountOptions extends PlainObject = EmptyObject, AdditionalContext extends PlainObject = EmptyObject, AdditionalActions extends PlainObject = EmptyObject, AdditionalAsync extends boolean = false>(options: CustomMountExtendOptions<AdditionalMountOptions, IfEmptyObject<MountOptions, AdditionalMountOptions, MountOptions & EraseIfEmpty<AdditionalMountOptions>>, AdditionalContext, IfEmptyObject<Context, AdditionalContext, Context & EraseIfEmpty<AdditionalContext>>, AdditionalActions, IfEmptyObject<Actions, AdditionalActions, Actions & EraseIfEmpty<AdditionalActions>>, Extensions, AdditionalAsync>): CustomMount<IfEmptyObject<MountOptions, AdditionalMountOptions, MountOptions & EraseIfEmpty<AdditionalMountOptions>>, IfEmptyObject<Context, AdditionalContext, Context & EraseIfEmpty<AdditionalContext>>, IfEmptyObject<Actions, AdditionalActions, Actions & EraseIfEmpty<AdditionalActions>>, Extensions, AdditionalAsync extends true ? AdditionalAsync : Async>; | ||
hook<T>(useHook: () => T, options?: MountOptions): Async extends true ? Promise<HookRunner<T, Context, Actions>> : HookRunner<T, Context, Actions>; | ||
} | ||
export interface HookRunner<HookReturn, Context extends PlainObject, Actions extends PlainObject> { | ||
readonly current: HookReturn; | ||
readonly value: HookReturn; | ||
readonly context: Context; | ||
readonly actions: Actions; | ||
mount(): void; | ||
unmount(): void; | ||
act<T>(action: (value: HookReturn) => T): T; | ||
} | ||
declare type CustomMountResult<Props, Context extends PlainObject, Actions extends PlainObject, Extensions extends PlainObject, Async extends boolean> = Async extends true ? Promise<RootNode<Props, Context, Actions, Extensions>> : RootNode<Props, Context, Actions, Extensions>; | ||
export declare function createEnvironment<EnvironmentContext = undefined, Extensions extends PlainObject = EmptyObject>(env: Environment<EnvironmentContext, Extensions>): { | ||
mount: <Props>(element: ReactElement<Props, string | import("react").JSXElementConstructor<any>>) => BaseNode<Props, Extensions> & BaseRoot<Props, EmptyObject, EmptyObject>; | ||
createMount: <MountOptions extends PlainObject = EmptyObject, Context extends PlainObject = EmptyObject, Actions extends PlainObject = EmptyObject, Async extends boolean = false>(createMountOptions: CustomMountOptions<MountOptions, Context, Context, Actions, Actions, Extensions, Async>) => CustomMount<MountOptions, Context, Actions, Extensions, Async>; | ||
mounted: Set<BaseNode<any, Extensions> & BaseRoot<any, any, any>>; | ||
unmountAll: () => void; | ||
}; | ||
interface Environment<Extensions extends PlainObject = EmptyObject> { | ||
readonly mounted: Set<RootNode<any, any, any, Extensions>>; | ||
readonly mount: CustomMount<EmptyObject, EmptyObject, EmptyObject, Extensions, false>; | ||
createMount<MountOptions extends PlainObject = EmptyObject, Context extends PlainObject = EmptyObject, Actions extends PlainObject = EmptyObject, Async extends boolean = false>(options: CustomMountOptions<MountOptions, Context, Context, Actions, Actions, Extensions, Async>): CustomMount<MountOptions, Context, Actions, Extensions, Async>; | ||
unmountAll(): void; | ||
} | ||
export declare function createEnvironment<EnvironmentContext = undefined, Extensions extends PlainObject = EmptyObject>(env: EnvironmentOptions<EnvironmentContext, Extensions>): Environment<Extensions>; | ||
export declare function isNode<Extensions extends PlainObject = EmptyObject>(maybeNode: unknown): maybeNode is BaseNode<unknown, Extensions>; | ||
export {}; | ||
//# sourceMappingURL=environment.d.ts.map |
@@ -5,3 +5,5 @@ "use strict"; | ||
const jsx_runtime_1 = require("react/jsx-runtime"); | ||
const react_1 = require("react"); | ||
const TestRenderer_1 = require("./TestRenderer"); | ||
const HookRunner_1 = require("./HookRunner"); | ||
const print_1 = require("./print"); | ||
@@ -11,2 +13,3 @@ const IS_NODE = Symbol.for('QuiltTesting.Node'); | ||
const allMounted = new Set(); | ||
const mount = createMount({}); | ||
return { mount, createMount, mounted: allMounted, unmountAll }; | ||
@@ -18,5 +21,3 @@ function createRoot(element, { context: rootContext, actions: rootActions, render, resolveRoot = defaultResolveRoot, } = {}) { | ||
let context; | ||
const testRenderer = { | ||
current: null, | ||
}; | ||
const testRendererRef = react_1.createRef(); | ||
const rootApi = { | ||
@@ -122,5 +123,3 @@ act, | ||
act(() => { | ||
context = env.mount(jsx_runtime_1.jsx(TestRenderer_1.TestRenderer, Object.assign({ ref: (renderer) => { | ||
testRenderer.current = renderer; | ||
}, render: render }, { children: element }), void 0)); | ||
context = env.mount(jsx_runtime_1.jsx(TestRenderer_1.TestRenderer, Object.assign({ ref: testRendererRef, render: render }, { children: element }), void 0)); | ||
}); | ||
@@ -145,3 +144,3 @@ allMounted.add(root); | ||
var _a; | ||
(_a = testRenderer.current) === null || _a === void 0 ? void 0 : _a.setProps(props); | ||
(_a = testRendererRef.current) === null || _a === void 0 ? void 0 : _a.setProps(props); | ||
}); | ||
@@ -183,5 +182,5 @@ } | ||
rootNode = | ||
testRenderer.current == null | ||
testRendererRef.current == null | ||
? null | ||
: env.update(testRenderer.current, createNode, context); | ||
: env.update(testRendererRef.current, createNode, context); | ||
rootNode = rootNode && resolveRoot(rootNode); | ||
@@ -209,7 +208,2 @@ } | ||
} | ||
function mount(element) { | ||
const root = createRoot(element); | ||
root.mount(); | ||
return root; | ||
} | ||
function createMount(createMountOptions) { | ||
@@ -238,2 +232,44 @@ const { render = defaultRender, context: createContext = defaultContext, actions: createActions = defaultActions, afterMount, } = createMountOptions; | ||
} | ||
function testHook(useHook, options) { | ||
const hookRunnerRef = react_1.createRef(); | ||
const rootOrPromise = mount(jsx_runtime_1.jsx(HookRunner_1.HookRunner, { useHook: useHook, ref: hookRunnerRef }, void 0), options); | ||
const withRoot = (root) => { | ||
const getCurrentValue = () => { | ||
if (hookRunnerRef.current == null) { | ||
throw new Error('Attempted to access the hook value while the hook runner was not mounted'); | ||
} | ||
return hookRunnerRef.current.current; | ||
}; | ||
return { | ||
get current() { | ||
return getCurrentValue(); | ||
}, | ||
get value() { | ||
return getCurrentValue(); | ||
}, | ||
get context() { | ||
return root.context; | ||
}, | ||
get actions() { | ||
return root.actions; | ||
}, | ||
act(action) { | ||
return root.act(() => action(getCurrentValue())); | ||
}, | ||
mount() { | ||
root.mount(); | ||
}, | ||
unmount() { | ||
root.unmount(); | ||
}, | ||
}; | ||
}; | ||
return 'then' in rootOrPromise | ||
? rootOrPromise.then((root) => withRoot(root)) | ||
: withRoot(rootOrPromise); | ||
} | ||
Reflect.defineProperty(mount, 'hook', { | ||
writable: false, | ||
value: testHook, | ||
}); | ||
Reflect.defineProperty(mount, 'extend', { | ||
@@ -240,0 +276,0 @@ writable: false, |
@@ -1,2 +0,1 @@ | ||
/// <reference types="react" /> | ||
import type { VNode, Component } from 'preact'; | ||
@@ -8,7 +7,7 @@ import { isNode } from '../environment'; | ||
export type { Node, Root, RootNode, HtmlNodeExtensions, CustomMount }; | ||
declare const mount: <Props>(element: import("react").ReactElement<Props, string | import("react").JSXElementConstructor<any>>) => import("../types").NodeApi<Props, HtmlNodeExtensions> & Omit<HtmlNodeExtensions, keyof Root<any, import("../types").EmptyObject, import("../types").EmptyObject>> & Root<Props, import("../types").EmptyObject, import("../types").EmptyObject>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(createMountOptions: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, HtmlNodeExtensions> & (Async extends true ? { | ||
declare const mount: CustomMount<import("../types").EmptyObject, import("../types").EmptyObject, import("../types").EmptyObject, HtmlNodeExtensions, false>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(options: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, HtmlNodeExtensions> & (Async extends true ? { | ||
afterMount(wrapper: RootNode<unknown, Context_1, Actions, HtmlNodeExtensions>, options: MountOptions): PromiseLike<void>; | ||
} : { | ||
afterMount?(wrapper: RootNode<unknown, Context_1, Actions, HtmlNodeExtensions>, options: MountOptions): void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, HtmlNodeExtensions, Async>, mounted: Set<import("../types").NodeApi<any, HtmlNodeExtensions> & Omit<HtmlNodeExtensions, keyof Root<any, import("../types").EmptyObject, import("../types").EmptyObject>> & Root<any, any, any>>, unmountAll: () => void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, HtmlNodeExtensions, Async>, mounted: Set<RootNode<any, any, any, HtmlNodeExtensions>>, unmountAll: () => void; | ||
export { mount, createMount, mounted, unmountAll }; | ||
@@ -15,0 +14,0 @@ /** |
@@ -1,16 +0,15 @@ | ||
/// <reference types="react" /> | ||
import { Environment, isNode } from '../environment'; | ||
import type { CustomMount } from '../environment'; | ||
import { isNode } from '../environment'; | ||
import type { CustomMount, EnvironmentOptions } from '../environment'; | ||
import type { Node, Root, RootNode, HtmlNodeExtensions } from '../types'; | ||
export { isNode }; | ||
export type { Node, Root, RootNode, HtmlNodeExtensions, CustomMount }; | ||
declare const mount: <Props>(element: import("react").ReactElement<Props, string | import("react").JSXElementConstructor<any>>) => import("../types").NodeApi<Props, HtmlNodeExtensions> & Omit<HtmlNodeExtensions, keyof Root<any, import("../types").EmptyObject, import("../types").EmptyObject>> & Root<Props, import("../types").EmptyObject, import("../types").EmptyObject>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(createMountOptions: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, HtmlNodeExtensions> & (Async extends true ? { | ||
declare const mount: CustomMount<import("../types").EmptyObject, import("../types").EmptyObject, import("../types").EmptyObject, HtmlNodeExtensions, false>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(options: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, HtmlNodeExtensions> & (Async extends true ? { | ||
afterMount(wrapper: RootNode<unknown, Context_1, Actions, HtmlNodeExtensions>, options: MountOptions): PromiseLike<void>; | ||
} : { | ||
afterMount?(wrapper: RootNode<unknown, Context_1, Actions, HtmlNodeExtensions>, options: MountOptions): void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, HtmlNodeExtensions, Async>, mounted: Set<import("../types").NodeApi<any, HtmlNodeExtensions> & Omit<HtmlNodeExtensions, keyof Root<any, import("../types").EmptyObject, import("../types").EmptyObject>> & Root<any, any, any>>, unmountAll: () => void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, HtmlNodeExtensions, Async>, mounted: Set<RootNode<any, any, any, HtmlNodeExtensions>>, unmountAll: () => void; | ||
export { mount, createMount, mounted, unmountAll }; | ||
declare type Create = Parameters<Environment<any, HtmlNodeExtensions>['update']>[1]; | ||
declare type Create = Parameters<EnvironmentOptions<any, HtmlNodeExtensions>['update']>[1]; | ||
declare type Child = ReturnType<Create> | string; | ||
export declare function createNodeFromFiber(element: any, create: Create): Child; | ||
//# sourceMappingURL=react-dom.d.ts.map |
/// <reference types="react" /> | ||
import type { Environment } from '../../environment'; | ||
import type { EnvironmentOptions } from '../../environment'; | ||
export declare enum Tag { | ||
@@ -42,3 +42,3 @@ FunctionComponent = 0, | ||
} | ||
declare type Create = Parameters<Environment<any>['update']>[1]; | ||
declare type Create = Parameters<EnvironmentOptions<any>['update']>[1]; | ||
declare type Child = ReturnType<Create> | string; | ||
@@ -45,0 +45,0 @@ export declare function createNodeFromFiber(element: any, create: Create): Child; |
@@ -1,2 +0,1 @@ | ||
/// <reference types="react" /> | ||
import { isNode } from '../environment'; | ||
@@ -7,8 +6,8 @@ import type { CustomMount } from '../environment'; | ||
export type { Node, Root, RootNode, CustomMount }; | ||
declare const mount: <Props>(element: import("react").ReactElement<Props, string | import("react").JSXElementConstructor<any>>) => import("../types").NodeApi<Props, import("../types").EmptyObject> & Root<Props, import("../types").EmptyObject, import("../types").EmptyObject>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(createMountOptions: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, import("../types").EmptyObject> & (Async extends true ? { | ||
declare const mount: CustomMount<import("../types").EmptyObject, import("../types").EmptyObject, import("../types").EmptyObject, import("../types").EmptyObject, false>, createMount: <MountOptions extends import("../types").PlainObject = import("../types").EmptyObject, Context_1 extends import("../types").PlainObject = import("../types").EmptyObject, Actions extends import("../types").PlainObject = import("../types").EmptyObject, Async extends boolean = false>(options: import("../environment").RenderOption<MountOptions, Context_1> & import("../environment").ContextOption<MountOptions, Context_1> & import("../environment").ActionsOption<MountOptions, Context_1, Actions, import("../types").EmptyObject> & (Async extends true ? { | ||
afterMount(wrapper: RootNode<unknown, Context_1, Actions, import("../types").EmptyObject>, options: MountOptions): PromiseLike<void>; | ||
} : { | ||
afterMount?(wrapper: RootNode<unknown, Context_1, Actions, import("../types").EmptyObject>, options: MountOptions): void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, import("../types").EmptyObject, Async>, mounted: Set<import("../types").NodeApi<any, import("../types").EmptyObject> & Root<any, any, any>>, unmountAll: () => void; | ||
})) => CustomMount<MountOptions, Context_1, Actions, import("../types").EmptyObject, Async>, mounted: Set<RootNode<any, any, any, import("../types").EmptyObject>>, unmountAll: () => void; | ||
export { mount, createMount, mounted, unmountAll }; | ||
//# sourceMappingURL=test-renderer.d.ts.map |
@@ -1,16 +0,13 @@ | ||
import { Component } from 'react'; | ||
import type { ReactElement, ReactNode } from 'react'; | ||
interface State<ChildProps> { | ||
props?: Partial<ChildProps>; | ||
} | ||
interface Props { | ||
import type { ReactNode, Ref, ReactElement } from 'react'; | ||
interface Props<ComponentProps = unknown> { | ||
children?: ReactNode; | ||
render?(element: ReactElement<any>): ReactElement<any>; | ||
render?(element: ReactElement<ComponentProps>): ReactElement<ComponentProps>; | ||
} | ||
export declare class TestRenderer<ChildProps> extends Component<Props, State<ChildProps>> { | ||
state: State<ChildProps>; | ||
setProps(props: Partial<ChildProps>): void; | ||
render(): ReactElement<any, string | import("react").JSXElementConstructor<any>>; | ||
export interface ImperativeApi<ComponentProps = unknown> { | ||
setProps(props: Partial<ComponentProps>): void; | ||
} | ||
export declare const TestRenderer: <ComponentProps>(props: Props<ComponentProps> & { | ||
ref?: Ref<ImperativeApi<ComponentProps>> | undefined; | ||
}) => ReactElement | null; | ||
export {}; | ||
//# sourceMappingURL=TestRenderer.d.ts.map |
@@ -6,16 +6,10 @@ "use strict"; | ||
const defaultRender = (element) => element; | ||
class TestRenderer extends react_1.Component { | ||
constructor() { | ||
super(...arguments); | ||
this.state = {}; | ||
} | ||
setProps(props) { | ||
this.setState({ props }); | ||
} | ||
render() { | ||
const { props } = this.state; | ||
const { children, render = defaultRender } = this.props; | ||
return render(props ? react_1.cloneElement(children, props) : children); | ||
} | ||
} | ||
exports.TestRenderer = TestRenderer; | ||
exports.TestRenderer = react_1.forwardRef(({ children, render = defaultRender }, ref) => { | ||
const [props, setProps] = react_1.useState(); | ||
react_1.useImperativeHandle(ref, () => ({ | ||
setProps(newProps) { | ||
setProps(newProps); | ||
}, | ||
})); | ||
return render(props ? react_1.cloneElement(children, props) : children); | ||
}); |
{ | ||
"name": "@quilted/react-testing", | ||
"version": "0.3.5", | ||
"version": "0.3.6", | ||
"description": "", | ||
@@ -74,3 +74,3 @@ "publishConfig": { | ||
}, | ||
"gitHead": "767cea3e0a994606fed15c1868a4a66cfa7ea7db" | ||
"gitHead": "99da19af59ea8140b89c613091d0e658ec8ffbf9" | ||
} |
@@ -18,2 +18,3 @@ # `@quilted/react-testing` | ||
- [`createMount()`](#createMount) | ||
- [`mount.hook()`](#mountHook) | ||
- [`destroyAll()`](#destroyAll) | ||
@@ -185,3 +186,3 @@ - [`Root`](#root) | ||
#### <a name="createMount"></a> `createMount<MountOptions, Context, Async>(options: CreateMountOptions<MountOptions, Context, Async>): MountFunction` | ||
#### <a name="createMount"></a> `createMount<MountOptions, Context, Actions, Async>(options: CreateMountOptions<MountOptions, Context, Actions, Async>): MountFunction` | ||
@@ -341,2 +342,34 @@ The [`mount`](#mount) function is powerful on its own, but applications will often want a more powerful version tailored to their application. A common example is app-wide context, where a set of context providers are generally assumed to be present for every component under test. It can also be useful for providing custom GraphQL infrastructure that enables easy testing of different API responses, such as the [`createGraphQL` factory from `@shopify/graphql-testing`](../graphql-testing). | ||
#### <a name="mountHook"></a> `mount.hook<HookResult>(useHook: HookResult, options?: MountOptions): HookRunner<HookResult, Context, Actions>` | ||
Whenever possible, you should use test on component boundaries using [`mount()`](#mount) and the [`Root`](#root) and [`Node`](#node) objects it creates. Sometimes, you might have a particularly complex bit of logic that you encapsulate in a custom hook. Every `mount()`, including [custom mount functions](#customMount), provide a `hook()` method to run your hook in a simulated component, and to access the current return result of your hook. Below, you can see how we can use this helper to inspect our custom hook’s initial result: | ||
```ts | ||
import {useState} from 'react'; | ||
import {mount} from '@quilted/react-testing'; | ||
function useIncrementingNumber(initial: number) { | ||
const [currentNumber, setCurrentNumber] = useState(initial); | ||
const incrementNumber = () => setCurrentNumber((current) => current + 1); | ||
return [currentNumber, incrementNumber]; | ||
} | ||
const incrementingNumber = mount.hook(() => useIncrementingNumber(5)); | ||
incrementingNumber.value[0]; // Our initial number, `5` in this case | ||
``` | ||
The returned “hook runner” can do more than just give you access to the hook’s result. You can also simulate actions that use the hook’s result using the `act()` method. After calling `act()`, the `value` property will be updated with the most recent result. | ||
```ts | ||
const incrementingNumber = mount.hook(() => useIncrementingNumber(5)); | ||
incrementingNumber.act(([currentNumber, incrementNumber]) => { | ||
incrementNumber(); | ||
}); | ||
incrementingNumber.value[1]; // It’s `6` now! | ||
``` | ||
If the “base” `mount` you used was created using `createMount()`, the second argument to its `hook()` method can be any options you could pass as the second argument to `mount()` itself. The resulting `hook` runner will also have the same [`context`](#context) and [`actions`](#actions) properties as a mounted component would have. If the base `mount` is asynchronous, `hook()` is asynchronous as well. | ||
#### <a name="destroyAll"></a> `destroyAll()` | ||
@@ -343,0 +376,0 @@ |
@@ -6,4 +6,4 @@ import {h, render} from 'preact'; | ||
import {createEnvironment, isNode, Environment} from '../environment'; | ||
import type {CustomMount} from '../environment'; | ||
import {createEnvironment, isNode} from '../environment'; | ||
import type {CustomMount, EnvironmentOptions} from '../environment'; | ||
import type {Node, Root, RootNode, HtmlNodeExtensions} from '../types'; | ||
@@ -42,3 +42,5 @@ | ||
type Create = Parameters<Environment<any, HtmlNodeExtensions>['update']>[1]; | ||
type Create = Parameters< | ||
EnvironmentOptions<any, HtmlNodeExtensions>['update'] | ||
>[1]; | ||
type Child = ReturnType<Create> | string; | ||
@@ -45,0 +47,0 @@ |
import {render, unmountComponentAtNode} from 'react-dom'; | ||
import {act} from 'react-dom/test-utils'; | ||
import {createEnvironment, Environment, isNode} from '../environment'; | ||
import type {CustomMount} from '../environment'; | ||
import {createEnvironment, isNode} from '../environment'; | ||
import type {CustomMount, EnvironmentOptions} from '../environment'; | ||
import type {Node, Root, RootNode, HtmlNodeExtensions} from '../types'; | ||
@@ -45,3 +45,5 @@ | ||
type Create = Parameters<Environment<any, HtmlNodeExtensions>['update']>[1]; | ||
type Create = Parameters< | ||
EnvironmentOptions<any, HtmlNodeExtensions>['update'] | ||
>[1]; | ||
type Child = ReturnType<Create> | string; | ||
@@ -48,0 +50,0 @@ |
@@ -1,2 +0,2 @@ | ||
import type {Environment} from '../../environment'; | ||
import type {EnvironmentOptions} from '../../environment'; | ||
@@ -49,3 +49,3 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires | ||
type Create = Parameters<Environment<any>['update']>[1]; | ||
type Create = Parameters<EnvironmentOptions<any>['update']>[1]; | ||
type Child = ReturnType<Create> | string; | ||
@@ -52,0 +52,0 @@ |
@@ -8,4 +8,4 @@ import { | ||
import {createEnvironment, Environment, isNode} from '../environment'; | ||
import type {CustomMount} from '../environment'; | ||
import {createEnvironment, isNode} from '../environment'; | ||
import type {CustomMount, EnvironmentOptions} from '../environment'; | ||
import type {Node, Root, RootNode} from '../types'; | ||
@@ -34,3 +34,3 @@ | ||
type Create = Parameters<Environment<any>['update']>[1]; | ||
type Create = Parameters<EnvironmentOptions<any>['update']>[1]; | ||
@@ -37,0 +37,0 @@ function createNodeFromTestInstance( |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
549658
160
5721
823