@youversion/platform-react-hooks 1.18.1 → 1.19.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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +3 -7
- package/CHANGELOG.md +17 -0
- package/dist/__tests__/mocks/bibles.d.ts +6 -1
- package/dist/__tests__/mocks/bibles.d.ts.map +1 -1
- package/dist/__tests__/mocks/bibles.js +10 -0
- package/dist/__tests__/mocks/bibles.js.map +1 -1
- package/dist/__tests__/mocks/core-mock-factory.d.ts +83 -0
- package/dist/__tests__/mocks/core-mock-factory.d.ts.map +1 -0
- package/dist/__tests__/mocks/core-mock-factory.js +138 -0
- package/dist/__tests__/mocks/core-mock-factory.js.map +1 -0
- package/dist/context/ReaderContext.d.ts +6 -0
- package/dist/context/ReaderContext.d.ts.map +1 -1
- package/dist/context/ReaderContext.js +6 -0
- package/dist/context/ReaderContext.js.map +1 -1
- package/dist/context/ReaderProvider.d.ts +3 -0
- package/dist/context/ReaderProvider.d.ts.map +1 -1
- package/dist/context/ReaderProvider.js +3 -0
- package/dist/context/ReaderProvider.js.map +1 -1
- package/dist/context/VerseSelectionContext.d.ts +6 -0
- package/dist/context/VerseSelectionContext.d.ts.map +1 -1
- package/dist/context/VerseSelectionContext.js +3 -0
- package/dist/context/VerseSelectionContext.js.map +1 -1
- package/dist/context/VerseSelectionProvider.d.ts +3 -0
- package/dist/context/VerseSelectionProvider.d.ts.map +1 -1
- package/dist/context/VerseSelectionProvider.js +3 -0
- package/dist/context/VerseSelectionProvider.js.map +1 -1
- package/dist/test/utils.d.ts +7 -0
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/test/utils.js +7 -0
- package/dist/test/utils.js.map +1 -0
- package/dist/useChapterNavigation.d.ts +3 -0
- package/dist/useChapterNavigation.d.ts.map +1 -1
- package/dist/useChapterNavigation.js +3 -0
- package/dist/useChapterNavigation.js.map +1 -1
- package/dist/useInitData.d.ts +4 -0
- package/dist/useInitData.d.ts.map +1 -1
- package/dist/useInitData.js +4 -0
- package/dist/useInitData.js.map +1 -1
- package/dist/useVerseSelection.d.ts +3 -0
- package/dist/useVerseSelection.d.ts.map +1 -1
- package/dist/useVerseSelection.js +3 -0
- package/dist/useVerseSelection.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/mocks/bibles.ts +18 -1
- package/src/__tests__/mocks/core-mock-factory.ts +226 -0
- package/src/context/ReaderContext.tsx +6 -0
- package/src/context/ReaderProvider.tsx +3 -0
- package/src/context/VerseSelectionContext.tsx +6 -0
- package/src/context/VerseSelectionProvider.tsx +3 -0
- package/src/context/YouVersionAuthProvider.test.tsx +14 -131
- package/src/test/utils.tsx +12 -0
- package/src/useBibleClient.test.tsx +8 -37
- package/src/useBook.test.tsx +158 -0
- package/src/useBooks.test.tsx +148 -0
- package/src/useChapter.test.tsx +70 -128
- package/src/useChapterNavigation.ts +3 -0
- package/src/useChapters.test.tsx +80 -150
- package/src/useHighlights.test.tsx +33 -104
- package/src/useInitData.ts +4 -0
- package/src/useLanguage.test.tsx +8 -10
- package/src/useLanguageClient.test.tsx +9 -25
- package/src/useLanguages.test.tsx +27 -64
- package/src/usePassage.test.tsx +304 -0
- package/src/useTheme.test.tsx +32 -0
- package/src/useVOTD.test.tsx +28 -67
- package/src/useVerse.test.tsx +73 -149
- package/src/useVerseSelection.ts +3 -0
- package/src/useVerses.test.tsx +37 -104
- package/src/useVersion.test.tsx +29 -66
- package/src/useVersions.test.tsx +72 -154
- package/src/useYVAuth.test.tsx +26 -134
- package/src/utility/getDayOfYear.test.ts +48 -0
- package/vitest.config.ts +12 -0
- package/src/context/ReaderProvider.test.tsx +0 -264
- package/src/context/VerseSelectionProvider.test.tsx +0 -362
- package/src/useChapterNavigation.test.tsx +0 -160
- package/src/useVerseSelection.test.tsx +0 -33
- package/vitest.setup.ts +0 -1
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { renderHook, act } from '@testing-library/react';
|
|
3
|
-
import type { ReactNode } from 'react';
|
|
4
|
-
import { VerseSelectionProvider } from './VerseSelectionProvider';
|
|
5
|
-
import { useVerseSelection } from '../useVerseSelection';
|
|
6
|
-
|
|
7
|
-
// Wrapper for renderHook
|
|
8
|
-
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
9
|
-
<VerseSelectionProvider>{children}</VerseSelectionProvider>
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
describe('VerseSelectionProvider', () => {
|
|
13
|
-
describe('initial state', () => {
|
|
14
|
-
it('should provide an empty Set instance', () => {
|
|
15
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
16
|
-
|
|
17
|
-
expect(result.current.selectedVerseUsfms).toBeInstanceOf(Set);
|
|
18
|
-
expect(result.current.selectedVerseUsfms.size).toBe(0);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should have selectedCount of 0', () => {
|
|
22
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
23
|
-
|
|
24
|
-
expect(result.current.selectedCount).toBe(0);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should return false for isSelected on any verse', () => {
|
|
28
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
29
|
-
|
|
30
|
-
expect(result.current.isSelected('MAT.1.1')).toBe(false);
|
|
31
|
-
expect(result.current.isSelected('GEN.1.1')).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('toggleVerse', () => {
|
|
36
|
-
it('should add verse to selection when not present', () => {
|
|
37
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
38
|
-
|
|
39
|
-
act(() => {
|
|
40
|
-
result.current.toggleVerse('MAT.1.1');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
expect(result.current.selectedVerseUsfms.has('MAT.1.1')).toBe(true);
|
|
44
|
-
expect(result.current.selectedCount).toBe(1);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should remove verse from selection when already present', () => {
|
|
48
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
49
|
-
|
|
50
|
-
act(() => {
|
|
51
|
-
result.current.toggleVerse('MAT.1.1');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
expect(result.current.selectedCount).toBe(1);
|
|
55
|
-
|
|
56
|
-
act(() => {
|
|
57
|
-
result.current.toggleVerse('MAT.1.1');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(result.current.selectedVerseUsfms.has('MAT.1.1')).toBe(false);
|
|
61
|
-
expect(result.current.selectedCount).toBe(0);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should support multiple verses selected simultaneously', () => {
|
|
65
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
66
|
-
|
|
67
|
-
act(() => {
|
|
68
|
-
result.current.toggleVerse('MAT.1.1');
|
|
69
|
-
result.current.toggleVerse('GEN.1.1');
|
|
70
|
-
result.current.toggleVerse('JHN.3.16');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(result.current.selectedCount).toBe(3);
|
|
74
|
-
expect(result.current.selectedVerseUsfms.has('MAT.1.1')).toBe(true);
|
|
75
|
-
expect(result.current.selectedVerseUsfms.has('GEN.1.1')).toBe(true);
|
|
76
|
-
expect(result.current.selectedVerseUsfms.has('JHN.3.16')).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should create new Set reference on each update (immutability)', () => {
|
|
80
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
81
|
-
|
|
82
|
-
const set1 = result.current.selectedVerseUsfms;
|
|
83
|
-
|
|
84
|
-
act(() => {
|
|
85
|
-
result.current.toggleVerse('MAT.1.1');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const set2 = result.current.selectedVerseUsfms;
|
|
89
|
-
|
|
90
|
-
expect(set1).not.toBe(set2);
|
|
91
|
-
expect(set1.size).toBe(0);
|
|
92
|
-
expect(set2.size).toBe(1);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should create new Set reference when removing a verse', () => {
|
|
96
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
97
|
-
|
|
98
|
-
act(() => {
|
|
99
|
-
result.current.toggleVerse('MAT.1.1');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const setWithVerse = result.current.selectedVerseUsfms;
|
|
103
|
-
|
|
104
|
-
act(() => {
|
|
105
|
-
result.current.toggleVerse('MAT.1.1');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const setWithoutVerse = result.current.selectedVerseUsfms;
|
|
109
|
-
|
|
110
|
-
expect(setWithVerse).not.toBe(setWithoutVerse);
|
|
111
|
-
expect(setWithVerse.size).toBe(1);
|
|
112
|
-
expect(setWithoutVerse.size).toBe(0);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should not add duplicate verses', () => {
|
|
116
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
117
|
-
|
|
118
|
-
act(() => {
|
|
119
|
-
result.current.toggleVerse('MAT.1.1');
|
|
120
|
-
result.current.toggleVerse('MAT.1.1');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Should toggle off, not add twice
|
|
124
|
-
expect(result.current.selectedCount).toBe(0);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe('isSelected', () => {
|
|
129
|
-
it('should return true for selected verses', () => {
|
|
130
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
131
|
-
|
|
132
|
-
act(() => {
|
|
133
|
-
result.current.toggleVerse('MAT.1.1');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
expect(result.current.isSelected('MAT.1.1')).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('should return false for unselected verses', () => {
|
|
140
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
141
|
-
|
|
142
|
-
act(() => {
|
|
143
|
-
result.current.toggleVerse('MAT.1.1');
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
expect(result.current.isSelected('GEN.1.1')).toBe(false);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should work correctly after toggle operations', () => {
|
|
150
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
151
|
-
|
|
152
|
-
// Initially not selected
|
|
153
|
-
expect(result.current.isSelected('MAT.1.1')).toBe(false);
|
|
154
|
-
|
|
155
|
-
// Add verse - now selected
|
|
156
|
-
act(() => {
|
|
157
|
-
result.current.toggleVerse('MAT.1.1');
|
|
158
|
-
});
|
|
159
|
-
expect(result.current.isSelected('MAT.1.1')).toBe(true);
|
|
160
|
-
|
|
161
|
-
// Remove verse - not selected again
|
|
162
|
-
act(() => {
|
|
163
|
-
result.current.toggleVerse('MAT.1.1');
|
|
164
|
-
});
|
|
165
|
-
expect(result.current.isSelected('MAT.1.1')).toBe(false);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
describe('clearSelection', () => {
|
|
170
|
-
it('should clear all selected verses', () => {
|
|
171
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
172
|
-
|
|
173
|
-
act(() => {
|
|
174
|
-
result.current.toggleVerse('MAT.1.1');
|
|
175
|
-
result.current.toggleVerse('GEN.1.1');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
expect(result.current.selectedCount).toBe(2);
|
|
179
|
-
|
|
180
|
-
act(() => {
|
|
181
|
-
result.current.clearSelection();
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
expect(result.current.selectedCount).toBe(0);
|
|
185
|
-
expect(result.current.selectedVerseUsfms.size).toBe(0);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should create new Set reference', () => {
|
|
189
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
190
|
-
|
|
191
|
-
act(() => {
|
|
192
|
-
result.current.toggleVerse('MAT.1.1');
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const setBeforeClear = result.current.selectedVerseUsfms;
|
|
196
|
-
|
|
197
|
-
act(() => {
|
|
198
|
-
result.current.clearSelection();
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const setAfterClear = result.current.selectedVerseUsfms;
|
|
202
|
-
|
|
203
|
-
expect(setBeforeClear).not.toBe(setAfterClear);
|
|
204
|
-
expect(setBeforeClear.size).toBe(1);
|
|
205
|
-
expect(setAfterClear.size).toBe(0);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('should work when already empty', () => {
|
|
209
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
210
|
-
|
|
211
|
-
const setBeforeClear = result.current.selectedVerseUsfms;
|
|
212
|
-
|
|
213
|
-
act(() => {
|
|
214
|
-
result.current.clearSelection();
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
const setAfterClear = result.current.selectedVerseUsfms;
|
|
218
|
-
|
|
219
|
-
expect(setBeforeClear).not.toBe(setAfterClear);
|
|
220
|
-
expect(setAfterClear.size).toBe(0);
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe('selectedCount', () => {
|
|
225
|
-
it('should start at 0', () => {
|
|
226
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
227
|
-
|
|
228
|
-
expect(result.current.selectedCount).toBe(0);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('should increment when verse added', () => {
|
|
232
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
233
|
-
|
|
234
|
-
act(() => {
|
|
235
|
-
result.current.toggleVerse('MAT.1.1');
|
|
236
|
-
});
|
|
237
|
-
expect(result.current.selectedCount).toBe(1);
|
|
238
|
-
|
|
239
|
-
act(() => {
|
|
240
|
-
result.current.toggleVerse('GEN.1.1');
|
|
241
|
-
});
|
|
242
|
-
expect(result.current.selectedCount).toBe(2);
|
|
243
|
-
|
|
244
|
-
act(() => {
|
|
245
|
-
result.current.toggleVerse('JHN.3.16');
|
|
246
|
-
});
|
|
247
|
-
expect(result.current.selectedCount).toBe(3);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('should decrement when verse removed', () => {
|
|
251
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
252
|
-
|
|
253
|
-
act(() => {
|
|
254
|
-
result.current.toggleVerse('MAT.1.1');
|
|
255
|
-
result.current.toggleVerse('GEN.1.1');
|
|
256
|
-
});
|
|
257
|
-
expect(result.current.selectedCount).toBe(2);
|
|
258
|
-
|
|
259
|
-
act(() => {
|
|
260
|
-
result.current.toggleVerse('MAT.1.1');
|
|
261
|
-
});
|
|
262
|
-
expect(result.current.selectedCount).toBe(1);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should return to 0 after clear', () => {
|
|
266
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
267
|
-
|
|
268
|
-
act(() => {
|
|
269
|
-
result.current.toggleVerse('MAT.1.1');
|
|
270
|
-
result.current.toggleVerse('GEN.1.1');
|
|
271
|
-
result.current.toggleVerse('JHN.3.16');
|
|
272
|
-
});
|
|
273
|
-
expect(result.current.selectedCount).toBe(3);
|
|
274
|
-
|
|
275
|
-
act(() => {
|
|
276
|
-
result.current.clearSelection();
|
|
277
|
-
});
|
|
278
|
-
expect(result.current.selectedCount).toBe(0);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe('callback stability', () => {
|
|
283
|
-
it('should have stable toggleVerse reference across renders', () => {
|
|
284
|
-
const { result, rerender } = renderHook(() => useVerseSelection(), { wrapper });
|
|
285
|
-
|
|
286
|
-
const toggleRef1 = result.current.toggleVerse;
|
|
287
|
-
|
|
288
|
-
rerender();
|
|
289
|
-
|
|
290
|
-
const toggleRef2 = result.current.toggleVerse;
|
|
291
|
-
|
|
292
|
-
expect(toggleRef1).toBe(toggleRef2);
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it('should have stable clearSelection reference across renders', () => {
|
|
296
|
-
const { result, rerender } = renderHook(() => useVerseSelection(), { wrapper });
|
|
297
|
-
|
|
298
|
-
const clearRef1 = result.current.clearSelection;
|
|
299
|
-
|
|
300
|
-
rerender();
|
|
301
|
-
|
|
302
|
-
const clearRef2 = result.current.clearSelection;
|
|
303
|
-
|
|
304
|
-
expect(clearRef1).toBe(clearRef2);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it('should have stable toggleVerse reference after state changes', () => {
|
|
308
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
309
|
-
|
|
310
|
-
const toggleRef1 = result.current.toggleVerse;
|
|
311
|
-
|
|
312
|
-
act(() => {
|
|
313
|
-
result.current.toggleVerse('MAT.1.1');
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
const toggleRef2 = result.current.toggleVerse;
|
|
317
|
-
|
|
318
|
-
expect(toggleRef1).toBe(toggleRef2);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it('should have stable clearSelection reference after state changes', () => {
|
|
322
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
323
|
-
|
|
324
|
-
const clearRef1 = result.current.clearSelection;
|
|
325
|
-
|
|
326
|
-
act(() => {
|
|
327
|
-
result.current.toggleVerse('MAT.1.1');
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const clearRef2 = result.current.clearSelection;
|
|
331
|
-
|
|
332
|
-
expect(clearRef1).toBe(clearRef2);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it('should update isSelected reference when selectedVerseUsfms changes', () => {
|
|
336
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
337
|
-
|
|
338
|
-
const isSelectedRef1 = result.current.isSelected;
|
|
339
|
-
|
|
340
|
-
act(() => {
|
|
341
|
-
result.current.toggleVerse('MAT.1.1');
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
const isSelectedRef2 = result.current.isSelected;
|
|
345
|
-
|
|
346
|
-
// isSelected has selectedVerseUsfms in its dependency array, so it should change
|
|
347
|
-
expect(isSelectedRef1).not.toBe(isSelectedRef2);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it('should have stable isSelected reference when no state changes', () => {
|
|
351
|
-
const { result, rerender } = renderHook(() => useVerseSelection(), { wrapper });
|
|
352
|
-
|
|
353
|
-
const isSelectedRef1 = result.current.isSelected;
|
|
354
|
-
|
|
355
|
-
rerender();
|
|
356
|
-
|
|
357
|
-
const isSelectedRef2 = result.current.isSelected;
|
|
358
|
-
|
|
359
|
-
expect(isSelectedRef1).toBe(isSelectedRef2);
|
|
360
|
-
});
|
|
361
|
-
});
|
|
362
|
-
});
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { renderHook, act } from '@testing-library/react';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { useChapterNavigation } from './useChapterNavigation';
|
|
5
|
-
import { useReaderContext } from './context/ReaderContext';
|
|
6
|
-
import { ReaderProvider } from './context/ReaderProvider';
|
|
7
|
-
import { createMockBook, createMockVersion } from './__tests__/mocks/bibles';
|
|
8
|
-
import type { BibleBook, BibleChapter } from '@youversion/platform-core';
|
|
9
|
-
|
|
10
|
-
function makeChapters(bookId: string, count: number): BibleChapter[] {
|
|
11
|
-
return Array.from({ length: count }, (_, i) => ({
|
|
12
|
-
id: (i + 1).toString(),
|
|
13
|
-
passage_id: `${bookId}.${i + 1}`,
|
|
14
|
-
title: (i + 1).toString(),
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const genChapters = makeChapters('GEN', 50);
|
|
19
|
-
const exoChapters = makeChapters('EXO', 40);
|
|
20
|
-
const revChapters = makeChapters('REV', 22);
|
|
21
|
-
|
|
22
|
-
const mockBooks: BibleBook[] = [
|
|
23
|
-
createMockBook({
|
|
24
|
-
id: 'GEN',
|
|
25
|
-
title: 'Genesis',
|
|
26
|
-
chapters: genChapters,
|
|
27
|
-
intro: { id: 'INTRO', passage_id: 'GEN.INTRO', title: 'Intro' },
|
|
28
|
-
}),
|
|
29
|
-
createMockBook({
|
|
30
|
-
id: 'EXO',
|
|
31
|
-
title: 'Exodus',
|
|
32
|
-
canon: 'old_testament',
|
|
33
|
-
chapters: exoChapters,
|
|
34
|
-
}),
|
|
35
|
-
createMockBook({
|
|
36
|
-
id: 'REV',
|
|
37
|
-
title: 'Revelation',
|
|
38
|
-
canon: 'new_testament',
|
|
39
|
-
chapters: revChapters,
|
|
40
|
-
}),
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
const mockUseBooks = vi.fn();
|
|
44
|
-
vi.mock('./useBooks', () => ({
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
46
|
-
useBooks: (...args: unknown[]) => mockUseBooks(...args),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
function useNavWithContext() {
|
|
50
|
-
const nav = useChapterNavigation();
|
|
51
|
-
const ctx = useReaderContext();
|
|
52
|
-
return { nav, ctx };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function wrapper(book: BibleBook, chapter: BibleChapter) {
|
|
56
|
-
return ({ children }: { children: React.ReactNode }) => (
|
|
57
|
-
<ReaderProvider
|
|
58
|
-
currentVersion={createMockVersion()}
|
|
59
|
-
currentBook={book}
|
|
60
|
-
currentChapter={chapter}
|
|
61
|
-
currentVerse={null}
|
|
62
|
-
>
|
|
63
|
-
{children}
|
|
64
|
-
</ReaderProvider>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const genBook = mockBooks[0]!;
|
|
69
|
-
const exoBook = mockBooks[1]!;
|
|
70
|
-
const revBook = mockBooks[2]!;
|
|
71
|
-
|
|
72
|
-
describe('useChapterNavigation', () => {
|
|
73
|
-
beforeEach(() => {
|
|
74
|
-
mockUseBooks.mockReturnValue({
|
|
75
|
-
books: { data: mockBooks },
|
|
76
|
-
loading: false,
|
|
77
|
-
error: null,
|
|
78
|
-
refetch: vi.fn(),
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('navigateToNext within same book updates chapter, keeps book', () => {
|
|
83
|
-
const { result } = renderHook(useNavWithContext, {
|
|
84
|
-
wrapper: wrapper(genBook, genChapters[0]!),
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
act(() => result.current.nav.navigateToNext());
|
|
88
|
-
|
|
89
|
-
expect(result.current.ctx.currentChapter.id).toBe('2');
|
|
90
|
-
expect(result.current.ctx.currentBook.id).toBe('GEN');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('navigateToNext cross-book updates both book and chapter', () => {
|
|
94
|
-
const { result } = renderHook(useNavWithContext, {
|
|
95
|
-
wrapper: wrapper(genBook, genChapters.at(-1)!),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
act(() => result.current.nav.navigateToNext());
|
|
99
|
-
|
|
100
|
-
expect(result.current.ctx.currentBook.id).toBe('EXO');
|
|
101
|
-
expect(result.current.ctx.currentChapter.id).toBe('1');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('navigateToPrevious to intro sets chapter to INTRO, keeps book', () => {
|
|
105
|
-
const { result } = renderHook(useNavWithContext, {
|
|
106
|
-
wrapper: wrapper(genBook, genChapters[0]!),
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
act(() => result.current.nav.navigateToPrevious());
|
|
110
|
-
|
|
111
|
-
expect(result.current.ctx.currentChapter.id).toBe('INTRO');
|
|
112
|
-
expect(result.current.ctx.currentBook.id).toBe('GEN');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('navigateToPrevious cross-book updates both book and chapter', () => {
|
|
116
|
-
const { result } = renderHook(useNavWithContext, {
|
|
117
|
-
wrapper: wrapper(exoBook, exoChapters[0]!),
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
act(() => result.current.nav.navigateToPrevious());
|
|
121
|
-
|
|
122
|
-
expect(result.current.ctx.currentBook.id).toBe('GEN');
|
|
123
|
-
expect(result.current.ctx.currentChapter.id).toBe('50');
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('canNavigatePrevious is false at Bible start', () => {
|
|
127
|
-
const introChapter: BibleChapter = { id: 'INTRO', passage_id: 'GEN.INTRO', title: 'Intro' };
|
|
128
|
-
|
|
129
|
-
const { result } = renderHook(useNavWithContext, {
|
|
130
|
-
wrapper: wrapper(genBook, introChapter),
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
expect(result.current.nav.canNavigatePrevious).toBe(false);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('canNavigateNext is false at Bible end', () => {
|
|
137
|
-
const { result } = renderHook(useNavWithContext, {
|
|
138
|
-
wrapper: wrapper(revBook, revChapters[21]!),
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(result.current.nav.canNavigateNext).toBe(false);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('both disabled while loading', () => {
|
|
145
|
-
mockUseBooks.mockReturnValue({
|
|
146
|
-
books: null,
|
|
147
|
-
loading: true,
|
|
148
|
-
error: null,
|
|
149
|
-
refetch: vi.fn(),
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const { result } = renderHook(useNavWithContext, {
|
|
153
|
-
wrapper: wrapper(genBook, genChapters[0]!),
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
expect(result.current.nav.canNavigateNext).toBe(false);
|
|
157
|
-
expect(result.current.nav.canNavigatePrevious).toBe(false);
|
|
158
|
-
expect(result.current.nav.isLoading).toBe(true);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import { renderHook } from '@testing-library/react';
|
|
3
|
-
import type { ReactNode } from 'react';
|
|
4
|
-
import { useVerseSelection } from './useVerseSelection';
|
|
5
|
-
import { VerseSelectionProvider } from './context/VerseSelectionProvider';
|
|
6
|
-
|
|
7
|
-
// Wrapper for renderHook
|
|
8
|
-
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
9
|
-
<VerseSelectionProvider>{children}</VerseSelectionProvider>
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
describe('useVerseSelection', () => {
|
|
13
|
-
it('should throw error when used outside provider', () => {
|
|
14
|
-
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(vi.fn());
|
|
15
|
-
|
|
16
|
-
expect(() => {
|
|
17
|
-
renderHook(() => useVerseSelection());
|
|
18
|
-
}).toThrow('useVerseSelection must be used within a VerseSelectionProvider');
|
|
19
|
-
|
|
20
|
-
consoleSpy.mockRestore();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should return expected shape with correct initial values', () => {
|
|
24
|
-
const { result } = renderHook(() => useVerseSelection(), { wrapper });
|
|
25
|
-
|
|
26
|
-
expect(result.current.selectedVerseUsfms).toBeInstanceOf(Set);
|
|
27
|
-
expect(result.current.selectedVerseUsfms.size).toBe(0);
|
|
28
|
-
expect(result.current.selectedCount).toBe(0);
|
|
29
|
-
expect(typeof result.current.toggleVerse).toBe('function');
|
|
30
|
-
expect(typeof result.current.isSelected).toBe('function');
|
|
31
|
-
expect(typeof result.current.clearSelection).toBe('function');
|
|
32
|
-
});
|
|
33
|
-
});
|
package/vitest.setup.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom/vitest';
|