@newskit-render/core 1.63.2 → 1.68.1-alpha.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/README.md +16 -0
  3. package/__tests__/pages/[articleSlug].test.tsx +1 -55
  4. package/__tests__/pages/__snapshots__/home.test.tsx.snap +657 -626
  5. package/__tests__/pages/__snapshots__/relatedArticles.test.tsx.snap +651 -0
  6. package/__tests__/pages/relatedArticles.test.tsx +23 -11
  7. package/components/article/__tests__/__snapshots__/index.test.tsx.snap +1091 -1060
  8. package/components/footer/index.tsx +1 -1
  9. package/components/header/banner-messages.ts +45 -0
  10. package/components/header/index.tsx +31 -287
  11. package/components/header/navigation-links.ts +20 -0
  12. package/components/layout/LayoutTemplate.tsx +4 -1
  13. package/config/__tests__/index.test.ts +53 -0
  14. package/config/environment.ts +67 -0
  15. package/config/index.ts +2 -85
  16. package/config/multiTenancy.ts +12 -0
  17. package/{app-context → context/app-context}/AppContext.test.tsx +7 -3
  18. package/{app-context/AppContext.tsx → context/app-context/index.tsx} +5 -1
  19. package/context/index.tsx +2 -0
  20. package/context/multi-tenancy/MultiTenancy.test.tsx +47 -0
  21. package/context/multi-tenancy/index.tsx +31 -0
  22. package/css/index.ts +224 -0
  23. package/cypress/support/commands.js +8 -4
  24. package/helpers/__tests__/createThemeDropdownObject.test.ts +3 -3
  25. package/helpers/__tests__/getRecommendation.test.ts +62 -0
  26. package/helpers/createThemeDropdownObject.ts +3 -3
  27. package/helpers/getRecommendations.ts +29 -0
  28. package/helpers/global-types.ts +8 -0
  29. package/{__tests__/pages/mocks.ts → helpers/mocks/getRecommendationsMock.ts} +2 -6
  30. package/helpers/multiTenancy.ts +19 -0
  31. package/infrastructure/helm/values-dev.yaml +1 -1
  32. package/infrastructure/helm/values-pr.yaml +1 -1
  33. package/infrastructure/helm/values-prod.yaml +1 -1
  34. package/jest.config.js +1 -2
  35. package/package.json +13 -11
  36. package/pages/[section]/[articleId]/[articleSlug].tsx +17 -10
  37. package/pages/[section]/[articleId]/relatedArticles.tsx +49 -40
  38. package/pages/_app.tsx +43 -257
  39. package/pages/account/cancellation/index.tsx +1 -1
  40. package/pages/account/edit/[field].tsx +1 -1
  41. package/pages/account/index.tsx +1 -1
  42. package/pages/account/newsletters-and-alerts/index.tsx +1 -1
  43. package/pages/account/payment/index.tsx +1 -1
  44. package/pages/account/subscription-and-billing/index.tsx +1 -1
  45. package/pages/api/auth/[...nextauth].ts +5 -1
  46. package/pages/api/recommendations/[...slug].ts +21 -0
  47. package/pages/checkout/account-creation/index.tsx +1 -1
  48. package/pages/checkout/payment-details/index.tsx +1 -1
  49. package/pages/help-hub/[id]/index.tsx +22 -9
  50. package/pages/help-hub/index.tsx +22 -9
  51. package/pages/help-hub/results.tsx +24 -0
  52. package/theme/strings/demo.ts +1 -0
  53. package/theme/strings/index.ts +1 -0
  54. package/components/header/index.test.tsx +0 -73
@@ -13,7 +13,7 @@ import {
13
13
  import { MainGrid } from '../layout/MainGrid'
14
14
  import NewsKitLogoShort from '../common/NewskitLogoShort'
15
15
  import NavLink from '../common/NavLink'
16
- import { AppContext } from '../../app-context/AppContext'
16
+ import { AppContext } from '../../context'
17
17
  import { getYear } from '../../helpers/getYear'
18
18
 
19
19
  const StyledFooter = styled.div`
@@ -0,0 +1,45 @@
1
+ export const pastDueBanner = {
2
+ firstNotice: {
3
+ title: "We haven't been able to take payment",
4
+ text:
5
+ 'You may need to update your payment details to keep your subscription.',
6
+ button: 'Update payment details',
7
+ },
8
+ secondNotice: {
9
+ title: 'Act now to keep your subscription',
10
+ text:
11
+ 'We’ve tried several times, but haven’t been able to take payment. Please update your payment details to keep your subscription.',
12
+ button: 'Update payment details',
13
+ },
14
+ terminated: {
15
+ title: 'Your subscription has been terminated',
16
+ phoneNumber: 'XXXX-XXX-XXXX',
17
+ text:
18
+ 'We didn’t receive payment for your subscription. To reactivate it, please call ##PHONE_NUMBER##.',
19
+ dismissDays: 7,
20
+ },
21
+ cancelled: {
22
+ title: 'Your subscription has been cancelled.',
23
+ phoneNumber: 'XXXX-XXX-XXXX',
24
+ text:
25
+ 'You’ll no longer have access to subscription benefits. To re-activate call ##PHONE_NUMBER##.',
26
+ dismissDays: 7,
27
+ },
28
+ toBeCancelled: {
29
+ title: 'Your subscription will end soon.',
30
+ phoneNumber: 'XXXX-XXX-XXXX',
31
+ text:
32
+ 'You have cancelled your subscription and will lose access to all benefits on ##DATE##. To re-activate your subscription call ##PHONE_NUMBER##.',
33
+ },
34
+ toBeCancelledWithRefund: {
35
+ title: 'Your subscription will end soon.',
36
+ phoneNumber: '0800 xxxx xxxxx',
37
+ text:
38
+ 'We have successfully cancelled your subscription and will be processing your refund shortly. If you have any question please call ##PHONE_NUMBER##.',
39
+ dismissDays: 7,
40
+ },
41
+ treshold: {
42
+ firstNotice: 26,
43
+ secondNotice: 30,
44
+ },
45
+ }
@@ -1,314 +1,58 @@
1
- import React, { useContext, useState } from 'react'
2
- import {
3
- Cell,
4
- styled,
5
- getColorCssFromTheme,
6
- getSizingCssFromTheme,
7
- getFontsFromTheme,
8
- Visible,
9
- getMediaQueryFromTheme,
10
- Stack,
11
- Block,
12
- IconFilledMenu,
13
- Image,
14
- } from 'newskit'
1
+ import React, { useContext } from 'react'
2
+ import { styled, Block } from 'newskit'
15
3
  import { UserData } from '@newskit-render/my-account'
16
4
  import {
17
- NextLink,
18
- theSunTheme,
19
- timesTheme,
20
- virginRadioTheme,
21
- ThemeDropdown,
22
5
  PastDueBannerExternal,
6
+ NavigationPrimary,
23
7
  } from '@newskit-render/shared-components'
24
8
  import {
25
9
  renderCustomLightTheme as LightTheme,
26
10
  renderCustomDarkTheme as DarkTheme,
27
11
  } from '../../theme'
28
- import { MainGrid } from '../layout/MainGrid'
29
- import NewsKitLogoFull from '../common/NewskitLogo'
30
- import NewsKitLogoShort from '../common/NewskitLogoShort'
31
- import NavLink from '../common/NavLink'
32
- import { AppContext } from '../../app-context/AppContext'
33
- import { handleEnterKeyPress } from '../../helpers/a11y'
34
- import IconNavLink from '../common/iconNavLink'
35
- import { IconAccount } from '../common/icons/IconAccount'
12
+ import { AppContext } from '../../context'
13
+ import { createThemeDropdownObject } from '../../helpers/createThemeDropdownObject'
14
+ import { sectionLinks } from './navigation-links'
15
+ import { pastDueBanner } from './banner-messages'
36
16
 
37
17
  export const headerSize = 'sizing100'
38
18
 
39
- const StyledHeader = styled.div`
40
- ${getSizingCssFromTheme('height', headerSize)}
41
- ${getColorCssFromTheme('backgroundColor', 'interfaceBrand010')};
42
- a,
43
- a:visited:not(:disabled) {
44
- ${getColorCssFromTheme('color', 'white')};
45
- font-weight: bold;
46
- line-height: ${getFontsFromTheme('fontLineHeight040')};
47
- }
48
- ${getMediaQueryFromTheme('xs')} {
49
- ${getSizingCssFromTheme('paddingTop', 'sizing040')};
50
- ${getSizingCssFromTheme('paddingBottom', 'sizing040')};
51
- ${getSizingCssFromTheme('paddingLeft', 'sizing000')};
52
- ${getSizingCssFromTheme('paddingRight', 'sizing000')};
53
- }
54
- ${getMediaQueryFromTheme('lg')} {
55
- ${getSizingCssFromTheme('paddingTop', 'sizing040')};
56
- ${getSizingCssFromTheme('paddingBottom', 'sizing040')};
57
- ${getSizingCssFromTheme('paddingLeft', 'sizing090')};
58
- ${getSizingCssFromTheme('paddingRight', 'sizing090')};
59
- }
60
- `
61
-
62
- const pastDueBanner = {
63
- firstNotice: {
64
- title: "We haven't been able to take payment",
65
- text:
66
- 'You may need to update your payment details to keep your subscription.',
67
- button: 'Update payment details',
68
- },
69
- secondNotice: {
70
- title: 'Act now to keep your subscription',
71
- text:
72
- 'We’ve tried several times, but haven’t been able to take payment. Please update your payment details to keep your subscription.',
73
- button: 'Update payment details',
74
- },
75
- terminated: {
76
- title: 'Your subscription has been terminated',
77
- phoneNumber: 'XXXX-XXX-XXXX',
78
- text:
79
- 'We didn’t receive payment for your subscription. To reactivate it, please call ##PHONE_NUMBER##.',
80
- dismissDays: 7,
81
- },
82
- cancelled: {
83
- title: 'Your subscription has been cancelled.',
84
- phoneNumber: 'XXXX-XXX-XXXX',
85
- text:
86
- 'You’ll no longer have access to subscription benefits. To re-activate call ##PHONE_NUMBER##.',
87
- dismissDays: 7,
88
- },
89
- toBeCancelled: {
90
- title: 'Your subscription will end soon.',
91
- phoneNumber: 'XXXX-XXX-XXXX',
92
- text:
93
- 'You have cancelled your subscription and will lose access to all benefits on ##DATE##. To re-activate your subscription call ##PHONE_NUMBER##.',
94
- },
95
- toBeCancelledWithRefund: {
96
- title: 'Your subscription will end soon.',
97
- phoneNumber: '0800 xxxx xxxxx',
98
- text:
99
- 'We have successfully cancelled your subscription and will be processing your refund shortly. If you have any question please call ##PHONE_NUMBER##.',
100
- dismissDays: 7,
101
- },
102
- treshold: {
103
- firstNotice: 26,
104
- secondNotice: 30,
105
- },
106
- }
107
-
108
- type NavigationProps = {
109
- show: boolean
110
- }
111
-
112
19
  const BannerContainer = styled(Block)`
113
20
  position: sticky;
114
21
  top: 0;
115
22
  z-index: 1;
116
23
  `
117
24
 
118
- const NavigationContainer = styled.div<NavigationProps>`
119
- position: fixed;
120
- overflow: auto;
121
- width: 100%;
122
- min-height: 100vh;
123
- ${getColorCssFromTheme('backgroundColor', 'interfaceBrand010')};
124
- left: 0;
125
- ${getSizingCssFromTheme('top', headerSize)}
126
- z-index: 2;
127
- display: ${(props) => (props.show ? 'block' : 'none')};
128
-
129
- ${getMediaQueryFromTheme('md')} {
130
- display: flex;
131
- position: relative;
132
- overflow: hidden;
133
- width: initial;
134
- min-height: initial;
135
- background-color: initial;
136
- left: initial;
137
- top: initial;
138
- z-index: 1;
139
- ${getSizingCssFromTheme('height', 'sizing080')}
140
- }
141
- `
142
-
143
- const Navigation = styled.div`
144
- display: flex;
145
- flex-flow: row wrap;
146
- justify-content: space-between;
147
- flex-direction: column;
148
- align-items: center;
149
-
150
- ${getMediaQueryFromTheme('md')} {
151
- justify-content: flex-end;
152
- flex-direction: row;
25
+ const Header: React.FC<{ user: UserData }> = ({ user }) => {
26
+ const navigationPrimary = {
27
+ nav: sectionLinks,
28
+ loggedInUser: !!user,
29
+ gridOverrides: {
30
+ width: '100%',
31
+ maxWidth: '1920px',
32
+ marginInline: 'auto',
33
+ },
153
34
  }
154
- `
155
-
156
- const NavButton = ({
157
- buttonText,
158
- href,
159
- ariaLabel,
160
- }: {
161
- buttonText: string
162
- href: string
163
- isLast?: boolean
164
- ariaLabel?: string
165
- }) => (
166
- <Block
167
- as="span"
168
- spaceInline={{
169
- xs: 'space000',
170
- md: 'space040',
171
- }}
172
- spaceStack={{
173
- xs: 'space050',
174
- md: 'space000',
175
- }}
176
- >
177
- <NavLink href={href} ariaLabel={ariaLabel} buttonText={buttonText} />
178
- </Block>
179
- )
180
35
 
181
- const clientNavigationLogos = {
182
- 'The-Sun': { src: 'navigationPrimary-brandMark-sun.svg', width: '115px' },
183
- 'Virgin-Radio': { src: 'navigationPrimary-brandMark-vr.svg', width: '150px' },
184
- 'The-Times': {
185
- src: 'navigationPrimary-brandMark-times.svg',
186
- width: '150px',
187
- },
188
- }
36
+ const { theme, setTheme } = useContext(AppContext)
37
+ const themeDropdownObject = createThemeDropdownObject(setTheme)
38
+ const { sharedTheme, ...restThemes } = themeDropdownObject.options
189
39
 
190
- const Header: React.FC<{ user: UserData }> = ({ user }) => {
191
- const [showMenu, setShowMenu] = useState(false)
192
- const mobileMenuControl = () => {
193
- setShowMenu(!showMenu)
194
- document.body.style.overflow = showMenu ? '' : 'hidden'
40
+ const themeDropdownObjectUpdated = {
41
+ ...themeDropdownObject,
42
+ options: {
43
+ LightTheme,
44
+ DarkTheme,
45
+ ...restThemes,
46
+ },
195
47
  }
196
- const { theme, setTheme } = useContext(AppContext)
197
48
 
198
49
  return (
199
50
  <>
200
- <StyledHeader>
201
- <MainGrid>
202
- <Cell xs={12}>
203
- <Stack
204
- flow="horizontal-center"
205
- stackDistribution="space-between"
206
- wrap="nowrap"
207
- >
208
- <NextLink
209
- type="standalone"
210
- overrides={{ stylePreset: 'linkStandaloneInverse' }}
211
- href="/"
212
- aria-label="Logo Link"
213
- >
214
- {!clientNavigationLogos[theme.name] ? (
215
- <>
216
- <Visible md lg xl>
217
- <NewsKitLogoFull color="white" size="sizing120" />
218
- </Visible>
219
- <Visible xs sm>
220
- <NewsKitLogoShort color="white" size="sizing120" />
221
- </Visible>
222
- </>
223
- ) : (
224
- <Block>
225
- <Image
226
- alt=""
227
- src={`/MyAccount/${
228
- clientNavigationLogos[theme.name].src
229
- }`}
230
- overrides={{
231
- width: clientNavigationLogos[theme.name].width,
232
- }}
233
- />
234
- </Block>
235
- )}
236
- </NextLink>
237
- <Stack
238
- flow="horizontal-center"
239
- stackDistribution="flex-end"
240
- wrap="nowrap"
241
- >
242
- <NavigationContainer
243
- show={showMenu}
244
- data-testid="NavigationContainer"
245
- >
246
- <Navigation data-testid="Navigation">
247
- {showMenu && (
248
- <Block
249
- spaceStack="space050"
250
- data-testid="mobile-block-space"
251
- />
252
- )}
253
- <NavButton
254
- buttonText="Section One"
255
- href="/section-one"
256
- ariaLabel="Section One Link"
257
- />
258
- <NavButton
259
- buttonText="Section Two"
260
- href="/section-two"
261
- ariaLabel="Section Two Link"
262
- />
263
- <NavButton
264
- buttonText="Section Three"
265
- href="/section-three"
266
- ariaLabel="Section Three Link"
267
- />
268
- {user && (
269
- <IconNavLink
270
- icon={<IconAccount data-testid="account-link" />}
271
- href="/account"
272
- text="Account"
273
- spaceInline="space040"
274
- typographyPreset="utilityMeta020"
275
- stylePreset="linkStandaloneInverse"
276
- />
277
- )}
278
- </Navigation>
279
- </NavigationContainer>
280
- <Visible xs sm>
281
- <Block spaceInline="space050">
282
- <IconFilledMenu
283
- overrides={{
284
- size: 'iconSize030',
285
- stylePreset: 'inkInverse',
286
- }}
287
- onClick={mobileMenuControl}
288
- onKeyDown={handleEnterKeyPress(mobileMenuControl)}
289
- role="button"
290
- tabIndex={0}
291
- aria-label="Mobile Menu Button"
292
- data-testid="mobile-menu-btn"
293
- />
294
- </Block>
295
- </Visible>
296
- <ThemeDropdown
297
- theme={theme}
298
- setTheme={setTheme}
299
- options={{
300
- LightTheme,
301
- DarkTheme,
302
- theSunTheme,
303
- timesTheme,
304
- virginRadioTheme,
305
- }}
306
- />
307
- </Stack>
308
- </Stack>
309
- </Cell>
310
- </MainGrid>
311
- </StyledHeader>
51
+ <NavigationPrimary
52
+ {...navigationPrimary}
53
+ customTheme={theme}
54
+ themeDropdownObject={themeDropdownObjectUpdated}
55
+ />
312
56
  <PastDueBannerExternal
313
57
  pastDueBanner={pastDueBanner}
314
58
  user={user}
@@ -0,0 +1,20 @@
1
+ export const sectionLinks = [
2
+ {
3
+ text: 'Section One',
4
+ link: '/section-one',
5
+ icon: null,
6
+ ariaLabel: 'Section One Link',
7
+ },
8
+ {
9
+ text: 'Section Two',
10
+ link: '/section-two',
11
+ icon: null,
12
+ ariaLabel: 'Section Two Link',
13
+ },
14
+ {
15
+ text: 'Section Three',
16
+ link: '/section-three',
17
+ icon: null,
18
+ ariaLabel: 'Section Three Link',
19
+ },
20
+ ]
@@ -1,5 +1,6 @@
1
1
  import React from 'react'
2
2
  import { UserData } from '@newskit-render/my-account'
3
+ import { Cell } from 'newskit'
3
4
  import Header from '../header'
4
5
  import Footer from '../footer'
5
6
  import { Gutter } from './Gutter'
@@ -14,7 +15,9 @@ const LayoutTemplate: React.FC<LayoutProps> = ({
14
15
  <>
15
16
  <Header user={user as UserData} />
16
17
  <Gutter>
17
- <MainGrid {...mainGridProps}>{children}</MainGrid>
18
+ <MainGrid {...mainGridProps}>
19
+ <Cell xs={12}>{children}</Cell>
20
+ </MainGrid>
18
21
  </Gutter>
19
22
  <Footer />
20
23
  </>
@@ -0,0 +1,53 @@
1
+ import { getSanitizedConfig } from '../index'
2
+
3
+ const originalEnv = process.env
4
+ const { window } = global
5
+
6
+ beforeAll(() => {
7
+ // @ts-ignore
8
+ delete global.window
9
+ })
10
+ afterAll(() => {
11
+ global.window = window
12
+ })
13
+ describe('getSanitizedConfig', () => {
14
+ it('should return required config values', () => {
15
+ process.env = {
16
+ ...originalEnv,
17
+ SITE_HOST: 'host',
18
+ NEWSKIT_API_ENV_URL: 'url',
19
+ NEWSKIT_API_X_API_KEY: 'key',
20
+ OKTA_CLIENT_ID: 'oktaId',
21
+ OKTA_CLIENT_SECRET: 'oktasecret',
22
+ OKTA_DOMAIN: 'domain',
23
+ PUBLISHER: 'publisher',
24
+ }
25
+ const res = getSanitizedConfig()
26
+
27
+ expect(res).toEqual(
28
+ expect.objectContaining({
29
+ publisher: 'publisher',
30
+ })
31
+ )
32
+ process.env = {
33
+ ...originalEnv,
34
+ }
35
+ })
36
+
37
+ it('should throw error when NEWSKIT_API_ENV_URL is missing', () => {
38
+ process.env = {
39
+ ...originalEnv,
40
+ SITE_HOST: 'host',
41
+ NEWSKIT_API_X_API_KEY: 'key',
42
+ OKTA_CLIENT_ID: 'oktaId',
43
+ OKTA_CLIENT_SECRET: 'oktasecret',
44
+ OKTA_DOMAIN: 'domain',
45
+ PUBLISHER: 'publisher',
46
+ }
47
+ try {
48
+ getSanitizedConfig()
49
+ } catch (e) {
50
+ expect(e.message).toEqual('Missing key NEWSKIT_API_ENV_URL in env')
51
+ }
52
+ })
53
+ })
@@ -0,0 +1,67 @@
1
+ const requiredConfigFields: string[] = [
2
+ 'SITE_HOST',
3
+ 'NEWSKIT_API_ENV_URL',
4
+ 'NEWSKIT_API_X_API_KEY',
5
+ 'OKTA_CLIENT_ID',
6
+ 'OKTA_CLIENT_SECRET',
7
+ 'OKTA_DOMAIN',
8
+ 'PUBLISHER',
9
+ ]
10
+
11
+ export const getSanitizedConfig = () => {
12
+ for (const key of requiredConfigFields) {
13
+ const value = process.env[key]
14
+ if (
15
+ typeof window == 'undefined' &&
16
+ (value === undefined || value.length <= 0)
17
+ ) {
18
+ throw new Error(`Missing key ${key} in env`)
19
+ }
20
+ }
21
+ return {
22
+ oktaClientId: process.env.OKTA_CLIENT_ID as string,
23
+ oktaClientSecret: process.env.OKTA_CLIENT_SECRET as string,
24
+ oktaDomain: process.env.OKTA_DOMAIN as string,
25
+ newskitApiEnvUrl: process.env.NEWSKIT_API_ENV_URL as string,
26
+ newskitApiXApiKey: process.env.NEWSKIT_API_X_API_KEY as string,
27
+ optimizelysdkKey: process.env.OPTIMIZELY_SDK_KEY as string,
28
+ siteHost: process.env.SITE_HOST as string,
29
+ sitemapFirstPublicationDate: process.env
30
+ .SITEMAP_FIRST_PUBLICATION_DATE as string,
31
+ sitemapPublicationName: process.env.SITEMAP_PUBLICATION_NAME as string,
32
+ newRelicEnabled: process.env.NEW_RELIC_ENABLED as string,
33
+ experimentationWeb: process.env.EXPERIMENTATION_WEB as string,
34
+ sourcepointAccountId: process.env.SOURCEPOINT_ACCOUNT_ID as string,
35
+ sourcepointPropertyHref: process.env.SOURCEPOINT_PROPERTY_HREF as string,
36
+ tealiumAccountId: process.env.TEALIUM_ACCOUNT_ID as string,
37
+ tealiumProfileId: process.env.TEALIUM_PROFILE_ID as string,
38
+ tealiumEnv: process.env.TEALIUM_ENV as string,
39
+ twitterUsername: process.env.TWITTER_USERNAME as string,
40
+ gscId: process.env.GSC_ID as string,
41
+ publisher: process.env.PUBLISHER as string,
42
+ }
43
+ }
44
+
45
+ const config = getSanitizedConfig()
46
+
47
+ export const {
48
+ oktaClientId,
49
+ oktaClientSecret,
50
+ oktaDomain,
51
+ newskitApiEnvUrl,
52
+ newskitApiXApiKey,
53
+ optimizelysdkKey,
54
+ siteHost,
55
+ sitemapFirstPublicationDate,
56
+ sitemapPublicationName,
57
+ newRelicEnabled,
58
+ experimentationWeb,
59
+ sourcepointAccountId,
60
+ sourcepointPropertyHref,
61
+ tealiumAccountId,
62
+ tealiumProfileId,
63
+ tealiumEnv,
64
+ twitterUsername,
65
+ gscId,
66
+ publisher,
67
+ } = config
package/config/index.ts CHANGED
@@ -1,85 +1,2 @@
1
- const {
2
- OKTA_CLIENT_ID,
3
- OKTA_CLIENT_SECRET,
4
- OKTA_DOMAIN,
5
- NEWSKIT_API_ENV_URL,
6
- NEWSKIT_API_X_API_KEY,
7
- SITE_HOST,
8
- OPTIMIZELY_SDK_KEY,
9
- SITEMAP_FIRST_PUBLICATION_DATE,
10
- SITEMAP_PUBLICATION_NAME,
11
- NEW_RELIC_ENABLED,
12
- EXPERIMENTATION_WEB,
13
- SOURCEPOINT_ACCOUNT_ID,
14
- SOURCEPOINT_PROPERTY_HREF,
15
- TEALIUM_ACCOUNT_ID,
16
- TEALIUM_PROFILE_ID,
17
- TEALIUM_ENV,
18
- TWITTER_USERNAME,
19
- GSC_ID,
20
- PUBLISHER,
21
- } = process?.env
22
-
23
- const requiredConfigFields: string[] = [
24
- 'SITE_HOST',
25
- 'NEWSKIT_API_ENV_URL',
26
- 'NEWSKIT_API_X_API_KEY',
27
- 'OKTA_CLIENT_ID',
28
- 'OKTA_CLIENT_SECRET',
29
- 'OKTA_DOMAIN',
30
- 'PUBLISHER',
31
- ]
32
- const getSanitizedConfig = () => {
33
- for (const key of requiredConfigFields) {
34
- const value = process.env[key]
35
- if (
36
- typeof window == 'undefined' &&
37
- (value === undefined || value.length <= 0)
38
- ) {
39
- throw new Error(`Missing key ${key} in env`)
40
- }
41
- }
42
- return {
43
- oktaClientId: OKTA_CLIENT_ID,
44
- oktaClientSecret: OKTA_CLIENT_SECRET,
45
- oktaDomain: OKTA_DOMAIN,
46
- newskitApiEnvUrl: NEWSKIT_API_ENV_URL,
47
- newskitApiXApiKey: NEWSKIT_API_X_API_KEY,
48
- optimizelysdkKey: OPTIMIZELY_SDK_KEY,
49
- siteHost: SITE_HOST,
50
- sitemapFirstPublicationDate: SITEMAP_FIRST_PUBLICATION_DATE,
51
- sitemapPublicationName: SITEMAP_PUBLICATION_NAME,
52
- newRelicEnabled: NEW_RELIC_ENABLED,
53
- experimentationWeb: EXPERIMENTATION_WEB,
54
- sourcepointAccountId: SOURCEPOINT_ACCOUNT_ID,
55
- sourcepointPropertyHref: SOURCEPOINT_PROPERTY_HREF,
56
- tealiumAccountId: TEALIUM_ACCOUNT_ID,
57
- tealiumProfileId: TEALIUM_PROFILE_ID,
58
- tealiumEnv: TEALIUM_ENV,
59
- twitterUsername: TWITTER_USERNAME,
60
- gscId: GSC_ID,
61
- publisher: PUBLISHER,
62
- }
63
- }
64
- const config = getSanitizedConfig()
65
- export const {
66
- oktaClientId,
67
- oktaClientSecret,
68
- oktaDomain,
69
- newskitApiEnvUrl,
70
- newskitApiXApiKey,
71
- optimizelysdkKey,
72
- siteHost,
73
- sitemapFirstPublicationDate,
74
- sitemapPublicationName,
75
- newRelicEnabled,
76
- experimentationWeb,
77
- sourcepointAccountId,
78
- sourcepointPropertyHref,
79
- tealiumAccountId,
80
- tealiumProfileId,
81
- tealiumEnv,
82
- twitterUsername,
83
- gscId,
84
- publisher,
85
- } = config
1
+ export * from './environment'
2
+ export * from './multiTenancy'
@@ -0,0 +1,12 @@
1
+ import { sharedTheme, timesTheme } from '@newskit-render/shared-components'
2
+ import { Publisher } from '@newskit-render/api'
3
+ import { demo } from '../theme/strings'
4
+
5
+ export const translationsMap = {
6
+ [Publisher.DEMO]: demo,
7
+ }
8
+
9
+ export const themesMap = {
10
+ [Publisher.DEMO]: sharedTheme,
11
+ [Publisher.TIMES]: timesTheme,
12
+ }
@@ -2,12 +2,16 @@ import React from 'react'
2
2
  import { render } from 'react-dom'
3
3
  import { act } from 'react-dom/test-utils'
4
4
  import { sharedTheme } from '@newskit-render/shared-components'
5
- import { renderCustomDarkTheme } from '../theme'
6
- import { AppContextProvider, AppContext } from './AppContext'
5
+ import { renderCustomDarkTheme } from '../../theme'
6
+ import { AppContextProvider, AppContext } from '.'
7
7
 
8
8
  const container = document.createElement('div')
9
9
  document.body.appendChild(container)
10
10
 
11
+ jest.mock('../multi-tenancy', () => ({
12
+ useMultiTenancy: jest.fn().mockReturnValue({ tenant: 'DEMO' }),
13
+ }))
14
+
11
15
  describe('AppContext tests', () => {
12
16
  test('renders the content with the default theme', () => {
13
17
  render(
@@ -32,7 +36,7 @@ describe('AppContext tests', () => {
32
36
  type="button"
33
37
  aria-label="btn"
34
38
  data-testid="button"
35
- onClick={(e) => setTheme(renderCustomDarkTheme)}
39
+ onClick={(_) => setTheme(renderCustomDarkTheme)}
36
40
  />
37
41
  {JSON.stringify(theme)}
38
42
  </div>