@faststore/core 4.7.0-dev.3 → 4.7.0-dev.5

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 (33) hide show
  1. package/.turbo/turbo-generate.log +3 -3
  2. package/.turbo/turbo-test.log +101 -92
  3. package/CHANGELOG.md +18 -0
  4. package/cms/faststore/components/cms_component__recommendationshelf.jsonc +1 -7
  5. package/cms/faststore/my-account/README.md +2 -2
  6. package/cms/faststore/schema.json +1 -7
  7. package/discovery.config.default.js +5 -0
  8. package/package.json +6 -6
  9. package/src/Layout.tsx +3 -3
  10. package/src/components/account/orders/OrderDetails/section.module.scss +44 -3
  11. package/src/components/cms/RenderSections.tsx +20 -2
  12. package/src/components/sections/RecommendationShelf/README.md +25 -15
  13. package/src/components/sections/RecommendationShelf/RecommendationShelf.tsx +0 -2
  14. package/src/components/sections/RecommendationShelf/RecommendationShelf.types.ts +0 -7
  15. package/src/pages/pvt/account/403.tsx +1 -0
  16. package/src/pages/pvt/account/404.tsx +5 -1
  17. package/src/pages/pvt/account/cards/index.tsx +1 -0
  18. package/src/pages/pvt/account/orders/[id].tsx +5 -1
  19. package/src/pages/pvt/account/orders/index.tsx +1 -0
  20. package/src/pages/pvt/account/profile.tsx +1 -0
  21. package/src/pages/pvt/account/security.tsx +1 -0
  22. package/src/pages/pvt/account/user-details.tsx +1 -0
  23. package/src/sdk/analytics/hooks/useStartRecommendationSession.ts +18 -13
  24. package/src/sdk/recommendations/useRecommendationShelf.ts +17 -15
  25. package/src/server/cms/myAccountDefaultSections.ts +8 -3
  26. package/test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx +11 -32
  27. package/test/components/cms/RenderSections.browser.test.tsx +135 -0
  28. package/test/sdk/analytics/useStartRecommendationSession.test.ts +27 -58
  29. package/test/sdk/recommendations/useRecommendationShelf.browser.test.tsx +32 -34
  30. package/test/sdk/recommendations/useRecommendationShelf.sessionFallback.browser.test.tsx +110 -0
  31. package/test/server/cms/myAccountDefaultSections.test.ts +44 -0
  32. package/src/sdk/analytics/utils/hasEnabledRecommendationShelf.ts +0 -49
  33. package/test/sdk/analytics/hasEnabledRecommendationShelf.test.ts +0 -88
@@ -18,50 +18,21 @@ vi.mock('src/sdk/graphql/useLazyQuery', () => ({
18
18
  const getCookie = vi.hoisted(() => vi.fn())
19
19
  vi.mock('src/utils/getCookie', () => ({ getCookie }))
20
20
 
21
+ const storeConfigMock = vi.hoisted(() => ({
22
+ experimental: { enableRecommendations: true },
23
+ }))
24
+ vi.mock('discovery.config', () => ({ default: storeConfigMock }))
25
+
21
26
  import {
22
27
  resetStartRecommendationSessionLock,
23
28
  useStartRecommendationSession,
24
29
  } from 'src/sdk/analytics/hooks/useStartRecommendationSession'
25
30
 
26
- const enabledPageProps = {
27
- sections: [
28
- {
29
- name: 'RecommendationShelf',
30
- data: { enableRecommendations: true },
31
- },
32
- ],
33
- }
34
-
35
- const multipleEnabledShelvesPageProps = {
36
- sections: [
37
- {
38
- name: 'RecommendationShelf',
39
- data: { enableRecommendations: true, campaignVrn: 'vrn:a' },
40
- },
41
- {
42
- name: 'RecommendationShelf',
43
- data: { enableRecommendations: true, campaignVrn: 'vrn:b' },
44
- },
45
- {
46
- name: 'ProductShelf',
47
- data: {},
48
- },
49
- ],
50
- }
51
-
52
- const disabledPageProps = {
53
- sections: [
54
- {
55
- name: 'RecommendationShelf',
56
- data: { enableRecommendations: false },
57
- },
58
- ],
59
- }
60
-
61
31
  beforeEach(() => {
62
32
  resetStartRecommendationSessionLock()
63
33
  useLazyQueryMock.mockReturnValue([runStartRecommendationSession, {}])
64
34
  runStartRecommendationSession.mockResolvedValue(true)
35
+ storeConfigMock.experimental.enableRecommendations = true
65
36
  })
66
37
 
67
38
  afterEach(() => {
@@ -69,18 +40,19 @@ afterEach(() => {
69
40
  })
70
41
 
71
42
  describe('useStartRecommendationSession', () => {
72
- it('does not start a session when no RecommendationShelf is enabled in CMS', async () => {
43
+ it('does not start a session when experimental.enableRecommendations is false', async () => {
44
+ storeConfigMock.experimental.enableRecommendations = false
73
45
  getCookie.mockReturnValue(undefined)
74
46
 
75
- renderHook(() => useStartRecommendationSession(disabledPageProps))
47
+ renderHook(() => useStartRecommendationSession())
76
48
 
77
49
  await waitFor(() => {
78
50
  expect(runStartRecommendationSession).not.toHaveBeenCalled()
79
51
  })
80
52
  })
81
53
 
82
- it('does not start a session when page props are missing', async () => {
83
- getCookie.mockReturnValue(undefined)
54
+ it('does not start a session when the session cookie already exists', async () => {
55
+ getCookie.mockReturnValue('already-started')
84
56
 
85
57
  renderHook(() => useStartRecommendationSession())
86
58
 
@@ -89,53 +61,50 @@ describe('useStartRecommendationSession', () => {
89
61
  })
90
62
  })
91
63
 
92
- it('does not start a session when the session cookie already exists', async () => {
93
- getCookie.mockReturnValue('already-started')
64
+ it('starts a session when the feature flag is on and no session cookie is present', async () => {
65
+ getCookie.mockReturnValue(undefined)
94
66
 
95
- renderHook(() => useStartRecommendationSession(enabledPageProps))
67
+ renderHook(() => useStartRecommendationSession())
96
68
 
97
69
  await waitFor(() => {
98
- expect(runStartRecommendationSession).not.toHaveBeenCalled()
70
+ expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
99
71
  })
100
72
  })
101
73
 
102
- it('starts a session when CMS enableRecommendations is true and no session cookie is present', async () => {
74
+ it('starts a session when enabled override is true even if the feature flag is off', async () => {
75
+ storeConfigMock.experimental.enableRecommendations = false
103
76
  getCookie.mockReturnValue(undefined)
104
77
 
105
- renderHook(() => useStartRecommendationSession(enabledPageProps))
78
+ renderHook(() => useStartRecommendationSession(true))
106
79
 
107
80
  await waitFor(() => {
108
81
  expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
109
82
  })
110
83
  })
111
84
 
112
- it('starts a session only once when the page has multiple enabled RecommendationShelves', async () => {
85
+ it('does not start a session when enabled override is false even if the feature flag is on', async () => {
113
86
  getCookie.mockReturnValue(undefined)
114
87
 
115
- const { rerender } = renderHook(
116
- ({ pageProps }) => useStartRecommendationSession(pageProps),
117
- { initialProps: { pageProps: multipleEnabledShelvesPageProps } }
118
- )
119
-
120
- // Simulate Layout re-renders caused by multiple shelves updating.
121
- rerender({ pageProps: multipleEnabledShelvesPageProps })
122
- rerender({ pageProps: multipleEnabledShelvesPageProps })
88
+ renderHook(() => useStartRecommendationSession(false))
123
89
 
124
90
  await waitFor(() => {
125
- expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
91
+ expect(runStartRecommendationSession).not.toHaveBeenCalled()
126
92
  })
127
93
  })
128
94
 
129
- it('does not start a second session when the hook mounts again without a cookie', async () => {
95
+ it('starts a session only once across remounts / re-renders (in-memory lock)', async () => {
130
96
  getCookie.mockReturnValue(undefined)
131
97
 
132
- renderHook(() => useStartRecommendationSession(enabledPageProps))
98
+ const { rerender } = renderHook(() => useStartRecommendationSession())
99
+
100
+ rerender()
101
+ rerender()
133
102
 
134
103
  await waitFor(() => {
135
104
  expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
136
105
  })
137
106
 
138
- renderHook(() => useStartRecommendationSession(enabledPageProps))
107
+ renderHook(() => useStartRecommendationSession())
139
108
 
140
109
  await waitFor(() => {
141
110
  expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
@@ -17,6 +17,11 @@ vi.mock('src/sdk/recommendations/useRecommendationUserId', () => ({
17
17
  useRecommendationUserId,
18
18
  }))
19
19
 
20
+ const useStartRecommendationSession = vi.hoisted(() => vi.fn())
21
+ vi.mock('src/sdk/analytics/hooks/useStartRecommendationSession', () => ({
22
+ useStartRecommendationSession,
23
+ }))
24
+
20
25
  import { useRecommendationShelf } from 'src/sdk/recommendations/useRecommendationShelf'
21
26
 
22
27
  const TOP_ITEMS_VRN = 'vrn:recommendations:acc:rec-top-items-v2:campaign-1'
@@ -53,12 +58,9 @@ afterEach(() => {
53
58
  })
54
59
 
55
60
  describe('useRecommendationShelf', () => {
56
- it('exposes the campaign payload when enabled', () => {
61
+ it('exposes the campaign payload', () => {
57
62
  const { result } = renderHook(() =>
58
- useRecommendationShelf({
59
- campaignVrn: TOP_ITEMS_VRN,
60
- enableRecommendations: true,
61
- })
63
+ useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN })
62
64
  )
63
65
 
64
66
  expect(result.current.items).toHaveLength(2)
@@ -66,32 +68,40 @@ describe('useRecommendationShelf', () => {
66
68
  expect(result.current.correlationId).toBe('corr-1')
67
69
  })
68
70
 
69
- it('never fetches while recommendations are disabled', () => {
71
+ it('never fetches before a userId resolves', () => {
72
+ useRecommendationUserId.mockReturnValue(null)
73
+
70
74
  renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
71
75
 
72
76
  expect(lastArgs()).toBeNull()
73
77
  })
74
78
 
75
- it('never fetches before a userId resolves', () => {
79
+ it('starts the recommendation session as a fallback when userId is missing', () => {
76
80
  useRecommendationUserId.mockReturnValue(null)
77
81
 
78
- renderHook(() =>
79
- useRecommendationShelf({
80
- campaignVrn: TOP_ITEMS_VRN,
81
- enableRecommendations: true,
82
- })
83
- )
82
+ renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
84
83
 
85
- expect(lastArgs()).toBeNull()
84
+ expect(useStartRecommendationSession).toHaveBeenCalledWith(true)
85
+ })
86
+
87
+ it('starts the recommendation session while userId is still resolving', () => {
88
+ useRecommendationUserId.mockReturnValue(undefined)
89
+
90
+ renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
91
+
92
+ expect(useStartRecommendationSession).toHaveBeenCalledWith(true)
93
+ })
94
+
95
+ it('does not start the recommendation session when userId already exists', () => {
96
+ useRecommendationUserId.mockReturnValue('user-1')
97
+
98
+ renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
99
+
100
+ expect(useStartRecommendationSession).toHaveBeenCalledWith(false)
86
101
  })
87
102
 
88
103
  it('never fetches on a malformed campaign vrn', () => {
89
- renderHook(() =>
90
- useRecommendationShelf({
91
- campaignVrn: 'not-a-vrn',
92
- enableRecommendations: true,
93
- })
94
- )
104
+ renderHook(() => useRecommendationShelf({ campaignVrn: 'not-a-vrn' }))
95
105
 
96
106
  expect(lastArgs()).toBeNull()
97
107
  })
@@ -104,7 +114,6 @@ describe('useRecommendationShelf', () => {
104
114
  renderHook(() =>
105
115
  useRecommendationShelf({
106
116
  campaignVrn: CROSS_SELL_VRN,
107
- enableRecommendations: true,
108
117
  itemsContext: 'CART',
109
118
  })
110
119
  )
@@ -120,7 +129,6 @@ describe('useRecommendationShelf', () => {
120
129
  renderHook(() =>
121
130
  useRecommendationShelf({
122
131
  campaignVrn: CROSS_SELL_VRN,
123
- enableRecommendations: true,
124
132
  itemsContext: 'CART',
125
133
  })
126
134
  )
@@ -132,7 +140,6 @@ describe('useRecommendationShelf', () => {
132
140
  renderHook(() =>
133
141
  useRecommendationShelf({
134
142
  campaignVrn: TOP_ITEMS_VRN,
135
- enableRecommendations: true,
136
143
  itemsContext: 'CART',
137
144
  })
138
145
  )
@@ -150,7 +157,6 @@ describe('useRecommendationShelf', () => {
150
157
  const { rerender } = renderHook(() =>
151
158
  useRecommendationShelf({
152
159
  campaignVrn: CROSS_SELL_VRN,
153
- enableRecommendations: true,
154
160
  itemsContext: 'CART',
155
161
  })
156
162
  )
@@ -166,12 +172,7 @@ describe('useRecommendationShelf', () => {
166
172
  data: { product: { isVariantOf: { productGroupID: 'pg-pdp' } } },
167
173
  })
168
174
 
169
- renderHook(() =>
170
- useRecommendationShelf({
171
- campaignVrn: CROSS_SELL_VRN,
172
- enableRecommendations: true,
173
- })
174
- )
175
+ renderHook(() => useRecommendationShelf({ campaignVrn: CROSS_SELL_VRN }))
175
176
 
176
177
  expect(lastArgs()?.products).toEqual(['pg-pdp'])
177
178
  })
@@ -185,10 +186,7 @@ describe('useRecommendationShelf', () => {
185
186
  })
186
187
 
187
188
  const { result } = renderHook(() =>
188
- useRecommendationShelf({
189
- campaignVrn: TOP_ITEMS_VRN,
190
- enableRecommendations: true,
191
- })
189
+ useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN })
192
190
  )
193
191
 
194
192
  expect(result.current.items).toEqual([])
@@ -0,0 +1,110 @@
1
+ import { renderHook, waitFor } from '@testing-library/react'
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3
+
4
+ const usePDP = vi.hoisted(() => vi.fn())
5
+ vi.mock('@faststore/core', () => ({ usePDP }))
6
+
7
+ vi.mock('@faststore/core/api', () => ({
8
+ gql: (s: string) => ({ __meta__: {}, query: s }),
9
+ }))
10
+
11
+ const useCart = vi.hoisted(() => vi.fn())
12
+ vi.mock('src/sdk/cart', () => ({ useCart }))
13
+
14
+ const useRecommendations = vi.hoisted(() => vi.fn())
15
+ vi.mock('src/sdk/recommendations/useRecommendations', () => ({
16
+ useRecommendations,
17
+ }))
18
+
19
+ const runStartRecommendationSession = vi.hoisted(() => vi.fn())
20
+ vi.mock('src/sdk/graphql/useLazyQuery', () => ({
21
+ useLazyQuery: () => [runStartRecommendationSession, {}],
22
+ }))
23
+
24
+ const cookies = vi.hoisted(() => ({
25
+ current: {} as Record<string, string | undefined>,
26
+ }))
27
+ vi.mock('src/utils/getCookie', () => ({
28
+ getCookie: (name: string) => cookies.current[name],
29
+ }))
30
+
31
+ const storeConfigMock = vi.hoisted(() => ({
32
+ experimental: { enableRecommendations: false },
33
+ }))
34
+ vi.mock('discovery.config', () => ({ default: storeConfigMock }))
35
+
36
+ // Keep retry semantics (loop until `until` / attempts) but skip wall-clock
37
+ // backoff so the cookie lookup can observe the session mutation in this test.
38
+ vi.mock('src/utils/retry', async (importOriginal) => {
39
+ const actual = await importOriginal<typeof import('src/utils/retry')>()
40
+ return {
41
+ retry: <T,>(
42
+ fn: () => T | Promise<T>,
43
+ options?: Parameters<typeof actual.retry>[1]
44
+ ) => actual.retry(fn, { ...options, delayMs: 0, maxDelayMs: 0 }),
45
+ }
46
+ })
47
+
48
+ import { resetStartRecommendationSessionLock } from 'src/sdk/analytics/hooks/useStartRecommendationSession'
49
+ import { useRecommendationShelf } from 'src/sdk/recommendations/useRecommendationShelf'
50
+
51
+ const TOP_ITEMS_VRN = 'vrn:recommendations:acc:rec-top-items-v2:campaign-1'
52
+
53
+ const lastArgs = () => useRecommendations.mock.calls.at(-1)?.[0]
54
+
55
+ beforeEach(() => {
56
+ cookies.current = {}
57
+ resetStartRecommendationSessionLock()
58
+ storeConfigMock.experimental.enableRecommendations = false
59
+ usePDP.mockReturnValue({ data: undefined })
60
+ useCart.mockReturnValue({ items: [] })
61
+ useRecommendations.mockReturnValue({
62
+ data: undefined,
63
+ isLoading: false,
64
+ error: null,
65
+ })
66
+ runStartRecommendationSession.mockImplementation(async () => {
67
+ cookies.current['vtex-rec-user-id'] = 'user-from-session'
68
+ cookies.current['vtex-rec-user-start-session'] = '1'
69
+ return true
70
+ })
71
+ })
72
+
73
+ afterEach(() => {
74
+ vi.clearAllMocks()
75
+ })
76
+
77
+ describe('useRecommendationShelf session fallback race', () => {
78
+ it('starts the session in parallel with cookie retry so the first page can fetch', async () => {
79
+ renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
80
+
81
+ await waitFor(() => {
82
+ expect(runStartRecommendationSession).toHaveBeenCalledTimes(1)
83
+ })
84
+
85
+ await waitFor(() => {
86
+ expect(lastArgs()).toEqual({
87
+ userId: 'user-from-session',
88
+ campaignVrn: TOP_ITEMS_VRN,
89
+ products: [],
90
+ })
91
+ })
92
+ })
93
+
94
+ it('does not start a session when the user id cookie is already present', async () => {
95
+ cookies.current['vtex-rec-user-id'] = 'existing-user'
96
+ cookies.current['vtex-rec-user-start-session'] = '1'
97
+
98
+ renderHook(() => useRecommendationShelf({ campaignVrn: TOP_ITEMS_VRN }))
99
+
100
+ await waitFor(() => {
101
+ expect(lastArgs()).toEqual({
102
+ userId: 'existing-user',
103
+ campaignVrn: TOP_ITEMS_VRN,
104
+ products: [],
105
+ })
106
+ })
107
+
108
+ expect(runStartRecommendationSession).not.toHaveBeenCalled()
109
+ })
110
+ })
@@ -20,6 +20,50 @@ describe('getDefaultMyAccountSections', () => {
20
20
  it('returns an empty list for store (unknown) content-types', () => {
21
21
  expect(getDefaultMyAccountSections('myAccountWishlist')).toEqual([])
22
22
  })
23
+
24
+ /**
25
+ * The order-details defaults must mirror the render order of the
26
+ * `@deprecated OrderDetails.tsx` component, which is the design reference
27
+ * available in the repo. The delivery option accordions travel with
28
+ * AccountOrderDelivery, which is the single known deviation.
29
+ */
30
+ it('orders the myAccountOrderDetails defaults like the deprecated component', () => {
31
+ expect(
32
+ getDefaultMyAccountSections('myAccountOrderDetails').map(
33
+ (section) => section.$componentKey
34
+ )
35
+ ).toEqual([
36
+ 'AccountNavigation',
37
+ 'AccountOrderDetails',
38
+ 'AccountOrderOrderedBy',
39
+ 'AccountOrderDelivery',
40
+ 'AccountOrderStatus',
41
+ 'AccountOrderPayment',
42
+ 'AccountOrderSummary',
43
+ 'AccountOrderMoreInfo',
44
+ 'AccountOrderBudgets',
45
+ ])
46
+ })
47
+
48
+ it('keeps the myAccountOrderDetails default section set unchanged', () => {
49
+ const keys = getDefaultMyAccountSections('myAccountOrderDetails').map(
50
+ (section) => section.$componentKey
51
+ )
52
+
53
+ expect(new Set(keys)).toEqual(
54
+ new Set([
55
+ 'AccountNavigation',
56
+ 'AccountOrderDetails',
57
+ 'AccountOrderStatus',
58
+ 'AccountOrderPayment',
59
+ 'AccountOrderDelivery',
60
+ 'AccountOrderSummary',
61
+ 'AccountOrderOrderedBy',
62
+ 'AccountOrderBudgets',
63
+ 'AccountOrderMoreInfo',
64
+ ])
65
+ )
66
+ })
23
67
  })
24
68
 
25
69
  describe('withDefaultMyAccountSections', () => {
@@ -1,49 +0,0 @@
1
- type CmsSection = {
2
- name?: string
3
- $componentKey?: string
4
- data?: {
5
- enableRecommendations?: boolean
6
- }
7
- }
8
-
9
- function pushSections(target: CmsSection[], value: unknown) {
10
- if (Array.isArray(value)) {
11
- for (const item of value) {
12
- if (item && typeof item === 'object') {
13
- target.push(item as CmsSection)
14
- }
15
- }
16
- return
17
- }
18
-
19
- if (value && typeof value === 'object') {
20
- const sections = (value as { sections?: unknown }).sections
21
- if (Array.isArray(sections)) {
22
- pushSections(target, sections)
23
- }
24
- }
25
- }
26
-
27
- /**
28
- * Returns true when the current page CMS data includes at least one
29
- * `RecommendationShelf` with `enableRecommendations: true`.
30
- */
31
- export function hasEnabledRecommendationShelf(pageProps: unknown): boolean {
32
- if (!pageProps || typeof pageProps !== 'object') {
33
- return false
34
- }
35
-
36
- const props = pageProps as Record<string, unknown>
37
- const sections: CmsSection[] = []
38
-
39
- pushSections(sections, props.sections)
40
- pushSections(sections, props.globalSections)
41
- pushSections(sections, props.page)
42
-
43
- return sections.some(
44
- (section) =>
45
- (section.name === 'RecommendationShelf' ||
46
- section.$componentKey === 'RecommendationShelf') &&
47
- section.data?.enableRecommendations === true
48
- )
49
- }
@@ -1,88 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { hasEnabledRecommendationShelf } from 'src/sdk/analytics/utils/hasEnabledRecommendationShelf'
4
-
5
- describe('hasEnabledRecommendationShelf', () => {
6
- it('returns false for empty or unrelated page props', () => {
7
- expect(hasEnabledRecommendationShelf(undefined)).toBe(false)
8
- expect(hasEnabledRecommendationShelf({})).toBe(false)
9
- expect(
10
- hasEnabledRecommendationShelf({
11
- sections: [{ name: 'ProductShelf', data: {} }],
12
- })
13
- ).toBe(false)
14
- })
15
-
16
- it('returns true when a page section enables recommendations', () => {
17
- expect(
18
- hasEnabledRecommendationShelf({
19
- sections: [
20
- {
21
- name: 'RecommendationShelf',
22
- data: { enableRecommendations: true, campaignVrn: 'vrn:x' },
23
- },
24
- ],
25
- })
26
- ).toBe(true)
27
- })
28
-
29
- it('returns true when a global section enables recommendations', () => {
30
- expect(
31
- hasEnabledRecommendationShelf({
32
- globalSections: {
33
- sections: [
34
- {
35
- $componentKey: 'RecommendationShelf',
36
- data: { enableRecommendations: true },
37
- },
38
- ],
39
- },
40
- })
41
- ).toBe(true)
42
- })
43
-
44
- it('returns true when page.sections enables recommendations', () => {
45
- expect(
46
- hasEnabledRecommendationShelf({
47
- page: {
48
- sections: [
49
- {
50
- name: 'RecommendationShelf',
51
- data: { enableRecommendations: true },
52
- },
53
- ],
54
- },
55
- })
56
- ).toBe(true)
57
- })
58
-
59
- it('returns false when the shelf is present but enableRecommendations is false', () => {
60
- expect(
61
- hasEnabledRecommendationShelf({
62
- sections: [
63
- {
64
- name: 'RecommendationShelf',
65
- data: { enableRecommendations: false },
66
- },
67
- ],
68
- })
69
- ).toBe(false)
70
- })
71
-
72
- it('returns true when at least one of multiple shelves enables recommendations', () => {
73
- expect(
74
- hasEnabledRecommendationShelf({
75
- sections: [
76
- {
77
- name: 'RecommendationShelf',
78
- data: { enableRecommendations: false },
79
- },
80
- {
81
- name: 'RecommendationShelf',
82
- data: { enableRecommendations: true },
83
- },
84
- ],
85
- })
86
- ).toBe(true)
87
- })
88
- })