@khanacademy/wonder-blocks-testing-core 3.0.1 → 4.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @khanacademy/wonder-blocks-testing-core
2
2
 
3
+ ## 4.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 4c03506: Upgrade wonder-blocks infrastructure to use Storybook v9
8
+
9
+ ## 4.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 82b5970: Removed Fixtures framework - please use the native Storybook CSFv3 format for stories
14
+
3
15
  ## 3.0.1
4
16
 
5
17
  ### Patch Changes
package/dist/es/index.js CHANGED
@@ -1,389 +1,34 @@
1
1
  import * as React from 'react';
2
- import { action } from '@storybook/addon-actions';
2
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { StaticRouter, MemoryRouter, Switch, Route } from 'react-router-dom';
4
4
  import { CompatRouter, useLocation } from 'react-router-dom-v5-compat';
5
- import _extends from '@babel/runtime/helpers/extends';
6
5
  import * as ReactDOMServer from 'react-dom/server';
7
6
 
8
- const fixtures = Component => {
9
- const templateMap = new WeakMap();
10
- let storyNumber = 1;
11
- const getPropsOptions = {
12
- log: (message, ...args) => action(message)(...args),
13
- logHandler: action
14
- };
15
- const makeStory = (description, props, wrapper = null) => {
16
- const storyName = `${storyNumber++} ${description}`;
17
- const getProps = options => typeof props === "function" ? props(options) : props;
18
- const RealComponent = wrapper || Component;
19
- let Template = templateMap.get(RealComponent);
20
- if (Template == null) {
21
- Template = args => React.createElement(RealComponent, args);
22
- templateMap.set(RealComponent, Template);
23
- }
24
- const story = Template.bind({});
25
- story.args = getProps(getPropsOptions);
26
- story.storyName = storyName;
27
- return story;
28
- };
29
- return makeStory;
30
- };
7
+ const getHref=input=>{if(typeof input==="string"){return input}else if(typeof input.url==="string"){return input.url}else if(typeof input.href==="string"){return input.href}else {throw new Error(`Unsupported input type`)}};const fetchRequestMatchesMock=(mock,input,init)=>{const href=getHref(input);if(typeof mock==="string"){return href===mock}else if(mock instanceof RegExp){return mock.test(href)}else {throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`)}};
31
8
 
32
- const getHref = input => {
33
- if (typeof input === "string") {
34
- return input;
35
- } else if (typeof input.url === "string") {
36
- return input.url;
37
- } else if (typeof input.href === "string") {
38
- return input.href;
39
- } else {
40
- throw new Error(`Unsupported input type`);
41
- }
42
- };
43
- const fetchRequestMatchesMock = (mock, input, init) => {
44
- const href = getHref(input);
45
- if (typeof mock === "string") {
46
- return href === mock;
47
- } else if (mock instanceof RegExp) {
48
- return mock.test(href);
49
- } else {
50
- throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`);
51
- }
52
- };
9
+ const mockRequester=(operationMatcher,operationToString)=>{const mocks=[];const configuration={hardFailOnUnmockedRequests:false};const getMatchingMock=(...args)=>{for(const mock of mocks){if(mock.onceOnly&&mock.used){continue}if(operationMatcher(mock.operation,...args)){mock.used=true;return mock}}return null};const mockFn=(...args)=>{const matchingMock=getMatchingMock(...args);if(matchingMock){return matchingMock.response()}const operation=operationToString(...args);const noMatchError=new Error(`No matching mock response found for request:
10
+ ${operation}`);if(configuration.hardFailOnUnmockedRequests){throw noMatchError}return Promise.reject(noMatchError)};const addMockedOperation=(operation,response,onceOnly)=>{const mockResponse=()=>response.toPromise();mocks.push({operation,response:mockResponse,onceOnly,used:false});return mockFn};mockFn.mockOperation=(operation,response)=>addMockedOperation(operation,response,false);mockFn.mockOperationOnce=(operation,response)=>addMockedOperation(operation,response,true);mockFn.configure=config=>{Object.assign(configuration,config);return mockFn};return mockFn};
53
11
 
54
- const mockRequester = (operationMatcher, operationToString) => {
55
- const mocks = [];
56
- const configuration = {
57
- hardFailOnUnmockedRequests: false
58
- };
59
- const getMatchingMock = (...args) => {
60
- for (const mock of mocks) {
61
- if (mock.onceOnly && mock.used) {
62
- continue;
63
- }
64
- if (operationMatcher(mock.operation, ...args)) {
65
- mock.used = true;
66
- return mock;
67
- }
68
- }
69
- return null;
70
- };
71
- const mockFn = (...args) => {
72
- const matchingMock = getMatchingMock(...args);
73
- if (matchingMock) {
74
- return matchingMock.response();
75
- }
76
- const operation = operationToString(...args);
77
- const noMatchError = new Error(`No matching mock response found for request:
78
- ${operation}`);
79
- if (configuration.hardFailOnUnmockedRequests) {
80
- throw noMatchError;
81
- }
82
- return Promise.reject(noMatchError);
83
- };
84
- const addMockedOperation = (operation, response, onceOnly) => {
85
- const mockResponse = () => response.toPromise();
86
- mocks.push({
87
- operation,
88
- response: mockResponse,
89
- onceOnly,
90
- used: false
91
- });
92
- return mockFn;
93
- };
94
- mockFn.mockOperation = (operation, response) => addMockedOperation(operation, response, false);
95
- mockFn.mockOperationOnce = (operation, response) => addMockedOperation(operation, response, true);
96
- mockFn.configure = config => {
97
- Object.assign(configuration, config);
98
- return mockFn;
99
- };
100
- return mockFn;
101
- };
12
+ const mockFetch=()=>mockRequester(fetchRequestMatchesMock,(input,init)=>`Input: ${typeof input==="string"?input:JSON.stringify(input,null,2)}
13
+ Options: ${init==null?"None":JSON.stringify(init,null,2)}`);
102
14
 
103
- const mockFetch = () => mockRequester(fetchRequestMatchesMock, (input, init) => `Input: ${typeof input === "string" ? input : JSON.stringify(input, null, 2)}
104
- Options: ${init == null ? "None" : JSON.stringify(init, null, 2)}`);
15
+ const ResponseImpl=typeof Response==="undefined"?require("node-fetch").Response:Response;
105
16
 
106
- const ResponseImpl = typeof Response === "undefined" ? require("node-fetch").Response : Response;
17
+ const textResponse=(text,statusCode,signal)=>({toPromise:()=>makeMockResponse({type:"text",text,statusCode,signal})});const rejectResponse=(error,signal)=>({toPromise:()=>makeMockResponse({type:"reject",error,signal})});const RespondWith=Object.freeze({text:(text,statusCode=200,signal=null)=>textResponse(text,statusCode,signal),json:(json,signal=null)=>textResponse(()=>JSON.stringify(json),200,signal),graphQLData:(data,signal=null)=>textResponse(()=>JSON.stringify({data}),200,signal),unparseableBody:(signal=null)=>textResponse("INVALID JSON",200,signal),abortedRequest:(signal=null)=>rejectResponse(()=>{const abortError=new Error("Mock request aborted");abortError.name="AbortError";return abortError},signal),reject:(error,signal=null)=>rejectResponse(error,signal),errorStatusCode:(statusCode,signal=null)=>{if(statusCode<300){throw new Error(`${statusCode} is not a valid error status code`)}return textResponse("{}",statusCode,signal)},nonGraphQLBody:(signal=null)=>textResponse(()=>JSON.stringify({valid:"json",that:"is not a valid graphql response"}),200,signal),graphQLErrors:(errorMessages,signal=null)=>textResponse(()=>JSON.stringify({errors:errorMessages.map(e=>({message:e}))}),200,signal)});const callOnSettled=(signal,fn)=>{if(signal==null||signal.settled){fn();return}const onSettled=()=>{signal.removeEventListener("settled",onSettled);fn();};signal.addEventListener("settled",onSettled);};const makeMockResponse=response=>{const{signal}=response;switch(response.type){case"text":return new Promise((resolve,reject)=>{callOnSettled(signal,()=>{const text=typeof response.text==="function"?response.text():response.text;resolve(new ResponseImpl(text,{status:response.statusCode}));});});case"reject":return new Promise((resolve,reject)=>{callOnSettled(signal,()=>reject(response.error instanceof Error?response.error:response.error()));});default:if(process.env.NODE_ENV!=="production"){throw new Error(`Unknown response type: ${response.type}`)}return makeMockResponse({type:"reject",error:new Error("Unknown response type"),signal})}};
107
18
 
108
- const textResponse = (text, statusCode, signal) => ({
109
- toPromise: () => makeMockResponse({
110
- type: "text",
111
- text,
112
- statusCode,
113
- signal
114
- })
115
- });
116
- const rejectResponse = (error, signal) => ({
117
- toPromise: () => makeMockResponse({
118
- type: "reject",
119
- error,
120
- signal
121
- })
122
- });
123
- const RespondWith = Object.freeze({
124
- text: (text, statusCode = 200, signal = null) => textResponse(text, statusCode, signal),
125
- json: (json, signal = null) => textResponse(() => JSON.stringify(json), 200, signal),
126
- graphQLData: (data, signal = null) => textResponse(() => JSON.stringify({
127
- data
128
- }), 200, signal),
129
- unparseableBody: (signal = null) => textResponse("INVALID JSON", 200, signal),
130
- abortedRequest: (signal = null) => rejectResponse(() => {
131
- const abortError = new Error("Mock request aborted");
132
- abortError.name = "AbortError";
133
- return abortError;
134
- }, signal),
135
- reject: (error, signal = null) => rejectResponse(error, signal),
136
- errorStatusCode: (statusCode, signal = null) => {
137
- if (statusCode < 300) {
138
- throw new Error(`${statusCode} is not a valid error status code`);
139
- }
140
- return textResponse("{}", statusCode, signal);
141
- },
142
- nonGraphQLBody: (signal = null) => textResponse(() => JSON.stringify({
143
- valid: "json",
144
- that: "is not a valid graphql response"
145
- }), 200, signal),
146
- graphQLErrors: (errorMessages, signal = null) => textResponse(() => JSON.stringify({
147
- errors: errorMessages.map(e => ({
148
- message: e
149
- }))
150
- }), 200, signal)
151
- });
152
- const callOnSettled = (signal, fn) => {
153
- if (signal == null || signal.settled) {
154
- fn();
155
- return;
156
- }
157
- const onSettled = () => {
158
- signal.removeEventListener("settled", onSettled);
159
- fn();
160
- };
161
- signal.addEventListener("settled", onSettled);
162
- };
163
- const makeMockResponse = response => {
164
- const {
165
- signal
166
- } = response;
167
- switch (response.type) {
168
- case "text":
169
- return new Promise((resolve, reject) => {
170
- callOnSettled(signal, () => {
171
- const text = typeof response.text === "function" ? response.text() : response.text;
172
- resolve(new ResponseImpl(text, {
173
- status: response.statusCode
174
- }));
175
- });
176
- });
177
- case "reject":
178
- return new Promise((resolve, reject) => {
179
- callOnSettled(signal, () => reject(response.error instanceof Error ? response.error : response.error()));
180
- });
181
- default:
182
- if (process.env.NODE_ENV !== "production") {
183
- throw new Error(`Unknown response type: ${response.type}`);
184
- }
185
- return makeMockResponse({
186
- type: "reject",
187
- error: new Error("Unknown response type"),
188
- signal
189
- });
190
- }
191
- };
192
-
193
- class SettleSignal extends EventTarget {
194
- constructor(setSettleFn = null) {
195
- super();
196
- this._settled = false;
197
- setSettleFn == null || setSettleFn(() => {
198
- if (this._settled) {
199
- throw new Error("SettleSignal already settled");
200
- }
201
- this._settled = true;
202
- this.dispatchEvent(new Event("settled"));
203
- });
204
- }
205
- static settle() {
206
- const signal = new SettleSignal();
207
- signal._settled = true;
208
- return signal;
209
- }
210
- get settled() {
211
- return this._settled;
212
- }
213
- }
19
+ class SettleSignal extends EventTarget{static settle(){const signal=new SettleSignal;signal._settled=true;return signal}get settled(){return this._settled}constructor(setSettleFn=null){super(),this._settled=false;setSettleFn?.(()=>{if(this._settled){throw new Error("SettleSignal already settled")}this._settled=true;this.dispatchEvent(new Event("settled"));});}}
214
20
 
215
- class SettleController {
216
- constructor() {
217
- this._settleFn = void 0;
218
- this._signal = void 0;
219
- this._signal = new SettleSignal(settleFn => this._settleFn = settleFn);
220
- }
221
- get signal() {
222
- return this._signal;
223
- }
224
- settle() {
225
- var _this$_settleFn;
226
- (_this$_settleFn = this._settleFn) == null || _this$_settleFn.call(this);
227
- }
228
- }
21
+ class SettleController{get signal(){return this._signal}settle(){this._settleFn?.();}constructor(){this._signal=new SettleSignal(settleFn=>this._settleFn=settleFn);}}
229
22
 
230
- const defaultConfig$3 = null;
231
- const normalizeConfig = config => {
232
- if (typeof config === "string") {
233
- return {
234
- classes: [config],
235
- style: {}
236
- };
237
- }
238
- if (Array.isArray(config)) {
239
- return {
240
- classes: config,
241
- style: {}
242
- };
243
- }
244
- if (typeof config === "object") {
245
- if ("classes" in config && config.classes != null && "style" in config && config.style != null) {
246
- return config;
247
- }
248
- return {
249
- classes: [],
250
- style: config
251
- };
252
- }
253
- throw new Error(`Invalid config: ${config}`);
254
- };
255
- const adapter$3 = (children, config) => {
256
- const {
257
- classes,
258
- style
259
- } = normalizeConfig(config);
260
- return React.createElement("div", {
261
- "data-testid": "css-adapter-container",
262
- className: classes.join(" "),
263
- style: style
264
- }, children);
265
- };
23
+ const defaultConfig$3=null;const normalizeConfig=config=>{if(typeof config==="string"){return {classes:[config],style:{}}}if(Array.isArray(config)){return {classes:config,style:{}}}if(typeof config==="object"){if("classes"in config&&config.classes!=null&&"style"in config&&config.style!=null){return config}return {classes:[],style:config}}throw new Error(`Invalid config: ${config}`)};const adapter$3=(children,config)=>{const{classes,style}=normalizeConfig(config);return jsx("div",{"data-testid":"css-adapter-container",className:classes.join(" "),style:style,children:children})};
266
24
 
267
- const defaultConfig$2 = null;
268
- class ErrorBoundary extends React.Component {
269
- constructor(...args) {
270
- super(...args);
271
- this.state = {
272
- renderError: false
273
- };
274
- }
275
- static getDerivedStateFromError(error) {
276
- return {
277
- renderError: true
278
- };
279
- }
280
- componentDidCatch(error, errorInfo) {
281
- const lastErrorUx = this.props.onError(error, errorInfo);
282
- this.setState({
283
- lastErrorUx
284
- });
285
- }
286
- render() {
287
- var _this$state$lastError;
288
- return this.state.renderError ? (_this$state$lastError = this.state.lastErrorUx) != null ? _this$state$lastError : "An error occurred" : this.props.children;
289
- }
290
- }
291
- const adapter$2 = (children, config) => React.createElement(ErrorBoundary, {
292
- onError: config
293
- }, children);
25
+ const defaultConfig$2=null;class ErrorBoundary extends React.Component{static getDerivedStateFromError(error){return {renderError:true}}componentDidCatch(error,errorInfo){const lastErrorUx=this.props.onError(error,errorInfo);this.setState({lastErrorUx});}render(){return this.state.renderError?this.state.lastErrorUx??"An error occurred":this.props.children}constructor(...args){super(...args),this.state={renderError:false};}}const adapter$2=(children,config)=>jsx(ErrorBoundary,{onError:config,children:children});
294
26
 
295
- const defaultConfig$1 = null;
296
- const adapter$1 = (children, config) => React.createElement(React.Fragment, null, React.createElement("div", {
297
- id: config,
298
- "data-testid": config
299
- }), children);
27
+ const defaultConfig$1=null;const adapter$1=(children,config)=>jsxs(Fragment,{children:[jsx("div",{id:config,"data-testid":config}),children]});
300
28
 
301
- const defaultConfig = {
302
- location: "/"
303
- };
304
- const MaybeWithRoute = ({
305
- children,
306
- path,
307
- configLocation
308
- }) => {
309
- if (path == null) {
310
- return React.createElement(React.Fragment, null, children);
311
- }
312
- const ErrorElement = () => {
313
- const actualLocation = useLocation();
314
- const configuredLocation = typeof configLocation === "string" ? configLocation : configLocation.pathname;
315
- const errorMessage = `The current location '${actualLocation.pathname}' ` + `does not match the configured path '${path}'. ` + `Did you provide the correct configured ` + `location, '${configuredLocation}', or did the ` + `routing lead to a different place than you ` + `expected?`;
316
- throw new Error(errorMessage);
317
- };
318
- return React.createElement(Switch, null, React.createElement(Route, {
319
- path: path,
320
- render: () => React.createElement(React.Fragment, null, children)
321
- }), React.createElement(Route, {
322
- path: "*",
323
- component: ErrorElement
324
- }));
325
- };
326
- const adapter = (children, config) => {
327
- var _config$initialIndex;
328
- if (typeof config === "string") {
329
- config = {
330
- location: config
331
- };
332
- }
333
- if ("forceStatic" in config && config.forceStatic) {
334
- if (config.disableCompatRouter) {
335
- return React.createElement(StaticRouter, {
336
- location: config.location,
337
- context: {}
338
- }, React.createElement(MaybeWithRoute, {
339
- path: config.path,
340
- configLocation: config.location
341
- }, children));
342
- }
343
- return React.createElement(StaticRouter, {
344
- location: config.location,
345
- context: {}
346
- }, React.createElement(CompatRouter, null, React.createElement(MaybeWithRoute, {
347
- path: config.path,
348
- configLocation: config.location
349
- }, children)));
350
- }
351
- if ("location" in config && config.location !== undefined) {
352
- return React.createElement(MemoryRouter, {
353
- initialEntries: [config.location]
354
- }, React.createElement(CompatRouter, null, React.createElement(MaybeWithRoute, {
355
- path: config.path,
356
- configLocation: config.location
357
- }, children)));
358
- }
359
- if (!("initialEntries" in config) || config.initialEntries === undefined) {
360
- throw new Error("A location or initial history entries must be provided.");
361
- }
362
- const entries = config.initialEntries.length === 0 ? [defaultConfig.location] : config.initialEntries;
363
- const routerProps = {
364
- initialEntries: entries
365
- };
366
- if (config.initialIndex != null) {
367
- routerProps.initialIndex = config.initialIndex;
368
- }
369
- return React.createElement(MemoryRouter, routerProps, React.createElement(CompatRouter, null, React.createElement(MaybeWithRoute, {
370
- path: config.path,
371
- configLocation: entries[(_config$initialIndex = config.initialIndex) != null ? _config$initialIndex : 0]
372
- }, children)));
373
- };
29
+ const defaultConfig={location:"/"};const MaybeWithRoute=({children,path,configLocation})=>{if(path==null){return jsx(Fragment,{children:children})}const ErrorElement=()=>{const actualLocation=useLocation();const configuredLocation=typeof configLocation==="string"?configLocation:configLocation.pathname;const errorMessage=`The current location '${actualLocation.pathname}' `+`does not match the configured path '${path}'. `+`Did you provide the correct configured `+`location, '${configuredLocation}', or did the `+`routing lead to a different place than you `+`expected?`;throw new Error(errorMessage)};return jsxs(Switch,{children:[jsx(Route,{path:path,render:()=>jsx(Fragment,{children:children})}),jsx(Route,{path:"*",component:ErrorElement})]})};const adapter=(children,config)=>{if(typeof config==="string"){config={location:config};}if("forceStatic"in config&&config.forceStatic){if(config.disableCompatRouter){return jsx(StaticRouter,{location:config.location,context:{},children:jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})}return jsx(StaticRouter,{location:config.location,context:{},children:jsx(CompatRouter,{children:jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})})}if("location"in config&&config.location!==undefined){return jsx(MemoryRouter,{initialEntries:[config.location],children:jsx(CompatRouter,{children:jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})})}if(!("initialEntries"in config)||config.initialEntries===undefined){throw new Error("A location or initial history entries must be provided.")}const entries=config.initialEntries.length===0?[defaultConfig.location]:config.initialEntries;const routerProps={initialEntries:entries};if(config.initialIndex!=null){routerProps.initialIndex=config.initialIndex;}return jsx(MemoryRouter,{...routerProps,children:jsx(CompatRouter,{children:jsx(MaybeWithRoute,{path:config.path,configLocation:entries[config.initialIndex??0],children:children})})})};
374
30
 
375
- const DefaultAdapters = {
376
- boundary: adapter$2,
377
- css: adapter$3,
378
- portal: adapter$1,
379
- router: adapter
380
- };
381
- const DefaultConfigs = {
382
- boundary: defaultConfig$2,
383
- css: defaultConfig$3,
384
- portal: defaultConfig$1,
385
- router: defaultConfig
386
- };
31
+ const DefaultAdapters={boundary:adapter$2,css:adapter$3,portal:adapter$1,router:adapter};const DefaultConfigs={boundary:defaultConfig$2,css:defaultConfig$3,portal:defaultConfig$1,router:defaultConfig};
387
32
 
388
33
  var adapters = /*#__PURE__*/Object.freeze({
389
34
  __proto__: null,
@@ -391,88 +36,18 @@ var adapters = /*#__PURE__*/Object.freeze({
391
36
  DefaultConfigs: DefaultConfigs
392
37
  });
393
38
 
394
- const componentCache = new Map();
395
- const getNamedAdapterComponent = name => {
396
- const existing = componentCache.get(name);
397
- if (existing != null) {
398
- return existing;
399
- }
400
- const newComponent = ({
401
- children,
402
- config,
403
- adapter
404
- }) => adapter(children, config);
405
- newComponent.displayName = `Adapter(${name})`;
406
- componentCache.set(name, newComponent);
407
- return newComponent;
408
- };
39
+ const componentCache=new Map;const getNamedAdapterComponent=name=>{const existing=componentCache.get(name);if(existing!=null){return existing}const newComponent=({children,config,adapter})=>adapter(children,config);newComponent.displayName=`Adapter(${name})`;componentCache.set(name,newComponent);return newComponent};
409
40
 
410
- const Adapt = ({
411
- children,
412
- adapters,
413
- configs
414
- }) => {
415
- return Object.entries(adapters).reduce((newChildren, [name, adapter]) => {
416
- const theConfig = configs[name];
417
- if (theConfig == null) {
418
- return newChildren;
419
- }
420
- const Adapter = getNamedAdapterComponent(name);
421
- return React.createElement(Adapter, {
422
- key: name,
423
- adapter: adapter,
424
- config: theConfig
425
- }, newChildren);
426
- }, React.createElement(React.Fragment, null, children));
427
- };
41
+ const Adapt=({children,adapters,configs})=>{return Object.entries(adapters).reduce((newChildren,[name,adapter])=>{const theConfig=configs[name];if(theConfig==null){return newChildren}const Adapter=getNamedAdapterComponent(name);return jsx(Adapter,{adapter:adapter,config:theConfig,children:newChildren},name)},jsx(Fragment,{children:children}))};
428
42
 
429
- const makeTestHarness = (adapters, defaultConfigs) => {
430
- return (Component, configs) => {
431
- const fullConfig = _extends({}, defaultConfigs, configs);
432
- const harnessedComponent = React.forwardRef((props, ref) => React.createElement(Adapt, {
433
- adapters: adapters,
434
- configs: fullConfig
435
- }, React.createElement(Component, _extends({}, props, {
436
- ref: ref
437
- }))));
438
- harnessedComponent.displayName = `testHarness(${Component.displayName || Component.name || "Component"})`;
439
- return harnessedComponent;
440
- };
441
- };
43
+ const makeTestHarness=(adapters,defaultConfigs)=>{return (Component,configs)=>{const fullConfig={...defaultConfigs,...configs};const harnessedComponent=React.forwardRef((props,ref)=>jsx(Adapt,{adapters:adapters,configs:fullConfig,children:jsx(Component,{...props,ref:ref})}));harnessedComponent.displayName=`testHarness(${Component.displayName||Component.name||"Component"})`;return harnessedComponent}};
442
44
 
443
- const HookHarness = ({
444
- children
445
- }) => React.createElement(React.Fragment, null, children);
446
- const makeHookHarness = (adapters, defaultConfigs) => {
447
- const testHarness = makeTestHarness(adapters, defaultConfigs);
448
- return configs => testHarness(HookHarness, configs);
449
- };
45
+ const HookHarness=({children})=>jsx(Fragment,{children:children});const makeHookHarness=(adapters,defaultConfigs)=>{const testHarness=makeTestHarness(adapters,defaultConfigs);return configs=>testHarness(HookHarness,configs)};
450
46
 
451
- const hookHarness = makeHookHarness(DefaultAdapters, DefaultConfigs);
47
+ const hookHarness=makeHookHarness(DefaultAdapters,DefaultConfigs);
452
48
 
453
- const testHarness = makeTestHarness(DefaultAdapters, DefaultConfigs);
49
+ const testHarness=makeTestHarness(DefaultAdapters,DefaultConfigs);
454
50
 
455
- const renderHookStatic = (render, {
456
- wrapper,
457
- initialProps
458
- } = {}) => {
459
- let result;
460
- function TestComponent({
461
- renderCallbackProps
462
- }) {
463
- result = render(renderCallbackProps);
464
- return null;
465
- }
466
- const component = React.createElement(TestComponent, {
467
- renderCallbackProps: initialProps
468
- });
469
- const componentWithWrapper = wrapper == null ? component : React.createElement(wrapper, null, component);
470
- ReactDOMServer.renderToString(componentWithWrapper);
471
- return {
472
- result: {
473
- current: result
474
- }
475
- };
476
- };
51
+ const renderHookStatic=(render,{wrapper,initialProps}={})=>{let result;function TestComponent({renderCallbackProps}){result=render(renderCallbackProps);return null}const component=jsx(TestComponent,{renderCallbackProps:initialProps});const componentWithWrapper=wrapper==null?component:React.createElement(wrapper,null,component);ReactDOMServer.renderToString(componentWithWrapper);return {result:{current:result}}};
477
52
 
478
- export { RespondWith, SettleController, fixtures, adapters as harnessAdapters, hookHarness, makeHookHarness, makeTestHarness, mockFetch, mockRequester, renderHookStatic, testHarness };
53
+ export { RespondWith, SettleController, adapters as harnessAdapters, hookHarness, makeHookHarness, makeTestHarness, mockFetch, mockRequester, renderHookStatic, testHarness };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export { fixtures } from "./fixtures/fixtures";
2
- export type { FixtureFn, FixtureProps, GetPropsOptions } from "./fixtures/types";
3
1
  export { mockFetch } from "./fetch/mock-fetch";
4
2
  export { mockRequester } from "./mock-requester";
5
3
  export { RespondWith } from "./respond-with";
package/dist/index.js CHANGED
@@ -3,14 +3,11 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
- var addonActions = require('@storybook/addon-actions');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
7
  var reactRouterDom = require('react-router-dom');
8
8
  var reactRouterDomV5Compat = require('react-router-dom-v5-compat');
9
- var _extends = require('@babel/runtime/helpers/extends');
10
9
  var ReactDOMServer = require('react-dom/server');
11
10
 
12
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
-
14
11
  function _interopNamespace(e) {
15
12
  if (e && e.__esModule) return e;
16
13
  var n = Object.create(null);
@@ -30,388 +27,33 @@ function _interopNamespace(e) {
30
27
  }
31
28
 
32
29
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
33
- var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
34
30
  var ReactDOMServer__namespace = /*#__PURE__*/_interopNamespace(ReactDOMServer);
35
31
 
36
- const fixtures = Component => {
37
- const templateMap = new WeakMap();
38
- let storyNumber = 1;
39
- const getPropsOptions = {
40
- log: (message, ...args) => addonActions.action(message)(...args),
41
- logHandler: addonActions.action
42
- };
43
- const makeStory = (description, props, wrapper = null) => {
44
- const storyName = `${storyNumber++} ${description}`;
45
- const getProps = options => typeof props === "function" ? props(options) : props;
46
- const RealComponent = wrapper || Component;
47
- let Template = templateMap.get(RealComponent);
48
- if (Template == null) {
49
- Template = args => React__namespace.createElement(RealComponent, args);
50
- templateMap.set(RealComponent, Template);
51
- }
52
- const story = Template.bind({});
53
- story.args = getProps(getPropsOptions);
54
- story.storyName = storyName;
55
- return story;
56
- };
57
- return makeStory;
58
- };
32
+ const getHref=input=>{if(typeof input==="string"){return input}else if(typeof input.url==="string"){return input.url}else if(typeof input.href==="string"){return input.href}else {throw new Error(`Unsupported input type`)}};const fetchRequestMatchesMock=(mock,input,init)=>{const href=getHref(input);if(typeof mock==="string"){return href===mock}else if(mock instanceof RegExp){return mock.test(href)}else {throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`)}};
59
33
 
60
- const getHref = input => {
61
- if (typeof input === "string") {
62
- return input;
63
- } else if (typeof input.url === "string") {
64
- return input.url;
65
- } else if (typeof input.href === "string") {
66
- return input.href;
67
- } else {
68
- throw new Error(`Unsupported input type`);
69
- }
70
- };
71
- const fetchRequestMatchesMock = (mock, input, init) => {
72
- const href = getHref(input);
73
- if (typeof mock === "string") {
74
- return href === mock;
75
- } else if (mock instanceof RegExp) {
76
- return mock.test(href);
77
- } else {
78
- throw new Error(`Unsupported mock operation: ${JSON.stringify(mock)}`);
79
- }
80
- };
34
+ const mockRequester=(operationMatcher,operationToString)=>{const mocks=[];const configuration={hardFailOnUnmockedRequests:false};const getMatchingMock=(...args)=>{for(const mock of mocks){if(mock.onceOnly&&mock.used){continue}if(operationMatcher(mock.operation,...args)){mock.used=true;return mock}}return null};const mockFn=(...args)=>{const matchingMock=getMatchingMock(...args);if(matchingMock){return matchingMock.response()}const operation=operationToString(...args);const noMatchError=new Error(`No matching mock response found for request:
35
+ ${operation}`);if(configuration.hardFailOnUnmockedRequests){throw noMatchError}return Promise.reject(noMatchError)};const addMockedOperation=(operation,response,onceOnly)=>{const mockResponse=()=>response.toPromise();mocks.push({operation,response:mockResponse,onceOnly,used:false});return mockFn};mockFn.mockOperation=(operation,response)=>addMockedOperation(operation,response,false);mockFn.mockOperationOnce=(operation,response)=>addMockedOperation(operation,response,true);mockFn.configure=config=>{Object.assign(configuration,config);return mockFn};return mockFn};
81
36
 
82
- const mockRequester = (operationMatcher, operationToString) => {
83
- const mocks = [];
84
- const configuration = {
85
- hardFailOnUnmockedRequests: false
86
- };
87
- const getMatchingMock = (...args) => {
88
- for (const mock of mocks) {
89
- if (mock.onceOnly && mock.used) {
90
- continue;
91
- }
92
- if (operationMatcher(mock.operation, ...args)) {
93
- mock.used = true;
94
- return mock;
95
- }
96
- }
97
- return null;
98
- };
99
- const mockFn = (...args) => {
100
- const matchingMock = getMatchingMock(...args);
101
- if (matchingMock) {
102
- return matchingMock.response();
103
- }
104
- const operation = operationToString(...args);
105
- const noMatchError = new Error(`No matching mock response found for request:
106
- ${operation}`);
107
- if (configuration.hardFailOnUnmockedRequests) {
108
- throw noMatchError;
109
- }
110
- return Promise.reject(noMatchError);
111
- };
112
- const addMockedOperation = (operation, response, onceOnly) => {
113
- const mockResponse = () => response.toPromise();
114
- mocks.push({
115
- operation,
116
- response: mockResponse,
117
- onceOnly,
118
- used: false
119
- });
120
- return mockFn;
121
- };
122
- mockFn.mockOperation = (operation, response) => addMockedOperation(operation, response, false);
123
- mockFn.mockOperationOnce = (operation, response) => addMockedOperation(operation, response, true);
124
- mockFn.configure = config => {
125
- Object.assign(configuration, config);
126
- return mockFn;
127
- };
128
- return mockFn;
129
- };
37
+ const mockFetch=()=>mockRequester(fetchRequestMatchesMock,(input,init)=>`Input: ${typeof input==="string"?input:JSON.stringify(input,null,2)}
38
+ Options: ${init==null?"None":JSON.stringify(init,null,2)}`);
130
39
 
131
- const mockFetch = () => mockRequester(fetchRequestMatchesMock, (input, init) => `Input: ${typeof input === "string" ? input : JSON.stringify(input, null, 2)}
132
- Options: ${init == null ? "None" : JSON.stringify(init, null, 2)}`);
40
+ const ResponseImpl=typeof Response==="undefined"?require("node-fetch").Response:Response;
133
41
 
134
- const ResponseImpl = typeof Response === "undefined" ? require("node-fetch").Response : Response;
135
-
136
- const textResponse = (text, statusCode, signal) => ({
137
- toPromise: () => makeMockResponse({
138
- type: "text",
139
- text,
140
- statusCode,
141
- signal
142
- })
143
- });
144
- const rejectResponse = (error, signal) => ({
145
- toPromise: () => makeMockResponse({
146
- type: "reject",
147
- error,
148
- signal
149
- })
150
- });
151
- const RespondWith = Object.freeze({
152
- text: (text, statusCode = 200, signal = null) => textResponse(text, statusCode, signal),
153
- json: (json, signal = null) => textResponse(() => JSON.stringify(json), 200, signal),
154
- graphQLData: (data, signal = null) => textResponse(() => JSON.stringify({
155
- data
156
- }), 200, signal),
157
- unparseableBody: (signal = null) => textResponse("INVALID JSON", 200, signal),
158
- abortedRequest: (signal = null) => rejectResponse(() => {
159
- const abortError = new Error("Mock request aborted");
160
- abortError.name = "AbortError";
161
- return abortError;
162
- }, signal),
163
- reject: (error, signal = null) => rejectResponse(error, signal),
164
- errorStatusCode: (statusCode, signal = null) => {
165
- if (statusCode < 300) {
166
- throw new Error(`${statusCode} is not a valid error status code`);
167
- }
168
- return textResponse("{}", statusCode, signal);
169
- },
170
- nonGraphQLBody: (signal = null) => textResponse(() => JSON.stringify({
171
- valid: "json",
172
- that: "is not a valid graphql response"
173
- }), 200, signal),
174
- graphQLErrors: (errorMessages, signal = null) => textResponse(() => JSON.stringify({
175
- errors: errorMessages.map(e => ({
176
- message: e
177
- }))
178
- }), 200, signal)
179
- });
180
- const callOnSettled = (signal, fn) => {
181
- if (signal == null || signal.settled) {
182
- fn();
183
- return;
184
- }
185
- const onSettled = () => {
186
- signal.removeEventListener("settled", onSettled);
187
- fn();
188
- };
189
- signal.addEventListener("settled", onSettled);
190
- };
191
- const makeMockResponse = response => {
192
- const {
193
- signal
194
- } = response;
195
- switch (response.type) {
196
- case "text":
197
- return new Promise((resolve, reject) => {
198
- callOnSettled(signal, () => {
199
- const text = typeof response.text === "function" ? response.text() : response.text;
200
- resolve(new ResponseImpl(text, {
201
- status: response.statusCode
202
- }));
203
- });
204
- });
205
- case "reject":
206
- return new Promise((resolve, reject) => {
207
- callOnSettled(signal, () => reject(response.error instanceof Error ? response.error : response.error()));
208
- });
209
- default:
210
- if (process.env.NODE_ENV !== "production") {
211
- throw new Error(`Unknown response type: ${response.type}`);
212
- }
213
- return makeMockResponse({
214
- type: "reject",
215
- error: new Error("Unknown response type"),
216
- signal
217
- });
218
- }
219
- };
42
+ const textResponse=(text,statusCode,signal)=>({toPromise:()=>makeMockResponse({type:"text",text,statusCode,signal})});const rejectResponse=(error,signal)=>({toPromise:()=>makeMockResponse({type:"reject",error,signal})});const RespondWith=Object.freeze({text:(text,statusCode=200,signal=null)=>textResponse(text,statusCode,signal),json:(json,signal=null)=>textResponse(()=>JSON.stringify(json),200,signal),graphQLData:(data,signal=null)=>textResponse(()=>JSON.stringify({data}),200,signal),unparseableBody:(signal=null)=>textResponse("INVALID JSON",200,signal),abortedRequest:(signal=null)=>rejectResponse(()=>{const abortError=new Error("Mock request aborted");abortError.name="AbortError";return abortError},signal),reject:(error,signal=null)=>rejectResponse(error,signal),errorStatusCode:(statusCode,signal=null)=>{if(statusCode<300){throw new Error(`${statusCode} is not a valid error status code`)}return textResponse("{}",statusCode,signal)},nonGraphQLBody:(signal=null)=>textResponse(()=>JSON.stringify({valid:"json",that:"is not a valid graphql response"}),200,signal),graphQLErrors:(errorMessages,signal=null)=>textResponse(()=>JSON.stringify({errors:errorMessages.map(e=>({message:e}))}),200,signal)});const callOnSettled=(signal,fn)=>{if(signal==null||signal.settled){fn();return}const onSettled=()=>{signal.removeEventListener("settled",onSettled);fn();};signal.addEventListener("settled",onSettled);};const makeMockResponse=response=>{const{signal}=response;switch(response.type){case"text":return new Promise((resolve,reject)=>{callOnSettled(signal,()=>{const text=typeof response.text==="function"?response.text():response.text;resolve(new ResponseImpl(text,{status:response.statusCode}));});});case"reject":return new Promise((resolve,reject)=>{callOnSettled(signal,()=>reject(response.error instanceof Error?response.error:response.error()));});default:if(process.env.NODE_ENV!=="production"){throw new Error(`Unknown response type: ${response.type}`)}return makeMockResponse({type:"reject",error:new Error("Unknown response type"),signal})}};
220
43
 
221
- class SettleSignal extends EventTarget {
222
- constructor(setSettleFn = null) {
223
- super();
224
- this._settled = false;
225
- setSettleFn == null || setSettleFn(() => {
226
- if (this._settled) {
227
- throw new Error("SettleSignal already settled");
228
- }
229
- this._settled = true;
230
- this.dispatchEvent(new Event("settled"));
231
- });
232
- }
233
- static settle() {
234
- const signal = new SettleSignal();
235
- signal._settled = true;
236
- return signal;
237
- }
238
- get settled() {
239
- return this._settled;
240
- }
241
- }
44
+ class SettleSignal extends EventTarget{static settle(){const signal=new SettleSignal;signal._settled=true;return signal}get settled(){return this._settled}constructor(setSettleFn=null){super(),this._settled=false;setSettleFn?.(()=>{if(this._settled){throw new Error("SettleSignal already settled")}this._settled=true;this.dispatchEvent(new Event("settled"));});}}
242
45
 
243
- class SettleController {
244
- constructor() {
245
- this._settleFn = void 0;
246
- this._signal = void 0;
247
- this._signal = new SettleSignal(settleFn => this._settleFn = settleFn);
248
- }
249
- get signal() {
250
- return this._signal;
251
- }
252
- settle() {
253
- var _this$_settleFn;
254
- (_this$_settleFn = this._settleFn) == null || _this$_settleFn.call(this);
255
- }
256
- }
46
+ class SettleController{get signal(){return this._signal}settle(){this._settleFn?.();}constructor(){this._signal=new SettleSignal(settleFn=>this._settleFn=settleFn);}}
257
47
 
258
- const defaultConfig$3 = null;
259
- const normalizeConfig = config => {
260
- if (typeof config === "string") {
261
- return {
262
- classes: [config],
263
- style: {}
264
- };
265
- }
266
- if (Array.isArray(config)) {
267
- return {
268
- classes: config,
269
- style: {}
270
- };
271
- }
272
- if (typeof config === "object") {
273
- if ("classes" in config && config.classes != null && "style" in config && config.style != null) {
274
- return config;
275
- }
276
- return {
277
- classes: [],
278
- style: config
279
- };
280
- }
281
- throw new Error(`Invalid config: ${config}`);
282
- };
283
- const adapter$3 = (children, config) => {
284
- const {
285
- classes,
286
- style
287
- } = normalizeConfig(config);
288
- return React__namespace.createElement("div", {
289
- "data-testid": "css-adapter-container",
290
- className: classes.join(" "),
291
- style: style
292
- }, children);
293
- };
48
+ const defaultConfig$3=null;const normalizeConfig=config=>{if(typeof config==="string"){return {classes:[config],style:{}}}if(Array.isArray(config)){return {classes:config,style:{}}}if(typeof config==="object"){if("classes"in config&&config.classes!=null&&"style"in config&&config.style!=null){return config}return {classes:[],style:config}}throw new Error(`Invalid config: ${config}`)};const adapter$3=(children,config)=>{const{classes,style}=normalizeConfig(config);return jsxRuntime.jsx("div",{"data-testid":"css-adapter-container",className:classes.join(" "),style:style,children:children})};
294
49
 
295
- const defaultConfig$2 = null;
296
- class ErrorBoundary extends React__namespace.Component {
297
- constructor(...args) {
298
- super(...args);
299
- this.state = {
300
- renderError: false
301
- };
302
- }
303
- static getDerivedStateFromError(error) {
304
- return {
305
- renderError: true
306
- };
307
- }
308
- componentDidCatch(error, errorInfo) {
309
- const lastErrorUx = this.props.onError(error, errorInfo);
310
- this.setState({
311
- lastErrorUx
312
- });
313
- }
314
- render() {
315
- var _this$state$lastError;
316
- return this.state.renderError ? (_this$state$lastError = this.state.lastErrorUx) != null ? _this$state$lastError : "An error occurred" : this.props.children;
317
- }
318
- }
319
- const adapter$2 = (children, config) => React__namespace.createElement(ErrorBoundary, {
320
- onError: config
321
- }, children);
50
+ const defaultConfig$2=null;class ErrorBoundary extends React__namespace.Component{static getDerivedStateFromError(error){return {renderError:true}}componentDidCatch(error,errorInfo){const lastErrorUx=this.props.onError(error,errorInfo);this.setState({lastErrorUx});}render(){return this.state.renderError?this.state.lastErrorUx??"An error occurred":this.props.children}constructor(...args){super(...args),this.state={renderError:false};}}const adapter$2=(children,config)=>jsxRuntime.jsx(ErrorBoundary,{onError:config,children:children});
322
51
 
323
- const defaultConfig$1 = null;
324
- const adapter$1 = (children, config) => React__namespace.createElement(React__namespace.Fragment, null, React__namespace.createElement("div", {
325
- id: config,
326
- "data-testid": config
327
- }), children);
52
+ const defaultConfig$1=null;const adapter$1=(children,config)=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{id:config,"data-testid":config}),children]});
328
53
 
329
- const defaultConfig = {
330
- location: "/"
331
- };
332
- const MaybeWithRoute = ({
333
- children,
334
- path,
335
- configLocation
336
- }) => {
337
- if (path == null) {
338
- return React__namespace.createElement(React__namespace.Fragment, null, children);
339
- }
340
- const ErrorElement = () => {
341
- const actualLocation = reactRouterDomV5Compat.useLocation();
342
- const configuredLocation = typeof configLocation === "string" ? configLocation : configLocation.pathname;
343
- const errorMessage = `The current location '${actualLocation.pathname}' ` + `does not match the configured path '${path}'. ` + `Did you provide the correct configured ` + `location, '${configuredLocation}', or did the ` + `routing lead to a different place than you ` + `expected?`;
344
- throw new Error(errorMessage);
345
- };
346
- return React__namespace.createElement(reactRouterDom.Switch, null, React__namespace.createElement(reactRouterDom.Route, {
347
- path: path,
348
- render: () => React__namespace.createElement(React__namespace.Fragment, null, children)
349
- }), React__namespace.createElement(reactRouterDom.Route, {
350
- path: "*",
351
- component: ErrorElement
352
- }));
353
- };
354
- const adapter = (children, config) => {
355
- var _config$initialIndex;
356
- if (typeof config === "string") {
357
- config = {
358
- location: config
359
- };
360
- }
361
- if ("forceStatic" in config && config.forceStatic) {
362
- if (config.disableCompatRouter) {
363
- return React__namespace.createElement(reactRouterDom.StaticRouter, {
364
- location: config.location,
365
- context: {}
366
- }, React__namespace.createElement(MaybeWithRoute, {
367
- path: config.path,
368
- configLocation: config.location
369
- }, children));
370
- }
371
- return React__namespace.createElement(reactRouterDom.StaticRouter, {
372
- location: config.location,
373
- context: {}
374
- }, React__namespace.createElement(reactRouterDomV5Compat.CompatRouter, null, React__namespace.createElement(MaybeWithRoute, {
375
- path: config.path,
376
- configLocation: config.location
377
- }, children)));
378
- }
379
- if ("location" in config && config.location !== undefined) {
380
- return React__namespace.createElement(reactRouterDom.MemoryRouter, {
381
- initialEntries: [config.location]
382
- }, React__namespace.createElement(reactRouterDomV5Compat.CompatRouter, null, React__namespace.createElement(MaybeWithRoute, {
383
- path: config.path,
384
- configLocation: config.location
385
- }, children)));
386
- }
387
- if (!("initialEntries" in config) || config.initialEntries === undefined) {
388
- throw new Error("A location or initial history entries must be provided.");
389
- }
390
- const entries = config.initialEntries.length === 0 ? [defaultConfig.location] : config.initialEntries;
391
- const routerProps = {
392
- initialEntries: entries
393
- };
394
- if (config.initialIndex != null) {
395
- routerProps.initialIndex = config.initialIndex;
396
- }
397
- return React__namespace.createElement(reactRouterDom.MemoryRouter, routerProps, React__namespace.createElement(reactRouterDomV5Compat.CompatRouter, null, React__namespace.createElement(MaybeWithRoute, {
398
- path: config.path,
399
- configLocation: entries[(_config$initialIndex = config.initialIndex) != null ? _config$initialIndex : 0]
400
- }, children)));
401
- };
54
+ const defaultConfig={location:"/"};const MaybeWithRoute=({children,path,configLocation})=>{if(path==null){return jsxRuntime.jsx(jsxRuntime.Fragment,{children:children})}const ErrorElement=()=>{const actualLocation=reactRouterDomV5Compat.useLocation();const configuredLocation=typeof configLocation==="string"?configLocation:configLocation.pathname;const errorMessage=`The current location '${actualLocation.pathname}' `+`does not match the configured path '${path}'. `+`Did you provide the correct configured `+`location, '${configuredLocation}', or did the `+`routing lead to a different place than you `+`expected?`;throw new Error(errorMessage)};return jsxRuntime.jsxs(reactRouterDom.Switch,{children:[jsxRuntime.jsx(reactRouterDom.Route,{path:path,render:()=>jsxRuntime.jsx(jsxRuntime.Fragment,{children:children})}),jsxRuntime.jsx(reactRouterDom.Route,{path:"*",component:ErrorElement})]})};const adapter=(children,config)=>{if(typeof config==="string"){config={location:config};}if("forceStatic"in config&&config.forceStatic){if(config.disableCompatRouter){return jsxRuntime.jsx(reactRouterDom.StaticRouter,{location:config.location,context:{},children:jsxRuntime.jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})}return jsxRuntime.jsx(reactRouterDom.StaticRouter,{location:config.location,context:{},children:jsxRuntime.jsx(reactRouterDomV5Compat.CompatRouter,{children:jsxRuntime.jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})})}if("location"in config&&config.location!==undefined){return jsxRuntime.jsx(reactRouterDom.MemoryRouter,{initialEntries:[config.location],children:jsxRuntime.jsx(reactRouterDomV5Compat.CompatRouter,{children:jsxRuntime.jsx(MaybeWithRoute,{path:config.path,configLocation:config.location,children:children})})})}if(!("initialEntries"in config)||config.initialEntries===undefined){throw new Error("A location or initial history entries must be provided.")}const entries=config.initialEntries.length===0?[defaultConfig.location]:config.initialEntries;const routerProps={initialEntries:entries};if(config.initialIndex!=null){routerProps.initialIndex=config.initialIndex;}return jsxRuntime.jsx(reactRouterDom.MemoryRouter,{...routerProps,children:jsxRuntime.jsx(reactRouterDomV5Compat.CompatRouter,{children:jsxRuntime.jsx(MaybeWithRoute,{path:config.path,configLocation:entries[config.initialIndex??0],children:children})})})};
402
55
 
403
- const DefaultAdapters = {
404
- boundary: adapter$2,
405
- css: adapter$3,
406
- portal: adapter$1,
407
- router: adapter
408
- };
409
- const DefaultConfigs = {
410
- boundary: defaultConfig$2,
411
- css: defaultConfig$3,
412
- portal: defaultConfig$1,
413
- router: defaultConfig
414
- };
56
+ const DefaultAdapters={boundary:adapter$2,css:adapter$3,portal:adapter$1,router:adapter};const DefaultConfigs={boundary:defaultConfig$2,css:defaultConfig$3,portal:defaultConfig$1,router:defaultConfig};
415
57
 
416
58
  var adapters = /*#__PURE__*/Object.freeze({
417
59
  __proto__: null,
@@ -419,93 +61,22 @@ var adapters = /*#__PURE__*/Object.freeze({
419
61
  DefaultConfigs: DefaultConfigs
420
62
  });
421
63
 
422
- const componentCache = new Map();
423
- const getNamedAdapterComponent = name => {
424
- const existing = componentCache.get(name);
425
- if (existing != null) {
426
- return existing;
427
- }
428
- const newComponent = ({
429
- children,
430
- config,
431
- adapter
432
- }) => adapter(children, config);
433
- newComponent.displayName = `Adapter(${name})`;
434
- componentCache.set(name, newComponent);
435
- return newComponent;
436
- };
64
+ const componentCache=new Map;const getNamedAdapterComponent=name=>{const existing=componentCache.get(name);if(existing!=null){return existing}const newComponent=({children,config,adapter})=>adapter(children,config);newComponent.displayName=`Adapter(${name})`;componentCache.set(name,newComponent);return newComponent};
437
65
 
438
- const Adapt = ({
439
- children,
440
- adapters,
441
- configs
442
- }) => {
443
- return Object.entries(adapters).reduce((newChildren, [name, adapter]) => {
444
- const theConfig = configs[name];
445
- if (theConfig == null) {
446
- return newChildren;
447
- }
448
- const Adapter = getNamedAdapterComponent(name);
449
- return React__namespace.createElement(Adapter, {
450
- key: name,
451
- adapter: adapter,
452
- config: theConfig
453
- }, newChildren);
454
- }, React__namespace.createElement(React__namespace.Fragment, null, children));
455
- };
66
+ const Adapt=({children,adapters,configs})=>{return Object.entries(adapters).reduce((newChildren,[name,adapter])=>{const theConfig=configs[name];if(theConfig==null){return newChildren}const Adapter=getNamedAdapterComponent(name);return jsxRuntime.jsx(Adapter,{adapter:adapter,config:theConfig,children:newChildren},name)},jsxRuntime.jsx(jsxRuntime.Fragment,{children:children}))};
456
67
 
457
- const makeTestHarness = (adapters, defaultConfigs) => {
458
- return (Component, configs) => {
459
- const fullConfig = _extends__default["default"]({}, defaultConfigs, configs);
460
- const harnessedComponent = React__namespace.forwardRef((props, ref) => React__namespace.createElement(Adapt, {
461
- adapters: adapters,
462
- configs: fullConfig
463
- }, React__namespace.createElement(Component, _extends__default["default"]({}, props, {
464
- ref: ref
465
- }))));
466
- harnessedComponent.displayName = `testHarness(${Component.displayName || Component.name || "Component"})`;
467
- return harnessedComponent;
468
- };
469
- };
68
+ const makeTestHarness=(adapters,defaultConfigs)=>{return (Component,configs)=>{const fullConfig={...defaultConfigs,...configs};const harnessedComponent=React__namespace.forwardRef((props,ref)=>jsxRuntime.jsx(Adapt,{adapters:adapters,configs:fullConfig,children:jsxRuntime.jsx(Component,{...props,ref:ref})}));harnessedComponent.displayName=`testHarness(${Component.displayName||Component.name||"Component"})`;return harnessedComponent}};
470
69
 
471
- const HookHarness = ({
472
- children
473
- }) => React__namespace.createElement(React__namespace.Fragment, null, children);
474
- const makeHookHarness = (adapters, defaultConfigs) => {
475
- const testHarness = makeTestHarness(adapters, defaultConfigs);
476
- return configs => testHarness(HookHarness, configs);
477
- };
70
+ const HookHarness=({children})=>jsxRuntime.jsx(jsxRuntime.Fragment,{children:children});const makeHookHarness=(adapters,defaultConfigs)=>{const testHarness=makeTestHarness(adapters,defaultConfigs);return configs=>testHarness(HookHarness,configs)};
478
71
 
479
- const hookHarness = makeHookHarness(DefaultAdapters, DefaultConfigs);
72
+ const hookHarness=makeHookHarness(DefaultAdapters,DefaultConfigs);
480
73
 
481
- const testHarness = makeTestHarness(DefaultAdapters, DefaultConfigs);
74
+ const testHarness=makeTestHarness(DefaultAdapters,DefaultConfigs);
482
75
 
483
- const renderHookStatic = (render, {
484
- wrapper,
485
- initialProps
486
- } = {}) => {
487
- let result;
488
- function TestComponent({
489
- renderCallbackProps
490
- }) {
491
- result = render(renderCallbackProps);
492
- return null;
493
- }
494
- const component = React__namespace.createElement(TestComponent, {
495
- renderCallbackProps: initialProps
496
- });
497
- const componentWithWrapper = wrapper == null ? component : React__namespace.createElement(wrapper, null, component);
498
- ReactDOMServer__namespace.renderToString(componentWithWrapper);
499
- return {
500
- result: {
501
- current: result
502
- }
503
- };
504
- };
76
+ const renderHookStatic=(render,{wrapper,initialProps}={})=>{let result;function TestComponent({renderCallbackProps}){result=render(renderCallbackProps);return null}const component=jsxRuntime.jsx(TestComponent,{renderCallbackProps:initialProps});const componentWithWrapper=wrapper==null?component:React__namespace.createElement(wrapper,null,component);ReactDOMServer__namespace.renderToString(componentWithWrapper);return {result:{current:result}}};
505
77
 
506
78
  exports.RespondWith = RespondWith;
507
79
  exports.SettleController = SettleController;
508
- exports.fixtures = fixtures;
509
80
  exports.harnessAdapters = adapters;
510
81
  exports.hookHarness = hookHarness;
511
82
  exports.makeHookHarness = makeHookHarness;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-testing-core",
3
- "version": "3.0.1",
3
+ "version": "4.0.1",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -9,12 +9,9 @@
9
9
  "main": "dist/index.js",
10
10
  "module": "dist/es/index.js",
11
11
  "types": "dist/index.d.ts",
12
- "dependencies": {
13
- "@babel/runtime": "^7.24.5"
14
- },
12
+ "dependencies": {},
15
13
  "peerDependencies": {
16
14
  "@khanacademy/wonder-stuff-core": "^1.5.4",
17
- "@storybook/addon-actions": "^8.5.2",
18
15
  "aphrodite": "^1.2.5",
19
16
  "node-fetch": "^2.6.7",
20
17
  "react": "18.2.0",
@@ -23,8 +20,8 @@
23
20
  "react-router-dom-v5-compat": "^6.30.0"
24
21
  },
25
22
  "devDependencies": {
26
- "@khanacademy/wonder-stuff-testing": "^3.0.1",
27
- "@khanacademy/wb-dev-build-settings": "2.1.1"
23
+ "@khanacademy/wonder-stuff-testing": "^3.0.5",
24
+ "@khanacademy/wb-dev-build-settings": "3.2.0"
28
25
  },
29
26
  "author": "",
30
27
  "license": "MIT",
@@ -1,13 +0,0 @@
1
- import * as React from "react";
2
- type Props = {
3
- propA: string;
4
- propB?: string;
5
- };
6
- export declare const F1: unknown;
7
- export declare const F2: unknown;
8
- export declare const F3: unknown;
9
- declare const _default: {
10
- title: string;
11
- component: (props: Props) => React.ReactElement;
12
- };
13
- export default _default;
@@ -1,16 +0,0 @@
1
- import * as React from "react";
2
- import type { FixtureFn } from "./types";
3
- /**
4
- * Describe a group of fixtures for a given component.
5
- *
6
- * Only one `fixtures` call should be used per fixture file as it returns
7
- * the exports for that file.
8
- *
9
- * @param {React.ComponentType<any>} Component The component we want to create
10
- * stories for.
11
- * @returns {FixtureFn<TProps>} A function to create a CSF compatible story.
12
- *
13
- * @deprecated Use CSFv3 style stories instead. This API was for migration
14
- * from our old fixtures framework and will be removed in a future release.
15
- */
16
- export declare const fixtures: <TComponent extends React.ComponentType<any>, TProps extends JSX.LibraryManagedAttributes<TComponent, React.ComponentProps<TComponent>>>(Component: TComponent) => FixtureFn<TProps>;
@@ -1,9 +0,0 @@
1
- import * as React from "react";
2
- type Props = Record<any, any>;
3
- export declare const F1: unknown;
4
- export declare const F2: unknown;
5
- declare const _default: {
6
- title: string;
7
- component: (props: Props) => React.ReactElement;
8
- };
9
- export default _default;
@@ -1,48 +0,0 @@
1
- import * as React from "react";
2
- /**
3
- * Options injected to the function that returns the fixture props.
4
- * @deprecated Use CSFv3 style stories instead. This API was for migration
5
- * from our old fixtures framework and will be removed in a future release.
6
- */
7
- export type GetPropsOptions = {
8
- /**
9
- * A function to call that will log output.
10
- */
11
- log: (message: string, ...args: Array<any>) => void;
12
- /**
13
- * A function to make a handler that will log all arguments with the given
14
- * name or message. Useful for logging events as it avoids the boilerplate
15
- * of the `log` function.
16
- */
17
- logHandler: (name: string) => (...args: Array<any>) => void;
18
- };
19
- /**
20
- * The props for a fixture.
21
- *
22
- * This can be either a static object or a function that returns an object.
23
- *
24
- * @deprecated Use CSFv3 style stories instead. This API was for migration
25
- * from our old fixtures framework and will be removed in a future release.
26
- */
27
- export type FixtureProps<TProps extends object> = Readonly<TProps> | ((options: Readonly<GetPropsOptions>) => Readonly<TProps>);
28
- /**
29
- * A function for defining a fixture.
30
- * @deprecated Use CSFv3 style stories instead. This API was for migration
31
- * from our old fixtures framework and will be removed in a future release.
32
- */
33
- export type FixtureFn<TProps extends object> = (
34
- /**
35
- * The name of the fixture.
36
- */
37
- description: string,
38
- /**
39
- * The props for the fixture or a function that returns the props.
40
- * The function is injected with an API to facilitate logging.
41
- */
42
- props: FixtureProps<TProps>,
43
- /**
44
- * An alternative component to render for the fixture.
45
- * Useful if the fixture requires some additional setup for testing the
46
- * component.
47
- */
48
- wrapper?: React.ComponentType<TProps>) => unknown;