@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.
Files changed (60) hide show
  1. package/build/cjs/__tests__/integration.test.js +51 -82
  2. package/build/cjs/index.js +0 -7
  3. package/build/cjs/lib/__tests__/cacheable-section-state.test.js +7 -14
  4. package/build/cjs/lib/__tests__/clear-sensitive-caches.test.js +17 -20
  5. package/build/cjs/lib/__tests__/network-status.test.js +135 -148
  6. package/build/cjs/lib/__tests__/offline-provider.test.js +12 -22
  7. package/build/cjs/lib/__tests__/use-cacheable-section.test.js +87 -98
  8. package/build/cjs/lib/__tests__/use-online-status-message.test.js +7 -14
  9. package/build/cjs/lib/cacheable-section-state.js +27 -38
  10. package/build/cjs/lib/cacheable-section.js +26 -27
  11. package/build/cjs/lib/clear-sensitive-caches.js +14 -24
  12. package/build/cjs/lib/dhis2-connection-status/dev-debug-log.js +1 -3
  13. package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.js +27 -58
  14. package/build/cjs/lib/dhis2-connection-status/dhis2-connection-status.test.js +287 -230
  15. package/build/cjs/lib/dhis2-connection-status/index.js +0 -1
  16. package/build/cjs/lib/dhis2-connection-status/is-ping-available.js +0 -6
  17. package/build/cjs/lib/dhis2-connection-status/is-ping-available.test.js +0 -1
  18. package/build/cjs/lib/dhis2-connection-status/smart-interval.js +35 -49
  19. package/build/cjs/lib/dhis2-connection-status/use-ping-query.js +4 -5
  20. package/build/cjs/lib/global-state-service.js +9 -27
  21. package/build/cjs/lib/network-status.js +10 -13
  22. package/build/cjs/lib/offline-interface.js +3 -14
  23. package/build/cjs/lib/offline-provider.js +1 -12
  24. package/build/cjs/lib/online-status-message.js +5 -17
  25. package/build/cjs/setupRTL.js +1 -1
  26. package/build/cjs/utils/__tests__/render-counter.test.js +3 -12
  27. package/build/cjs/utils/render-counter.js +2 -10
  28. package/build/cjs/utils/test-mocks.js +13 -18
  29. package/build/es/__tests__/integration.test.js +51 -74
  30. package/build/es/index.js +2 -2
  31. package/build/es/lib/__tests__/cacheable-section-state.test.js +2 -4
  32. package/build/es/lib/__tests__/clear-sensitive-caches.test.js +19 -16
  33. package/build/es/lib/__tests__/network-status.test.js +105 -114
  34. package/build/es/lib/__tests__/offline-provider.test.js +13 -15
  35. package/build/es/lib/__tests__/use-cacheable-section.test.js +69 -73
  36. package/build/es/lib/__tests__/use-online-status-message.test.js +2 -3
  37. package/build/es/lib/cacheable-section-state.js +25 -26
  38. package/build/es/lib/cacheable-section.js +23 -15
  39. package/build/es/lib/clear-sensitive-caches.js +13 -21
  40. package/build/es/lib/dhis2-connection-status/dev-debug-log.js +1 -3
  41. package/build/es/lib/dhis2-connection-status/dhis2-connection-status.js +26 -37
  42. package/build/es/lib/dhis2-connection-status/dhis2-connection-status.test.js +223 -159
  43. package/build/es/lib/dhis2-connection-status/is-ping-available.js +0 -5
  44. package/build/es/lib/dhis2-connection-status/smart-interval.js +34 -42
  45. package/build/es/lib/dhis2-connection-status/use-ping-query.js +6 -3
  46. package/build/es/lib/global-state-service.js +6 -12
  47. package/build/es/lib/network-status.js +10 -9
  48. package/build/es/lib/offline-interface.js +0 -3
  49. package/build/es/lib/offline-provider.js +0 -3
  50. package/build/es/lib/online-status-message.js +3 -2
  51. package/build/es/setupRTL.js +1 -1
  52. package/build/es/utils/__tests__/render-counter.test.js +2 -4
  53. package/build/es/utils/render-counter.js +1 -3
  54. package/build/es/utils/test-mocks.js +8 -9
  55. package/build/types/lib/cacheable-section.d.ts +1 -1
  56. package/build/types/lib/dhis2-connection-status/dhis2-connection-status.d.ts +1 -1
  57. package/build/types/lib/network-status.d.ts +1 -1
  58. package/build/types/lib/online-status-message.d.ts +1 -1
  59. package/build/types/types.d.ts +1 -1
  60. 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
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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
- } // in 200ms, call 'onCompleted' callback
17
-
15
+ }
18
16
 
17
+ // in 200ms, call 'onCompleted' callback
19
18
  if (onCompleted) {
20
19
  setTimeout(onCompleted, 200);
21
- } // resolve
22
-
20
+ }
23
21
 
22
+ // resolve
24
23
  return Promise.resolve();
25
24
  });
26
- exports.successfulRecordingMock = successfulRecordingMock;
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
- } // in 200ms, call 'onError'
37
-
33
+ }
38
34
 
39
- setTimeout(() => onError(new Error('test err')), 200); // resolve to signal successful initiation
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.errorRecordingMock = errorRecordingMock;
44
- const failedMessageRecordingMock = jest.fn().mockRejectedValue(new Error('Failed message'));
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 || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
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
- const TestControls = (_ref) => {
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
- }; // Suppress 'act' warning for these tests
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() // This syntax appeases typescript:
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( /*#__PURE__*/React.createElement(TestSingleSection, null));
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
- }); // At this stage, should be pending
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 = { ...mockOfflineInterface,
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
- }); // ! After bumping testing-library versions, something about this test
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 = { ...mockOfflineInterface,
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
- }))); // test that other sections don't rerender when one section does
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( /*#__PURE__*/React.createElement(TwoTestSections, null));
230
+ render(/*#__PURE__*/React.createElement(TwoTestSections, null));
250
231
  const {
251
232
  getByTestId
252
- } = screen; // Two renders for controls: undefined and 'default' states
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'); // Just one render for sections
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; // Make assertions
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'); // Section that did not record (should be same as pre-recording):
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
- const onStarted = () => {
309
- expect(getByTestId(/recording-state/)).toHaveTextContent('recording');
310
- expect(getByTestId(/loading-mask/)).toBeInTheDocument();
311
- expect(getByTestId(/section-rc/)).toBeInTheDocument();
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
- }); // At this stage, should be pending
335
- // - In this test case, 'controls' should not be rendered
336
-
337
- expect(queryByTestId(/recording-state/)).not.toBeInTheDocument();
338
- expect(queryByTestId(/section-rc/)).not.toBeInTheDocument();
339
- expect.assertions(7);
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'; // Use "useOnlineStatus" name for backwards compatibility
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-hooks';
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'; // Mocks for CacheStorage API
5
- // Returns true if an existing cache is deleted
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
- }); // silence debug logs for these tests
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 = { ...cachesDefault,
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 = { ...cachesDefault,
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 = { ...cachesDefault,
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(); // Sections-db should be cleared
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; // Remove 'databases' from indexedDB prototype for this test
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(); // Restore indexedDB prototype for later tests
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
  });