@khanacademy/wonder-blocks-data 8.0.0 → 8.0.3
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 +22 -0
- package/dist/es/index.js +6 -11
- package/dist/index.js +24 -144
- package/package.json +3 -2
- package/src/util/__tests__/ssr-cache.test.js +48 -0
- package/src/util/ssr-cache.js +12 -10
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -337
- package/src/__tests__/generated-snapshot.test.js +0 -350
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-data
|
|
2
2
|
|
|
3
|
+
## 8.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5f4a4297: Make dependency on `flow-enums-runtime` explicit
|
|
8
|
+
- 2b96fd59: Change flow-enums-runtime to be peer dependencies
|
|
9
|
+
- Updated dependencies [5f4a4297]
|
|
10
|
+
- Updated dependencies [2b96fd59]
|
|
11
|
+
- @khanacademy/wonder-blocks-core@4.3.2
|
|
12
|
+
|
|
13
|
+
## 8.0.2
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 580141ed: Always initialize SSR-only cache
|
|
18
|
+
|
|
19
|
+
## 8.0.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- e5fa4d9e: Make sure ssr-only cache is initialized when purging caches in test environment
|
|
24
|
+
|
|
3
25
|
## 8.0.0
|
|
4
26
|
|
|
5
27
|
### Major Changes
|
package/dist/es/index.js
CHANGED
|
@@ -172,11 +172,10 @@ class SsrCache {
|
|
|
172
172
|
};
|
|
173
173
|
|
|
174
174
|
this.getEntry = id => {
|
|
175
|
-
|
|
175
|
+
const ssrEntry = Server.isServerSide() ? this._ssrOnlyCache.get(DefaultScope$2, id) : null;
|
|
176
|
+
const internalEntry = ssrEntry != null ? ssrEntry : this._hydrationCache.get(DefaultScope$2, id);
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (this._ssrOnlyCache == null && internalEntry != null) {
|
|
178
|
+
if (!Server.isServerSide() && internalEntry != null) {
|
|
180
179
|
this._hydrationCache.purge(DefaultScope$2, id);
|
|
181
180
|
}
|
|
182
181
|
|
|
@@ -184,13 +183,11 @@ class SsrCache {
|
|
|
184
183
|
};
|
|
185
184
|
|
|
186
185
|
this.purgeData = predicate => {
|
|
187
|
-
var _this$_ssrOnlyCache2;
|
|
188
|
-
|
|
189
186
|
const realPredicate = predicate ? (_, key, cachedEntry) => predicate(key, cachedEntry) : undefined;
|
|
190
187
|
|
|
191
188
|
this._hydrationCache.purgeAll(realPredicate);
|
|
192
189
|
|
|
193
|
-
|
|
190
|
+
this._ssrOnlyCache.purgeAll(realPredicate);
|
|
194
191
|
};
|
|
195
192
|
|
|
196
193
|
this.cloneHydratableData = () => {
|
|
@@ -201,7 +198,7 @@ class SsrCache {
|
|
|
201
198
|
return (_cache$DefaultScope = cache[DefaultScope$2]) != null ? _cache$DefaultScope : {};
|
|
202
199
|
};
|
|
203
200
|
|
|
204
|
-
this._ssrOnlyCache =
|
|
201
|
+
this._ssrOnlyCache = ssrOnlyCache || new SerializableInMemoryCache();
|
|
205
202
|
this._hydrationCache = hydrationCache || new SerializableInMemoryCache();
|
|
206
203
|
}
|
|
207
204
|
|
|
@@ -212,9 +209,7 @@ class SsrCache {
|
|
|
212
209
|
if (hydrate) {
|
|
213
210
|
this._hydrationCache.set(DefaultScope$2, id, frozenEntry);
|
|
214
211
|
} else {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
(_this$_ssrOnlyCache3 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache3.set(DefaultScope$2, id, frozenEntry);
|
|
212
|
+
this._ssrOnlyCache.set(DefaultScope$2, id, frozenEntry);
|
|
218
213
|
}
|
|
219
214
|
}
|
|
220
215
|
|
package/dist/index.js
CHANGED
|
@@ -165,6 +165,12 @@ module.exports = require("react");
|
|
|
165
165
|
|
|
166
166
|
/***/ }),
|
|
167
167
|
/* 2 */
|
|
168
|
+
/***/ (function(module, exports) {
|
|
169
|
+
|
|
170
|
+
module.exports = require("@khanacademy/wonder-blocks-core");
|
|
171
|
+
|
|
172
|
+
/***/ }),
|
|
173
|
+
/* 3 */
|
|
168
174
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
169
175
|
|
|
170
176
|
"use strict";
|
|
@@ -187,12 +193,6 @@ const FetchPolicy = __webpack_require__(22).Mirrored(["CacheBeforeNetwork", "Cac
|
|
|
187
193
|
* and functions are not allowed.
|
|
188
194
|
*/
|
|
189
195
|
|
|
190
|
-
/***/ }),
|
|
191
|
-
/* 3 */
|
|
192
|
-
/***/ (function(module, exports) {
|
|
193
|
-
|
|
194
|
-
module.exports = require("@khanacademy/wonder-blocks-core");
|
|
195
|
-
|
|
196
196
|
/***/ }),
|
|
197
197
|
/* 4 */
|
|
198
198
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
@@ -556,7 +556,7 @@ class RequestTracker {
|
|
|
556
556
|
|
|
557
557
|
"use strict";
|
|
558
558
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return SsrCache; });
|
|
559
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
559
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
560
560
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
561
561
|
/* harmony import */ var _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13);
|
|
562
562
|
|
|
@@ -608,14 +608,14 @@ class SsrCache {
|
|
|
608
608
|
};
|
|
609
609
|
|
|
610
610
|
this.getEntry = id => {
|
|
611
|
-
var _this$_ssrOnlyCache$g, _this$_ssrOnlyCache;
|
|
612
|
-
|
|
613
611
|
// Get the cached entry for this value.
|
|
614
|
-
// We first look in the ssr cache
|
|
615
|
-
const
|
|
612
|
+
// We first look in the ssr cache, if we need to.
|
|
613
|
+
const ssrEntry = _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? this._ssrOnlyCache.get(DefaultScope, id) : null; // Now we defer to the SSR value, and fallback to the hydration cache.
|
|
614
|
+
|
|
615
|
+
const internalEntry = ssrEntry != null ? ssrEntry : this._hydrationCache.get(DefaultScope, id); // If we are not server-side and we hydrated something, let's clear
|
|
616
616
|
// that from the hydration cache to save memory.
|
|
617
617
|
|
|
618
|
-
if (
|
|
618
|
+
if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() && internalEntry != null) {
|
|
619
619
|
// We now delete this from our hydration cache as we don't need it.
|
|
620
620
|
// This does mean that if another handler of the same type but
|
|
621
621
|
// without some sort of linked cache won't get the value, but
|
|
@@ -632,8 +632,6 @@ class SsrCache {
|
|
|
632
632
|
};
|
|
633
633
|
|
|
634
634
|
this.purgeData = predicate => {
|
|
635
|
-
var _this$_ssrOnlyCache2;
|
|
636
|
-
|
|
637
635
|
const realPredicate = predicate ? // We know what we're putting into the cache so let's assume it
|
|
638
636
|
// conforms.
|
|
639
637
|
// $FlowIgnore[incompatible-call]
|
|
@@ -641,7 +639,7 @@ class SsrCache {
|
|
|
641
639
|
|
|
642
640
|
this._hydrationCache.purgeAll(realPredicate);
|
|
643
641
|
|
|
644
|
-
|
|
642
|
+
this._ssrOnlyCache.purgeAll(realPredicate);
|
|
645
643
|
};
|
|
646
644
|
|
|
647
645
|
this.cloneHydratableData = () => {
|
|
@@ -658,7 +656,7 @@ class SsrCache {
|
|
|
658
656
|
return (_cache$DefaultScope = cache[DefaultScope]) != null ? _cache$DefaultScope : {};
|
|
659
657
|
};
|
|
660
658
|
|
|
661
|
-
this._ssrOnlyCache =
|
|
659
|
+
this._ssrOnlyCache = ssrOnlyCache || new _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* SerializableInMemoryCache */ "a"]();
|
|
662
660
|
this._hydrationCache = hydrationCache || new _serializable_in_memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* SerializableInMemoryCache */ "a"]();
|
|
663
661
|
}
|
|
664
662
|
|
|
@@ -671,12 +669,10 @@ class SsrCache {
|
|
|
671
669
|
if (hydrate) {
|
|
672
670
|
this._hydrationCache.set(DefaultScope, id, frozenEntry);
|
|
673
671
|
} else {
|
|
674
|
-
var _this$_ssrOnlyCache3;
|
|
675
|
-
|
|
676
672
|
// Usually, when server-side, this cache will always be present.
|
|
677
673
|
// We do fake server-side in our doc example though, when it
|
|
678
674
|
// won't be.
|
|
679
|
-
|
|
675
|
+
this._ssrOnlyCache.set(DefaultScope, id, frozenEntry);
|
|
680
676
|
}
|
|
681
677
|
}
|
|
682
678
|
|
|
@@ -921,7 +917,7 @@ class ScopedInMemoryCache {
|
|
|
921
917
|
/* harmony import */ var _use_server_effect_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16);
|
|
922
918
|
/* harmony import */ var _use_shared_cache_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
|
|
923
919
|
/* harmony import */ var _use_cached_effect_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
|
|
924
|
-
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(
|
|
920
|
+
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
|
|
925
921
|
|
|
926
922
|
|
|
927
923
|
|
|
@@ -1123,7 +1119,7 @@ const purgeHydrationCache = predicate => _ssr_cache_js__WEBPACK_IMPORTED_MODULE_
|
|
|
1123
1119
|
|
|
1124
1120
|
"use strict";
|
|
1125
1121
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useServerEffect; });
|
|
1126
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
1122
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
1127
1123
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
1128
1124
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1);
|
|
1129
1125
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
|
|
@@ -1188,14 +1184,14 @@ const useServerEffect = (requestId, handler, options = {}) => {
|
|
|
1188
1184
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useCachedEffect; });
|
|
1189
1185
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
1190
1186
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
1191
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
1187
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
1192
1188
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
|
|
1193
1189
|
/* harmony import */ var _util_data_error_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(0);
|
|
1194
1190
|
/* harmony import */ var _util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
|
|
1195
1191
|
/* harmony import */ var _util_status_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
|
|
1196
1192
|
/* harmony import */ var _use_shared_cache_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5);
|
|
1197
1193
|
/* harmony import */ var _use_request_interception_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19);
|
|
1198
|
-
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(
|
|
1194
|
+
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(3);
|
|
1199
1195
|
|
|
1200
1196
|
|
|
1201
1197
|
|
|
@@ -1584,125 +1580,9 @@ const mergeGqlContext = (defaultContext, overrides) => {
|
|
|
1584
1580
|
|
|
1585
1581
|
/***/ }),
|
|
1586
1582
|
/* 22 */
|
|
1587
|
-
/***/ (function(module, exports
|
|
1588
|
-
|
|
1589
|
-
"use strict";
|
|
1590
|
-
/**
|
|
1591
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
1592
|
-
*
|
|
1593
|
-
* This source code is licensed under the MIT license found in the
|
|
1594
|
-
* LICENSE file in the root directory of this source tree.
|
|
1595
|
-
*/
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
// Below we want to use `hasOwnProperty` on an object that doesn't have
|
|
1600
|
-
// `Object.prototype` in its proto chain, so we must extract it here.
|
|
1601
|
-
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
1602
|
-
|
|
1603
|
-
// Map from an enum object to a reverse map of its values to names
|
|
1604
|
-
var reverseMapCache = typeof WeakMap === 'function' ? new WeakMap() : new Map();
|
|
1605
|
-
|
|
1606
|
-
// Computes the reverse mapping of the enum object: from value to name.
|
|
1607
|
-
// Flow Enum values are unique (enforced by the parser), so this is a
|
|
1608
|
-
// one to one mapping.
|
|
1609
|
-
function getReverseMap(enumObject) {
|
|
1610
|
-
var reverseMap = reverseMapCache.get(enumObject);
|
|
1611
|
-
if (reverseMap !== undefined) {
|
|
1612
|
-
return reverseMap;
|
|
1613
|
-
}
|
|
1614
|
-
// We aren't using `Object.values` because that gets enumerable
|
|
1615
|
-
// properties, and our properties aren't enumerable.
|
|
1616
|
-
var newReverseMap = new Map();
|
|
1617
|
-
Object.getOwnPropertyNames(enumObject).forEach(function (name) {
|
|
1618
|
-
newReverseMap.set(enumObject[name], name);
|
|
1619
|
-
});
|
|
1620
|
-
reverseMapCache.set(enumObject, newReverseMap);
|
|
1621
|
-
return newReverseMap;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
var EnumPrototype = Object.freeze(
|
|
1625
|
-
Object.defineProperties(Object.create(null), {
|
|
1626
|
-
isValid: {
|
|
1627
|
-
value: function (x) {
|
|
1628
|
-
return getReverseMap(this).has(x);
|
|
1629
|
-
},
|
|
1630
|
-
},
|
|
1631
|
-
cast: {
|
|
1632
|
-
value: function (x) {
|
|
1633
|
-
return this.isValid(x) ? x : undefined;
|
|
1634
|
-
},
|
|
1635
|
-
},
|
|
1636
|
-
members: {
|
|
1637
|
-
value: function () {
|
|
1638
|
-
return getReverseMap(this).keys();
|
|
1639
|
-
},
|
|
1640
|
-
},
|
|
1641
|
-
getName: {
|
|
1642
|
-
value: function (value) {
|
|
1643
|
-
return getReverseMap(this).get(value);
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
})
|
|
1647
|
-
);
|
|
1648
|
-
|
|
1649
|
-
// `members` is an object mapping name to value.
|
|
1650
|
-
function Enum(members) {
|
|
1651
|
-
var o = Object.create(EnumPrototype);
|
|
1652
|
-
for (var k in members) {
|
|
1653
|
-
if (hasOwnProperty.call(members, k)) {
|
|
1654
|
-
// Create non-enumerable properties.
|
|
1655
|
-
Object.defineProperty(o, k, {value: members[k]});
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
return Object.freeze(o);
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
// Mirrored enum (string enum with no member initializers).
|
|
1662
|
-
// Optimized implementation, taking advantage of the fact that
|
|
1663
|
-
// keys and values are identical.
|
|
1664
|
-
var EnumMirroredPrototype = Object.freeze(
|
|
1665
|
-
Object.defineProperties(Object.create(null), {
|
|
1666
|
-
isValid: {
|
|
1667
|
-
value: function (x) {
|
|
1668
|
-
if (typeof x === 'string') {
|
|
1669
|
-
return hasOwnProperty.call(this, x);
|
|
1670
|
-
}
|
|
1671
|
-
return false;
|
|
1672
|
-
},
|
|
1673
|
-
},
|
|
1674
|
-
cast: {
|
|
1675
|
-
value: EnumPrototype.cast,
|
|
1676
|
-
},
|
|
1677
|
-
members: {
|
|
1678
|
-
value: function () {
|
|
1679
|
-
// We aren't using `Object.values` because that gets enumerable
|
|
1680
|
-
// properties, and our properties aren't enumerable.
|
|
1681
|
-
return Object.getOwnPropertyNames(this).values();
|
|
1682
|
-
},
|
|
1683
|
-
},
|
|
1684
|
-
getName: {
|
|
1685
|
-
value: function (value) {
|
|
1686
|
-
return value;
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
})
|
|
1690
|
-
);
|
|
1691
|
-
|
|
1692
|
-
// `members` is an array of names (which, are also the values).
|
|
1693
|
-
Enum.Mirrored = function EnumMirrored(members) {
|
|
1694
|
-
var o = Object.create(EnumMirroredPrototype);
|
|
1695
|
-
for (var i = 0, len = members.length; i < len; ++i) {
|
|
1696
|
-
// Value is same as key. Also, non-enumerable.
|
|
1697
|
-
Object.defineProperty(o, members[i], {value: members[i]});
|
|
1698
|
-
}
|
|
1699
|
-
return Object.freeze(o);
|
|
1700
|
-
};
|
|
1701
|
-
|
|
1702
|
-
Object.freeze(Enum.Mirrored);
|
|
1703
|
-
|
|
1704
|
-
module.exports = Object.freeze(Enum);
|
|
1583
|
+
/***/ (function(module, exports) {
|
|
1705
1584
|
|
|
1585
|
+
module.exports = require("flow-enums-runtime");
|
|
1706
1586
|
|
|
1707
1587
|
/***/ }),
|
|
1708
1588
|
/* 23 */
|
|
@@ -1712,7 +1592,7 @@ module.exports = Object.freeze(Enum);
|
|
|
1712
1592
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return fetchTrackedRequests; });
|
|
1713
1593
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return hasTrackedRequestsToBeFetched; });
|
|
1714
1594
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return abortInflightRequests; });
|
|
1715
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
1595
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
1716
1596
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
1717
1597
|
/* harmony import */ var _request_tracking_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
|
|
1718
1598
|
/* harmony import */ var _request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
|
|
@@ -1812,7 +1692,7 @@ const purgeCaches = () => {
|
|
|
1812
1692
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TrackData; });
|
|
1813
1693
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
1814
1694
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
1815
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
1695
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
1816
1696
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
|
|
1817
1697
|
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
|
|
1818
1698
|
|
|
@@ -2266,7 +2146,7 @@ const getGqlDataFromResponse = async response => {
|
|
|
2266
2146
|
|
|
2267
2147
|
"use strict";
|
|
2268
2148
|
__webpack_require__.r(__webpack_exports__);
|
|
2269
|
-
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
2149
|
+
/* harmony import */ var _util_types_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
|
|
2270
2150
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FetchPolicy", function() { return _util_types_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
|
|
2271
2151
|
|
|
2272
2152
|
/* harmony import */ var _util_hydration_cache_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-data",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.3",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@babel/runtime": "^7.16.3",
|
|
17
|
-
"@khanacademy/wonder-blocks-core": "^4.3.
|
|
17
|
+
"@khanacademy/wonder-blocks-core": "^4.3.2"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@khanacademy/wonder-stuff-core": "^0.1.2",
|
|
21
|
+
"flow-enums-runtime": "^0.0.6",
|
|
21
22
|
"react": "16.14.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
@@ -16,6 +16,54 @@ describe("../ssr-cache.js", () => {
|
|
|
16
16
|
jest.restoreAllMocks();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
describe("#constructor", () => {
|
|
20
|
+
it("should default the ssr-only cache to a cache instance", () => {
|
|
21
|
+
// Arrange
|
|
22
|
+
|
|
23
|
+
// Act
|
|
24
|
+
const cache = new SsrCache();
|
|
25
|
+
|
|
26
|
+
// Assert
|
|
27
|
+
expect(cache._ssrOnlyCache).toBeInstanceOf(
|
|
28
|
+
SerializableInMemoryCache,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should set the hydration cache to the passed instance if there is one", () => {
|
|
33
|
+
// Arrange
|
|
34
|
+
const passedInstance = new SerializableInMemoryCache();
|
|
35
|
+
|
|
36
|
+
// Act
|
|
37
|
+
const cache = new SsrCache(null, passedInstance);
|
|
38
|
+
|
|
39
|
+
// Assert
|
|
40
|
+
expect(cache._ssrOnlyCache).toBe(passedInstance);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should default the hydration cache to a cache instance", () => {
|
|
44
|
+
// Arrange
|
|
45
|
+
|
|
46
|
+
// Act
|
|
47
|
+
const cache = new SsrCache();
|
|
48
|
+
|
|
49
|
+
// Assert
|
|
50
|
+
expect(cache._hydrationCache).toBeInstanceOf(
|
|
51
|
+
SerializableInMemoryCache,
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should set the hydration cache to the passed instance if there is one", () => {
|
|
56
|
+
// Arrange
|
|
57
|
+
const passedInstance = new SerializableInMemoryCache();
|
|
58
|
+
|
|
59
|
+
// Act
|
|
60
|
+
const cache = new SsrCache(passedInstance);
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
expect(cache._hydrationCache).toBe(passedInstance);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
19
67
|
describe("@Default", () => {
|
|
20
68
|
it("should return an instance of SsrCache", () => {
|
|
21
69
|
// Arrange
|
package/src/util/ssr-cache.js
CHANGED
|
@@ -26,15 +26,13 @@ export class SsrCache {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
_hydrationCache: SerializableInMemoryCache;
|
|
29
|
-
_ssrOnlyCache:
|
|
29
|
+
_ssrOnlyCache: SerializableInMemoryCache;
|
|
30
30
|
|
|
31
31
|
constructor(
|
|
32
32
|
hydrationCache: ?SerializableInMemoryCache = null,
|
|
33
33
|
ssrOnlyCache: ?SerializableInMemoryCache = null,
|
|
34
34
|
) {
|
|
35
|
-
this._ssrOnlyCache =
|
|
36
|
-
? ssrOnlyCache || new SerializableInMemoryCache()
|
|
37
|
-
: undefined;
|
|
35
|
+
this._ssrOnlyCache = ssrOnlyCache || new SerializableInMemoryCache();
|
|
38
36
|
this._hydrationCache =
|
|
39
37
|
hydrationCache || new SerializableInMemoryCache();
|
|
40
38
|
}
|
|
@@ -54,7 +52,7 @@ export class SsrCache {
|
|
|
54
52
|
// Usually, when server-side, this cache will always be present.
|
|
55
53
|
// We do fake server-side in our doc example though, when it
|
|
56
54
|
// won't be.
|
|
57
|
-
this._ssrOnlyCache
|
|
55
|
+
this._ssrOnlyCache.set(DefaultScope, id, frozenEntry);
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
return frozenEntry;
|
|
@@ -120,14 +118,18 @@ export class SsrCache {
|
|
|
120
118
|
): ?$ReadOnly<CachedResponse<TData>> => {
|
|
121
119
|
// Get the cached entry for this value.
|
|
122
120
|
|
|
123
|
-
// We first look in the ssr cache
|
|
121
|
+
// We first look in the ssr cache, if we need to.
|
|
122
|
+
const ssrEntry = Server.isServerSide()
|
|
123
|
+
? this._ssrOnlyCache.get(DefaultScope, id)
|
|
124
|
+
: null;
|
|
125
|
+
|
|
126
|
+
// Now we defer to the SSR value, and fallback to the hydration cache.
|
|
124
127
|
const internalEntry =
|
|
125
|
-
this.
|
|
126
|
-
this._hydrationCache.get(DefaultScope, id);
|
|
128
|
+
ssrEntry ?? this._hydrationCache.get(DefaultScope, id);
|
|
127
129
|
|
|
128
130
|
// If we are not server-side and we hydrated something, let's clear
|
|
129
131
|
// that from the hydration cache to save memory.
|
|
130
|
-
if (
|
|
132
|
+
if (!Server.isServerSide() && internalEntry != null) {
|
|
131
133
|
// We now delete this from our hydration cache as we don't need it.
|
|
132
134
|
// This does mean that if another handler of the same type but
|
|
133
135
|
// without some sort of linked cache won't get the value, but
|
|
@@ -165,7 +167,7 @@ export class SsrCache {
|
|
|
165
167
|
|
|
166
168
|
// Apply the predicate to what we have in our caches.
|
|
167
169
|
this._hydrationCache.purgeAll(realPredicate);
|
|
168
|
-
this._ssrOnlyCache
|
|
170
|
+
this._ssrOnlyCache.purgeAll(realPredicate);
|
|
169
171
|
};
|
|
170
172
|
|
|
171
173
|
/**
|
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`wonder-blocks-data example 1 1`] = `
|
|
4
|
-
<div
|
|
5
|
-
className=""
|
|
6
|
-
style={
|
|
7
|
-
Object {
|
|
8
|
-
"alignItems": "stretch",
|
|
9
|
-
"borderStyle": "solid",
|
|
10
|
-
"borderWidth": 0,
|
|
11
|
-
"boxSizing": "border-box",
|
|
12
|
-
"display": "flex",
|
|
13
|
-
"flexDirection": "column",
|
|
14
|
-
"margin": 0,
|
|
15
|
-
"minHeight": 0,
|
|
16
|
-
"minWidth": 0,
|
|
17
|
-
"padding": 0,
|
|
18
|
-
"position": "relative",
|
|
19
|
-
"zIndex": 0,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
>
|
|
23
|
-
<div
|
|
24
|
-
className=""
|
|
25
|
-
style={
|
|
26
|
-
Object {
|
|
27
|
-
"alignItems": "stretch",
|
|
28
|
-
"borderStyle": "solid",
|
|
29
|
-
"borderWidth": 0,
|
|
30
|
-
"boxSizing": "border-box",
|
|
31
|
-
"display": "flex",
|
|
32
|
-
"flexDirection": "column",
|
|
33
|
-
"margin": 0,
|
|
34
|
-
"minHeight": 0,
|
|
35
|
-
"minWidth": 0,
|
|
36
|
-
"padding": 0,
|
|
37
|
-
"position": "relative",
|
|
38
|
-
"zIndex": 0,
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
>
|
|
42
|
-
<span
|
|
43
|
-
className=""
|
|
44
|
-
style={
|
|
45
|
-
Object {
|
|
46
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
47
|
-
"WebkitFontSmoothing": "antialiased",
|
|
48
|
-
"display": "block",
|
|
49
|
-
"fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
|
|
50
|
-
"fontSize": 16,
|
|
51
|
-
"fontWeight": 400,
|
|
52
|
-
"lineHeight": "22px",
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
>
|
|
56
|
-
This request will succeed and give us data!
|
|
57
|
-
</span>
|
|
58
|
-
Loading...
|
|
59
|
-
</div>
|
|
60
|
-
<div
|
|
61
|
-
aria-hidden="true"
|
|
62
|
-
className=""
|
|
63
|
-
style={
|
|
64
|
-
Object {
|
|
65
|
-
"MsFlexBasis": 12,
|
|
66
|
-
"MsFlexPreferredSize": 12,
|
|
67
|
-
"WebkitFlexBasis": 12,
|
|
68
|
-
"alignItems": "stretch",
|
|
69
|
-
"borderStyle": "solid",
|
|
70
|
-
"borderWidth": 0,
|
|
71
|
-
"boxSizing": "border-box",
|
|
72
|
-
"display": "flex",
|
|
73
|
-
"flexBasis": 12,
|
|
74
|
-
"flexDirection": "column",
|
|
75
|
-
"flexShrink": 0,
|
|
76
|
-
"margin": 0,
|
|
77
|
-
"minHeight": 0,
|
|
78
|
-
"minWidth": 0,
|
|
79
|
-
"padding": 0,
|
|
80
|
-
"position": "relative",
|
|
81
|
-
"width": 12,
|
|
82
|
-
"zIndex": 0,
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
/>
|
|
86
|
-
<div
|
|
87
|
-
className=""
|
|
88
|
-
style={
|
|
89
|
-
Object {
|
|
90
|
-
"alignItems": "stretch",
|
|
91
|
-
"borderStyle": "solid",
|
|
92
|
-
"borderWidth": 0,
|
|
93
|
-
"boxSizing": "border-box",
|
|
94
|
-
"display": "flex",
|
|
95
|
-
"flexDirection": "column",
|
|
96
|
-
"margin": 0,
|
|
97
|
-
"minHeight": 0,
|
|
98
|
-
"minWidth": 0,
|
|
99
|
-
"padding": 0,
|
|
100
|
-
"position": "relative",
|
|
101
|
-
"zIndex": 0,
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
>
|
|
105
|
-
<span
|
|
106
|
-
className=""
|
|
107
|
-
style={
|
|
108
|
-
Object {
|
|
109
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
110
|
-
"WebkitFontSmoothing": "antialiased",
|
|
111
|
-
"display": "block",
|
|
112
|
-
"fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
|
|
113
|
-
"fontSize": 16,
|
|
114
|
-
"fontWeight": 400,
|
|
115
|
-
"lineHeight": "22px",
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
>
|
|
119
|
-
This request will go boom and give us an error!
|
|
120
|
-
</span>
|
|
121
|
-
Loading...
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
`;
|
|
125
|
-
|
|
126
|
-
exports[`wonder-blocks-data example 2 1`] = `
|
|
127
|
-
<div
|
|
128
|
-
className=""
|
|
129
|
-
style={
|
|
130
|
-
Object {
|
|
131
|
-
"alignItems": "stretch",
|
|
132
|
-
"borderStyle": "solid",
|
|
133
|
-
"borderWidth": 0,
|
|
134
|
-
"boxSizing": "border-box",
|
|
135
|
-
"display": "flex",
|
|
136
|
-
"flexDirection": "column",
|
|
137
|
-
"margin": 0,
|
|
138
|
-
"minHeight": 0,
|
|
139
|
-
"minWidth": 0,
|
|
140
|
-
"padding": 0,
|
|
141
|
-
"position": "relative",
|
|
142
|
-
"zIndex": 0,
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
>
|
|
146
|
-
<div
|
|
147
|
-
className=""
|
|
148
|
-
style={
|
|
149
|
-
Object {
|
|
150
|
-
"alignItems": "stretch",
|
|
151
|
-
"borderStyle": "solid",
|
|
152
|
-
"borderWidth": 0,
|
|
153
|
-
"boxSizing": "border-box",
|
|
154
|
-
"display": "flex",
|
|
155
|
-
"flexDirection": "column",
|
|
156
|
-
"margin": 0,
|
|
157
|
-
"minHeight": 0,
|
|
158
|
-
"minWidth": 0,
|
|
159
|
-
"padding": 0,
|
|
160
|
-
"position": "relative",
|
|
161
|
-
"zIndex": 0,
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
>
|
|
165
|
-
<span
|
|
166
|
-
className=""
|
|
167
|
-
style={
|
|
168
|
-
Object {
|
|
169
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
170
|
-
"WebkitFontSmoothing": "antialiased",
|
|
171
|
-
"display": "block",
|
|
172
|
-
"fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
|
|
173
|
-
"fontSize": 16,
|
|
174
|
-
"fontWeight": 400,
|
|
175
|
-
"lineHeight": "22px",
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
>
|
|
179
|
-
This cache has data!
|
|
180
|
-
</span>
|
|
181
|
-
<span
|
|
182
|
-
className=""
|
|
183
|
-
style={
|
|
184
|
-
Object {
|
|
185
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
186
|
-
"WebkitFontSmoothing": "antialiased",
|
|
187
|
-
"display": "block",
|
|
188
|
-
"fontFamily": "Inconsolata, monospace",
|
|
189
|
-
"fontSize": 17,
|
|
190
|
-
"fontWeight": 400,
|
|
191
|
-
"lineHeight": "22px",
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
>
|
|
195
|
-
I'm DATA from the hydration cache
|
|
196
|
-
</span>
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
`;
|
|
200
|
-
|
|
201
|
-
exports[`wonder-blocks-data example 3 1`] = `
|
|
202
|
-
<div
|
|
203
|
-
className=""
|
|
204
|
-
style={
|
|
205
|
-
Object {
|
|
206
|
-
"alignItems": "stretch",
|
|
207
|
-
"borderStyle": "solid",
|
|
208
|
-
"borderWidth": 0,
|
|
209
|
-
"boxSizing": "border-box",
|
|
210
|
-
"display": "flex",
|
|
211
|
-
"flexDirection": "column",
|
|
212
|
-
"margin": 0,
|
|
213
|
-
"minHeight": 0,
|
|
214
|
-
"minWidth": 0,
|
|
215
|
-
"padding": 0,
|
|
216
|
-
"position": "relative",
|
|
217
|
-
"zIndex": 0,
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
>
|
|
221
|
-
<span
|
|
222
|
-
className=""
|
|
223
|
-
style={
|
|
224
|
-
Object {
|
|
225
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
226
|
-
"WebkitFontSmoothing": "antialiased",
|
|
227
|
-
"display": "block",
|
|
228
|
-
"fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
|
|
229
|
-
"fontSize": 16,
|
|
230
|
-
"fontWeight": 400,
|
|
231
|
-
"lineHeight": "22px",
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
>
|
|
235
|
-
This received intercepted data!
|
|
236
|
-
</span>
|
|
237
|
-
If you see this, the example is broken!
|
|
238
|
-
</div>
|
|
239
|
-
`;
|
|
240
|
-
|
|
241
|
-
exports[`wonder-blocks-data example 4 1`] = `"Sorry, no snapshot for you"`;
|
|
242
|
-
|
|
243
|
-
exports[`wonder-blocks-data example 5 1`] = `
|
|
244
|
-
<div
|
|
245
|
-
className=""
|
|
246
|
-
style={
|
|
247
|
-
Object {
|
|
248
|
-
"alignItems": "stretch",
|
|
249
|
-
"borderStyle": "solid",
|
|
250
|
-
"borderWidth": 0,
|
|
251
|
-
"boxSizing": "border-box",
|
|
252
|
-
"display": "flex",
|
|
253
|
-
"flexDirection": "column",
|
|
254
|
-
"margin": 0,
|
|
255
|
-
"minHeight": 0,
|
|
256
|
-
"minWidth": 0,
|
|
257
|
-
"padding": 0,
|
|
258
|
-
"position": "relative",
|
|
259
|
-
"zIndex": 0,
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
>
|
|
263
|
-
<button
|
|
264
|
-
aria-disabled={false}
|
|
265
|
-
className=""
|
|
266
|
-
onBlur={[Function]}
|
|
267
|
-
onClick={[Function]}
|
|
268
|
-
onDragStart={[Function]}
|
|
269
|
-
onFocus={[Function]}
|
|
270
|
-
onKeyDown={[Function]}
|
|
271
|
-
onKeyUp={[Function]}
|
|
272
|
-
onMouseDown={[Function]}
|
|
273
|
-
onMouseEnter={[Function]}
|
|
274
|
-
onMouseLeave={[Function]}
|
|
275
|
-
onMouseUp={[Function]}
|
|
276
|
-
onTouchCancel={[Function]}
|
|
277
|
-
onTouchEnd={[Function]}
|
|
278
|
-
onTouchStart={[Function]}
|
|
279
|
-
role="button"
|
|
280
|
-
style={
|
|
281
|
-
Object {
|
|
282
|
-
"::MozFocusInner": Object {
|
|
283
|
-
"border": 0,
|
|
284
|
-
},
|
|
285
|
-
":focus": Object {
|
|
286
|
-
"WebkitTapHighlightColor": "rgba(0,0,0,0)",
|
|
287
|
-
},
|
|
288
|
-
"alignItems": "center",
|
|
289
|
-
"background": "#1865f2",
|
|
290
|
-
"border": "none",
|
|
291
|
-
"borderRadius": 4,
|
|
292
|
-
"boxSizing": "border-box",
|
|
293
|
-
"color": "#ffffff",
|
|
294
|
-
"cursor": "pointer",
|
|
295
|
-
"display": "inline-flex",
|
|
296
|
-
"height": 40,
|
|
297
|
-
"justifyContent": "center",
|
|
298
|
-
"margin": 0,
|
|
299
|
-
"outline": "none",
|
|
300
|
-
"paddingBottom": 0,
|
|
301
|
-
"paddingLeft": 16,
|
|
302
|
-
"paddingRight": 16,
|
|
303
|
-
"paddingTop": 0,
|
|
304
|
-
"position": "relative",
|
|
305
|
-
"textDecoration": "none",
|
|
306
|
-
"touchAction": "manipulation",
|
|
307
|
-
"userSelect": "none",
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
tabIndex={0}
|
|
311
|
-
type="button"
|
|
312
|
-
>
|
|
313
|
-
<span
|
|
314
|
-
className=""
|
|
315
|
-
style={
|
|
316
|
-
Object {
|
|
317
|
-
"MozOsxFontSmoothing": "grayscale",
|
|
318
|
-
"WebkitFontSmoothing": "antialiased",
|
|
319
|
-
"alignItems": "center",
|
|
320
|
-
"display": "inline-block",
|
|
321
|
-
"fontFamily": "Lato, \\"Noto Sans\\", sans-serif",
|
|
322
|
-
"fontSize": 16,
|
|
323
|
-
"fontWeight": "bold",
|
|
324
|
-
"lineHeight": "20px",
|
|
325
|
-
"overflow": "hidden",
|
|
326
|
-
"pointerEvents": "none",
|
|
327
|
-
"textOverflow": "ellipsis",
|
|
328
|
-
"whiteSpace": "nowrap",
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
>
|
|
332
|
-
Enable Server-side Mode
|
|
333
|
-
</span>
|
|
334
|
-
</button>
|
|
335
|
-
Sorry, no snapshot for you
|
|
336
|
-
</div>
|
|
337
|
-
`;
|
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
// This file is auto-generated by gen-snapshot-tests.js
|
|
2
|
-
// Do not edit this file. To make changes to these snapshot tests:
|
|
3
|
-
// 1. edit the markdown documentation files in the package,
|
|
4
|
-
// packages/wonder-blocks-data
|
|
5
|
-
// 2. Run `yarn run gen-snapshot-tests`.
|
|
6
|
-
import React from "react";
|
|
7
|
-
import renderer from "react-test-renderer";
|
|
8
|
-
|
|
9
|
-
// Mock react-dom as jest doesn't like findDOMNode.
|
|
10
|
-
jest.mock("react-dom");
|
|
11
|
-
import {Body, BodyMonospace} from "@khanacademy/wonder-blocks-typography";
|
|
12
|
-
import {View, Server} from "@khanacademy/wonder-blocks-core";
|
|
13
|
-
import {
|
|
14
|
-
Data,
|
|
15
|
-
initializeHydrationCache,
|
|
16
|
-
InterceptRequests,
|
|
17
|
-
TrackData,
|
|
18
|
-
fetchTrackedRequests,
|
|
19
|
-
} from "@khanacademy/wonder-blocks-data";
|
|
20
|
-
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
21
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
22
|
-
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
23
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
24
|
-
|
|
25
|
-
describe("wonder-blocks-data", () => {
|
|
26
|
-
it("example 1", () => {
|
|
27
|
-
const myValidHandler = () =>
|
|
28
|
-
new Promise((resolve, reject) =>
|
|
29
|
-
setTimeout(() => resolve("I'm DATA from a request"), 3000),
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const myInvalidHandler = () =>
|
|
33
|
-
new Promise((resolve, reject) =>
|
|
34
|
-
setTimeout(() => reject("I'm an ERROR from a request"), 3000),
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const example = (
|
|
38
|
-
<View>
|
|
39
|
-
<View>
|
|
40
|
-
<Body>This request will succeed and give us data!</Body>
|
|
41
|
-
<Data handler={myValidHandler} requestId="VALID">
|
|
42
|
-
{(result) => {
|
|
43
|
-
if (result.status === "loading") {
|
|
44
|
-
return "Loading...";
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return <BodyMonospace>{result.data}</BodyMonospace>;
|
|
48
|
-
}}
|
|
49
|
-
</Data>
|
|
50
|
-
</View>
|
|
51
|
-
<Strut size={Spacing.small_12} />
|
|
52
|
-
<View>
|
|
53
|
-
<Body>This request will go boom and give us an error!</Body>
|
|
54
|
-
<Data handler={myInvalidHandler} requestId="INVALID">
|
|
55
|
-
{(result) => {
|
|
56
|
-
if (result.status === "loading") {
|
|
57
|
-
return "Loading...";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<BodyMonospace
|
|
62
|
-
style={{
|
|
63
|
-
color: Color.red,
|
|
64
|
-
}}
|
|
65
|
-
>
|
|
66
|
-
ERROR: {result.error}
|
|
67
|
-
</BodyMonospace>
|
|
68
|
-
);
|
|
69
|
-
}}
|
|
70
|
-
</Data>
|
|
71
|
-
</View>
|
|
72
|
-
</View>
|
|
73
|
-
);
|
|
74
|
-
const tree = renderer.create(example).toJSON();
|
|
75
|
-
expect(tree).toMatchSnapshot();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("example 2", () => {
|
|
79
|
-
const myHandler = () => {
|
|
80
|
-
throw new Error(
|
|
81
|
-
"If you're seeing this error, the examples are broken and data isn't in the cache that should be.",
|
|
82
|
-
);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
initializeHydrationCache({
|
|
86
|
-
DATA: {
|
|
87
|
-
data: "I'm DATA from the hydration cache",
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
const example = (
|
|
91
|
-
<View>
|
|
92
|
-
<View>
|
|
93
|
-
<Body>This cache has data!</Body>
|
|
94
|
-
<Data handler={myHandler} requestId="DATA">
|
|
95
|
-
{(result) => {
|
|
96
|
-
if (result.status !== "success") {
|
|
97
|
-
return "If you see this, the example is broken!";
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return <BodyMonospace>{result.data}</BodyMonospace>;
|
|
101
|
-
}}
|
|
102
|
-
</Data>
|
|
103
|
-
</View>
|
|
104
|
-
</View>
|
|
105
|
-
);
|
|
106
|
-
const tree = renderer.create(example).toJSON();
|
|
107
|
-
expect(tree).toMatchSnapshot();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("example 3", () => {
|
|
111
|
-
const myHandler = () =>
|
|
112
|
-
Promise.reject(new Error("You should not see this!"));
|
|
113
|
-
|
|
114
|
-
const interceptor = (requestId) =>
|
|
115
|
-
requestId === "INTERCEPT_EXAMPLE"
|
|
116
|
-
? Promise.resolve("INTERCEPTED DATA!")
|
|
117
|
-
: null;
|
|
118
|
-
|
|
119
|
-
const example = (
|
|
120
|
-
<InterceptRequests interceptor={interceptor}>
|
|
121
|
-
<View>
|
|
122
|
-
<Body>This received intercepted data!</Body>
|
|
123
|
-
<Data handler={myHandler} requestId="INTERCEPT_EXAMPLE">
|
|
124
|
-
{(result) => {
|
|
125
|
-
if (result.status !== "success") {
|
|
126
|
-
return "If you see this, the example is broken!";
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return <BodyMonospace>{result.data}</BodyMonospace>;
|
|
130
|
-
}}
|
|
131
|
-
</Data>
|
|
132
|
-
</View>
|
|
133
|
-
</InterceptRequests>
|
|
134
|
-
);
|
|
135
|
-
const tree = renderer.create(example).toJSON();
|
|
136
|
-
expect(tree).toMatchSnapshot();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("example 4", () => {
|
|
140
|
-
class ErrorBoundary extends React.Component {
|
|
141
|
-
constructor(props) {
|
|
142
|
-
super(props);
|
|
143
|
-
this.state = {};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
static getDerivedStateFromError(error) {
|
|
147
|
-
return {
|
|
148
|
-
error: error.message,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
render() {
|
|
153
|
-
if (typeof jest !== "undefined") {
|
|
154
|
-
/**
|
|
155
|
-
* The snapshot test just sees the error getting thrown, not the
|
|
156
|
-
* awesome error boundary, so we have to hack around it to keep
|
|
157
|
-
* this live example, but not get test failures.
|
|
158
|
-
*/
|
|
159
|
-
return "Sorry, no snapshot for you";
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (this.state.error) {
|
|
163
|
-
return <View>{this.state.error}</View>;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return this.props.children;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const example = (
|
|
171
|
-
<ErrorBoundary>
|
|
172
|
-
<View>
|
|
173
|
-
<TrackData>
|
|
174
|
-
<Body>
|
|
175
|
-
This only renders if we're in server-side mode and
|
|
176
|
-
the page hot reloaded
|
|
177
|
-
</Body>
|
|
178
|
-
</TrackData>
|
|
179
|
-
</View>
|
|
180
|
-
</ErrorBoundary>
|
|
181
|
-
);
|
|
182
|
-
const tree = renderer.create(example).toJSON();
|
|
183
|
-
expect(tree).toMatchSnapshot();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("example 5", () => {
|
|
187
|
-
const myPretendHandler = () =>
|
|
188
|
-
new Promise((resolve, reject) =>
|
|
189
|
-
setTimeout(() => resolve("DATA!"), 3000),
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
class Example extends React.Component {
|
|
193
|
-
constructor() {
|
|
194
|
-
super();
|
|
195
|
-
/**
|
|
196
|
-
* For this demonstration, we need to hack the return of isServerSide solely
|
|
197
|
-
* for the scope of this component.
|
|
198
|
-
*/
|
|
199
|
-
|
|
200
|
-
this.state = {};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
static getDerivedStateFromError(error) {
|
|
204
|
-
return {
|
|
205
|
-
error,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
componentDidMount() {
|
|
210
|
-
this._mounted = true;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
componentWillUnmount() {
|
|
214
|
-
this._mounted = false;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
setClientMode() {
|
|
218
|
-
window.location.reload();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
setServerMode() {
|
|
222
|
-
Server.setServerSide();
|
|
223
|
-
this.setState({
|
|
224
|
-
refresh: Date.now(),
|
|
225
|
-
error: null,
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
_renderErrorOrContent() {
|
|
230
|
-
if (typeof jest !== "undefined") {
|
|
231
|
-
/**
|
|
232
|
-
* The snapshot test just sees the error getting thrown, not the
|
|
233
|
-
* awesome error boundary, so we have to hack around it to keep
|
|
234
|
-
* this live example, but not get test failures.
|
|
235
|
-
*/
|
|
236
|
-
return "Sorry, no snapshot for you";
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (this.state.error) {
|
|
240
|
-
return (
|
|
241
|
-
<React.Fragment>
|
|
242
|
-
<Strut size={Spacing.small_12} />
|
|
243
|
-
<Body>
|
|
244
|
-
We can't show you anything useful in client-side
|
|
245
|
-
mode
|
|
246
|
-
</Body>
|
|
247
|
-
</React.Fragment>
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const data = this.state.data
|
|
252
|
-
? JSON.stringify(this.state.data, undefined, " ")
|
|
253
|
-
: "Data requested...";
|
|
254
|
-
return (
|
|
255
|
-
<React.Fragment>
|
|
256
|
-
<Strut size={Spacing.small_12} />
|
|
257
|
-
<TrackData>
|
|
258
|
-
<Data
|
|
259
|
-
handler={myPretendHandler}
|
|
260
|
-
requestId="TRACK_DATA_EXAMPLE"
|
|
261
|
-
>
|
|
262
|
-
{(result) => (
|
|
263
|
-
<View>
|
|
264
|
-
<BodyMonospace>{`Loading: ${
|
|
265
|
-
result.status === "loading"
|
|
266
|
-
}`}</BodyMonospace>
|
|
267
|
-
<BodyMonospace>{`Data: ${JSON.stringify(
|
|
268
|
-
result.data,
|
|
269
|
-
)}`}</BodyMonospace>
|
|
270
|
-
</View>
|
|
271
|
-
)}
|
|
272
|
-
</Data>
|
|
273
|
-
</TrackData>
|
|
274
|
-
<Strut size={Spacing.small_12} />
|
|
275
|
-
<View>
|
|
276
|
-
<Body>
|
|
277
|
-
The above components requested data, but we're
|
|
278
|
-
server-side, so all that happened is we tracked
|
|
279
|
-
the request. In this example, we've also called
|
|
280
|
-
`fetchTrackedRequests` to fetch that tracked
|
|
281
|
-
data.
|
|
282
|
-
</Body>
|
|
283
|
-
<Strut size={Spacing.small_12} />
|
|
284
|
-
<Body>
|
|
285
|
-
In about 3 seconds, it will appear below. Notice
|
|
286
|
-
that when it does, the above still doesn't
|
|
287
|
-
update. That's because during SSR, the data is
|
|
288
|
-
not updated in the rendered tree.
|
|
289
|
-
</Body>
|
|
290
|
-
<Strut size={Spacing.small_12} />
|
|
291
|
-
<BodyMonospace>{data}</BodyMonospace>
|
|
292
|
-
</View>
|
|
293
|
-
</React.Fragment>
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
render() {
|
|
298
|
-
try {
|
|
299
|
-
return (
|
|
300
|
-
<View key={this.state.refresh}>
|
|
301
|
-
{Server.isServerSide() ? (
|
|
302
|
-
<React.Fragment>
|
|
303
|
-
<Button
|
|
304
|
-
kind={"secondary"}
|
|
305
|
-
onClick={() => this.setClientMode()}
|
|
306
|
-
>
|
|
307
|
-
Back to Client-side Mode (reloads page)
|
|
308
|
-
</Button>
|
|
309
|
-
<Strut size={Spacing.small_12} />
|
|
310
|
-
<Button
|
|
311
|
-
kind={"secondary"}
|
|
312
|
-
onClick={() => this.setServerMode()}
|
|
313
|
-
>
|
|
314
|
-
Re-mount
|
|
315
|
-
</Button>
|
|
316
|
-
</React.Fragment>
|
|
317
|
-
) : (
|
|
318
|
-
<Button
|
|
319
|
-
kind={"primary"}
|
|
320
|
-
onClick={() => this.setServerMode()}
|
|
321
|
-
>
|
|
322
|
-
Enable Server-side Mode
|
|
323
|
-
</Button>
|
|
324
|
-
)}
|
|
325
|
-
{this._renderErrorOrContent()}
|
|
326
|
-
</View>
|
|
327
|
-
);
|
|
328
|
-
} finally {
|
|
329
|
-
if (!this.state.data && Server.isServerSide()) {
|
|
330
|
-
setTimeout(
|
|
331
|
-
() =>
|
|
332
|
-
fetchTrackedRequests().then((data) => {
|
|
333
|
-
if (this._mounted) {
|
|
334
|
-
this.setState({
|
|
335
|
-
data,
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
}),
|
|
339
|
-
0,
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const example = <Example />;
|
|
347
|
-
const tree = renderer.create(example).toJSON();
|
|
348
|
-
expect(tree).toMatchSnapshot();
|
|
349
|
-
});
|
|
350
|
-
});
|