@dhis2/app-service-offline 3.11.3 → 3.12.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/__tests__/integration.test.js +51 -82
- package/build/cjs/index.js +0 -7
- package/build/cjs/lib/__tests__/cacheable-section-state.test.js +7 -14
- package/build/cjs/lib/__tests__/clear-sensitive-caches.test.js +17 -20
- package/build/cjs/lib/__tests__/network-status.test.js +135 -148
- package/build/cjs/lib/__tests__/offline-provider.test.js +12 -22
- package/build/cjs/lib/__tests__/use-cacheable-section.test.js +87 -98
- package/build/cjs/lib/__tests__/use-online-status-message.test.js +7 -14
- package/build/cjs/lib/cacheable-section-state.js +27 -38
- package/build/cjs/lib/cacheable-section.js +26 -27
- package/build/cjs/lib/clear-sensitive-caches.js +14 -24
- package/build/cjs/lib/dhis2-connection-status/dev-debug-log.js +1 -3
- package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.js +27 -58
- package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.test.js +287 -230
- package/build/cjs/lib/dhis2-connection-status/index.js +0 -1
- package/build/cjs/lib/dhis2-connection-status/is-ping-available.js +0 -6
- package/build/cjs/lib/dhis2-connection-status/is-ping-available.test.js +0 -1
- package/build/cjs/lib/dhis2-connection-status/smart-interval.js +35 -49
- package/build/cjs/lib/dhis2-connection-status/use-ping-query.js +4 -5
- package/build/cjs/lib/global-state-service.js +9 -27
- package/build/cjs/lib/network-status.js +10 -13
- package/build/cjs/lib/offline-interface.js +3 -14
- package/build/cjs/lib/offline-provider.js +1 -12
- package/build/cjs/lib/online-status-message.js +5 -17
- package/build/cjs/setupRTL.js +1 -1
- package/build/cjs/utils/__tests__/render-counter.test.js +3 -12
- package/build/cjs/utils/render-counter.js +2 -10
- package/build/cjs/utils/test-mocks.js +13 -18
- package/build/es/__tests__/integration.test.js +51 -74
- package/build/es/index.js +2 -2
- package/build/es/lib/__tests__/cacheable-section-state.test.js +2 -4
- package/build/es/lib/__tests__/clear-sensitive-caches.test.js +19 -16
- package/build/es/lib/__tests__/network-status.test.js +105 -114
- package/build/es/lib/__tests__/offline-provider.test.js +13 -15
- package/build/es/lib/__tests__/use-cacheable-section.test.js +69 -73
- package/build/es/lib/__tests__/use-online-status-message.test.js +2 -3
- package/build/es/lib/cacheable-section-state.js +25 -26
- package/build/es/lib/cacheable-section.js +23 -15
- package/build/es/lib/clear-sensitive-caches.js +13 -21
- package/build/es/lib/dhis2-connection-status/dev-debug-log.js +1 -3
- package/build/es/lib/dhis2-connection-status/dhis2-connection-status.js +26 -37
- package/build/es/lib/dhis2-connection-status/dhis2-connection-status.test.js +223 -159
- package/build/es/lib/dhis2-connection-status/is-ping-available.js +0 -5
- package/build/es/lib/dhis2-connection-status/smart-interval.js +34 -42
- package/build/es/lib/dhis2-connection-status/use-ping-query.js +6 -3
- package/build/es/lib/global-state-service.js +6 -12
- package/build/es/lib/network-status.js +10 -9
- package/build/es/lib/offline-interface.js +0 -3
- package/build/es/lib/offline-provider.js +0 -3
- package/build/es/lib/online-status-message.js +3 -2
- package/build/es/setupRTL.js +1 -1
- package/build/es/utils/__tests__/render-counter.test.js +2 -4
- package/build/es/utils/render-counter.js +1 -3
- package/build/es/utils/test-mocks.js +8 -9
- package/build/types/lib/cacheable-section.d.ts +1 -1
- package/build/types/lib/dhis2-connection-status/dhis2-connection-status.d.ts +1 -1
- package/build/types/lib/network-status.d.ts +1 -1
- package/build/types/lib/online-status-message.d.ts +1 -1
- package/build/types/types.d.ts +1 -1
- package/package.json +4 -4
|
@@ -4,28 +4,20 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.resetRenderCounts = exports.RenderCounter = void 0;
|
|
7
|
-
|
|
8
7
|
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const RenderCounter = (_ref) => {
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
const RenderCounter = _ref => {
|
|
13
10
|
let {
|
|
14
11
|
id,
|
|
15
12
|
countsObj
|
|
16
13
|
} = _ref;
|
|
17
|
-
|
|
18
14
|
if (!(id in countsObj)) {
|
|
19
15
|
countsObj[id] = 0;
|
|
20
16
|
}
|
|
21
|
-
|
|
22
17
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
23
18
|
"data-testid": id
|
|
24
19
|
}, ++countsObj[id]);
|
|
25
20
|
};
|
|
26
|
-
|
|
27
21
|
exports.RenderCounter = RenderCounter;
|
|
28
|
-
|
|
29
22
|
const resetRenderCounts = renderCounts => Object.keys(renderCounts).forEach(key => renderCounts[key] = 0);
|
|
30
|
-
|
|
31
23
|
exports.resetRenderCounts = resetRenderCounts;
|
|
@@ -4,46 +4,42 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.successfulRecordingMock = exports.mockOfflineInterface = exports.failedMessageRecordingMock = exports.errorRecordingMock = void 0;
|
|
7
|
-
const successfulRecordingMock = jest.fn().mockImplementation(async function () {
|
|
7
|
+
const successfulRecordingMock = exports.successfulRecordingMock = jest.fn().mockImplementation(async function () {
|
|
8
8
|
let {
|
|
9
9
|
onStarted,
|
|
10
10
|
onCompleted
|
|
11
11
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
12
|
-
|
|
13
12
|
// in 100ms, call 'onStarted' callback (allows 'pending' state)
|
|
14
13
|
if (onStarted) {
|
|
15
14
|
setTimeout(onStarted, 100);
|
|
16
|
-
}
|
|
17
|
-
|
|
15
|
+
}
|
|
18
16
|
|
|
17
|
+
// in 200ms, call 'onCompleted' callback
|
|
19
18
|
if (onCompleted) {
|
|
20
19
|
setTimeout(onCompleted, 200);
|
|
21
|
-
}
|
|
22
|
-
|
|
20
|
+
}
|
|
23
21
|
|
|
22
|
+
// resolve
|
|
24
23
|
return Promise.resolve();
|
|
25
24
|
});
|
|
26
|
-
exports.
|
|
27
|
-
const errorRecordingMock = jest.fn().mockImplementation(function () {
|
|
25
|
+
const errorRecordingMock = exports.errorRecordingMock = jest.fn().mockImplementation(function () {
|
|
28
26
|
let {
|
|
29
27
|
onStarted,
|
|
30
28
|
onError
|
|
31
29
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
32
|
-
|
|
33
30
|
// in 100ms, call 'onStarted' callback (allows 'pending' state)
|
|
34
31
|
if (onStarted) {
|
|
35
32
|
setTimeout(onStarted, 100);
|
|
36
|
-
}
|
|
37
|
-
|
|
33
|
+
}
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
// in 200ms, call 'onError'
|
|
36
|
+
setTimeout(() => onError(new Error('test err')), 200);
|
|
40
37
|
|
|
38
|
+
// resolve to signal successful initiation
|
|
41
39
|
return Promise.resolve();
|
|
42
40
|
});
|
|
43
|
-
exports.
|
|
44
|
-
const
|
|
45
|
-
exports.failedMessageRecordingMock = failedMessageRecordingMock;
|
|
46
|
-
const mockOfflineInterface = {
|
|
41
|
+
const failedMessageRecordingMock = exports.failedMessageRecordingMock = jest.fn().mockRejectedValue(new Error('Failed message'));
|
|
42
|
+
const mockOfflineInterface = exports.mockOfflineInterface = {
|
|
47
43
|
pwaEnabled: true,
|
|
48
44
|
latestIsConnected: true,
|
|
49
45
|
startRecording: successfulRecordingMock,
|
|
@@ -51,5 +47,4 @@ const mockOfflineInterface = {
|
|
|
51
47
|
removeSection: jest.fn().mockResolvedValue(true),
|
|
52
48
|
// returns an unsubscribe function
|
|
53
49
|
subscribeToDhis2ConnectionStatus: jest.fn().mockReturnValue(() => undefined)
|
|
54
|
-
};
|
|
55
|
-
exports.mockOfflineInterface = mockOfflineInterface;
|
|
50
|
+
};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
function _extends() { _extends = Object.assign
|
|
2
|
-
|
|
1
|
+
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); }
|
|
3
2
|
import { AlertsProvider } from '@dhis2/app-service-alerts';
|
|
4
|
-
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
5
4
|
import React from 'react';
|
|
6
5
|
import { useCacheableSection, CacheableSection } from '../lib/cacheable-section';
|
|
7
6
|
import { OfflineProvider } from '../lib/offline-provider';
|
|
8
7
|
import { RenderCounter, resetRenderCounts } from '../utils/render-counter';
|
|
9
8
|
import { errorRecordingMock, failedMessageRecordingMock, mockOfflineInterface } from '../utils/test-mocks';
|
|
10
9
|
const renderCounts = {};
|
|
11
|
-
|
|
12
10
|
const identity = arg => arg;
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const TestControls = _ref => {
|
|
12
|
+
var _lastUpdated$toISOStr;
|
|
15
13
|
let {
|
|
16
14
|
id,
|
|
17
15
|
makeRecordingHandler = identity
|
|
@@ -38,12 +36,11 @@ const TestControls = (_ref) => {
|
|
|
38
36
|
"data-testid": `is-cached-${id}`
|
|
39
37
|
}, isCached ? 'yes' : 'no'), /*#__PURE__*/React.createElement("div", {
|
|
40
38
|
"data-testid": `last-updated-${id}`
|
|
41
|
-
}, lastUpdated || 'never'), /*#__PURE__*/React.createElement("div", {
|
|
39
|
+
}, (_lastUpdated$toISOStr = lastUpdated === null || lastUpdated === void 0 ? void 0 : lastUpdated.toISOString()) !== null && _lastUpdated$toISOStr !== void 0 ? _lastUpdated$toISOStr : 'never'), /*#__PURE__*/React.createElement("div", {
|
|
42
40
|
"data-testid": `recording-state-${id}`
|
|
43
41
|
}, recordingState));
|
|
44
42
|
};
|
|
45
|
-
|
|
46
|
-
const TestSection = (_ref2) => {
|
|
43
|
+
const TestSection = _ref2 => {
|
|
47
44
|
let {
|
|
48
45
|
id,
|
|
49
46
|
children
|
|
@@ -58,7 +55,6 @@ const TestSection = (_ref2) => {
|
|
|
58
55
|
countsObj: renderCounts
|
|
59
56
|
}), children);
|
|
60
57
|
};
|
|
61
|
-
|
|
62
58
|
const TestSingleSection = props => {
|
|
63
59
|
// Props are spread so they can be overwritten
|
|
64
60
|
return /*#__PURE__*/React.createElement(AlertsProvider, null, /*#__PURE__*/React.createElement(OfflineProvider, _extends({
|
|
@@ -68,36 +64,34 @@ const TestSingleSection = props => {
|
|
|
68
64
|
}, props)), /*#__PURE__*/React.createElement(TestSection, _extends({
|
|
69
65
|
id: '1'
|
|
70
66
|
}, props))));
|
|
71
|
-
};
|
|
72
|
-
|
|
67
|
+
};
|
|
73
68
|
|
|
69
|
+
// Suppress 'act' warning for these tests
|
|
74
70
|
const originalError = console.error;
|
|
75
71
|
beforeEach(() => {
|
|
76
72
|
// This is done before each because the 'recording error' test uses its own
|
|
77
73
|
// spy on console.error
|
|
78
74
|
jest.spyOn(console, 'error').mockImplementation(function () {
|
|
79
75
|
const pattern = /Warning: An update to .* inside a test was not wrapped in act/;
|
|
80
|
-
|
|
81
76
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
82
77
|
args[_key] = arguments[_key];
|
|
83
78
|
}
|
|
84
|
-
|
|
85
79
|
if (typeof args[0] === 'string' && pattern.test(args[0])) {
|
|
86
80
|
return;
|
|
87
81
|
}
|
|
88
|
-
|
|
89
82
|
return originalError.call(console, ...args);
|
|
90
83
|
});
|
|
91
84
|
});
|
|
92
85
|
afterEach(() => {
|
|
93
|
-
jest.clearAllMocks()
|
|
86
|
+
jest.clearAllMocks()
|
|
87
|
+
// This syntax appeases typescript:
|
|
94
88
|
;
|
|
95
89
|
console.error.mockRestore();
|
|
96
90
|
resetRenderCounts(renderCounts);
|
|
97
91
|
});
|
|
98
92
|
describe('Coordination between useCacheableSection and CacheableSection', () => {
|
|
99
93
|
it('renders in the default state initially', async () => {
|
|
100
|
-
render(
|
|
94
|
+
render(/*#__PURE__*/React.createElement(TestSingleSection, null));
|
|
101
95
|
const {
|
|
102
96
|
getByTestId
|
|
103
97
|
} = screen;
|
|
@@ -112,35 +106,31 @@ describe('Coordination between useCacheableSection and CacheableSection', () =>
|
|
|
112
106
|
getByTestId,
|
|
113
107
|
queryByTestId
|
|
114
108
|
} = screen;
|
|
115
|
-
|
|
116
109
|
const onStarted = () => {
|
|
117
110
|
expect(getByTestId(/recording-state/)).toHaveTextContent('recording');
|
|
118
111
|
expect(getByTestId(/loading-mask/)).toBeInTheDocument();
|
|
119
112
|
expect(getByTestId(/section-rc/)).toBeInTheDocument();
|
|
120
113
|
};
|
|
121
|
-
|
|
122
114
|
const onCompleted = () => {
|
|
123
115
|
expect(getByTestId(/recording-state/)).toHaveTextContent('default');
|
|
124
116
|
expect(queryByTestId(/loading-mask/)).not.toBeInTheDocument();
|
|
125
117
|
done();
|
|
126
118
|
};
|
|
127
|
-
|
|
128
119
|
const recordingOptions = {
|
|
129
120
|
onStarted,
|
|
130
121
|
onCompleted
|
|
131
122
|
};
|
|
132
|
-
|
|
133
123
|
const makeRecordingHandler = startRecording => {
|
|
134
124
|
return () => startRecording(recordingOptions);
|
|
135
125
|
};
|
|
136
|
-
|
|
137
|
-
render( /*#__PURE__*/React.createElement(TestSingleSection, {
|
|
126
|
+
render(/*#__PURE__*/React.createElement(TestSingleSection, {
|
|
138
127
|
makeRecordingHandler: makeRecordingHandler
|
|
139
128
|
}));
|
|
140
129
|
await act(async () => {
|
|
141
130
|
fireEvent.click(getByTestId(/start-recording/));
|
|
142
|
-
});
|
|
131
|
+
});
|
|
143
132
|
|
|
133
|
+
// At this stage, should be pending
|
|
144
134
|
expect(getByTestId(/recording-state/)).toHaveTextContent('pending');
|
|
145
135
|
expect(queryByTestId(/section-rc/)).not.toBeInTheDocument();
|
|
146
136
|
expect.assertions(7);
|
|
@@ -150,41 +140,35 @@ describe('Coordination between useCacheableSection and CacheableSection', () =>
|
|
|
150
140
|
jest.spyOn(console, 'error').mockImplementation(function () {
|
|
151
141
|
const actPattern = /Warning: An update to .* inside a test was not wrapped in act/;
|
|
152
142
|
const errPattern = /Error during recording/;
|
|
153
|
-
|
|
154
143
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
155
144
|
args[_key2] = arguments[_key2];
|
|
156
145
|
}
|
|
157
|
-
|
|
158
146
|
const matchesPattern = actPattern.test(args[0]) || errPattern.test(args[0]);
|
|
159
|
-
|
|
160
147
|
if (typeof args[0] === 'string' && matchesPattern) {
|
|
161
148
|
return;
|
|
162
149
|
}
|
|
163
|
-
|
|
164
150
|
return originalError.call(console, ...args);
|
|
165
151
|
});
|
|
166
152
|
const {
|
|
167
153
|
getByTestId,
|
|
168
154
|
queryByTestId
|
|
169
155
|
} = screen;
|
|
170
|
-
const testOfflineInterface = {
|
|
156
|
+
const testOfflineInterface = {
|
|
157
|
+
...mockOfflineInterface,
|
|
171
158
|
startRecording: errorRecordingMock
|
|
172
159
|
};
|
|
173
|
-
|
|
174
160
|
const onError = () => {
|
|
175
161
|
expect(getByTestId(/recording-state/)).toHaveTextContent('error');
|
|
176
162
|
expect(queryByTestId(/loading-mask/)).not.toBeInTheDocument();
|
|
177
163
|
expect(getByTestId(/section-rc/)).toBeInTheDocument();
|
|
178
164
|
done();
|
|
179
165
|
};
|
|
180
|
-
|
|
181
166
|
const makeRecordingHandler = startRecording => {
|
|
182
167
|
return () => startRecording({
|
|
183
168
|
onError
|
|
184
169
|
});
|
|
185
170
|
};
|
|
186
|
-
|
|
187
|
-
render( /*#__PURE__*/React.createElement(TestSingleSection, {
|
|
171
|
+
render(/*#__PURE__*/React.createElement(TestSingleSection, {
|
|
188
172
|
offlineInterface: testOfflineInterface,
|
|
189
173
|
makeRecordingHandler: makeRecordingHandler
|
|
190
174
|
}));
|
|
@@ -192,33 +176,31 @@ describe('Coordination between useCacheableSection and CacheableSection', () =>
|
|
|
192
176
|
fireEvent.click(getByTestId(/start-recording/));
|
|
193
177
|
});
|
|
194
178
|
expect.assertions(3);
|
|
195
|
-
});
|
|
196
|
-
// ! causes the following ones to mysteriously fail 😤
|
|
179
|
+
});
|
|
197
180
|
|
|
181
|
+
// ! After bumping testing-library versions, something about this test
|
|
182
|
+
// ! causes the following ones to mysteriously fail 😤
|
|
198
183
|
it.skip('handles an error starting the recording', async done => {
|
|
199
184
|
const {
|
|
200
185
|
getByTestId
|
|
201
186
|
} = screen;
|
|
202
|
-
const testOfflineInterface = {
|
|
187
|
+
const testOfflineInterface = {
|
|
188
|
+
...mockOfflineInterface,
|
|
203
189
|
startRecording: failedMessageRecordingMock
|
|
204
190
|
};
|
|
205
191
|
const onStarted = jest.fn();
|
|
206
|
-
|
|
207
192
|
const testErrCondition = err => {
|
|
208
193
|
expect(err.message).toBe('Failed message'); // from the mock
|
|
209
|
-
|
|
210
194
|
expect(onStarted).not.toHaveBeenCalled();
|
|
211
195
|
expect(getByTestId(/recording-state/)).toHaveTextContent('default');
|
|
212
196
|
done();
|
|
213
197
|
};
|
|
214
|
-
|
|
215
198
|
const makeRecordingHandler = startRecording => {
|
|
216
199
|
return () => startRecording({
|
|
217
200
|
onStarted
|
|
218
201
|
}).catch(testErrCondition);
|
|
219
202
|
};
|
|
220
|
-
|
|
221
|
-
render( /*#__PURE__*/React.createElement(TestSingleSection, {
|
|
203
|
+
render(/*#__PURE__*/React.createElement(TestSingleSection, {
|
|
222
204
|
offlineInterface: testOfflineInterface,
|
|
223
205
|
makeRecordingHandler: makeRecordingHandler
|
|
224
206
|
}));
|
|
@@ -227,7 +209,6 @@ describe('Coordination between useCacheableSection and CacheableSection', () =>
|
|
|
227
209
|
});
|
|
228
210
|
});
|
|
229
211
|
});
|
|
230
|
-
|
|
231
212
|
const TwoTestSections = props =>
|
|
232
213
|
/*#__PURE__*/
|
|
233
214
|
// Props are spread so they can be overwritten (but only on one section)
|
|
@@ -241,44 +222,42 @@ React.createElement(AlertsProvider, null, /*#__PURE__*/React.createElement(Offli
|
|
|
241
222
|
id: '2'
|
|
242
223
|
}), /*#__PURE__*/React.createElement(TestSection, {
|
|
243
224
|
id: '2'
|
|
244
|
-
})));
|
|
245
|
-
|
|
225
|
+
})));
|
|
246
226
|
|
|
227
|
+
// test that other sections don't rerender when one section does
|
|
247
228
|
describe('Performant state management', () => {
|
|
248
229
|
it('establishes a pre-recording render count', () => {
|
|
249
|
-
render(
|
|
230
|
+
render(/*#__PURE__*/React.createElement(TwoTestSections, null));
|
|
250
231
|
const {
|
|
251
232
|
getByTestId
|
|
252
|
-
} = screen;
|
|
253
|
-
|
|
233
|
+
} = screen;
|
|
234
|
+
// Two renders for controls: undefined and 'default' states
|
|
254
235
|
expect(getByTestId('controls-rc-1')).toHaveTextContent('2');
|
|
255
|
-
expect(getByTestId('controls-rc-2')).toHaveTextContent('2');
|
|
256
|
-
|
|
236
|
+
expect(getByTestId('controls-rc-2')).toHaveTextContent('2');
|
|
237
|
+
// Just one render for sections
|
|
257
238
|
expect(getByTestId('section-rc-1')).toHaveTextContent('1');
|
|
258
239
|
expect(getByTestId('section-rc-2')).toHaveTextContent('1');
|
|
259
240
|
});
|
|
260
241
|
it('isolates rerenders from other consumers', async done => {
|
|
261
242
|
const {
|
|
262
243
|
getByTestId
|
|
263
|
-
} = screen;
|
|
264
|
-
|
|
244
|
+
} = screen;
|
|
245
|
+
// Make assertions
|
|
265
246
|
const onCompleted = () => {
|
|
266
247
|
// Before refactor: controls components have 6 renders EACH, and
|
|
267
248
|
// sections 1 and 2 have 2 and 1 renders, respectively
|
|
268
249
|
// After refactor, render counts for section that recorded:
|
|
269
250
|
expect(getByTestId('controls-rc-1')).toHaveTextContent('5');
|
|
270
|
-
expect(getByTestId('section-rc-1')).toHaveTextContent('2');
|
|
271
|
-
|
|
251
|
+
expect(getByTestId('section-rc-1')).toHaveTextContent('2');
|
|
252
|
+
// Section that did not record (should be same as pre-recording):
|
|
272
253
|
expect(getByTestId('controls-rc-2')).toHaveTextContent('2');
|
|
273
254
|
expect(getByTestId('section-rc-2')).toHaveTextContent('1');
|
|
274
255
|
done();
|
|
275
256
|
};
|
|
276
|
-
|
|
277
257
|
const makeRecordingHandler = startRecording => () => startRecording({
|
|
278
258
|
onCompleted
|
|
279
259
|
});
|
|
280
|
-
|
|
281
|
-
render( /*#__PURE__*/React.createElement(TwoTestSections, {
|
|
260
|
+
render(/*#__PURE__*/React.createElement(TwoTestSections, {
|
|
282
261
|
makeRecordingHandler: makeRecordingHandler
|
|
283
262
|
}));
|
|
284
263
|
await act(async () => {
|
|
@@ -298,44 +277,42 @@ describe('useCacheableSection can be used inside a child of CacheableSection', (
|
|
|
298
277
|
id: '1'
|
|
299
278
|
}, props)))));
|
|
300
279
|
};
|
|
301
|
-
|
|
302
280
|
it('handles a successful recording', async done => {
|
|
303
281
|
const {
|
|
304
282
|
getByTestId,
|
|
305
283
|
queryByTestId
|
|
306
284
|
} = screen;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
285
|
+
const onStarted = async () => {
|
|
286
|
+
await waitFor(() => {
|
|
287
|
+
expect(getByTestId(/recording-state/)).toHaveTextContent('recording');
|
|
288
|
+
expect(getByTestId(/loading-mask/)).toBeInTheDocument();
|
|
289
|
+
expect(getByTestId(/section-rc/)).toBeInTheDocument();
|
|
290
|
+
});
|
|
312
291
|
};
|
|
313
|
-
|
|
314
292
|
const onCompleted = () => {
|
|
315
293
|
expect(getByTestId(/recording-state/)).toHaveTextContent('default');
|
|
316
294
|
expect(queryByTestId(/loading-mask/)).not.toBeInTheDocument();
|
|
317
295
|
done();
|
|
318
296
|
};
|
|
319
|
-
|
|
320
297
|
const recordingOptions = {
|
|
321
298
|
onStarted,
|
|
322
299
|
onCompleted
|
|
323
300
|
};
|
|
324
|
-
|
|
325
301
|
const makeRecordingHandler = startRecording => {
|
|
326
302
|
return () => startRecording(recordingOptions);
|
|
327
303
|
};
|
|
328
|
-
|
|
329
|
-
render( /*#__PURE__*/React.createElement(ChildTest, {
|
|
304
|
+
render(/*#__PURE__*/React.createElement(ChildTest, {
|
|
330
305
|
makeRecordingHandler: makeRecordingHandler
|
|
331
306
|
}));
|
|
332
307
|
await act(async () => {
|
|
333
|
-
fireEvent.click(getByTestId(/start-recording/));
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
308
|
+
await fireEvent.click(getByTestId(/start-recording/));
|
|
309
|
+
});
|
|
310
|
+
await waitFor(() => {
|
|
311
|
+
// At this stage, should be pending
|
|
312
|
+
// - In this test case, 'controls' should not be rendered
|
|
313
|
+
expect(queryByTestId(/recording-state/)).not.toBeInTheDocument();
|
|
314
|
+
expect(queryByTestId(/section-rc/)).not.toBeInTheDocument();
|
|
315
|
+
expect.assertions(7);
|
|
316
|
+
});
|
|
340
317
|
});
|
|
341
318
|
});
|
package/build/es/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { OfflineProvider } from './lib/offline-provider';
|
|
2
2
|
export { CacheableSection, useCacheableSection } from './lib/cacheable-section';
|
|
3
|
-
export { useCachedSections } from './lib/cacheable-section-state';
|
|
4
|
-
|
|
3
|
+
export { useCachedSections } from './lib/cacheable-section-state';
|
|
4
|
+
// Use "useOnlineStatus" name for backwards compatibility
|
|
5
5
|
export { useNetworkStatus as useOnlineStatus } from './lib/network-status';
|
|
6
6
|
export { useOnlineStatusMessage, useSetOnlineStatusMessage, useOnlineStatusMessageValue } from './lib/online-status-message';
|
|
7
7
|
export { clearSensitiveCaches } from './lib/clear-sensitive-caches';
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { renderHook } from '@testing-library/react
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { mockOfflineInterface } from '../../utils/test-mocks';
|
|
4
4
|
import { useCachedSection, useRecordingState } from '../cacheable-section-state';
|
|
5
5
|
import { OfflineProvider } from '../offline-provider';
|
|
6
|
-
|
|
7
|
-
const wrapper = (_ref) => {
|
|
6
|
+
const wrapper = _ref => {
|
|
8
7
|
let {
|
|
9
8
|
children
|
|
10
9
|
} = _ref;
|
|
@@ -12,7 +11,6 @@ const wrapper = (_ref) => {
|
|
|
12
11
|
offlineInterface: mockOfflineInterface
|
|
13
12
|
}, children);
|
|
14
13
|
};
|
|
15
|
-
|
|
16
14
|
test('useRecordingState has stable references', () => {
|
|
17
15
|
const {
|
|
18
16
|
result,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import FDBFactory from 'fake-indexeddb/lib/FDBFactory';
|
|
2
2
|
import { openDB } from 'idb';
|
|
3
3
|
import 'fake-indexeddb/auto';
|
|
4
|
-
import { clearSensitiveCaches, SECTIONS_DB, SECTIONS_STORE } from '../clear-sensitive-caches';
|
|
5
|
-
|
|
4
|
+
import { clearSensitiveCaches, SECTIONS_DB, SECTIONS_STORE } from '../clear-sensitive-caches';
|
|
5
|
+
|
|
6
|
+
// Mocks for CacheStorage API
|
|
6
7
|
|
|
8
|
+
// Returns true if an existing cache is deleted
|
|
7
9
|
const makeCachesDeleteMock = keys => {
|
|
8
10
|
return jest.fn().mockImplementation(key => Promise.resolve(keys.includes(key)));
|
|
9
11
|
};
|
|
10
|
-
|
|
11
12
|
const keysMockDefault = jest.fn().mockImplementation(async () => []);
|
|
12
13
|
const deleteMockDefault = makeCachesDeleteMock([]);
|
|
13
14
|
const cachesDefault = {
|
|
@@ -22,21 +23,19 @@ window.caches = cachesDefault;
|
|
|
22
23
|
afterEach(() => {
|
|
23
24
|
window.caches = cachesDefault;
|
|
24
25
|
jest.clearAllMocks();
|
|
25
|
-
});
|
|
26
|
+
});
|
|
26
27
|
|
|
28
|
+
// silence debug logs for these tests
|
|
27
29
|
const originalDebug = console.debug;
|
|
28
30
|
beforeAll(() => {
|
|
29
31
|
jest.spyOn(console, 'debug').mockImplementation(function () {
|
|
30
32
|
const pattern = /Clearing sensitive caches/;
|
|
31
|
-
|
|
32
33
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
33
34
|
args[_key] = arguments[_key];
|
|
34
35
|
}
|
|
35
|
-
|
|
36
36
|
if (typeof args[0] === 'string' && pattern.test(args[0])) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
|
|
40
39
|
return originalDebug.call(console, ...args);
|
|
41
40
|
});
|
|
42
41
|
});
|
|
@@ -51,7 +50,8 @@ it('returns false if caches.keys throws', async () => {
|
|
|
51
50
|
const spy = jest.fn(() => {
|
|
52
51
|
throw new Error('Security Error');
|
|
53
52
|
});
|
|
54
|
-
window.caches = {
|
|
53
|
+
window.caches = {
|
|
54
|
+
...cachesDefault,
|
|
55
55
|
keys: spy
|
|
56
56
|
};
|
|
57
57
|
const result = await clearSensitiveCaches();
|
|
@@ -62,7 +62,8 @@ it('clears potentially sensitive caches', async () => {
|
|
|
62
62
|
const testKeys = ['cache1', 'cache2', 'app-shell', 'other-assets'];
|
|
63
63
|
const keysMock = jest.fn().mockImplementation(() => Promise.resolve(testKeys));
|
|
64
64
|
const deleteMock = makeCachesDeleteMock(testKeys);
|
|
65
|
-
window.caches = {
|
|
65
|
+
window.caches = {
|
|
66
|
+
...cachesDefault,
|
|
66
67
|
keys: keysMock,
|
|
67
68
|
delete: deleteMock
|
|
68
69
|
};
|
|
@@ -76,7 +77,8 @@ it('clears potentially sensitive caches', async () => {
|
|
|
76
77
|
});
|
|
77
78
|
it('preserves keepable caches', async () => {
|
|
78
79
|
const keysMock = jest.fn().mockImplementation(async () => ['cache1', 'cache2', 'app-shell', 'other-assets', 'workbox-precache-v2-https://hey.howareya.now/']);
|
|
79
|
-
window.caches = {
|
|
80
|
+
window.caches = {
|
|
81
|
+
...cachesDefault,
|
|
80
82
|
keys: keysMock
|
|
81
83
|
};
|
|
82
84
|
await clearSensitiveCaches();
|
|
@@ -97,10 +99,8 @@ describe('clears sections-db', () => {
|
|
|
97
99
|
keyPath: 'sectionId'
|
|
98
100
|
});
|
|
99
101
|
}
|
|
100
|
-
|
|
101
102
|
});
|
|
102
103
|
}
|
|
103
|
-
|
|
104
104
|
afterEach(() => {
|
|
105
105
|
// reset indexedDB state
|
|
106
106
|
window.indexedDB = new FDBFactory();
|
|
@@ -118,8 +118,9 @@ describe('clears sections-db', () => {
|
|
|
118
118
|
lastUpdated: new Date(),
|
|
119
119
|
requests: 3
|
|
120
120
|
});
|
|
121
|
-
await clearSensitiveCaches();
|
|
121
|
+
await clearSensitiveCaches();
|
|
122
122
|
|
|
123
|
+
// Sections-db should be cleared
|
|
123
124
|
const allSections = await db.getAll(SECTIONS_STORE);
|
|
124
125
|
expect(allSections).toHaveLength(0);
|
|
125
126
|
});
|
|
@@ -136,16 +137,18 @@ describe('clears sections-db', () => {
|
|
|
136
137
|
// if 'databases' property exists
|
|
137
138
|
await openTestDB(SECTIONS_DB);
|
|
138
139
|
const openMock = jest.fn();
|
|
139
|
-
window.indexedDB.open = openMock;
|
|
140
|
-
// (simulates Firefox environment)
|
|
140
|
+
window.indexedDB.open = openMock;
|
|
141
141
|
|
|
142
|
+
// Remove 'databases' from indexedDB prototype for this test
|
|
143
|
+
// (simulates Firefox environment)
|
|
142
144
|
const idbProto = Object.getPrototypeOf(window.indexedDB);
|
|
143
145
|
const databases = idbProto.databases;
|
|
144
146
|
delete idbProto.databases;
|
|
145
147
|
expect('databases' in window.indexedDB).toBe(false);
|
|
146
148
|
await expect(clearSensitiveCaches()).resolves.toBeDefined();
|
|
147
|
-
expect(openMock).not.toHaveBeenCalled();
|
|
149
|
+
expect(openMock).not.toHaveBeenCalled();
|
|
148
150
|
|
|
151
|
+
// Restore indexedDB prototype for later tests
|
|
149
152
|
idbProto.databases = databases;
|
|
150
153
|
expect('databases' in window.indexedDB).toBe(true);
|
|
151
154
|
});
|