musora-content-services 2.167.2 → 2.167.4

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 (140) hide show
  1. package/.agent/decisions/2026-07-20-mu2-1724-songs-lessons-counts.md +33 -0
  2. package/.agent/decisions/2026-07-20-query-builder-tostring.md +37 -0
  3. package/.idea/codeStyles/Project.xml +61 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/musora-content-services.iml +8 -0
  7. package/.idea/php.xml +19 -0
  8. package/.idea/prettier.xml +6 -0
  9. package/.idea/vcs.xml +7 -0
  10. package/.yarn/install-state.gz +0 -0
  11. package/CHANGELOG.md +10 -0
  12. package/package.json +2 -1
  13. package/src/contentTypeConfig.js +1 -0
  14. package/src/lib/sanity/query.ts +5 -0
  15. package/src/services/config.js +15 -0
  16. package/src/services/content/artist.ts +1 -3
  17. package/src/services/content/counts.ts +47 -0
  18. package/src/services/content/genre.ts +1 -3
  19. package/src/services/content/instructor.ts +1 -3
  20. package/src/services/multi-user-accounts/multi-user-accounts.ts +1 -0
  21. package/src/services/userActivity.js +2 -0
  22. package/src/version-info.js +1 -0
  23. package/.claude/settings.local.json +0 -53
  24. package/test/initializeTests.js +0 -60
  25. package/test/integration/awards/award-exclusion-handling.test.ts +0 -275
  26. package/test/integration/awards/internal/image-utils.test.ts +0 -86
  27. package/test/integration/content-progress/__mocks__/mocks.ts +0 -104
  28. package/test/integration/content-progress/contentProgress.test.ts +0 -335
  29. package/test/integration/content-progress/e2eOfflineProgress.test.ts +0 -352
  30. package/test/integration/content-progress/e2eProgress.test.ts +0 -612
  31. package/test/integration/content-progress/getters.test.ts +0 -334
  32. package/test/integration/content-progress/helpers.test.ts +0 -263
  33. package/test/integration/content-progress/offlineContentProgress.test.ts +0 -226
  34. package/test/integration/forums.test.ts +0 -209
  35. package/test/integration/infrastructure/FetchRequestExecutor.test.ts +0 -88
  36. package/test/integration/initializeTestDB.ts +0 -80
  37. package/test/integration/learning-paths.test.ts +0 -854
  38. package/test/integration/notifications.test.ts +0 -178
  39. package/test/integration/progress-row/content-card.test.ts +0 -283
  40. package/test/integration/sync/adapters/idb-errors.test.ts +0 -144
  41. package/test/integration/sync/adapters/sqlite-errors.test.ts +0 -173
  42. package/test/integration/sync/fetch.test.ts +0 -224
  43. package/test/integration/sync/repositories/content-likes.test.ts +0 -99
  44. package/test/integration/sync/repositories/practices.test.ts +0 -179
  45. package/test/integration/sync/repositories/progress.test.ts +0 -245
  46. package/test/integration/sync/repositories/user-award-progress.static.test.ts +0 -68
  47. package/test/integration/sync/repositories/user-award-progress.test.ts +0 -387
  48. package/test/integration/sync/store/cross-user-protection.test.ts +0 -217
  49. package/test/integration/sync/store/store-idb.test.ts +0 -180
  50. package/test/integration/sync/store/store.test.ts +0 -361
  51. package/test/integration/user/permissions.test.js +0 -20
  52. package/test/integration/userActivity.test.ts +0 -102
  53. package/test/live/README.md +0 -29
  54. package/test/live/content.test.js +0 -116
  55. package/test/localStorageMock.js +0 -21
  56. package/test/log.js +0 -5
  57. package/test/mockData/award-definitions.js +0 -171
  58. package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -35
  59. package/test/mockData/mockData_progress_content.json +0 -182
  60. package/test/mockData/mockData_sanity_progress_content.json +0 -1451
  61. package/test/mockData/mockData_user_practices.json +0 -9
  62. package/test/setupConsole.js +0 -6
  63. package/test/setupNetworkGuard.js +0 -3
  64. package/test/setupTimers.js +0 -13
  65. package/test/unit/HttpClient.test.ts +0 -267
  66. package/test/unit/awards/award-alacarte-observer.test.ts +0 -199
  67. package/test/unit/awards/award-auto-refresh.test.ts +0 -84
  68. package/test/unit/awards/award-calculations.test.ts +0 -34
  69. package/test/unit/awards/award-callbacks.test.ts +0 -144
  70. package/test/unit/awards/award-certificate-display.test.ts +0 -330
  71. package/test/unit/awards/award-collection-edge-cases.test.ts +0 -212
  72. package/test/unit/awards/award-collection-filtering.test.ts +0 -287
  73. package/test/unit/awards/award-completion-flow.test.ts +0 -306
  74. package/test/unit/awards/award-multi-lesson.test.ts +0 -243
  75. package/test/unit/awards/award-observer-integration.test.ts +0 -327
  76. package/test/unit/awards/award-query-messages.test.ts +0 -448
  77. package/test/unit/awards/award-user-collection.test.ts +0 -416
  78. package/test/unit/awards/duplicate-prevention.test.ts +0 -120
  79. package/test/unit/awards/helpers/completion-mock.ts +0 -56
  80. package/test/unit/awards/helpers/index.ts +0 -3
  81. package/test/unit/awards/helpers/mock-setup.ts +0 -79
  82. package/test/unit/awards/helpers/progress-emitter.ts +0 -45
  83. package/test/unit/awards/message-generator.test.ts +0 -162
  84. package/test/unit/content-progress/bubbleTrickle.test.ts +0 -322
  85. package/test/unit/content-progress/helpers.test.ts +0 -329
  86. package/test/unit/content-progress/navigateTo.test.ts +0 -392
  87. package/test/unit/contentLikes.test.ts +0 -62
  88. package/test/unit/contentMetaData.test.ts +0 -58
  89. package/test/unit/dataContext.test.ts +0 -38
  90. package/test/unit/dateUtils.test.ts +0 -188
  91. package/test/unit/endScreen.test.js +0 -712
  92. package/test/unit/eventsAPI.test.ts +0 -159
  93. package/test/unit/imageSRCBuilder.test.ts +0 -37
  94. package/test/unit/imageSRCVerify.test.ts +0 -155
  95. package/test/unit/infrastructure/DefaultHeaderProvider.test.ts +0 -39
  96. package/test/unit/infrastructure/sanity/ContentClient.test.ts +0 -168
  97. package/test/unit/infrastructure/sanity/DefaultConfigProvider.test.ts +0 -93
  98. package/test/unit/infrastructure/sanity/FetchQueryExecutor.test.ts +0 -174
  99. package/test/unit/infrastructure/sanity/SanityClient.test.ts +0 -140
  100. package/test/unit/lib/__snapshots__/filter.test.ts.snap +0 -5
  101. package/test/unit/lib/filter.test.ts +0 -1154
  102. package/test/unit/lib/lastUpdated.test.ts +0 -21
  103. package/test/unit/lib/query.test.ts +0 -1469
  104. package/test/unit/lib/sanity/decorators/base.test.ts +0 -368
  105. package/test/unit/lib/sanity/decorators/navigate-to.test.ts +0 -361
  106. package/test/unit/lib/sanity/decorators/need-access.test.ts +0 -89
  107. package/test/unit/lib/sanity/decorators/need-lifetime-upgrade.test.ts +0 -85
  108. package/test/unit/lib/sanity/decorators/page-type.test.ts +0 -81
  109. package/test/unit/playerSettings.test.ts +0 -73
  110. package/test/unit/progress-row/content-card.test.ts +0 -314
  111. package/test/unit/progress-row/playlist-card.test.ts +0 -104
  112. package/test/unit/progressRows.test.ts +0 -243
  113. package/test/unit/recommendations.test.js +0 -47
  114. package/test/unit/sanityQueryService.test.ts +0 -200
  115. package/test/unit/search.test.ts +0 -44
  116. package/test/unit/sentry.test.ts +0 -62
  117. package/test/unit/services/progress-internal/bubble.test.ts +0 -279
  118. package/test/unit/services/progress.test.ts +0 -396
  119. package/test/unit/streakMessage.test.ts +0 -251
  120. package/test/unit/sync/context.test.ts +0 -51
  121. package/test/unit/sync/effects/logout-warning.test.ts +0 -158
  122. package/test/unit/sync/effects/push-failure-notification.test.ts +0 -196
  123. package/test/unit/sync/errors/sync-errors.test.ts +0 -106
  124. package/test/unit/sync/errors/validators.test.ts +0 -61
  125. package/test/unit/sync/helpers/TestModel.ts +0 -44
  126. package/test/unit/sync/helpers/index.ts +0 -172
  127. package/test/unit/sync/manager.test.ts +0 -303
  128. package/test/unit/sync/models/user-award-progress.test.ts +0 -82
  129. package/test/unit/sync/resolver.test.ts +0 -229
  130. package/test/unit/sync/retry.test.ts +0 -314
  131. package/test/unit/sync/run-scope.test.ts +0 -23
  132. package/test/unit/sync/stale-record-cleanup.test.ts +0 -107
  133. package/test/unit/sync/store/push-coalescer.test.ts +0 -156
  134. package/test/unit/sync/store-configs.test.ts +0 -37
  135. package/test/unit/sync/telemetry/sync-telemetry.test.ts +0 -118
  136. package/test/unit/sync/utils/event-emitter.test.ts +0 -64
  137. package/test/unit/sync/utils/throttle.test.ts +0 -245
  138. package/test/unit/url-builder.test.ts +0 -72
  139. package/test/unit/user/account.test.ts +0 -66
  140. package/test/unit/user/permissions.test.js +0 -191
@@ -1,217 +0,0 @@
1
- import { Database } from '@nozbe/watermelondb'
2
- import { makeTelemetry, makeContext, makePullMock, makePushMock } from '../../../unit/sync/helpers/index'
3
- import TestModel, { makeTestDatabase } from '../../../unit/sync/helpers/TestModel'
4
- import SyncStore from '@/services/sync/store/index'
5
- import SyncRetry from '@/services/sync/retry'
6
- import SyncRunScope from '@/services/sync/run-scope'
7
- import type { SyncUserScope } from '@/services/sync/index'
8
- import { SyncError } from '@/services/sync/errors/index'
9
-
10
- // ---
11
-
12
- let db: Database
13
-
14
- function makeStore(userScope: SyncUserScope, pull = makePullMock()) {
15
- const context = makeContext()
16
- const telemetry = makeTelemetry(userScope)
17
- const retry = new SyncRetry(context, telemetry)
18
- const runScope = new SyncRunScope()
19
-
20
- return new SyncStore<TestModel>(
21
- { model: TestModel, pull, push: makePushMock() },
22
- userScope,
23
- context,
24
- db,
25
- retry,
26
- runScope,
27
- telemetry
28
- )
29
- }
30
-
31
- function makeScope(overrides: Partial<SyncUserScope> = {}): SyncUserScope {
32
- return {
33
- initialId: 1,
34
- getCurrentId: () => 1,
35
- ...overrides,
36
- }
37
- }
38
-
39
- function makePullResponse(overrides: Partial<{ intendedUserId: number }> = {}) {
40
- return jest.fn().mockResolvedValue({
41
- ok: true,
42
- entries: [],
43
- token: Date.now(),
44
- previousToken: null,
45
- intendedUserId: 1,
46
- ...overrides,
47
- })
48
- }
49
-
50
- beforeEach(() => {
51
- db = makeTestDatabase()
52
- })
53
-
54
- afterEach(async () => {
55
- await db.write(async () => db.unsafeResetDatabase())
56
- })
57
-
58
- // ---
59
-
60
- describe('write protection (paranoidWrite)', () => {
61
- describe('same user', () => {
62
- test('write proceeds when getCurrentId matches initialId', async () => {
63
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => 1 }))
64
- const result = await store.insertOne(r => { r.value = 'hello' })
65
- store.destroy()
66
-
67
- expect(result.value).toBe('hello')
68
- })
69
- })
70
-
71
- describe('different user', () => {
72
- test('throws SyncError when getCurrentId returns different id', async () => {
73
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => 2 }))
74
-
75
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(SyncError)
76
- store.destroy()
77
- })
78
-
79
- test('error message indicates cross-user write', async () => {
80
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => 2 }))
81
-
82
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(
83
- 'Aborted cross-user write operation'
84
- )
85
- store.destroy()
86
- })
87
- })
88
-
89
- describe('null getCurrentId without fetchCurrentId', () => {
90
- test('throws SyncError', async () => {
91
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => null }))
92
-
93
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(SyncError)
94
- store.destroy()
95
- })
96
-
97
- test('error message indicates cross-user write', async () => {
98
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => null }))
99
-
100
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(
101
- 'Aborted cross-user write operation'
102
- )
103
- store.destroy()
104
- })
105
- })
106
-
107
- describe('fetchCurrentId fallback', () => {
108
- test('fetchCurrentId is called when getCurrentId returns null', async () => {
109
- const fetchCurrentId = jest.fn().mockResolvedValue(1)
110
- const store = makeStore(makeScope({ initialId: 1, getCurrentId: () => null, fetchCurrentId }))
111
-
112
- await store.insertOne(r => { r.value = 'hello' })
113
- store.destroy()
114
-
115
- expect(fetchCurrentId).toHaveBeenCalledTimes(1)
116
- })
117
-
118
- test('write proceeds when fetchCurrentId resolves to same id', async () => {
119
- const store = makeStore(makeScope({
120
- initialId: 1,
121
- getCurrentId: () => null,
122
- fetchCurrentId: () => Promise.resolve(1),
123
- }))
124
-
125
- const result = await store.insertOne(r => { r.value = 'resolved' })
126
- store.destroy()
127
-
128
- expect(result.value).toBe('resolved')
129
- })
130
-
131
- test('throws when fetchCurrentId resolves to different id', async () => {
132
- const store = makeStore(makeScope({
133
- initialId: 1,
134
- getCurrentId: () => null,
135
- fetchCurrentId: () => Promise.resolve(2),
136
- }))
137
-
138
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(
139
- 'Aborted cross-user write operation'
140
- )
141
- store.destroy()
142
- })
143
-
144
- test('throws SyncError when fetchCurrentId rejects', async () => {
145
- const store = makeStore(makeScope({
146
- initialId: 1,
147
- getCurrentId: () => null,
148
- fetchCurrentId: () => Promise.reject(new Error('network error')),
149
- }))
150
-
151
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toBeInstanceOf(SyncError)
152
- store.destroy()
153
- })
154
-
155
- test('error message indicates fetchCurrentId failed', async () => {
156
- const store = makeStore(makeScope({
157
- initialId: 1,
158
- getCurrentId: () => null,
159
- fetchCurrentId: () => Promise.reject(new Error('network error')),
160
- }))
161
-
162
- await expect(store.insertOne(r => { r.value = 'hello' })).rejects.toThrow(
163
- 'Aborted cross-user write operation after fetchCurrentId failed'
164
- )
165
- store.destroy()
166
- })
167
- })
168
- })
169
-
170
- // ---
171
-
172
- describe('pull protection (intendedUserId)', () => {
173
- test('pull succeeds when intendedUserId matches initialId', async () => {
174
- const store = makeStore(makeScope({ initialId: 1 }), makePullResponse({ intendedUserId: 1 }))
175
-
176
- await expect(store.pull('test')).resolves.not.toThrow()
177
- store.destroy()
178
- })
179
-
180
- test('throws SyncError when intendedUserId does not match initialId', async () => {
181
- const store = makeStore(makeScope({ initialId: 1 }), makePullResponse({ intendedUserId: 2 }))
182
-
183
- await expect(store.pull('test')).rejects.toThrow(SyncError)
184
- store.destroy()
185
- })
186
-
187
- test('throws when intendedUserId does not match currentId', async () => {
188
- const store = makeStore(
189
- makeScope({ initialId: 1, getCurrentId: () => 2 }),
190
- makePullResponse({ intendedUserId: 1 })
191
- )
192
-
193
- await expect(store.pull('test')).rejects.toThrow(SyncError)
194
- store.destroy()
195
- })
196
-
197
- test('error message indicates intended user mismatch', async () => {
198
- const store = makeStore(makeScope({ initialId: 1 }), makePullResponse({ intendedUserId: 2 }))
199
-
200
- await expect(store.pull('test')).rejects.toThrow('Intended user ID does not match')
201
- store.destroy()
202
- })
203
-
204
- test('throws SyncError when getCurrentId is null and fetchCurrentId rejects during pull', async () => {
205
- const store = makeStore(
206
- makeScope({
207
- initialId: 1,
208
- getCurrentId: () => null,
209
- fetchCurrentId: () => Promise.reject(new Error('auth error')),
210
- }),
211
- makePullResponse({ intendedUserId: 1 })
212
- )
213
-
214
- await expect(store.pull('test')).rejects.toThrow(SyncError)
215
- store.destroy()
216
- })
217
- })
@@ -1,180 +0,0 @@
1
- /**
2
- * @jest-environment jsdom
3
- *
4
- * Tests SyncStore with the IncrementalIndexedDB-backed LokiJS adapter.
5
- *
6
- * Scope: IDB-specific behavior only (fetch token persistence, initialization,
7
- * and bootstrapping — data loading from IDB into a new Database instance).
8
- * General CRUD/event/coalescing behavior is covered in store.test.ts, which uses
9
- * the plain LokiJS in-memory adapter.
10
- *
11
- * Concurrency note: loki.saveDatabase() with fakeIndexedDB's IncrementalIDBAdapter
12
- * produces conflicting IDB transactions when multiple writes happen in rapid sequence
13
- * (IncrementalIDBAdapter auto-save overlaps with ensurePersistence()'s saveDatabase()).
14
- * Bootstrapping tests use a single write per "session" to stay within the safe window.
15
- */
16
-
17
- import { IDBFactory } from 'fake-indexeddb'
18
- import { makeTelemetry, makeContext, makeUserScope, makePullMock, makePushMock, TEST_USER_ID } from '../../../unit/sync/helpers/index'
19
- import TestModel, { makeTestDatabase } from '../../../unit/sync/helpers/TestModel'
20
- import SyncStore from '@/services/sync/store/index'
21
- import SyncRetry from '@/services/sync/retry'
22
- import SyncRunScope from '@/services/sync/run-scope'
23
- import type { SyncPullResponse } from '@/services/sync/fetch'
24
-
25
- // Fresh IDB instance per test — prevents cross-test transaction leakage
26
- beforeEach(() => {
27
- ;(global as any).indexedDB = new IDBFactory()
28
- })
29
-
30
- function makeStore(overrides: { pull?: any; push?: any; dbName?: string } = {}) {
31
- const db = makeTestDatabase({ useIncrementalIndexedDB: true, dbName: overrides.dbName })
32
- const userScope = makeUserScope()
33
- const context = makeContext()
34
- const telemetry = makeTelemetry(userScope)
35
- const retry = new SyncRetry(context, telemetry)
36
- const runScope = new SyncRunScope()
37
-
38
- const store = new SyncStore<TestModel>(
39
- {
40
- model: TestModel,
41
- pull: overrides.pull ?? makePullMock(),
42
- push: overrides.push ?? makePushMock(),
43
- },
44
- userScope,
45
- context,
46
- db,
47
- retry,
48
- runScope,
49
- telemetry
50
- )
51
-
52
- return { store, db }
53
- }
54
-
55
- // ---
56
-
57
- describe('fetch token persistence (IDB localStorage)', () => {
58
- test('getLastFetchToken returns null before any pull', async () => {
59
- const { store } = makeStore()
60
- const token = await store.getLastFetchToken()
61
- store.destroy()
62
-
63
- expect(token).toBeNull()
64
- })
65
-
66
- test('getLastFetchToken is set after successful pull', async () => {
67
- const expectedToken = 1700000000000
68
- const pull = jest.fn().mockResolvedValue({
69
- ok: true,
70
- entries: [],
71
- token: expectedToken,
72
- intendedUserId: TEST_USER_ID,
73
- previousToken: null,
74
- } as Extract<SyncPullResponse, { ok: true }>)
75
-
76
- const { store } = makeStore({ pull })
77
- await store.pullRecords()
78
- const token = await store.getLastFetchToken()
79
- store.destroy()
80
-
81
- expect(token).toBe(expectedToken)
82
- })
83
-
84
- test('pullCompleted event fires after successful pull', async () => {
85
- const handler = jest.fn()
86
- const { store } = makeStore()
87
- store.on('pullCompleted', handler)
88
-
89
- await store.pullRecords()
90
- store.destroy()
91
-
92
- expect(handler).toHaveBeenCalledTimes(1)
93
- })
94
-
95
- test('failed pull does not set fetch token', async () => {
96
- const pull = jest.fn().mockResolvedValue({ ok: false, failureType: 'fetch', isRetryable: false })
97
-
98
- const { store } = makeStore({ pull })
99
- await store.pullRecords()
100
- const token = await store.getLastFetchToken()
101
- store.destroy()
102
-
103
- expect(token).toBeNull()
104
- })
105
- })
106
-
107
- // ---
108
-
109
- describe('IDB bootstrapping (prior session data loaded into new Database instance)', () => {
110
- const BOOTSTRAP_DB = 'test-bootstrap'
111
-
112
- test('records written locally are readable from a new Database instance', async () => {
113
- const { store: session1 } = makeStore({ dbName: BOOTSTRAP_DB })
114
- await session1.upsertOne('boot-rec-1', r => {
115
- r.value = 'persisted-value'
116
- r.score = 42
117
- })
118
- session1.destroy()
119
-
120
- const { store: session2 } = makeStore({ dbName: BOOTSTRAP_DB })
121
- const records = await session2.readAll()
122
- session2.destroy()
123
-
124
- expect(records).toHaveLength(1)
125
- expect(records[0].id).toBe('boot-rec-1')
126
- expect(records[0].value).toBe('persisted-value')
127
- expect(records[0].score).toBe(42)
128
- })
129
-
130
- test('fetch token written during pull is readable from a new Database instance', async () => {
131
- const TOKEN = 1700000000000
132
- const pull = jest.fn().mockResolvedValue({
133
- ok: true,
134
- entries: [],
135
- token: TOKEN,
136
- intendedUserId: TEST_USER_ID,
137
- previousToken: null,
138
- })
139
-
140
- const { store: session1 } = makeStore({ pull, dbName: BOOTSTRAP_DB })
141
- await session1.pullRecords()
142
- // pull doesn't call ensurePersistence — flush explicitly so IDB has the token
143
- await (session1 as any).ensurePersistence()
144
- session1.destroy()
145
-
146
- const { store: session2 } = makeStore({ dbName: BOOTSTRAP_DB })
147
- const token = await session2.getLastFetchToken()
148
- session2.destroy()
149
-
150
- expect(token).toBe(TOKEN)
151
- })
152
-
153
- // Two sequential upserts — if this flakes with IDB transaction conflicts,
154
- // collapse them into a single upsertSome call instead.
155
- test('multiple records survive a restart', async () => {
156
- const { store: session1 } = makeStore({ dbName: BOOTSTRAP_DB })
157
- await session1.upsertOne('boot-a', r => { r.value = 'alpha'; r.score = 1 })
158
- await session1.upsertOne('boot-b', r => { r.value = 'beta'; r.score = 2 })
159
- session1.destroy()
160
-
161
- const { store: session2 } = makeStore({ dbName: BOOTSTRAP_DB })
162
- const records = await session2.readAll()
163
- session2.destroy()
164
-
165
- expect(records).toHaveLength(2)
166
- const byId = Object.fromEntries(records.map(r => [r.id, r]))
167
- expect(byId['boot-a'].value).toBe('alpha')
168
- expect(byId['boot-b'].value).toBe('beta')
169
- })
170
-
171
- test('new Database instance with no prior IDB data starts empty', async () => {
172
- const { store } = makeStore({ dbName: BOOTSTRAP_DB })
173
- const records = await store.readAll()
174
- const token = await store.getLastFetchToken()
175
- store.destroy()
176
-
177
- expect(records).toHaveLength(0)
178
- expect(token).toBeNull()
179
- })
180
- })