@khanacademy/wonder-blocks-testing 9.0.0 → 9.2.0

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,24 @@
1
1
  # @khanacademy/wonder-blocks-testing
2
2
 
3
+ ## 9.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 76883b4e: Make sure Wonder Blocks Testing is dependent on Core
8
+
9
+ ### Patch Changes
10
+
11
+ - 76883b4e: Output the adapter name with the Adapter component
12
+ - Updated dependencies [f19da46e]
13
+ - @khanacademy/wonder-blocks-core@6.0.2
14
+ - @khanacademy/wonder-blocks-data@13.0.1
15
+
16
+ ## 9.1.0
17
+
18
+ ### Minor Changes
19
+
20
+ - 6ed7e928: Test harness adapters are now rendered as React components which should ensure that contexts are properly available when children are rendered inside the adapters that require those contexts
21
+
3
22
  ## 9.0.0
4
23
 
5
24
  ### Major Changes
package/dist/es/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import * as React from 'react';
2
- import { useContext } from 'react';
3
2
  import { action } from '@storybook/addon-actions';
4
3
  import { InterceptRequests } from '@khanacademy/wonder-blocks-data';
5
4
  import { StaticRouter, MemoryRouter, Switch, Route } from 'react-router-dom';
6
5
  import { KindError, Errors } from '@khanacademy/wonder-stuff-core';
7
- import { StyleSheet, css } from 'aphrodite';
6
+ import { RenderStateRoot } from '@khanacademy/wonder-blocks-core';
8
7
 
9
8
  const fixtures = Component => {
10
9
  const templateMap = new WeakMap();
@@ -361,385 +360,10 @@ const adapter$1 = (children, config) => {
361
360
  return React.createElement(MemoryRouter, routerProps, wrappedWithRoute);
362
361
  };
363
362
 
364
- function _extends$1() {
365
- _extends$1 = Object.assign ? Object.assign.bind() : function (target) {
366
- for (var i = 1; i < arguments.length; i++) {
367
- var source = arguments[i];
368
- for (var key in source) {
369
- if (Object.prototype.hasOwnProperty.call(source, key)) {
370
- target[key] = source[key];
371
- }
372
- }
373
- }
374
- return target;
375
- };
376
- return _extends$1.apply(this, arguments);
377
- }
378
- function _objectWithoutPropertiesLoose(source, excluded) {
379
- if (source == null) return {};
380
- var target = {};
381
- var sourceKeys = Object.keys(source);
382
- var key, i;
383
- for (i = 0; i < sourceKeys.length; i++) {
384
- key = sourceKeys[i];
385
- if (excluded.indexOf(key) >= 0) continue;
386
- target[key] = source[key];
387
- }
388
- return target;
389
- }
390
- function flatten(list) {
391
- const result = [];
392
- if (!list) {
393
- return result;
394
- } else if (Array.isArray(list)) {
395
- for (const item of list) {
396
- result.push(...flatten(item));
397
- }
398
- } else {
399
- result.push(list);
400
- }
401
- return result;
402
- }
403
- function processStyleList(style) {
404
- const stylesheetStyles = [];
405
- const inlineStyles = [];
406
- if (!style) {
407
- return {
408
- style: {},
409
- className: ""
410
- };
411
- }
412
- const shouldInlineStyles = typeof global !== "undefined" && global.SNAPSHOT_INLINE_APHRODITE;
413
- flatten(style).forEach(child => {
414
- const _definition = child._definition;
415
- if (_definition != null) {
416
- if (shouldInlineStyles) {
417
- const def = {};
418
- for (const [key, value] of Object.entries(_definition)) {
419
- def[key.replace(/-[a-z]/g, match => match[1].toUpperCase())] = value;
420
- }
421
- inlineStyles.push(def);
422
- } else {
423
- stylesheetStyles.push(child);
424
- }
425
- } else {
426
- inlineStyles.push(child);
427
- }
428
- });
429
- const inlineStylesObject = Object.assign({}, ...inlineStyles);
430
- if (inlineStyles.length > 0 && !shouldInlineStyles) {
431
- const inlineStylesStyleSheet = StyleSheet.create({
432
- inlineStyles: inlineStylesObject
433
- });
434
- stylesheetStyles.push(inlineStylesStyleSheet.inlineStyles);
435
- }
436
- return {
437
- style: shouldInlineStyles ? inlineStylesObject : {},
438
- className: css(...stylesheetStyles)
439
- };
440
- }
441
- const _excluded$2 = ["children", "style", "tag", "testId"];
442
- const isHeaderRegex = /^h[1-6]$/;
443
- const styles$1 = StyleSheet.create({
444
- text: {
445
- WebkitFontSmoothing: "antialiased",
446
- MozOsxFontSmoothing: "grayscale"
447
- },
448
- header: {
449
- marginTop: 0,
450
- marginBottom: 0
451
- }
452
- });
453
- React.forwardRef(function Text(_ref, ref) {
454
- let {
455
- children,
456
- style,
457
- tag: Tag = "span",
458
- testId
459
- } = _ref,
460
- otherProps = _objectWithoutPropertiesLoose(_ref, _excluded$2);
461
- const isHeader = isHeaderRegex.test(Tag);
462
- const styleAttributes = processStyleList([styles$1.text, isHeader && styles$1.header, style]);
463
- return React.createElement(Tag, _extends$1({}, otherProps, {
464
- style: styleAttributes.style,
465
- className: styleAttributes.className,
466
- "data-test-id": testId,
467
- ref: ref
468
- }), children);
469
- });
470
- const _excluded$1 = ["className", "style"];
471
- function addStyle(Component, defaultStyle) {
472
- return React.forwardRef((props, ref) => {
473
- const {
474
- className,
475
- style
476
- } = props,
477
- otherProps = _objectWithoutPropertiesLoose(props, _excluded$1);
478
- const reset = typeof Component === "string" ? overrides[Component] : null;
479
- const {
480
- className: aphroditeClassName,
481
- style: inlineStyles
482
- } = processStyleList([reset, defaultStyle, style]);
483
- return React.createElement(Component, _extends$1({}, otherProps, {
484
- ref: ref,
485
- className: [aphroditeClassName, className].filter(Boolean).join(" "),
486
- style: inlineStyles
487
- }));
488
- });
489
- }
490
- const overrides = StyleSheet.create({
491
- button: {
492
- margin: 0,
493
- "::-moz-focus-inner": {
494
- border: 0
495
- }
496
- }
497
- });
498
- const _excluded = ["testId", "tag"];
499
- const styles = StyleSheet.create({
500
- default: {
501
- alignItems: "stretch",
502
- borderWidth: 0,
503
- borderStyle: "solid",
504
- boxSizing: "border-box",
505
- display: "flex",
506
- flexDirection: "column",
507
- margin: 0,
508
- padding: 0,
509
- position: "relative",
510
- zIndex: 0,
511
- minHeight: 0,
512
- minWidth: 0
513
- }
514
- });
515
- const StyledDiv = addStyle("div", styles.default);
516
- const StyledArticle = addStyle("article", styles.default);
517
- const StyledAside = addStyle("aside", styles.default);
518
- const StyledNav = addStyle("nav", styles.default);
519
- const StyledSection = addStyle("section", styles.default);
520
- React.forwardRef(function View(props, ref) {
521
- const {
522
- testId,
523
- tag = "div"
524
- } = props,
525
- restProps = _objectWithoutPropertiesLoose(props, _excluded);
526
- const commonProps = _extends$1({}, restProps, {
527
- "data-test-id": testId
528
- });
529
- switch (tag) {
530
- case "article":
531
- return React.createElement(StyledArticle, _extends$1({}, commonProps, {
532
- ref: ref
533
- }));
534
- case "aside":
535
- return React.createElement(StyledAside, _extends$1({}, commonProps, {
536
- ref: ref
537
- }));
538
- case "nav":
539
- return React.createElement(StyledNav, _extends$1({}, commonProps, {
540
- ref: ref
541
- }));
542
- case "section":
543
- return React.createElement(StyledSection, _extends$1({}, commonProps, {
544
- ref: ref
545
- }));
546
- case "div":
547
- return React.createElement(StyledDiv, _extends$1({}, commonProps, {
548
- ref: ref
549
- }));
550
- default:
551
- throw Error(`${tag} is not an allowed value for the 'tag' prop`);
552
- }
553
- });
554
- let RenderState = function (RenderState) {
555
- RenderState["Root"] = "root";
556
- RenderState["Initial"] = "initial";
557
- RenderState["Standard"] = "standard";
558
- return RenderState;
559
- }({});
560
- const RenderStateContext = React.createContext(RenderState.Root);
561
- RenderStateContext.displayName = "RenderStateContext";
562
- class WithSSRPlaceholder extends React.Component {
563
- constructor(...args) {
564
- super(...args);
565
- this.state = {
566
- mounted: false
567
- };
568
- this._isTheRootComponent = false;
569
- }
570
- componentDidMount() {
571
- if (this._isTheRootComponent) {
572
- this.setState({
573
- mounted: true
574
- });
575
- }
576
- }
577
- _renderAsRootComponent() {
578
- const {
579
- mounted
580
- } = this.state;
581
- const {
582
- children,
583
- placeholder
584
- } = this.props;
585
- this._isTheRootComponent = true;
586
- if (mounted) {
587
- return React.createElement(RenderStateContext.Provider, {
588
- value: RenderState.Standard
589
- }, children());
590
- }
591
- if (placeholder) {
592
- return React.createElement(RenderStateContext.Provider, {
593
- value: RenderState.Initial
594
- }, placeholder());
595
- }
596
- return null;
597
- }
598
- _maybeRender(renderState) {
599
- const {
600
- children,
601
- placeholder
602
- } = this.props;
603
- switch (renderState) {
604
- case RenderState.Root:
605
- return this._renderAsRootComponent();
606
- case RenderState.Initial:
607
- if (placeholder) {
608
- return placeholder();
609
- }
610
- return null;
611
- case RenderState.Standard:
612
- return children();
613
- }
614
- {
615
- var _JSON$stringify;
616
- console.log(`We got a render state we don't understand: "${(_JSON$stringify = JSON.stringify(renderState)) != null ? _JSON$stringify : ""}"`);
617
- return this._maybeRender(RenderState.Root);
618
- }
619
- }
620
- render() {
621
- return React.createElement(RenderStateContext.Consumer, null, value => this._maybeRender(value));
622
- }
623
- }
624
- class UniqueIDFactory {
625
- constructor(scope) {
626
- this._uniqueFactoryName = void 0;
627
- this.get = key => {
628
- const normalizedKey = key.toLowerCase();
629
- if (!this._hasValidIdChars(key)) {
630
- throw new Error(`Invalid identifier key: ${key}`);
631
- }
632
- return `${this._uniqueFactoryName}-${normalizedKey}`;
633
- };
634
- scope = typeof scope === "string" ? scope : "";
635
- const normalizedScope = scope.toLowerCase();
636
- if (!this._hasValidIdChars(normalizedScope)) {
637
- throw new Error(`Invalid factory scope: ${scope}`);
638
- }
639
- this._uniqueFactoryName = `uid-${normalizedScope}-${UniqueIDFactory._factoryUniquenessCounter++}`;
640
- }
641
- _hasValidIdChars(value) {
642
- if (typeof value !== "string") {
643
- return false;
644
- }
645
- const invalidCharsReplaced = value.replace(/[^\d\w-]/g, "-");
646
- return value === invalidCharsReplaced;
647
- }
648
- }
649
- UniqueIDFactory._factoryUniquenessCounter = 0;
650
- class SsrIDFactory {
651
- get(id) {
652
- return id;
653
- }
654
- }
655
- SsrIDFactory.Default = new SsrIDFactory();
656
- var SsrIDFactory$1 = SsrIDFactory.Default;
657
- class UniqueIDProvider extends React.Component {
658
- constructor(...args) {
659
- super(...args);
660
- this._idFactory = void 0;
661
- }
662
- _performRender(firstRender) {
663
- const {
664
- children,
665
- mockOnFirstRender,
666
- scope
667
- } = this.props;
668
- if (firstRender) {
669
- if (mockOnFirstRender) {
670
- return children(SsrIDFactory$1);
671
- }
672
- return null;
673
- }
674
- if (!this._idFactory) {
675
- this._idFactory = new UniqueIDFactory(scope);
676
- }
677
- return children(this._idFactory);
678
- }
679
- render() {
680
- return React.createElement(WithSSRPlaceholder, {
681
- placeholder: () => this._performRender(true)
682
- }, () => this._performRender(false));
683
- }
684
- }
685
- class IDProvider extends React.Component {
686
- renderChildren(ids) {
687
- const {
688
- id,
689
- children
690
- } = this.props;
691
- const uniqueId = ids ? ids.get(IDProvider.defaultId) : id;
692
- if (!uniqueId) {
693
- throw new Error("Did not get an identifier factory nor a id prop");
694
- }
695
- return children(uniqueId);
696
- }
697
- render() {
698
- const {
699
- id,
700
- scope
701
- } = this.props;
702
- if (id) {
703
- return this.renderChildren();
704
- } else {
705
- return React.createElement(UniqueIDProvider, {
706
- scope: scope,
707
- mockOnFirstRender: true
708
- }, ids => this.renderChildren(ids));
709
- }
710
- }
711
- }
712
- IDProvider.defaultId = "wb-id";
713
- const useRenderState = () => useContext(RenderStateContext);
714
- const {
715
- useEffect,
716
- useState
717
- } = React;
718
- const RenderStateRoot = ({
719
- children,
720
- throwIfNested: _throwIfNested = true
721
- }) => {
722
- const [firstRender, setFirstRender] = useState(true);
723
- const renderState = useRenderState();
724
- useEffect(() => {
725
- setFirstRender(false);
726
- }, []);
727
- if (renderState !== RenderState.Root) {
728
- if (_throwIfNested) {
729
- throw new Error("There's already a <RenderStateRoot> above this instance in " + "the render tree. This instance should be removed.");
730
- }
731
- return React.createElement(React.Fragment, null, children);
732
- }
733
- const value = firstRender ? RenderState.Initial : RenderState.Standard;
734
- return React.createElement(RenderStateContext.Provider, {
735
- value: value
736
- }, children);
737
- };
738
-
739
363
  const defaultConfig = null;
740
364
  const adapter = (children, config) => {
741
365
  if (config !== true) {
742
- throw new KindError("Unexpected configuraiton", Errors.InvalidInput, {
366
+ throw new KindError("Unexpected configuration: set config to null to turn this adapter off", Errors.InvalidInput, {
743
367
  metadata: {
744
368
  config
745
369
  }
@@ -784,22 +408,29 @@ function _extends() {
784
408
  return _extends.apply(this, arguments);
785
409
  }
786
410
 
787
- const renderAdapters = (adapters, configs, children) => {
788
- let currentChildren = children;
789
- for (const adapterName of Object.keys(adapters)) {
790
- const adapter = adapters[adapterName];
791
- const config = configs[adapterName];
792
- if (config != null) {
793
- currentChildren = adapter(currentChildren, config);
794
- }
795
- }
796
- return React.createElement(React.Fragment, null, currentChildren);
797
- };
411
+ const Adapt = ({
412
+ children,
413
+ adapters,
414
+ configs
415
+ }) => Object.entries(adapters).reduce((newChildren, [name, adapter]) => {
416
+ const config = configs[name];
417
+ if (config == null) {
418
+ return newChildren;
419
+ }
420
+ const Adapter = ({
421
+ children
422
+ }) => adapter(children, config);
423
+ Adapter.displayName = `Adapter(${name})`;
424
+ return React.createElement(Adapter, null, newChildren);
425
+ }, React.createElement(React.Fragment, null, children));
798
426
 
799
427
  const makeTestHarness = (adapters, defaultConfigs) => {
800
428
  return (Component, configs) => {
801
429
  const fullConfig = _extends({}, defaultConfigs, configs);
802
- const harnessedComponent = React.forwardRef((props, ref) => renderAdapters(adapters, fullConfig, React.createElement(Component, _extends({}, props, {
430
+ const harnessedComponent = React.forwardRef((props, ref) => React.createElement(Adapt, {
431
+ adapters: adapters,
432
+ configs: fullConfig
433
+ }, React.createElement(Component, _extends({}, props, {
803
434
  ref: ref
804
435
  }))));
805
436
  harnessedComponent.displayName = `testHarness(${Component.displayName || Component.name || "Component"})`;
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ import type { TestHarnessConfigs, TestHarnessAdapters } from "./types";
3
+ type Props<TAdapters extends TestHarnessAdapters> = {
4
+ children: React.ReactNode;
5
+ adapters: TAdapters;
6
+ configs: TestHarnessConfigs<TAdapters>;
7
+ };
8
+ /**
9
+ * Render a set of adapters around the given children.
10
+ *
11
+ * Adapters are rendered with the last adapter being the outermost and the first
12
+ * adapter being the innermost, with children being the innermost of all. This
13
+ * ensures that we are backwards compatible with previous releases of the
14
+ * test harness.
15
+ */
16
+ export declare const Adapt: <TAdapters extends TestHarnessAdapters>({ children, adapters, configs, }: Props<TAdapters>) => React.ReactElement;
17
+ export {};