@salesforce/pwa-kit-react-sdk 3.8.0-preview.0-basepath → 3.8.0-preview.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 +3 -7
- package/package.json +6 -5
- package/ssr/browser/main.js +130 -0
- package/ssr/browser/main.test.js +54 -0
- package/ssr/server/react-rendering.js +434 -0
- package/ssr/server/react-rendering.test.js +745 -0
- package/ssr/universal/compatibility.js +31 -0
- package/ssr/universal/components/_app/index.js +35 -0
- package/ssr/universal/components/_app/index.test.js +20 -0
- package/ssr/universal/components/_app-config/index.js +87 -0
- package/ssr/universal/components/_app-config/index.test.js +21 -0
- package/ssr/universal/components/_document/index.js +92 -0
- package/ssr/universal/components/_document/index.test.js +58 -0
- package/ssr/universal/components/_error/index.js +55 -0
- package/ssr/universal/components/_error/index.test.js +28 -0
- package/ssr/universal/components/app-error-boundary/index.js +113 -0
- package/ssr/universal/components/app-error-boundary/index.test.js +109 -0
- package/ssr/universal/components/fetch-strategy/index.js +42 -0
- package/ssr/universal/components/refresh/index.js +123 -0
- package/ssr/universal/components/refresh/index.test.js +78 -0
- package/ssr/universal/components/route-component/index.js +415 -0
- package/ssr/universal/components/route-component/index.test.js +378 -0
- package/ssr/universal/components/switch/index.js +62 -0
- package/ssr/universal/components/throw-404/index.js +36 -0
- package/ssr/universal/components/throw-404/index.test.js +26 -0
- package/ssr/universal/components/with-correlation-id/index.js +36 -0
- package/ssr/universal/components/with-legacy-get-props/index.js +100 -0
- package/ssr/universal/components/with-legacy-get-props/index.test.js +35 -0
- package/ssr/universal/components/with-react-query/index.js +130 -0
- package/ssr/universal/components/with-react-query/index.test.js +101 -0
- package/ssr/universal/contexts/index.js +72 -0
- package/ssr/universal/contexts/index.test.js +101 -0
- package/ssr/universal/errors.js +34 -0
- package/ssr/universal/errors.test.js +20 -0
- package/ssr/universal/events.js +38 -0
- package/ssr/universal/events.test.js +39 -0
- package/ssr/universal/hooks/index.js +84 -0
- package/ssr/universal/routes.js +15 -0
- package/ssr/universal/utils.client.test.js +46 -0
- package/ssr/universal/utils.js +61 -0
- package/ssr/universal/utils.server.test.js +24 -0
- package/utils/assets.js +120 -0
- package/utils/assets.test.js +106 -0
- package/utils/logger-instance.js +19 -0
- package/utils/performance.js +126 -0
- package/utils/performance.test.js +50 -0
- package/utils/url.js +41 -0
- package/utils/url.test.js +47 -0
- package/utils/uuidv4.client.js +21 -0
- package/utils/uuidv4.client.test.js +27 -0
- package/utils/warnings.js +81 -0
- package/utils/warnings.test.js +48 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _index = require("./index");
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
8
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
9
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
10
|
+
* All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
12
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
+
*/
|
|
14
|
+
// TODO: The way mocks are set up in this file is kinda weird...
|
|
15
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
16
|
+
|
|
17
|
+
const delay = t => new Promise(resolve => setTimeout(resolve, t));
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Return a mock that returns true, false, false, false, which is what
|
|
21
|
+
* we want when testing shouldGetProps – always returning true would cause
|
|
22
|
+
* an infinite loop.
|
|
23
|
+
*/
|
|
24
|
+
const trueOnceThenFalse = () => jest.fn().mockReturnValue(false).mockReturnValueOnce(true);
|
|
25
|
+
const falseOnceThenTrue = () => jest.fn().mockReturnValue(true).mockReturnValueOnce(false);
|
|
26
|
+
jest.mock('../_app-config', () => {
|
|
27
|
+
const React = require('react');
|
|
28
|
+
const PropTypes = require('prop-types');
|
|
29
|
+
const MockAppConfig = () => /*#__PURE__*/React.createElement("h1", null, "MockAppConfig");
|
|
30
|
+
MockAppConfig.freeze = jest.fn(() => ({
|
|
31
|
+
frozen: 'frozen'
|
|
32
|
+
}));
|
|
33
|
+
MockAppConfig.restore = jest.fn(() => undefined);
|
|
34
|
+
MockAppConfig.extraGetPropsArgs = jest.fn(() => ({
|
|
35
|
+
anotherArg: 'anotherArg'
|
|
36
|
+
}));
|
|
37
|
+
MockAppConfig.propTypes = {
|
|
38
|
+
children: PropTypes.node
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
__esModule: true,
|
|
42
|
+
default: MockAppConfig
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
jest.mock('../../routes', () => {
|
|
46
|
+
const React = require('react');
|
|
47
|
+
const PropTypes = require('prop-types');
|
|
48
|
+
const Component = ({
|
|
49
|
+
children
|
|
50
|
+
}) => /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h1", null, "This is the root"), children);
|
|
51
|
+
Component.propTypes = {
|
|
52
|
+
children: PropTypes.node
|
|
53
|
+
};
|
|
54
|
+
return [{
|
|
55
|
+
path: '',
|
|
56
|
+
component: Component,
|
|
57
|
+
exact: true
|
|
58
|
+
}];
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// NOTE: `react-router-dom` is being mocked because I was not able to get around the
|
|
62
|
+
// issue where you can't use a `withRoute` HoC outside of a Router component for this
|
|
63
|
+
// specific test. TODO: Revisit this, so that we don't have to mock `react-router-dom`
|
|
64
|
+
jest.mock('react-router-dom', () => {
|
|
65
|
+
const React = require('react');
|
|
66
|
+
const hoistNonReactStatic = require('hoist-non-react-statics');
|
|
67
|
+
const withRouter = Wrapped => {
|
|
68
|
+
const wrappedComponentName = Wrapped.displayName || Wrapped.name;
|
|
69
|
+
const WithRouter = props => /*#__PURE__*/React.createElement(Wrapped, props);
|
|
70
|
+
hoistNonReactStatic(WithRouter, Wrapped);
|
|
71
|
+
WithRouter.displayName = `withRouter(${wrappedComponentName})`;
|
|
72
|
+
return WithRouter;
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
__esModule: true,
|
|
76
|
+
default: {},
|
|
77
|
+
withRouter
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
const getMockComponent = () => {
|
|
81
|
+
const MockComponent = () => /*#__PURE__*/_react.default.createElement("p", null, "MockComponent");
|
|
82
|
+
MockComponent.displayName = 'MockComponent';
|
|
83
|
+
MockComponent.shouldGetProps = trueOnceThenFalse();
|
|
84
|
+
MockComponent.getProps = jest.fn(() => {
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
});
|
|
87
|
+
MockComponent.getTemplateName = jest.fn(() => 'MockComponent');
|
|
88
|
+
return MockComponent;
|
|
89
|
+
};
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
delete global.__HYDRATING__;
|
|
92
|
+
});
|
|
93
|
+
describe('The routeComponent component', () => {
|
|
94
|
+
test('Is a higher-order component', () => {
|
|
95
|
+
const Mock = getMockComponent();
|
|
96
|
+
const Component = (0, _index.routeComponent)(Mock);
|
|
97
|
+
(0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
98
|
+
isHydrating: false
|
|
99
|
+
}));
|
|
100
|
+
expect(_react2.screen.getByText(/mockComponent/i)).toBeInTheDocument();
|
|
101
|
+
});
|
|
102
|
+
test('Should call getProps on components at the right times during updates/rendering', () => {
|
|
103
|
+
const Mock = getMockComponent();
|
|
104
|
+
const Component = (0, _index.routeComponent)(Mock);
|
|
105
|
+
Component.displayName = 'routeComponent';
|
|
106
|
+
expect(Mock.shouldGetProps.mock.calls).toHaveLength(0);
|
|
107
|
+
expect(Mock.getProps.mock.calls).toHaveLength(0);
|
|
108
|
+
let wrapper;
|
|
109
|
+
return Promise.resolve().then(() => {
|
|
110
|
+
// Mock Hydrating Start
|
|
111
|
+
global.__HYDRATING__ = true;
|
|
112
|
+
}).then(() => {
|
|
113
|
+
// Simulate the initial client-side mount (hydrating=true)
|
|
114
|
+
return new Promise(resolve => {
|
|
115
|
+
wrapper = (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
116
|
+
history: {
|
|
117
|
+
location: {
|
|
118
|
+
pathname: '/home/'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
onUpdateComplete: resolve
|
|
122
|
+
}));
|
|
123
|
+
});
|
|
124
|
+
}).then(() => {
|
|
125
|
+
expect(Mock.shouldGetProps.mock.calls).toHaveLength(0);
|
|
126
|
+
expect(Mock.getProps.mock.calls).toHaveLength(0);
|
|
127
|
+
}).then(() => {
|
|
128
|
+
// Mock Hydrating Complete
|
|
129
|
+
global.__HYDRATING__ = false;
|
|
130
|
+
}).then(() => {
|
|
131
|
+
// Simulate visiting a different URL, which should trigger shouldMount() and getProps()
|
|
132
|
+
return new Promise(resolve => {
|
|
133
|
+
wrapper.rerender( /*#__PURE__*/_react.default.createElement(Component, {
|
|
134
|
+
history: {
|
|
135
|
+
location: {
|
|
136
|
+
pathname: '/plp/'
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
onUpdateComplete: resolve
|
|
140
|
+
}));
|
|
141
|
+
});
|
|
142
|
+
}).then(() => {
|
|
143
|
+
expect(Mock.shouldGetProps.mock.calls).toHaveLength(1);
|
|
144
|
+
expect(Mock.getProps.mock.calls).toHaveLength(1);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
test('Provides defaults for getProps(), shouldGetProps() and getTemplateName()', () => {
|
|
148
|
+
const ComponentWithoutStatics = () => /*#__PURE__*/_react.default.createElement("p", null, "ComponentWithoutStatics");
|
|
149
|
+
const Component = (0, _index.routeComponent)(ComponentWithoutStatics);
|
|
150
|
+
const l1 = {
|
|
151
|
+
pathname: '/location-one/'
|
|
152
|
+
};
|
|
153
|
+
const l2 = {
|
|
154
|
+
pathname: '/location-two/'
|
|
155
|
+
};
|
|
156
|
+
const checks = [Component.shouldGetProps({
|
|
157
|
+
previousLocation: l1,
|
|
158
|
+
location: l1
|
|
159
|
+
}).then(v => expect(v).toBe(false)), Component.shouldGetProps({
|
|
160
|
+
previousLocation: l1,
|
|
161
|
+
location: l2
|
|
162
|
+
}).then(v => expect(v).toBe(true)), Component.getTemplateName().then(v => expect(v).toBe('ComponentWithoutStatics')), Component.getProps().then(result => expect(result).toBeUndefined())];
|
|
163
|
+
expect.assertions(checks.length);
|
|
164
|
+
return Promise.all(checks);
|
|
165
|
+
});
|
|
166
|
+
test('Allows the wrapped component to override getProps(), shouldGetProps and getTemplateName()', () => {
|
|
167
|
+
class Mock extends _react.default.Component {
|
|
168
|
+
static shouldGetProps({
|
|
169
|
+
location
|
|
170
|
+
}) {
|
|
171
|
+
return location.pathname === '/should-get-props/';
|
|
172
|
+
}
|
|
173
|
+
static getProps() {
|
|
174
|
+
return Promise.resolve('overridden-get-props');
|
|
175
|
+
}
|
|
176
|
+
static getTemplateName() {
|
|
177
|
+
return 'overriden-template-name';
|
|
178
|
+
}
|
|
179
|
+
render() {
|
|
180
|
+
return /*#__PURE__*/_react.default.createElement("div", null, "Mock");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const Component = (0, _index.routeComponent)(Mock);
|
|
184
|
+
const l1 = {
|
|
185
|
+
pathname: '/location-one/'
|
|
186
|
+
};
|
|
187
|
+
const l2 = {
|
|
188
|
+
pathname: '/location-two/'
|
|
189
|
+
};
|
|
190
|
+
const l3 = {
|
|
191
|
+
pathname: '/should-get-props/'
|
|
192
|
+
};
|
|
193
|
+
const checks = [Component.shouldGetProps({
|
|
194
|
+
previousLocation: l1,
|
|
195
|
+
location: l1
|
|
196
|
+
}).then(v => expect(v).toBe(false)), Component.shouldGetProps({
|
|
197
|
+
previousLocation: l1,
|
|
198
|
+
location: l2
|
|
199
|
+
}).then(v => expect(v).toBe(false)), Component.shouldGetProps({
|
|
200
|
+
previousLocation: l1,
|
|
201
|
+
location: l3
|
|
202
|
+
}).then(v => expect(v).toBe(true)), Component.getTemplateName().then(v => expect(v).toBe('overriden-template-name')), Component.getProps().then(v => expect(v).toBe('overridden-get-props'))];
|
|
203
|
+
expect.assertions(checks.length);
|
|
204
|
+
return Promise.all(checks);
|
|
205
|
+
});
|
|
206
|
+
test(`Catches and calls onGetPropsError() when getProps throws`, () => {
|
|
207
|
+
const error = 'throwErrorText';
|
|
208
|
+
const Mock = () => /*#__PURE__*/_react.default.createElement("div", null, "Mock");
|
|
209
|
+
Mock.shouldGetProps = trueOnceThenFalse();
|
|
210
|
+
Mock.getProps = () => {
|
|
211
|
+
throw error;
|
|
212
|
+
};
|
|
213
|
+
const Component = (0, _index.routeComponent)(Mock, {}, true);
|
|
214
|
+
return new Promise(resolve => (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
215
|
+
isHydrating: false,
|
|
216
|
+
onGetPropsError: resolve
|
|
217
|
+
}))).then(caught => expect(caught).toBe(error));
|
|
218
|
+
});
|
|
219
|
+
test(`Catches and calls onGetPropsError() when getProps rejects`, () => {
|
|
220
|
+
const errorText = 'rejectErrorText';
|
|
221
|
+
const Mock = () => /*#__PURE__*/_react.default.createElement("div", null, "Mock");
|
|
222
|
+
Mock.shouldGetProps = trueOnceThenFalse();
|
|
223
|
+
Mock.getProps = () => delay(10).then(() => Promise.reject(errorText));
|
|
224
|
+
const Component = (0, _index.routeComponent)(Mock);
|
|
225
|
+
return new Promise(resolve => (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
226
|
+
isHydrating: false,
|
|
227
|
+
onGetPropsError: resolve
|
|
228
|
+
}))).then(caught => expect(caught).toBe(errorText));
|
|
229
|
+
});
|
|
230
|
+
test(`Passes props returned from getProps to the wrapped component`, /*#__PURE__*/_asyncToGenerator(function* () {
|
|
231
|
+
const initialProps = {
|
|
232
|
+
foo: 'bar'
|
|
233
|
+
};
|
|
234
|
+
const Mock = props => /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", {
|
|
235
|
+
"data-testid": "props"
|
|
236
|
+
}, JSON.stringify(props)));
|
|
237
|
+
Mock.displayName = 'MockComponent';
|
|
238
|
+
Mock.getProps = () => delay(150).then(() => initialProps);
|
|
239
|
+
Mock.shouldGetProps = trueOnceThenFalse();
|
|
240
|
+
const Component = (0, _index.routeComponent)(Mock, {}, true);
|
|
241
|
+
yield new Promise(resolve => {
|
|
242
|
+
(0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
243
|
+
onUpdateComplete: () => {
|
|
244
|
+
resolve();
|
|
245
|
+
}
|
|
246
|
+
}));
|
|
247
|
+
});
|
|
248
|
+
yield (0, _react2.waitFor)(() => {
|
|
249
|
+
expect(_react2.screen.getByTestId('props').innerHTML).toEqual(JSON.stringify({
|
|
250
|
+
foo: 'bar',
|
|
251
|
+
isLoading: false
|
|
252
|
+
}));
|
|
253
|
+
});
|
|
254
|
+
}));
|
|
255
|
+
});
|
|
256
|
+
describe('getRoutes', () => {
|
|
257
|
+
test('wraps components with the routeComponent HOC', () => {
|
|
258
|
+
const mappedRoutes = (0, _index.getRoutes)();
|
|
259
|
+
expect(mappedRoutes).toHaveLength(3);
|
|
260
|
+
const [first, second, third] = mappedRoutes;
|
|
261
|
+
const expectedRefetchName = 'WithErrorHandling(withRouter(routeComponent(Refresh)))';
|
|
262
|
+
expect(first.component.displayName).toBe(expectedRefetchName);
|
|
263
|
+
const expectedName = 'WithErrorHandling(withRouter(routeComponent(Component)))';
|
|
264
|
+
expect(second.component.displayName).toBe(expectedName);
|
|
265
|
+
const expected404Name = 'WithErrorHandling(withRouter(routeComponent(Throw404)))';
|
|
266
|
+
expect(third.component.displayName).toBe(expected404Name);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* A race condition is created when a user clicks two links for the same
|
|
272
|
+
* component. If the getProps call for the second link resolves before the
|
|
273
|
+
* first, we want to make sure the results of the first are ignored. In this
|
|
274
|
+
* test we rerender returned from first rendering twice to trigger getProps calls and make sure only the
|
|
275
|
+
* second one updates the component.
|
|
276
|
+
*/
|
|
277
|
+
describe('Handles race conditions for getProps', () => {
|
|
278
|
+
test(`unresolved calls to 'getProps' are squashed by new new calls`, /*#__PURE__*/_asyncToGenerator(function* () {
|
|
279
|
+
const renderFunc = jest.fn();
|
|
280
|
+
|
|
281
|
+
// We can't inspect the render directly, so include this mock function
|
|
282
|
+
// in the render and inspect that
|
|
283
|
+
// eslint-disable-next-line react/prop-types
|
|
284
|
+
const MockComponent = ({
|
|
285
|
+
callId
|
|
286
|
+
}) => /*#__PURE__*/_react.default.createElement("p", null, renderFunc(callId));
|
|
287
|
+
// Skip getProps on mount by returning false the first time
|
|
288
|
+
MockComponent.shouldGetProps = falseOnceThenTrue();
|
|
289
|
+
MockComponent.getProps = jest.fn().mockImplementationOnce(() => Promise.resolve({
|
|
290
|
+
callId: 1
|
|
291
|
+
})).mockImplementationOnce(() => Promise.resolve({
|
|
292
|
+
callId: 2
|
|
293
|
+
}));
|
|
294
|
+
const Component = (0, _index.routeComponent)(MockComponent, {}, true);
|
|
295
|
+
let resolver = [];
|
|
296
|
+
let wrapper;
|
|
297
|
+
const onUpdateComplete = () => {
|
|
298
|
+
const r = resolver.pop();
|
|
299
|
+
if (r) {
|
|
300
|
+
r(wrapper);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
yield new Promise(resolve => {
|
|
304
|
+
resolver.push(resolve);
|
|
305
|
+
wrapper = (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
306
|
+
onUpdateComplete: onUpdateComplete
|
|
307
|
+
}));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Update the wrappers props 2 times in succession, this will cause `getProps` to be called
|
|
311
|
+
// twice, but only the later should call `setStateAsync` causing a re-render.
|
|
312
|
+
const p1 = new Promise(resolve => {
|
|
313
|
+
resolver.push(resolve);
|
|
314
|
+
wrapper.rerender( /*#__PURE__*/_react.default.createElement(Component, {
|
|
315
|
+
onUpdateComplete: onUpdateComplete
|
|
316
|
+
}));
|
|
317
|
+
});
|
|
318
|
+
const p2 = new Promise(resolve => {
|
|
319
|
+
resolver.push(resolve);
|
|
320
|
+
wrapper.rerender( /*#__PURE__*/_react.default.createElement(Component, {
|
|
321
|
+
onUpdateComplete: onUpdateComplete
|
|
322
|
+
}));
|
|
323
|
+
});
|
|
324
|
+
yield Promise.all([p1, p2]);
|
|
325
|
+
expect(MockComponent.getProps.mock.calls).toHaveLength(2);
|
|
326
|
+
expect(renderFunc).not.toHaveBeenCalledWith(1);
|
|
327
|
+
expect(renderFunc).toHaveBeenCalledWith(2);
|
|
328
|
+
}));
|
|
329
|
+
});
|
|
330
|
+
describe('Uses preloaded props on initial clientside page load', () => {
|
|
331
|
+
test('Uses preloadedProps when hydrating', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
332
|
+
global.__HYDRATING__ = true;
|
|
333
|
+
const preloadedProps = {
|
|
334
|
+
foo: 'bar'
|
|
335
|
+
};
|
|
336
|
+
const expectedPreloadedChildProps = {
|
|
337
|
+
foo: 'bar',
|
|
338
|
+
isLoading: false
|
|
339
|
+
};
|
|
340
|
+
const Mock = props => /*#__PURE__*/_react.default.createElement("div", {
|
|
341
|
+
"data-testid": "props"
|
|
342
|
+
}, JSON.stringify(props));
|
|
343
|
+
Mock.displayName = 'MockComponent';
|
|
344
|
+
const Component = (0, _index.routeComponent)(Mock, true, {});
|
|
345
|
+
yield new Promise(resolve => {
|
|
346
|
+
const wrapper = (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
347
|
+
preloadedProps: preloadedProps,
|
|
348
|
+
onUpdateComplete: () => resolve(wrapper)
|
|
349
|
+
}));
|
|
350
|
+
});
|
|
351
|
+
yield (0, _react2.waitFor)(() => {
|
|
352
|
+
expect(_react2.screen.getByTestId('props').innerHTML).toEqual(JSON.stringify(expectedPreloadedChildProps));
|
|
353
|
+
});
|
|
354
|
+
}));
|
|
355
|
+
test('Does not use preloadedProps when not hydrating', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
356
|
+
global.__HYDRATING__ = false;
|
|
357
|
+
const preloadedProps = {
|
|
358
|
+
foo: 'bar'
|
|
359
|
+
};
|
|
360
|
+
const expectedNotPreloadedChildProps = {
|
|
361
|
+
isLoading: false
|
|
362
|
+
};
|
|
363
|
+
const Mock = props => /*#__PURE__*/_react.default.createElement("div", {
|
|
364
|
+
"data-testid": "props"
|
|
365
|
+
}, JSON.stringify(props));
|
|
366
|
+
Mock.displayName = 'MockComponent';
|
|
367
|
+
const Component = (0, _index.routeComponent)(Mock, true, {});
|
|
368
|
+
yield new Promise(resolve => {
|
|
369
|
+
const wrapper = (0, _react2.render)( /*#__PURE__*/_react.default.createElement(Component, {
|
|
370
|
+
preloadedProps: preloadedProps,
|
|
371
|
+
onUpdateComplete: () => resolve(wrapper)
|
|
372
|
+
}));
|
|
373
|
+
});
|
|
374
|
+
yield (0, _react2.waitFor)(() => {
|
|
375
|
+
expect(_react2.screen.getByTestId('props').innerHTML).toEqual(JSON.stringify(expectedNotPreloadedChildProps));
|
|
376
|
+
});
|
|
377
|
+
}));
|
|
378
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
|
+
var _reactRouterDom = require("react-router-dom");
|
|
10
|
+
var _appErrorBoundary = _interopRequireDefault(require("../app-error-boundary"));
|
|
11
|
+
var _reactUid = require("react-uid");
|
|
12
|
+
const _excluded = ["component"];
|
|
13
|
+
/*
|
|
14
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
15
|
+
* All rights reserved.
|
|
16
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
17
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
18
|
+
*/
|
|
19
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
21
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
22
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
|
|
23
|
+
/**
|
|
24
|
+
* The Switch component packages up the bits of rendering that are shared between
|
|
25
|
+
* server and client-side. It's *mostly* a react-router Switch component, hence the
|
|
26
|
+
* name.
|
|
27
|
+
*
|
|
28
|
+
* This is for internal use only.
|
|
29
|
+
*
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
const Switch = props => {
|
|
33
|
+
const {
|
|
34
|
+
error,
|
|
35
|
+
appState,
|
|
36
|
+
routes,
|
|
37
|
+
App
|
|
38
|
+
} = props;
|
|
39
|
+
return /*#__PURE__*/_react.default.createElement(_reactUid.UIDReset, null, /*#__PURE__*/_react.default.createElement(_appErrorBoundary.default, {
|
|
40
|
+
error: error
|
|
41
|
+
}, !error && /*#__PURE__*/_react.default.createElement(App, {
|
|
42
|
+
preloadedProps: appState.appProps
|
|
43
|
+
}, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Switch, null, routes.map((route, i) => {
|
|
44
|
+
const {
|
|
45
|
+
component: Component
|
|
46
|
+
} = route,
|
|
47
|
+
routeProps = _objectWithoutProperties(route, _excluded);
|
|
48
|
+
return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Route, _extends({
|
|
49
|
+
key: i
|
|
50
|
+
}, routeProps), /*#__PURE__*/_react.default.createElement(_reactUid.UIDFork, null, /*#__PURE__*/_react.default.createElement(Component, {
|
|
51
|
+
preloadedProps: appState.pageProps
|
|
52
|
+
})));
|
|
53
|
+
})))));
|
|
54
|
+
};
|
|
55
|
+
Switch.propTypes = {
|
|
56
|
+
error: _propTypes.default.object,
|
|
57
|
+
appState: _propTypes.default.object,
|
|
58
|
+
routes: _propTypes.default.array,
|
|
59
|
+
App: _propTypes.default.func,
|
|
60
|
+
preloadedProps: _propTypes.default.object
|
|
61
|
+
};
|
|
62
|
+
var _default = exports.default = Switch;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var errors = _interopRequireWildcard(require("../../errors"));
|
|
9
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
10
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/*
|
|
13
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
14
|
+
* All rights reserved.
|
|
15
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
16
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* This is designed to be put into a react-router config as a fallback
|
|
21
|
+
* with path="*", simply to trigger the normal error handling code we have.
|
|
22
|
+
* As a result, this component should never be rendered – it should
|
|
23
|
+
* trigger the error page instead.
|
|
24
|
+
*
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
class Throw404 extends _react.default.Component {
|
|
28
|
+
static getProps() {
|
|
29
|
+
throw new errors.HTTPNotFound('Not found');
|
|
30
|
+
}
|
|
31
|
+
render() {
|
|
32
|
+
// This should be unreachable
|
|
33
|
+
return /*#__PURE__*/_react.default.createElement("div", null);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
var _default = exports.default = Throw404;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _index = _interopRequireDefault(require("./index"));
|
|
6
|
+
var errors = _interopRequireWildcard(require("../../errors"));
|
|
7
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
8
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/*
|
|
11
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
12
|
+
* All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
14
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
describe('Throw404', () => {
|
|
18
|
+
test('Renders correctly', () => {
|
|
19
|
+
(0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.default, null));
|
|
20
|
+
const content = document.querySelector('body').firstElementChild.innerHTML;
|
|
21
|
+
expect(content).toBe('<div></div>');
|
|
22
|
+
});
|
|
23
|
+
test('Throws on getProps', () => {
|
|
24
|
+
expect(() => _index.default.getProps()).toThrow(errors.HTTPNotFound);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.withCorrelationId = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _hooks = require("../../hooks");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
function _objectDestructuringEmpty(t) { if (null == t) throw new TypeError("Cannot destructure " + t); }
|
|
11
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /*
|
|
12
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
13
|
+
* All rights reserved.
|
|
14
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
15
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* An HOC that injects the correlation id to a component
|
|
19
|
+
* @param Component
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
const withCorrelationId = Component => {
|
|
23
|
+
const wrappedComponentName = Component.displayName || Component.name;
|
|
24
|
+
const WrappedComponent = _ref => {
|
|
25
|
+
let passThroughProps = _extends({}, (_objectDestructuringEmpty(_ref), _ref));
|
|
26
|
+
const {
|
|
27
|
+
correlationId
|
|
28
|
+
} = (0, _hooks.useCorrelationId)();
|
|
29
|
+
return /*#__PURE__*/_react.default.createElement(Component, _extends({}, passThroughProps, {
|
|
30
|
+
correlationId: correlationId
|
|
31
|
+
}));
|
|
32
|
+
};
|
|
33
|
+
WrappedComponent.displayName = `withCorrelationId(${wrappedComponentName})`;
|
|
34
|
+
return WrappedComponent;
|
|
35
|
+
};
|
|
36
|
+
exports.withCorrelationId = withCorrelationId;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.withLegacyGetProps = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-statics"));
|
|
9
|
+
var _fetchStrategy = require("../fetch-strategy");
|
|
10
|
+
var _performance = require("../../../../utils/performance");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
13
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
14
|
+
* Copyright (c) 2022, Salesforce, Inc.
|
|
15
|
+
* All rights reserved.
|
|
16
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
17
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
18
|
+
*/
|
|
19
|
+
const withLegacyGetProps = Wrapped => {
|
|
20
|
+
/* istanbul ignore next */
|
|
21
|
+
const wrappedComponentName = Wrapped.displayName || Wrapped.name;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
class WithLegacyGetProps extends _fetchStrategy.FetchStrategy {
|
|
27
|
+
render() {
|
|
28
|
+
return /*#__PURE__*/_react.default.createElement(Wrapped, this.props);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
static doInitAppState({
|
|
35
|
+
App,
|
|
36
|
+
match,
|
|
37
|
+
route,
|
|
38
|
+
req,
|
|
39
|
+
res,
|
|
40
|
+
location
|
|
41
|
+
}) {
|
|
42
|
+
return _asyncToGenerator(function* () {
|
|
43
|
+
const {
|
|
44
|
+
params
|
|
45
|
+
} = match;
|
|
46
|
+
const components = [App, route.component];
|
|
47
|
+
const promises = components.map((c, i) => {
|
|
48
|
+
// getTemplateName is a promise and it's intentially not awaited here
|
|
49
|
+
// to avoid blocking the execution of the getProps function to maximize performance
|
|
50
|
+
// getTemplateName should be very fast, under 0.2ms
|
|
51
|
+
c.getTemplateName().then(templateName => {
|
|
52
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}::${templateName}`, 'start');
|
|
53
|
+
});
|
|
54
|
+
return c.getProps ? c.getProps({
|
|
55
|
+
req,
|
|
56
|
+
res,
|
|
57
|
+
params,
|
|
58
|
+
location
|
|
59
|
+
}).then(result => {
|
|
60
|
+
c.getTemplateName().then(templateName => {
|
|
61
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}::${templateName}`, 'end');
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
}) : Promise.resolve({});
|
|
65
|
+
});
|
|
66
|
+
const [appProps, pageProps] = yield Promise.all(promises);
|
|
67
|
+
return {
|
|
68
|
+
appProps,
|
|
69
|
+
pageProps
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
static getInitializers() {
|
|
78
|
+
var _Wrapped$getInitializ;
|
|
79
|
+
return [WithLegacyGetProps.doInitAppState, ...(((_Wrapped$getInitializ = Wrapped.getInitializers) === null || _Wrapped$getInitializ === void 0 ? void 0 : _Wrapped$getInitializ.call(Wrapped)) ?? [])];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
static getHOCsInUse() {
|
|
86
|
+
var _Wrapped$getHOCsInUse;
|
|
87
|
+
return [withLegacyGetProps, ...(((_Wrapped$getHOCsInUse = Wrapped.getHOCsInUse) === null || _Wrapped$getHOCsInUse === void 0 ? void 0 : _Wrapped$getHOCsInUse.call(Wrapped)) ?? [])];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
WithLegacyGetProps.displayName = `withLegacyGetProps(${wrappedComponentName})`;
|
|
91
|
+
const exclude = {
|
|
92
|
+
doInitAppState: true,
|
|
93
|
+
getInitializers: true,
|
|
94
|
+
initAppState: true,
|
|
95
|
+
getHOCsInUse: true
|
|
96
|
+
};
|
|
97
|
+
(0, _hoistNonReactStatics.default)(WithLegacyGetProps, Wrapped, exclude);
|
|
98
|
+
return WithLegacyGetProps;
|
|
99
|
+
};
|
|
100
|
+
exports.withLegacyGetProps = withLegacyGetProps;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _index = require("./index");
|
|
4
|
+
var _react = require("@testing-library/react");
|
|
5
|
+
var _react2 = _interopRequireDefault(require("react"));
|
|
6
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
/*
|
|
8
|
+
* Copyright (c) 2022, Salesforce, Inc.
|
|
9
|
+
* All rights reserved.
|
|
10
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
11
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
describe('withLegacyGetProps', function () {
|
|
15
|
+
test('Renders correctly', () => {
|
|
16
|
+
const Wrapped = () => /*#__PURE__*/_react2.default.createElement("p", null, "Hello world");
|
|
17
|
+
const Component = (0, _index.withLegacyGetProps)(Wrapped);
|
|
18
|
+
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(Component, {
|
|
19
|
+
locals: {}
|
|
20
|
+
}));
|
|
21
|
+
expect(_react.screen.getByText(/Hello world/i)).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
test(`Has working getInitializers method`, () => {
|
|
24
|
+
expect((0, _index.withLegacyGetProps)({}).getInitializers()).toHaveLength(1);
|
|
25
|
+
expect((0, _index.withLegacyGetProps)({
|
|
26
|
+
getInitializers: () => ['xyz']
|
|
27
|
+
}).getInitializers()).toHaveLength(2);
|
|
28
|
+
});
|
|
29
|
+
test(`Has working getHOCsInUse method`, () => {
|
|
30
|
+
expect((0, _index.withLegacyGetProps)({}).getHOCsInUse()).toHaveLength(1);
|
|
31
|
+
expect((0, _index.withLegacyGetProps)({
|
|
32
|
+
getHOCsInUse: () => ['xyz']
|
|
33
|
+
}).getHOCsInUse()).toHaveLength(2);
|
|
34
|
+
});
|
|
35
|
+
});
|