@youversion/platform-react-hooks 1.11.0 → 1.12.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @youversion/platform-react-hooks@1.11.0 build /home/runner/work/platform-sdk-react/platform-sdk-react/packages/hooks
2
+ > @youversion/platform-react-hooks@1.12.0 build /home/runner/work/platform-sdk-react/platform-sdk-react/packages/hooks
3
3
  > tsc -p tsconfig.build.json
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @youversion/platform-react-hooks
2
2
 
3
+ ## 1.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1bafe50: Add all_available and fields parameters to getVersions api call in core package and useVersions in hooks package.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [1bafe50]
12
+ - @youversion/platform-core@1.12.0
13
+
3
14
  ## 1.11.0
4
15
 
5
16
  ### Minor Changes
@@ -0,0 +1,22 @@
1
+ import type { BibleBook, BibleChapter, BibleVerse, BibleVersion } from '@youversion/platform-core';
2
+ /**
3
+ * Creates a mock Bible version for testing
4
+ * @param overrides Optional properties to override defaults
5
+ */
6
+ export declare const createMockVersion: (overrides?: Partial<BibleVersion>) => BibleVersion;
7
+ /**
8
+ * Creates a mock Bible book for testing
9
+ * @param overrides Optional properties to override defaults
10
+ */
11
+ export declare const createMockBook: (overrides?: Partial<BibleBook>) => BibleBook;
12
+ /**
13
+ * Creates a mock Bible chapter for testing
14
+ * @param overrides Optional properties to override defaults
15
+ */
16
+ export declare const createMockChapter: (overrides?: Partial<BibleChapter>) => BibleChapter;
17
+ /**
18
+ * Creates a mock Bible verse for testing
19
+ * @param overrides Optional properties to override defaults
20
+ */
21
+ export declare const createMockVerse: (overrides?: Partial<BibleVerse>) => BibleVerse;
22
+ //# sourceMappingURL=bibles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bibles.d.ts","sourceRoot":"","sources":["../../../src/__tests__/mocks/bibles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEnG;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,YAAY,OAAO,CAAC,YAAY,CAAC,KAAG,YAcpE,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,YAAY,OAAO,CAAC,SAAS,CAAC,KAAG,SAO9D,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,YAAY,OAAO,CAAC,YAAY,CAAC,KAAG,YAKpE,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,OAAO,CAAC,UAAU,CAAC,KAAG,UAKhE,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Creates a mock Bible version for testing
3
+ * @param overrides Optional properties to override defaults
4
+ */
5
+ export const createMockVersion = (overrides) => ({
6
+ id: 1,
7
+ title: 'King James Version',
8
+ abbreviation: 'KJV',
9
+ copyright: '',
10
+ promotional_content: '',
11
+ info: null,
12
+ publisher_url: null,
13
+ language_tag: 'en',
14
+ localized_abbreviation: 'KJV',
15
+ localized_title: 'King James Version',
16
+ books: [],
17
+ youversion_deep_link: 'https://www.bible.com/versions/1',
18
+ ...overrides,
19
+ });
20
+ /**
21
+ * Creates a mock Bible book for testing
22
+ * @param overrides Optional properties to override defaults
23
+ */
24
+ export const createMockBook = (overrides) => ({
25
+ id: 'GEN',
26
+ title: 'Genesis',
27
+ full_title: 'The First Book of Moses, Commonly Called Genesis',
28
+ abbreviation: 'Gen',
29
+ canon: 'old_testament',
30
+ ...overrides,
31
+ });
32
+ /**
33
+ * Creates a mock Bible chapter for testing
34
+ * @param overrides Optional properties to override defaults
35
+ */
36
+ export const createMockChapter = (overrides) => ({
37
+ id: '1',
38
+ passage_id: 'GEN.1',
39
+ title: '1',
40
+ ...overrides,
41
+ });
42
+ /**
43
+ * Creates a mock Bible verse for testing
44
+ * @param overrides Optional properties to override defaults
45
+ */
46
+ export const createMockVerse = (overrides) => ({
47
+ id: '1',
48
+ passage_id: 'GEN.1.1',
49
+ title: '1',
50
+ ...overrides,
51
+ });
52
+ //# sourceMappingURL=bibles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bibles.js","sourceRoot":"","sources":["../../../src/__tests__/mocks/bibles.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiC,EAAgB,EAAE,CAAC,CAAC;IACrF,EAAE,EAAE,CAAC;IACL,KAAK,EAAE,oBAAoB;IAC3B,YAAY,EAAE,KAAK;IACnB,SAAS,EAAE,EAAE;IACb,mBAAmB,EAAE,EAAE;IACvB,IAAI,EAAE,IAAI;IACV,aAAa,EAAE,IAAI;IACnB,YAAY,EAAE,IAAI;IAClB,sBAAsB,EAAE,KAAK;IAC7B,eAAe,EAAE,oBAAoB;IACrC,KAAK,EAAE,EAAE;IACT,oBAAoB,EAAE,kCAAkC;IACxD,GAAG,SAAS;CACb,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAA8B,EAAa,EAAE,CAAC,CAAC;IAC5E,EAAE,EAAE,KAAK;IACT,KAAK,EAAE,SAAS;IAChB,UAAU,EAAE,kDAAkD;IAC9D,YAAY,EAAE,KAAK;IACnB,KAAK,EAAE,eAAe;IACtB,GAAG,SAAS;CACb,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiC,EAAgB,EAAE,CAAC,CAAC;IACrF,EAAE,EAAE,GAAG;IACP,UAAU,EAAE,OAAO;IACnB,KAAK,EAAE,GAAG;IACV,GAAG,SAAS;CACb,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,SAA+B,EAAc,EAAE,CAAC,CAAC;IAC/E,EAAE,EAAE,GAAG;IACP,UAAU,EAAE,SAAS;IACrB,KAAK,EAAE,GAAG;IACV,GAAG,SAAS;CACb,CAAC,CAAC"}
@@ -1,6 +1,16 @@
1
1
  import { type UseApiDataOptions } from './useApiData';
2
2
  import type { Collection, BibleVersion } from '@youversion/platform-core';
3
- export declare function useVersions(languageRanges?: string, licenseId?: string | number, options?: UseApiDataOptions): {
3
+ export interface UseVersionsOptions extends UseApiDataOptions {
4
+ /** Maximum number of results per page, or '*' for all (requires 1-3 fields) */
5
+ page_size?: number | '*';
6
+ /** Token for pagination */
7
+ page_token?: string;
8
+ /** Specific fields to return (required when page_size is '*', must be 1-3 fields) */
9
+ fields?: (keyof BibleVersion)[];
10
+ /** Include all available versions regardless of license */
11
+ all_available?: boolean;
12
+ }
13
+ export declare function useVersions(languageRanges?: string | string[], licenseId?: string | number, options?: UseVersionsOptions): {
4
14
  versions: Collection<BibleVersion> | null;
5
15
  loading: boolean;
6
16
  error: Error | null;
@@ -1 +1 @@
1
- {"version":3,"file":"useVersions.d.ts","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE1E,wBAAgB,WAAW,CACzB,cAAc,GAAE,MAAa,EAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC1B;IACD,QAAQ,EAAE,UAAU,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAiBA"}
1
+ {"version":3,"file":"useVersions.d.ts","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE1E,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACzB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,MAAM,CAAC,EAAE,CAAC,MAAM,YAAY,CAAC,EAAE,CAAC;IAChC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,WAAW,CACzB,cAAc,GAAE,MAAM,GAAG,MAAM,EAAS,EACxC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,OAAO,CAAC,EAAE,kBAAkB,GAC3B;IACD,QAAQ,EAAE,UAAU,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CA4CA"}
@@ -3,7 +3,31 @@ import { useBibleClient } from './useBibleClient';
3
3
  import { useApiData } from './useApiData';
4
4
  export function useVersions(languageRanges = 'en', licenseId, options) {
5
5
  const bibleClient = useBibleClient();
6
- const { data: versions, loading, error, refetch, } = useApiData(() => bibleClient.getVersions(languageRanges, licenseId), [bibleClient, languageRanges, licenseId], {
6
+ const getVersionsOptions = options?.page_size !== undefined ||
7
+ options?.page_token !== undefined ||
8
+ options?.fields !== undefined ||
9
+ options?.all_available !== undefined
10
+ ? {
11
+ page_size: options?.page_size,
12
+ page_token: options?.page_token,
13
+ fields: options?.fields,
14
+ all_available: options?.all_available,
15
+ }
16
+ : undefined;
17
+ // Create stable keys for arrays to avoid unnecessary refetches
18
+ const languageRangesKey = Array.isArray(languageRanges)
19
+ ? languageRanges.join(',')
20
+ : languageRanges;
21
+ const fieldsKey = options?.fields?.join(',');
22
+ const { data: versions, loading, error, refetch, } = useApiData(() => bibleClient.getVersions(languageRanges, licenseId, getVersionsOptions), [
23
+ bibleClient,
24
+ languageRangesKey,
25
+ licenseId,
26
+ options?.page_size,
27
+ options?.page_token,
28
+ fieldsKey,
29
+ options?.all_available,
30
+ ], {
7
31
  enabled: options?.enabled !== false,
8
32
  });
9
33
  return { versions, loading, error, refetch };
@@ -1 +1 @@
1
- {"version":3,"file":"useVersions.js","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AAGlE,MAAM,UAAU,WAAW,CACzB,iBAAyB,IAAI,EAC7B,SAA2B,EAC3B,OAA2B;IAO3B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,EACJ,IAAI,EAAE,QAAQ,EACd,OAAO,EACP,KAAK,EACL,OAAO,GACR,GAAG,UAAU,CACZ,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS,CAAC,EACxD,CAAC,WAAW,EAAE,cAAc,EAAE,SAAS,CAAC,EACxC;QACE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK;KACpC,CACF,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"useVersions.js","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AAclE,MAAM,UAAU,WAAW,CACzB,iBAAoC,IAAI,EACxC,SAA2B,EAC3B,OAA4B;IAO5B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,kBAAkB,GACtB,OAAO,EAAE,SAAS,KAAK,SAAS;QAChC,OAAO,EAAE,UAAU,KAAK,SAAS;QACjC,OAAO,EAAE,MAAM,KAAK,SAAS;QAC7B,OAAO,EAAE,aAAa,KAAK,SAAS;QAClC,CAAC,CAAC;YACE,SAAS,EAAE,OAAO,EAAE,SAAS;YAC7B,UAAU,EAAE,OAAO,EAAE,UAAU;YAC/B,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,aAAa,EAAE,OAAO,EAAE,aAAa;SACtC;QACH,CAAC,CAAC,SAAS,CAAC;IAEhB,+DAA+D;IAC/D,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;QACrD,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;QAC1B,CAAC,CAAC,cAAc,CAAC;IACnB,MAAM,SAAS,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAE7C,MAAM,EACJ,IAAI,EAAE,QAAQ,EACd,OAAO,EACP,KAAK,EACL,OAAO,GACR,GAAG,UAAU,CACZ,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS,EAAE,kBAAkB,CAAC,EAC5E;QACE,WAAW;QACX,iBAAiB;QACjB,SAAS;QACT,OAAO,EAAE,SAAS;QAClB,OAAO,EAAE,UAAU;QACnB,SAAS;QACT,OAAO,EAAE,aAAa;KACvB,EACD;QACE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK;KACpC,CACF,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youversion/platform-react-hooks",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -22,7 +22,7 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@youversion/platform-core": "1.11.0"
25
+ "@youversion/platform-core": "1.12.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": ">=19.1.0 <20.0.0"
@@ -0,0 +1,56 @@
1
+ import type { BibleBook, BibleChapter, BibleVerse, BibleVersion } from '@youversion/platform-core';
2
+
3
+ /**
4
+ * Creates a mock Bible version for testing
5
+ * @param overrides Optional properties to override defaults
6
+ */
7
+ export const createMockVersion = (overrides?: Partial<BibleVersion>): BibleVersion => ({
8
+ id: 1,
9
+ title: 'King James Version',
10
+ abbreviation: 'KJV',
11
+ copyright: '',
12
+ promotional_content: '',
13
+ info: null,
14
+ publisher_url: null,
15
+ language_tag: 'en',
16
+ localized_abbreviation: 'KJV',
17
+ localized_title: 'King James Version',
18
+ books: [],
19
+ youversion_deep_link: 'https://www.bible.com/versions/1',
20
+ ...overrides,
21
+ });
22
+
23
+ /**
24
+ * Creates a mock Bible book for testing
25
+ * @param overrides Optional properties to override defaults
26
+ */
27
+ export const createMockBook = (overrides?: Partial<BibleBook>): BibleBook => ({
28
+ id: 'GEN',
29
+ title: 'Genesis',
30
+ full_title: 'The First Book of Moses, Commonly Called Genesis',
31
+ abbreviation: 'Gen',
32
+ canon: 'old_testament',
33
+ ...overrides,
34
+ });
35
+
36
+ /**
37
+ * Creates a mock Bible chapter for testing
38
+ * @param overrides Optional properties to override defaults
39
+ */
40
+ export const createMockChapter = (overrides?: Partial<BibleChapter>): BibleChapter => ({
41
+ id: '1',
42
+ passage_id: 'GEN.1',
43
+ title: '1',
44
+ ...overrides,
45
+ });
46
+
47
+ /**
48
+ * Creates a mock Bible verse for testing
49
+ * @param overrides Optional properties to override defaults
50
+ */
51
+ export const createMockVerse = (overrides?: Partial<BibleVerse>): BibleVerse => ({
52
+ id: '1',
53
+ passage_id: 'GEN.1.1',
54
+ title: '1',
55
+ ...overrides,
56
+ });
@@ -0,0 +1,264 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { renderHook, act } from '@testing-library/react';
3
+ import React from 'react';
4
+ import { useReaderContext } from './ReaderContext';
5
+ import { ReaderProvider } from './ReaderProvider';
6
+ import {
7
+ createMockBook,
8
+ createMockChapter,
9
+ createMockVerse,
10
+ createMockVersion,
11
+ } from '../__tests__/mocks/bibles';
12
+
13
+ // Mock Bible data
14
+ const mockVersion = createMockVersion();
15
+ const mockBook = createMockBook();
16
+ const mockChapter = createMockChapter();
17
+ const mockVerse = createMockVerse();
18
+
19
+ // Alternative mock data for update tests
20
+ const mockVersion2 = createMockVersion({
21
+ id: 2,
22
+ title: 'New International Version',
23
+ abbreviation: 'NIV',
24
+ localized_abbreviation: 'NIV',
25
+ localized_title: 'New International Version',
26
+ youversion_deep_link: 'https://www.bible.com/versions/2',
27
+ });
28
+
29
+ const mockBook2 = createMockBook({
30
+ id: 'JHN',
31
+ title: 'John',
32
+ full_title: 'The Gospel According to John',
33
+ abbreviation: 'Jn',
34
+ canon: 'new_testament',
35
+ });
36
+
37
+ const mockChapter2 = createMockChapter({
38
+ id: '3',
39
+ passage_id: 'JHN.3',
40
+ title: '3',
41
+ });
42
+
43
+ const mockVerse2 = createMockVerse({
44
+ id: '16',
45
+ passage_id: 'JHN.3.16',
46
+ title: '16',
47
+ });
48
+
49
+ // Test wrappers
50
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
51
+ <ReaderProvider
52
+ currentVersion={mockVersion}
53
+ currentBook={mockBook}
54
+ currentChapter={mockChapter}
55
+ currentVerse={mockVerse}
56
+ >
57
+ {children}
58
+ </ReaderProvider>
59
+ );
60
+
61
+ const wrapperWithNullVerse = ({ children }: { children: React.ReactNode }) => (
62
+ <ReaderProvider
63
+ currentVersion={mockVersion}
64
+ currentBook={mockBook}
65
+ currentChapter={mockChapter}
66
+ currentVerse={null}
67
+ >
68
+ {children}
69
+ </ReaderProvider>
70
+ );
71
+
72
+ describe('ReaderProvider', () => {
73
+ describe('initialization', () => {
74
+ it('should initialize with provided version', () => {
75
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
76
+
77
+ expect(result.current.currentVersion).toEqual(mockVersion);
78
+ });
79
+
80
+ it('should initialize with provided book', () => {
81
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
82
+
83
+ expect(result.current.currentBook).toEqual(mockBook);
84
+ });
85
+
86
+ it('should initialize with provided chapter', () => {
87
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
88
+
89
+ expect(result.current.currentChapter).toEqual(mockChapter);
90
+ });
91
+
92
+ it('should initialize with provided verse', () => {
93
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
94
+
95
+ expect(result.current.currentVerse).toEqual(mockVerse);
96
+ });
97
+
98
+ it('should initialize with null verse when provided', () => {
99
+ const { result } = renderHook(() => useReaderContext(), { wrapper: wrapperWithNullVerse });
100
+
101
+ expect(result.current.currentVerse).toBeNull();
102
+ });
103
+
104
+ it('should throw error when useReaderContext is used outside provider', () => {
105
+ const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined);
106
+
107
+ expect(() => renderHook(() => useReaderContext())).toThrow(
108
+ 'useReaderContext() must be used within a ReaderProvider',
109
+ );
110
+
111
+ consoleError.mockRestore();
112
+ });
113
+ });
114
+
115
+ describe('setVersion', () => {
116
+ it('should update version when setVersion is called', () => {
117
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
118
+
119
+ act(() => {
120
+ result.current.setVersion(mockVersion2);
121
+ });
122
+
123
+ expect(result.current.currentVersion).toEqual(mockVersion2);
124
+ });
125
+
126
+ it('should preserve other state when version changes', () => {
127
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
128
+
129
+ act(() => {
130
+ result.current.setVersion(mockVersion2);
131
+ });
132
+
133
+ expect(result.current.currentVersion).toMatchObject({ abbreviation: 'NIV' });
134
+ expect(result.current.currentBook).toEqual(mockBook);
135
+ expect(result.current.currentChapter).toEqual(mockChapter);
136
+ expect(result.current.currentVerse).toEqual(mockVerse);
137
+ });
138
+ });
139
+
140
+ describe('setBook', () => {
141
+ it('should update book when setBook is called', () => {
142
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
143
+
144
+ act(() => {
145
+ result.current.setBook(mockBook2);
146
+ });
147
+
148
+ expect(result.current.currentBook).toEqual(mockBook2);
149
+ });
150
+
151
+ it('should preserve other state when book changes', () => {
152
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
153
+
154
+ act(() => {
155
+ result.current.setBook(mockBook2);
156
+ });
157
+
158
+ expect(result.current.currentBook).toMatchObject({ id: 'JHN' });
159
+ expect(result.current.currentVersion).toEqual(mockVersion);
160
+ expect(result.current.currentChapter).toEqual(mockChapter);
161
+ expect(result.current.currentVerse).toEqual(mockVerse);
162
+ });
163
+ });
164
+
165
+ describe('setChapter', () => {
166
+ it('should update chapter when setChapter is called', () => {
167
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
168
+
169
+ act(() => {
170
+ result.current.setChapter(mockChapter2);
171
+ });
172
+
173
+ expect(result.current.currentChapter).toEqual(mockChapter2);
174
+ });
175
+
176
+ it('should preserve other state when chapter changes', () => {
177
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
178
+
179
+ act(() => {
180
+ result.current.setChapter(mockChapter2);
181
+ });
182
+
183
+ expect(result.current.currentChapter).toMatchObject({ id: '3' });
184
+ expect(result.current.currentVersion).toEqual(mockVersion);
185
+ expect(result.current.currentBook).toEqual(mockBook);
186
+ expect(result.current.currentVerse).toEqual(mockVerse);
187
+ });
188
+ });
189
+
190
+ describe('setVerse', () => {
191
+ it('should update verse when setVerse is called', () => {
192
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
193
+
194
+ act(() => {
195
+ result.current.setVerse(mockVerse2);
196
+ });
197
+
198
+ expect(result.current.currentVerse).toEqual(mockVerse2);
199
+ });
200
+
201
+ it('should update verse to null when setVerse is called with null', () => {
202
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
203
+
204
+ act(() => {
205
+ result.current.setVerse(null);
206
+ });
207
+
208
+ expect(result.current.currentVerse).toBeNull();
209
+ });
210
+
211
+ it('should preserve other state when verse changes', () => {
212
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
213
+
214
+ act(() => {
215
+ result.current.setVerse(mockVerse2);
216
+ });
217
+
218
+ expect(result.current.currentVerse).toMatchObject({ id: '16' });
219
+ expect(result.current.currentVersion).toEqual(mockVersion);
220
+ expect(result.current.currentBook).toEqual(mockBook);
221
+ expect(result.current.currentChapter).toEqual(mockChapter);
222
+ });
223
+
224
+ it('should preserve other state when verse changes to null', () => {
225
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
226
+
227
+ act(() => {
228
+ result.current.setVerse(null);
229
+ });
230
+
231
+ expect(result.current.currentVerse).toBeNull();
232
+ expect(result.current.currentVersion).toEqual(mockVersion);
233
+ expect(result.current.currentBook).toEqual(mockBook);
234
+ expect(result.current.currentChapter).toEqual(mockChapter);
235
+ });
236
+ });
237
+
238
+ describe('state persistence', () => {
239
+ it('should initialize with all provided props', () => {
240
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
241
+
242
+ expect(result.current.currentVersion).toEqual(mockVersion);
243
+ expect(result.current.currentBook).toEqual(mockBook);
244
+ expect(result.current.currentChapter).toEqual(mockChapter);
245
+ expect(result.current.currentVerse).toEqual(mockVerse);
246
+ });
247
+
248
+ it('should handle rapid successive state updates without corruption', () => {
249
+ const { result } = renderHook(() => useReaderContext(), { wrapper });
250
+
251
+ act(() => {
252
+ result.current.setVersion(mockVersion2);
253
+ result.current.setBook(mockBook2);
254
+ result.current.setChapter(mockChapter2);
255
+ result.current.setVerse(mockVerse2);
256
+ });
257
+
258
+ expect(result.current.currentVersion).toEqual(mockVersion2);
259
+ expect(result.current.currentBook).toEqual(mockBook2);
260
+ expect(result.current.currentChapter).toEqual(mockChapter2);
261
+ expect(result.current.currentVerse).toEqual(mockVerse2);
262
+ });
263
+ });
264
+ });