@storybook/tanstack-react 0.0.0 → 10.4.0-alpha.17
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/README.md +7 -0
- package/dist/_browser-chunks/chunk-4BE7D4DS.js +9 -0
- package/dist/_browser-chunks/chunk-4CKCBIXI.js +7 -0
- package/dist/_browser-chunks/chunk-73EPJ7AY.js +230 -0
- package/dist/export-mocks/react-router.d.ts +344 -0
- package/dist/export-mocks/react-router.js +79 -0
- package/dist/export-mocks/start-storage-context.d.ts +16 -0
- package/dist/export-mocks/start-storage-context.js +33 -0
- package/dist/export-mocks/start.d.ts +120 -0
- package/dist/export-mocks/start.js +334 -0
- package/dist/index.d.ts +438 -0
- package/dist/index.js +17 -0
- package/dist/node/index.d.ts +28 -0
- package/dist/node/index.js +19 -0
- package/dist/preset.d.ts +8 -0
- package/dist/preset.js +398 -0
- package/dist/preview.d.ts +111 -0
- package/dist/preview.js +13 -0
- package/package.json +108 -5
- package/template/cli/ts/Button.stories.ts +54 -0
- package/template/cli/ts/Button.tsx +36 -0
- package/template/cli/ts/Header.stories.ts +34 -0
- package/template/cli/ts/Header.tsx +56 -0
- package/template/cli/ts/Page.stories.ts +41 -0
- package/template/cli/ts/Page.tsx +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Storybook for TanStack (React + Vite)
|
|
2
|
+
|
|
3
|
+
Develop, document, and test UI components in isolation with built-in TanStack Router and TanStack Query support.
|
|
4
|
+
|
|
5
|
+
See [documentation](https://storybook.js.org/docs/get-started?ref=readme) for installation instructions, usage examples, APIs, and more.
|
|
6
|
+
|
|
7
|
+
Learn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./chunk-4BE7D4DS.js";
|
|
4
|
+
|
|
5
|
+
// src/preview.tsx
|
|
6
|
+
var preview_exports = {};
|
|
7
|
+
__export(preview_exports, {
|
|
8
|
+
applyDecorators: () => applyDecorators,
|
|
9
|
+
loaders: () => loaders,
|
|
10
|
+
optimizeDeps: () => optimizeDeps,
|
|
11
|
+
parameters: () => parameters
|
|
12
|
+
});
|
|
13
|
+
import { applyDecorators as reactApplyDecorators } from "@storybook/react/entry-preview-docs";
|
|
14
|
+
|
|
15
|
+
// src/routing/decorator.tsx
|
|
16
|
+
import React from "react";
|
|
17
|
+
import {
|
|
18
|
+
createMemoryHistory,
|
|
19
|
+
createRootRoute,
|
|
20
|
+
createRoute as createRoute2,
|
|
21
|
+
createRouter,
|
|
22
|
+
RouterProvider,
|
|
23
|
+
interpolatePath,
|
|
24
|
+
defaultStringifySearch
|
|
25
|
+
} from "@tanstack/react-router";
|
|
26
|
+
|
|
27
|
+
// src/routing/duplicate-tree.ts
|
|
28
|
+
import { createRoute, RootRoute, createRootRouteWithContext } from "@tanstack/react-router";
|
|
29
|
+
var MAX_PARENT_WALK = 50;
|
|
30
|
+
function findRootRoute(route) {
|
|
31
|
+
let current = route;
|
|
32
|
+
for (let i = 0; i < MAX_PARENT_WALK && current; i += 1) {
|
|
33
|
+
if (current instanceof RootRoute)
|
|
34
|
+
return current;
|
|
35
|
+
let getParent = current.options?.getParentRoute;
|
|
36
|
+
current = typeof getParent == "function" ? getParent() : void 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getOverrideFor(overrides, routeId) {
|
|
40
|
+
return overrides ? overrides[routeId] ?? {} : {};
|
|
41
|
+
}
|
|
42
|
+
function initSourceTree(route, counter) {
|
|
43
|
+
route.init({ originalIndex: counter.i }), counter.i += 1;
|
|
44
|
+
let children = route.children;
|
|
45
|
+
if (children?.length)
|
|
46
|
+
for (let child of children)
|
|
47
|
+
initSourceTree(child, counter);
|
|
48
|
+
}
|
|
49
|
+
function cloneChild(oldRoute, parent, overrides, byId) {
|
|
50
|
+
let options = oldRoute.options ?? {}, { id: _id, getParentRoute: _g, ...rest } = options, override = getOverrideFor(overrides, oldRoute.id), cloned = createRoute({
|
|
51
|
+
...rest,
|
|
52
|
+
...override,
|
|
53
|
+
getParentRoute: () => parent
|
|
54
|
+
});
|
|
55
|
+
byId.set(oldRoute.id, cloned);
|
|
56
|
+
let children = oldRoute.children;
|
|
57
|
+
if (children?.length) {
|
|
58
|
+
let clonedChildren = children.map(
|
|
59
|
+
(child) => cloneChild(child, cloned, overrides, byId)
|
|
60
|
+
);
|
|
61
|
+
cloned.addChildren(clonedChildren);
|
|
62
|
+
}
|
|
63
|
+
return cloned;
|
|
64
|
+
}
|
|
65
|
+
function duplicateRouteTree(rootRoute, { overrides } = {}) {
|
|
66
|
+
initSourceTree(rootRoute, { i: 0 });
|
|
67
|
+
let byId = /* @__PURE__ */ new Map(), rootOptions = rootRoute.options ?? {}, rootOverride = getOverrideFor(overrides, "__root__"), { id: _rootId, getParentRoute: _rootGetParent, ...restRoot } = rootOptions, newRoot = createRootRouteWithContext()({
|
|
68
|
+
...restRoot,
|
|
69
|
+
...rootOverride
|
|
70
|
+
});
|
|
71
|
+
byId.set("__root__", newRoot);
|
|
72
|
+
let children = rootRoute.children;
|
|
73
|
+
if (children?.length) {
|
|
74
|
+
let clonedChildren = children.map(
|
|
75
|
+
(child) => cloneChild(child, newRoot, overrides, byId)
|
|
76
|
+
);
|
|
77
|
+
newRoot.addChildren(clonedChildren);
|
|
78
|
+
}
|
|
79
|
+
return { root: newRoot, byId };
|
|
80
|
+
}
|
|
81
|
+
function resolveStoryLeaf(tree, { path, boundRouteId }) {
|
|
82
|
+
let { root, byId } = tree;
|
|
83
|
+
if (path) {
|
|
84
|
+
let bestMatch, bestMatchLength = -1;
|
|
85
|
+
for (let route of byId.values()) {
|
|
86
|
+
let fullPath = route.fullPath;
|
|
87
|
+
fullPath && fullPath === path && fullPath.length > bestMatchLength && (bestMatch = route, bestMatchLength = fullPath.length);
|
|
88
|
+
}
|
|
89
|
+
if (bestMatch)
|
|
90
|
+
return bestMatch;
|
|
91
|
+
}
|
|
92
|
+
if (boundRouteId) {
|
|
93
|
+
let bound = byId.get(boundRouteId);
|
|
94
|
+
if (bound)
|
|
95
|
+
return bound;
|
|
96
|
+
}
|
|
97
|
+
let firstChild = root.children?.[0];
|
|
98
|
+
return firstChild || root;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/routing/utils.ts
|
|
102
|
+
import { Route, RootRoute as RootRoute2 } from "@tanstack/react-router";
|
|
103
|
+
function isRoute(value) {
|
|
104
|
+
return value instanceof Route || value instanceof RootRoute2;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/routing/decorator.tsx
|
|
108
|
+
var StoryContext = React.createContext({ Story: () => null }), StoryFromContext = () => {
|
|
109
|
+
let { Story } = React.useContext(StoryContext);
|
|
110
|
+
return React.createElement(Story, null);
|
|
111
|
+
}, tanstackRouteDecorator = (Story, context) => React.createElement(TanStackRouterStory, { Story, context });
|
|
112
|
+
function TanStackRouterStory({ Story, context }) {
|
|
113
|
+
let routerContext = context.parameters.tanstack?.router?.useRouterContext?.({
|
|
114
|
+
storyContext: context
|
|
115
|
+
}), router = React.useMemo(
|
|
116
|
+
() => createStoryRouter({ Story: StoryFromContext, context, routerContext }),
|
|
117
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
118
|
+
[context.id]
|
|
119
|
+
), providerContext = React.useMemo(
|
|
120
|
+
() => ({
|
|
121
|
+
...context.parameters.tanstack?.router?.context,
|
|
122
|
+
...routerContext
|
|
123
|
+
}),
|
|
124
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
125
|
+
[context.id, routerContext]
|
|
126
|
+
);
|
|
127
|
+
return React.createElement(StoryContext.Provider, { value: { Story } }, React.createElement(RouterProvider, { router, context: providerContext }));
|
|
128
|
+
}
|
|
129
|
+
function createStoryRouter({
|
|
130
|
+
Story,
|
|
131
|
+
context,
|
|
132
|
+
routerContext
|
|
133
|
+
}) {
|
|
134
|
+
let routerParameters = context.parameters.tanstack?.router ?? {}, { tree, leaf } = resolveTree(Story, context), routeTree = tree.root, inferredPath = routerParameters?.path || leaf.fullPath || routeTree.children?.[0]?.fullPath || "/", resolvedPath = interpolatePath({
|
|
135
|
+
path: inferredPath,
|
|
136
|
+
params: routerParameters?.params ?? {}
|
|
137
|
+
}).interpolatedPath, search = routerParameters?.query ? defaultStringifySearch(routerParameters.query) : "";
|
|
138
|
+
search && (resolvedPath += search);
|
|
139
|
+
let history = createMemoryHistory({
|
|
140
|
+
initialEntries: [resolvedPath]
|
|
141
|
+
});
|
|
142
|
+
return history.replace(resolvedPath), createRouter({
|
|
143
|
+
routeTree,
|
|
144
|
+
history,
|
|
145
|
+
defaultNotFoundComponent(props) {
|
|
146
|
+
return React.createElement("div", null, "Route not found: ", props.routeId);
|
|
147
|
+
},
|
|
148
|
+
defaultErrorComponent({ error }) {
|
|
149
|
+
return React.createElement("div", null, "Story did something wrong : ", String(error));
|
|
150
|
+
},
|
|
151
|
+
context: routerContext
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function injectStoryComponent(leaf, Story, overrides, leafId) {
|
|
155
|
+
let userOverride = overrides?.[leafId];
|
|
156
|
+
userOverride && "component" in userOverride && userOverride.component !== void 0 || leaf.update({ component: () => React.createElement(Story, null) });
|
|
157
|
+
}
|
|
158
|
+
function resolveTree(Story, context) {
|
|
159
|
+
let metaRoute = context.route, routerParameters = context.parameters.tanstack?.router ?? {}, routerParameterRoute = routerParameters.route, routeOverrides = routerParameters.routeOverrides, resolvedRoute = isRoute(routerParameterRoute) ? routerParameterRoute : isRoute(metaRoute) ? metaRoute : void 0, rootRoute = resolvedRoute ? findRootRoute(resolvedRoute) : void 0;
|
|
160
|
+
if (rootRoute) {
|
|
161
|
+
let tree = duplicateRouteTree(rootRoute, { overrides: routeOverrides }), leaf = resolveStoryLeaf(tree, {
|
|
162
|
+
path: routerParameters.path,
|
|
163
|
+
boundRouteId: resolvedRoute && resolvedRoute !== rootRoute ? resolvedRoute.id : void 0
|
|
164
|
+
});
|
|
165
|
+
return injectStoryComponent(leaf, Story, routeOverrides, leaf.id), { tree, leaf };
|
|
166
|
+
}
|
|
167
|
+
if (isRoute(routerParameterRoute)) {
|
|
168
|
+
let syntheticRoot2 = createRootRoute(
|
|
169
|
+
routeOverrides?.__root__ ?? {}
|
|
170
|
+
);
|
|
171
|
+
routerParameterRoute.update({ getParentRoute: () => syntheticRoot2 }), syntheticRoot2.addChildren([routerParameterRoute]);
|
|
172
|
+
let tree = duplicateRouteTree(syntheticRoot2, { overrides: routeOverrides }), leaf = tree.byId.get(routerParameterRoute.id) ?? tree.root;
|
|
173
|
+
return injectStoryComponent(leaf, Story, routeOverrides, leaf.id), { tree, leaf };
|
|
174
|
+
}
|
|
175
|
+
let plainOptions = routerParameterRoute ?? {}, syntheticRoot = createRootRoute(
|
|
176
|
+
routeOverrides?.__root__ ?? {}
|
|
177
|
+
), syntheticChild = createRoute2({
|
|
178
|
+
component: () => React.createElement(Story, null),
|
|
179
|
+
id: "storybook-story",
|
|
180
|
+
...plainOptions,
|
|
181
|
+
getParentRoute: () => syntheticRoot
|
|
182
|
+
});
|
|
183
|
+
return syntheticRoot.addChildren([syntheticChild]), injectStoryComponent(syntheticChild, Story, routeOverrides, syntheticChild.id), {
|
|
184
|
+
tree: { root: syntheticRoot, byId: /* @__PURE__ */ new Map([[syntheticChild.id, syntheticChild]]) },
|
|
185
|
+
leaf: syntheticChild
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/routing/loader.ts
|
|
190
|
+
import { RootRoute as RootRoute3 } from "@tanstack/react-router";
|
|
191
|
+
function getComponentFromRoute(route) {
|
|
192
|
+
if (route.options?.component)
|
|
193
|
+
return route.options.component;
|
|
194
|
+
if (route instanceof RootRoute3)
|
|
195
|
+
return route.children?.[0]?.options?.component;
|
|
196
|
+
}
|
|
197
|
+
var routeComponentLoader = (context) => {
|
|
198
|
+
let routerParameters = context.parameters.tanstack?.router ?? {}, parameterRoute = isRoute(routerParameters.route) ? routerParameters.route : void 0;
|
|
199
|
+
if (parameterRoute) {
|
|
200
|
+
if (!context.component) {
|
|
201
|
+
let component = getComponentFromRoute(parameterRoute);
|
|
202
|
+
component && !context.component && (context.component = component);
|
|
203
|
+
}
|
|
204
|
+
context.route || (context.route = parameterRoute);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// src/preview.tsx
|
|
209
|
+
var loaders = [routeComponentLoader], applyDecorators = (storyFn, allDecorators) => (
|
|
210
|
+
// reorder decorators so `jsxDecorator` is innermost, and `tanstackRouteDecorator` is just outside it
|
|
211
|
+
// There is an issue if `tanstackRouteDecorator` is innermost. All stories crashes due to a bug with the jsxDecorator.
|
|
212
|
+
reactApplyDecorators(storyFn, [
|
|
213
|
+
tanstackRouteDecorator,
|
|
214
|
+
...allDecorators
|
|
215
|
+
])
|
|
216
|
+
), parameters = {
|
|
217
|
+
tanstack: {}
|
|
218
|
+
}, optimizeDeps = [
|
|
219
|
+
"@tanstack/react-devtools",
|
|
220
|
+
"@tanstack/react-query-devtools",
|
|
221
|
+
"@tanstack/react-router-devtools"
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
loaders,
|
|
226
|
+
applyDecorators,
|
|
227
|
+
parameters,
|
|
228
|
+
optimizeDeps,
|
|
229
|
+
preview_exports
|
|
230
|
+
};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import * as _tanstack_react_router from '@tanstack/react-router';
|
|
2
|
+
import { useNavigate as useNavigate$1, useRouter as useRouter$1, useBlocker as useBlocker$1, useSearch as useSearch$1, useParams as useParams$1, useLocation as useLocation$1, useRouterState as useRouterState$1, useLoaderData as useLoaderData$1, useLoaderDeps as useLoaderDeps$1, useRouteContext as useRouteContext$1, useCanGoBack as useCanGoBack$1, useLinkProps as useLinkProps$1, Navigate as Navigate$1 } from '@tanstack/react-router';
|
|
3
|
+
export * from '@tanstack/react-router';
|
|
4
|
+
import * as _tanstack_router_core from '@tanstack/router-core';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
interface MockResultReturn<T> {
|
|
8
|
+
type: "return";
|
|
9
|
+
/**
|
|
10
|
+
* The value that was returned from the function. If function returned a Promise, then this will be a resolved value.
|
|
11
|
+
*/
|
|
12
|
+
value: T;
|
|
13
|
+
}
|
|
14
|
+
interface MockResultIncomplete {
|
|
15
|
+
type: "incomplete";
|
|
16
|
+
value: undefined;
|
|
17
|
+
}
|
|
18
|
+
interface MockResultThrow {
|
|
19
|
+
type: "throw";
|
|
20
|
+
/**
|
|
21
|
+
* An error that was thrown during function execution.
|
|
22
|
+
*/
|
|
23
|
+
value: any;
|
|
24
|
+
}
|
|
25
|
+
interface MockSettledResultFulfilled<T> {
|
|
26
|
+
type: "fulfilled";
|
|
27
|
+
value: T;
|
|
28
|
+
}
|
|
29
|
+
interface MockSettledResultRejected {
|
|
30
|
+
type: "rejected";
|
|
31
|
+
value: any;
|
|
32
|
+
}
|
|
33
|
+
type MockResult<T> = MockResultReturn<T> | MockResultThrow | MockResultIncomplete;
|
|
34
|
+
type MockSettledResult<T> = MockSettledResultFulfilled<T> | MockSettledResultRejected;
|
|
35
|
+
interface MockContext<T extends Procedure> {
|
|
36
|
+
/**
|
|
37
|
+
* This is an array containing all arguments for each call. One item of the array is the arguments of that call.
|
|
38
|
+
*
|
|
39
|
+
* @see https://vitest.dev/api/mock#mock-calls
|
|
40
|
+
* @example
|
|
41
|
+
* const fn = vi.fn()
|
|
42
|
+
*
|
|
43
|
+
* fn('arg1', 'arg2')
|
|
44
|
+
* fn('arg3')
|
|
45
|
+
*
|
|
46
|
+
* fn.mock.calls === [
|
|
47
|
+
* ['arg1', 'arg2'], // first call
|
|
48
|
+
* ['arg3'], // second call
|
|
49
|
+
* ]
|
|
50
|
+
*/
|
|
51
|
+
calls: Parameters<T>[];
|
|
52
|
+
/**
|
|
53
|
+
* This is an array containing all instances that were instantiated when mock was called with a `new` keyword. Note that this is an actual context (`this`) of the function, not a return value.
|
|
54
|
+
* @see https://vitest.dev/api/mock#mock-instances
|
|
55
|
+
*/
|
|
56
|
+
instances: ReturnType<T>[];
|
|
57
|
+
/**
|
|
58
|
+
* An array of `this` values that were used during each call to the mock function.
|
|
59
|
+
* @see https://vitest.dev/api/mock#mock-contexts
|
|
60
|
+
*/
|
|
61
|
+
contexts: ThisParameterType<T>[];
|
|
62
|
+
/**
|
|
63
|
+
* The order of mock's execution. This returns an array of numbers which are shared between all defined mocks.
|
|
64
|
+
*
|
|
65
|
+
* @see https://vitest.dev/api/mock#mock-invocationcallorder
|
|
66
|
+
* @example
|
|
67
|
+
* const fn1 = vi.fn()
|
|
68
|
+
* const fn2 = vi.fn()
|
|
69
|
+
*
|
|
70
|
+
* fn1()
|
|
71
|
+
* fn2()
|
|
72
|
+
* fn1()
|
|
73
|
+
*
|
|
74
|
+
* fn1.mock.invocationCallOrder === [1, 3]
|
|
75
|
+
* fn2.mock.invocationCallOrder === [2]
|
|
76
|
+
*/
|
|
77
|
+
invocationCallOrder: number[];
|
|
78
|
+
/**
|
|
79
|
+
* This is an array containing all values that were `returned` from the function.
|
|
80
|
+
*
|
|
81
|
+
* The `value` property contains the returned value or thrown error. If the function returned a `Promise`, then `result` will always be `'return'` even if the promise was rejected.
|
|
82
|
+
*
|
|
83
|
+
* @see https://vitest.dev/api/mock#mock-results
|
|
84
|
+
* @example
|
|
85
|
+
* const fn = vi.fn()
|
|
86
|
+
* .mockReturnValueOnce('result')
|
|
87
|
+
* .mockImplementationOnce(() => { throw new Error('thrown error') })
|
|
88
|
+
*
|
|
89
|
+
* const result = fn()
|
|
90
|
+
*
|
|
91
|
+
* try {
|
|
92
|
+
* fn()
|
|
93
|
+
* }
|
|
94
|
+
* catch {}
|
|
95
|
+
*
|
|
96
|
+
* fn.mock.results === [
|
|
97
|
+
* {
|
|
98
|
+
* type: 'return',
|
|
99
|
+
* value: 'result',
|
|
100
|
+
* },
|
|
101
|
+
* {
|
|
102
|
+
* type: 'throw',
|
|
103
|
+
* value: Error,
|
|
104
|
+
* },
|
|
105
|
+
* ]
|
|
106
|
+
*/
|
|
107
|
+
results: MockResult<ReturnType<T>>[];
|
|
108
|
+
/**
|
|
109
|
+
* An array containing all values that were `resolved` or `rejected` from the function.
|
|
110
|
+
*
|
|
111
|
+
* This array will be empty if the function was never resolved or rejected.
|
|
112
|
+
*
|
|
113
|
+
* @see https://vitest.dev/api/mock#mock-settledresults
|
|
114
|
+
* @example
|
|
115
|
+
* const fn = vi.fn().mockResolvedValueOnce('result')
|
|
116
|
+
*
|
|
117
|
+
* const result = fn()
|
|
118
|
+
*
|
|
119
|
+
* fn.mock.settledResults === []
|
|
120
|
+
* fn.mock.results === [
|
|
121
|
+
* {
|
|
122
|
+
* type: 'return',
|
|
123
|
+
* value: Promise<'result'>,
|
|
124
|
+
* },
|
|
125
|
+
* ]
|
|
126
|
+
*
|
|
127
|
+
* await result
|
|
128
|
+
*
|
|
129
|
+
* fn.mock.settledResults === [
|
|
130
|
+
* {
|
|
131
|
+
* type: 'fulfilled',
|
|
132
|
+
* value: 'result',
|
|
133
|
+
* },
|
|
134
|
+
* ]
|
|
135
|
+
*/
|
|
136
|
+
settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];
|
|
137
|
+
/**
|
|
138
|
+
* This contains the arguments of the last call. If spy wasn't called, will return `undefined`.
|
|
139
|
+
* @see https://vitest.dev/api/mock#mock-lastcall
|
|
140
|
+
*/
|
|
141
|
+
lastCall: Parameters<T> | undefined;
|
|
142
|
+
}
|
|
143
|
+
type Procedure = (...args: any[]) => any;
|
|
144
|
+
// pick a single function type from function overloads, unions, etc...
|
|
145
|
+
type NormalizedProcedure<T extends Procedure> = (...args: Parameters<T>) => ReturnType<T>;
|
|
146
|
+
/*
|
|
147
|
+
cf. https://typescript-eslint.io/rules/method-signature-style/
|
|
148
|
+
|
|
149
|
+
Typescript assignability is different between
|
|
150
|
+
{ foo: (f: T) => U } (this is "method-signature-style")
|
|
151
|
+
and
|
|
152
|
+
{ foo(f: T): U }
|
|
153
|
+
|
|
154
|
+
Jest uses the latter for `MockInstance.mockImplementation` etc... and it allows assignment such as:
|
|
155
|
+
const boolFn: Jest.Mock<() => boolean> = jest.fn<() => true>(() => true)
|
|
156
|
+
*/
|
|
157
|
+
/* eslint-disable ts/method-signature-style */
|
|
158
|
+
interface MockInstance<T extends Procedure = Procedure> extends Disposable {
|
|
159
|
+
/**
|
|
160
|
+
* Use it to return the name assigned to the mock with the `.mockName(name)` method. By default, it will return `vi.fn()`.
|
|
161
|
+
* @see https://vitest.dev/api/mock#getmockname
|
|
162
|
+
*/
|
|
163
|
+
getMockName(): string;
|
|
164
|
+
/**
|
|
165
|
+
* Sets the internal mock name. This is useful for identifying the mock when an assertion fails.
|
|
166
|
+
* @see https://vitest.dev/api/mock#mockname
|
|
167
|
+
*/
|
|
168
|
+
mockName(name: string): this;
|
|
169
|
+
/**
|
|
170
|
+
* Current context of the mock. It stores information about all invocation calls, instances, and results.
|
|
171
|
+
*/
|
|
172
|
+
mock: MockContext<T>;
|
|
173
|
+
/**
|
|
174
|
+
* Clears all information about every call. After calling it, all properties on `.mock` will return to their initial state. This method does not reset implementations. It is useful for cleaning up mocks between different assertions.
|
|
175
|
+
*
|
|
176
|
+
* To automatically call this method before each test, enable the [`clearMocks`](https://vitest.dev/config/#clearmocks) setting in the configuration.
|
|
177
|
+
* @see https://vitest.dev/api/mock#mockclear
|
|
178
|
+
*/
|
|
179
|
+
mockClear(): this;
|
|
180
|
+
/**
|
|
181
|
+
* Does what `mockClear` does and resets inner implementation to the original function. This also resets all "once" implementations.
|
|
182
|
+
*
|
|
183
|
+
* Note that resetting a mock from `vi.fn()` will set implementation to an empty function that returns `undefined`.
|
|
184
|
+
* Resetting a mock from `vi.fn(impl)` will set implementation to `impl`. It is useful for completely resetting a mock to its default state.
|
|
185
|
+
*
|
|
186
|
+
* To automatically call this method before each test, enable the [`mockReset`](https://vitest.dev/config/#mockreset) setting in the configuration.
|
|
187
|
+
* @see https://vitest.dev/api/mock#mockreset
|
|
188
|
+
*/
|
|
189
|
+
mockReset(): this;
|
|
190
|
+
/**
|
|
191
|
+
* Does what `mockReset` does and restores original descriptors of spied-on objects.
|
|
192
|
+
*
|
|
193
|
+
* Note that restoring mock from `vi.fn()` will set implementation to an empty function that returns `undefined`. Restoring a `vi.fn(impl)` will restore implementation to `impl`.
|
|
194
|
+
* @see https://vitest.dev/api/mock#mockrestore
|
|
195
|
+
*/
|
|
196
|
+
mockRestore(): void;
|
|
197
|
+
/**
|
|
198
|
+
* Returns current permanent mock implementation if there is one.
|
|
199
|
+
*
|
|
200
|
+
* If mock was created with `vi.fn`, it will consider passed down method as a mock implementation.
|
|
201
|
+
*
|
|
202
|
+
* If mock was created with `vi.spyOn`, it will return `undefined` unless a custom implementation was provided.
|
|
203
|
+
*/
|
|
204
|
+
getMockImplementation(): NormalizedProcedure<T> | undefined;
|
|
205
|
+
/**
|
|
206
|
+
* Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function.
|
|
207
|
+
* @see https://vitest.dev/api/mock#mockimplementation
|
|
208
|
+
* @example
|
|
209
|
+
* const increment = vi.fn().mockImplementation(count => count + 1);
|
|
210
|
+
* expect(increment(3)).toBe(4);
|
|
211
|
+
*/
|
|
212
|
+
mockImplementation(fn: NormalizedProcedure<T>): this;
|
|
213
|
+
/**
|
|
214
|
+
* Accepts a function to be used as the mock implementation. TypeScript expects the arguments and return type to match those of the original function. This method can be chained to produce different results for multiple function calls.
|
|
215
|
+
*
|
|
216
|
+
* When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
|
|
217
|
+
* @see https://vitest.dev/api/mock#mockimplementationonce
|
|
218
|
+
* @example
|
|
219
|
+
* const fn = vi.fn(count => count).mockImplementationOnce(count => count + 1);
|
|
220
|
+
* expect(fn(3)).toBe(4);
|
|
221
|
+
* expect(fn(3)).toBe(3);
|
|
222
|
+
*/
|
|
223
|
+
mockImplementationOnce(fn: NormalizedProcedure<T>): this;
|
|
224
|
+
/**
|
|
225
|
+
* Overrides the original mock implementation temporarily while the callback is being executed.
|
|
226
|
+
*
|
|
227
|
+
* Note that this method takes precedence over the [`mockImplementationOnce`](https://vitest.dev/api/mock#mockimplementationonce).
|
|
228
|
+
* @see https://vitest.dev/api/mock#withimplementation
|
|
229
|
+
* @example
|
|
230
|
+
* const myMockFn = vi.fn(() => 'original')
|
|
231
|
+
*
|
|
232
|
+
* myMockFn.withImplementation(() => 'temp', () => {
|
|
233
|
+
* myMockFn() // 'temp'
|
|
234
|
+
* })
|
|
235
|
+
*
|
|
236
|
+
* myMockFn() // 'original'
|
|
237
|
+
*/
|
|
238
|
+
withImplementation<T2>(fn: NormalizedProcedure<T>, cb: () => T2): T2 extends Promise<unknown> ? Promise<this> : this;
|
|
239
|
+
/**
|
|
240
|
+
* Use this if you need to return the `this` context from the method without invoking the actual implementation.
|
|
241
|
+
* @see https://vitest.dev/api/mock#mockreturnthis
|
|
242
|
+
*/
|
|
243
|
+
mockReturnThis(): this;
|
|
244
|
+
/**
|
|
245
|
+
* Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
|
|
246
|
+
* @see https://vitest.dev/api/mock#mockreturnvalue
|
|
247
|
+
* @example
|
|
248
|
+
* const mock = vi.fn()
|
|
249
|
+
* mock.mockReturnValue(42)
|
|
250
|
+
* mock() // 42
|
|
251
|
+
* mock.mockReturnValue(43)
|
|
252
|
+
* mock() // 43
|
|
253
|
+
*/
|
|
254
|
+
mockReturnValue(value: ReturnType<T>): this;
|
|
255
|
+
/**
|
|
256
|
+
* Accepts a value that will be returned whenever the mock function is called. TypeScript will only accept values that match the return type of the original function.
|
|
257
|
+
*
|
|
258
|
+
* When the mocked function runs out of implementations, it will invoke the default implementation set with `vi.fn(() => defaultValue)` or `.mockImplementation(() => defaultValue)` if they were called.
|
|
259
|
+
* @example
|
|
260
|
+
* const myMockFn = vi
|
|
261
|
+
* .fn()
|
|
262
|
+
* .mockReturnValue('default')
|
|
263
|
+
* .mockReturnValueOnce('first call')
|
|
264
|
+
* .mockReturnValueOnce('second call')
|
|
265
|
+
*
|
|
266
|
+
* // 'first call', 'second call', 'default'
|
|
267
|
+
* console.log(myMockFn(), myMockFn(), myMockFn())
|
|
268
|
+
*/
|
|
269
|
+
mockReturnValueOnce(value: ReturnType<T>): this;
|
|
270
|
+
/**
|
|
271
|
+
* Accepts a value that will be resolved when the async function is called. TypeScript will only accept values that match the return type of the original function.
|
|
272
|
+
* @example
|
|
273
|
+
* const asyncMock = vi.fn().mockResolvedValue(42)
|
|
274
|
+
* asyncMock() // Promise<42>
|
|
275
|
+
*/
|
|
276
|
+
mockResolvedValue(value: Awaited<ReturnType<T>>): this;
|
|
277
|
+
/**
|
|
278
|
+
* Accepts a value that will be resolved during the next function call. TypeScript will only accept values that match the return type of the original function. If chained, each consecutive call will resolve the specified value.
|
|
279
|
+
* @example
|
|
280
|
+
* const myMockFn = vi
|
|
281
|
+
* .fn()
|
|
282
|
+
* .mockResolvedValue('default')
|
|
283
|
+
* .mockResolvedValueOnce('first call')
|
|
284
|
+
* .mockResolvedValueOnce('second call')
|
|
285
|
+
*
|
|
286
|
+
* // Promise<'first call'>, Promise<'second call'>, Promise<'default'>
|
|
287
|
+
* console.log(myMockFn(), myMockFn(), myMockFn())
|
|
288
|
+
*/
|
|
289
|
+
mockResolvedValueOnce(value: Awaited<ReturnType<T>>): this;
|
|
290
|
+
/**
|
|
291
|
+
* Accepts an error that will be rejected when async function is called.
|
|
292
|
+
* @example
|
|
293
|
+
* const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'))
|
|
294
|
+
* await asyncMock() // throws Error<'Async error'>
|
|
295
|
+
*/
|
|
296
|
+
mockRejectedValue(error: unknown): this;
|
|
297
|
+
/**
|
|
298
|
+
* Accepts a value that will be rejected during the next function call. If chained, each consecutive call will reject the specified value.
|
|
299
|
+
* @example
|
|
300
|
+
* const asyncMock = vi
|
|
301
|
+
* .fn()
|
|
302
|
+
* .mockResolvedValueOnce('first call')
|
|
303
|
+
* .mockRejectedValueOnce(new Error('Async error'))
|
|
304
|
+
*
|
|
305
|
+
* await asyncMock() // first call
|
|
306
|
+
* await asyncMock() // throws Error<'Async error'>
|
|
307
|
+
*/
|
|
308
|
+
mockRejectedValueOnce(error: unknown): this;
|
|
309
|
+
}
|
|
310
|
+
/* eslint-enable ts/method-signature-style */
|
|
311
|
+
interface Mock<T extends Procedure = Procedure> extends MockInstance<T> {
|
|
312
|
+
new (...args: Parameters<T>): ReturnType<T>;
|
|
313
|
+
(...args: Parameters<T>): ReturnType<T>;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
declare const useNavigate: Mock<typeof useNavigate$1>;
|
|
317
|
+
declare const useRouter: Mock<typeof useRouter$1>;
|
|
318
|
+
declare const useBlocker: Mock<typeof useBlocker$1>;
|
|
319
|
+
declare const useSearch: Mock<typeof useSearch$1>;
|
|
320
|
+
declare const useParams: Mock<typeof useParams$1>;
|
|
321
|
+
declare const useLocation: Mock<typeof useLocation$1>;
|
|
322
|
+
declare const useRouterState: Mock<typeof useRouterState$1>;
|
|
323
|
+
declare const useLoaderData: Mock<typeof useLoaderData$1>;
|
|
324
|
+
declare const useLoaderDeps: Mock<typeof useLoaderDeps$1>;
|
|
325
|
+
declare const useRouteContext: Mock<typeof useRouteContext$1>;
|
|
326
|
+
declare const useCanGoBack: Mock<typeof useCanGoBack$1>;
|
|
327
|
+
declare const useLinkProps: Mock<typeof useLinkProps$1>;
|
|
328
|
+
declare const Outlet: () => null;
|
|
329
|
+
declare const Navigate: typeof Navigate$1;
|
|
330
|
+
declare const Link: ({ to, children, ...props }: {
|
|
331
|
+
to: string;
|
|
332
|
+
children?: React.ReactNode;
|
|
333
|
+
[key: string]: unknown;
|
|
334
|
+
}) => React.DetailedReactHTMLElement<{
|
|
335
|
+
href: string;
|
|
336
|
+
onClick: (e: React.MouseEvent) => void;
|
|
337
|
+
}, HTMLElement>;
|
|
338
|
+
/**
|
|
339
|
+
* Override createFileRoute from tanstack react router
|
|
340
|
+
* because the org `createFileRoute` doesn't set the path in the Route
|
|
341
|
+
*/
|
|
342
|
+
declare function createFileRoute(path: string): (options: any) => _tanstack_react_router.Route<unknown, _tanstack_router_core.AnyRoute, "/", "/" | `/${any}/`, string, "/" | `/${any}/`, undefined, _tanstack_router_core.ResolveParams<"/">, _tanstack_router_core.AnyContext, _tanstack_router_core.AnyContext, _tanstack_router_core.AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>;
|
|
343
|
+
|
|
344
|
+
export { Link, Navigate, Outlet, createFileRoute, useBlocker, useCanGoBack, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useNavigate, useParams, useRouteContext, useRouter, useRouterState, useSearch };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
onNavigate
|
|
3
|
+
} from "../_browser-chunks/chunk-4CKCBIXI.js";
|
|
4
|
+
import "../_browser-chunks/chunk-4BE7D4DS.js";
|
|
5
|
+
|
|
6
|
+
// src/export-mocks/react-router.ts
|
|
7
|
+
import { createRoute } from "@tanstack/react-router";
|
|
8
|
+
export * from "@tanstack/react-router";
|
|
9
|
+
import { fn } from "storybook/test";
|
|
10
|
+
import React from "react";
|
|
11
|
+
import { useEffect } from "storybook/internal/preview-api";
|
|
12
|
+
import {
|
|
13
|
+
useNavigate as _useNavigate,
|
|
14
|
+
useRouter as _useRouter,
|
|
15
|
+
useBlocker as _useBlocker,
|
|
16
|
+
useSearch as _useSearch,
|
|
17
|
+
useParams as _useParams,
|
|
18
|
+
useLocation as _useLocation,
|
|
19
|
+
useRouterState as _useRouterState,
|
|
20
|
+
useLoaderData as _useLoaderData,
|
|
21
|
+
useLoaderDeps as _useLoaderDeps,
|
|
22
|
+
useRouteContext as _useRouteContext,
|
|
23
|
+
useCanGoBack as _useCanGoBack,
|
|
24
|
+
useLinkProps as _useLinkProps
|
|
25
|
+
} from "@tanstack/react-router";
|
|
26
|
+
var useNavigate = fn(_useNavigate).mockName("@tanstack/react-router::useNavigate"), useRouter = fn(_useRouter).mockName("@tanstack/react-router::useRouter"), useBlocker = fn(_useBlocker).mockName("@tanstack/react-router::useBlocker"), useSearch = fn(_useSearch).mockName("@tanstack/react-router::useSearch"), useParams = fn(_useParams).mockName("@tanstack/react-router::useParams"), useLocation = fn(_useLocation).mockName("@tanstack/react-router::useLocation"), useRouterState = fn(_useRouterState).mockName(
|
|
27
|
+
"@tanstack/react-router::useRouterState"
|
|
28
|
+
), useLoaderData = fn(_useLoaderData).mockName("@tanstack/react-router::useLoaderData"), useLoaderDeps = fn(_useLoaderDeps).mockName("@tanstack/react-router::useLoaderDeps"), useRouteContext = fn(_useRouteContext).mockName(
|
|
29
|
+
"@tanstack/react-router::useRouteContext"
|
|
30
|
+
), useCanGoBack = fn(_useCanGoBack).mockName("@tanstack/react-router::useCanGoBack"), useLinkProps = fn(_useLinkProps).mockName("@tanstack/react-router::useLinkProps"), Outlet = () => null, Navigate = ({ to, href }) => (useEffect(() => {
|
|
31
|
+
onNavigate({ to: to || href });
|
|
32
|
+
}, [to, href]), null), Link = ({
|
|
33
|
+
to,
|
|
34
|
+
children,
|
|
35
|
+
...props
|
|
36
|
+
}) => {
|
|
37
|
+
let location = useLocation();
|
|
38
|
+
return React.createElement(
|
|
39
|
+
"a",
|
|
40
|
+
{
|
|
41
|
+
href: to,
|
|
42
|
+
onClick: (e) => {
|
|
43
|
+
e.preventDefault(), onNavigate({ to, from: location.href });
|
|
44
|
+
},
|
|
45
|
+
...props
|
|
46
|
+
},
|
|
47
|
+
children
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
function createFileRoute(path) {
|
|
51
|
+
return (options) => createRoute({
|
|
52
|
+
path,
|
|
53
|
+
...options,
|
|
54
|
+
isRoot: !1
|
|
55
|
+
}).update({
|
|
56
|
+
id: path,
|
|
57
|
+
path,
|
|
58
|
+
fullPath: path
|
|
59
|
+
// any because tanstack router does that
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
Link,
|
|
64
|
+
Navigate,
|
|
65
|
+
Outlet,
|
|
66
|
+
createFileRoute,
|
|
67
|
+
useBlocker,
|
|
68
|
+
useCanGoBack,
|
|
69
|
+
useLinkProps,
|
|
70
|
+
useLoaderData,
|
|
71
|
+
useLoaderDeps,
|
|
72
|
+
useLocation,
|
|
73
|
+
useNavigate,
|
|
74
|
+
useParams,
|
|
75
|
+
useRouteContext,
|
|
76
|
+
useRouter,
|
|
77
|
+
useRouterState,
|
|
78
|
+
useSearch
|
|
79
|
+
};
|