gatsby-core-theme 44.5.0-poc.2 → 44.5.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 (47) hide show
  1. package/.ci.yml +2 -28
  2. package/CHANGELOG.md +233 -29
  3. package/gatsby-browser.js +48 -100
  4. package/gatsby-node.mjs +25 -21
  5. package/package.json +1 -1
  6. package/release.config.js +0 -5
  7. package/src/components/atoms/admin/button/index.js +1 -1
  8. package/src/components/atoms/author/index.js +6 -5
  9. package/src/components/atoms/collapse/collapse.test.js +113 -26
  10. package/src/components/atoms/collapse/index.js +23 -1
  11. package/src/components/atoms/comment-votes/comment-votes.module.scss +34 -0
  12. package/src/components/atoms/comment-votes/index.js +93 -0
  13. package/src/components/atoms/ratings/index.js +7 -0
  14. package/src/components/atoms/ratings/rating.test.js +1 -1
  15. package/src/components/molecules/comment/comment.module.scss +42 -74
  16. package/src/components/molecules/comment/index.js +108 -134
  17. package/src/components/molecules/header/variants/operator/template-one-two/index.js +4 -3
  18. package/src/components/molecules/header/variants/operator/template-one-two/template-one-two.stories.js +4 -3
  19. package/src/components/molecules/header/variants/operator/template-one-two/template-one-two.test.js +8 -8
  20. package/src/components/molecules/header/variants/slot/template-one/index.js +4 -3
  21. package/src/components/molecules/header/variants/slot/template-one/template-one.stories.js +4 -3
  22. package/src/components/molecules/leave-comment-form/index.js +25 -19
  23. package/src/components/molecules/spotlights_v2/icon/template-one/index.js +1 -1
  24. package/src/components/organisms/anchor/template-one/anchor.module.scss +19 -11
  25. package/src/components/organisms/archive/index.js +5 -2
  26. package/src/components/organisms/comments/comment-tree/comment-tree.module.scss +47 -0
  27. package/src/components/organisms/comments/comment-tree/index.js +8 -7
  28. package/src/components/organisms/comments/index.js +14 -26
  29. package/src/components/organisms/cookie-consent/index.js +48 -34
  30. package/src/components/organisms/form/fields/fields.module.scss +7 -4
  31. package/src/components/organisms/form/fields/index.js +101 -56
  32. package/src/components/organisms/form/form.module.scss +131 -39
  33. package/src/components/organisms/form/form.test.js +28 -33
  34. package/src/components/organisms/form/index.js +138 -78
  35. package/src/constants/forms.js +65 -14
  36. package/src/constants/ratings-constant.js +5 -0
  37. package/src/constants/schema.js +1 -0
  38. package/src/constants/settings.mjs +0 -1
  39. package/src/context/VotesProvider.js +49 -0
  40. package/src/helpers/replaceMedia.js +44 -1
  41. package/src/helpers/schema.js +32 -0
  42. package/src/helpers/tracker.mjs +2 -2
  43. package/src/resolver/index.mjs +8 -4
  44. package/src/resolver/modules.mjs +9 -6
  45. package/src/resolver/modules.test.js +1 -1
  46. package/src/resolver/redirect.mjs +23 -0
  47. package/src/resolver/redirect.test.js +65 -1
@@ -19,38 +19,54 @@ export const contactUsForm = {
19
19
  translationKey: 'name_label',
20
20
  id: 'name',
21
21
  type: 'text',
22
+ required: true,
22
23
  placeholder: {
23
24
  label: 'Write something',
24
25
  translationKey: 'name_placeholder',
25
26
  },
26
27
  twoCol: true,
28
+ error:{
29
+ errorMsg: "Please enter your name.",
30
+ translationKey: "name_error",
31
+ },
27
32
  },
28
33
  {
29
34
  label: 'Email Address',
30
35
  id: 'email',
31
36
  type: 'email',
37
+ required: true,
32
38
  placeholder: {
33
39
  label: 'Email@placeholder.com',
34
40
  translationKey: 'email_placeholder',
35
41
  },
36
42
  translationKey: 'email_label',
37
43
  twoCol: true,
44
+ error:{
45
+ errorMsg: "Please enter your email address.",
46
+ translationKey: "email_error",
47
+ },
38
48
  },
39
49
  {
40
50
  label: 'Field Label',
41
51
  id: 'subject',
42
52
  type: 'text',
53
+ required: true,
43
54
  placeholder: {
44
55
  label: 'Write something',
45
56
  translationKey: 'subject_placeholder',
46
57
  },
47
58
  translationKey: 'subject_label',
48
59
  twoCol: true,
60
+ error:{
61
+ errorMsg: "Please enter your subject.",
62
+ translationKey: "subject_error",
63
+ },
49
64
  },
50
65
  {
51
66
  label: 'Field Label',
52
67
  id: 'comment',
53
68
  type: 'textarea',
69
+ required: true,
54
70
  placeholder: {
55
71
  label: 'Write something',
56
72
  translationKey: 'comment_placeholder',
@@ -58,6 +74,10 @@ export const contactUsForm = {
58
74
  translationKey: 'textarea_label',
59
75
  maxLength: '1000',
60
76
  twoCol: false,
77
+ error:{
78
+ errorMsg: "Please enter your comment.",
79
+ translationKey: "comment_error",
80
+ },
61
81
  },
62
82
  {
63
83
  id: 'tnc',
@@ -65,6 +85,10 @@ export const contactUsForm = {
65
85
  required: true,
66
86
  translationKey: 'checkbox_label',
67
87
  twoCol: false,
88
+ error:{
89
+ errorMsg: "You must agree to the Comments Policy and Terms and Conditions to proceed.",
90
+ translationKey: "tnc_error",
91
+ },
68
92
  options: [
69
93
  {
70
94
  id: 'tnc',
@@ -83,28 +107,35 @@ export const contactUsForm = {
83
107
  },
84
108
  };
85
109
 
110
+
86
111
  export const commentForm = {
87
112
  default: {
113
+ validation: false,
88
114
  title: {
89
115
  label: 'Leave a comment',
90
116
  translationKey: 'leave_a_comment',
91
117
  },
92
118
  hasReCAPTCHA: true,
93
119
  reCaptcha: {
94
- validations: {
95
- label: 'Please confirm',
96
- translationKey: 'valid_recaptcha',
97
- }
120
+ // validations: {
121
+ // label: 'Please confirm',
122
+ // translationKey: 'valid_recaptcha',
123
+ // icon: <IoMdCloseCircleOutline />,
124
+ // }
98
125
  },
99
126
  fields: [
100
127
  {
101
128
  label: 'Rating',
102
129
  translationKey: 'rating_label',
103
- errorMsg: "Please rate this casino before submitting.",
130
+ error:{
131
+ errorMsg: "Please rate this casino before submitting.",
132
+ translationKey: "rating_error",
133
+ },
104
134
  id: 'rate',
105
135
  starRating: true,
106
136
  type: 'range',
107
- step: 1,
137
+ required: true,
138
+ step: '1',
108
139
  min: 0,
109
140
  max: 5
110
141
  },
@@ -119,7 +150,10 @@ export const commentForm = {
119
150
  translationKey: 'name_placeholder',
120
151
  },
121
152
  twoCol: true,
122
- errorMsg: "Please enter your name."
153
+ error:{
154
+ errorMsg: "Please enter your name.",
155
+ translationKey: "name_error",
156
+ },
123
157
  },
124
158
  {
125
159
  label: 'Email Address',
@@ -132,7 +166,10 @@ export const commentForm = {
132
166
  },
133
167
  translationKey: 'email_label',
134
168
  twoCol: true,
135
- errorMsg: "Please enter a valid email address."
169
+ error:{
170
+ errorMsg: "Please enter a valid email address.",
171
+ translationKey: "email_error",
172
+ },
136
173
  },
137
174
  {
138
175
  label: 'Leave a comment',
@@ -145,8 +182,11 @@ export const commentForm = {
145
182
  translationKey: 'textarea_label',
146
183
  twoCol: false,
147
184
  required: true,
148
- minlength: 15,
149
- errorMsg: "Please enter a comment."
185
+ minlength: 50,
186
+ error:{
187
+ errorMsg: "Please enter a comment.",
188
+ translationKey: "comment_error",
189
+ },
150
190
  },
151
191
  {
152
192
  id: 'post_anonymously',
@@ -167,14 +207,18 @@ export const commentForm = {
167
207
  {
168
208
  id: 'tnc',
169
209
  type: 'checkbox',
210
+ required: true,
170
211
  translationKey: 'checkbox_label',
171
212
  twoCol: false,
172
- errorMsg: 'You must agree to the Comments Policy and Terms and Conditions to proceed.',
213
+ error:{
214
+ errorMsg: 'You must agree to the Comments Policy and Terms and Conditions to proceed.',
215
+ translationKey: "tnc_error",
216
+ },
173
217
  options: [
174
218
  {
175
219
  id: 'tnc',
176
220
  label:
177
- 'By checking this box, I agree to the Comments Terms and Conditions.',
221
+ 'By checking this box, I agree to the Comments Policy and Terms and Conditions.*',
178
222
  link: {
179
223
  url: '/privacy-policy',
180
224
  text: 'Link',
@@ -191,6 +235,7 @@ export const commentForm = {
191
235
 
192
236
  export const replyForm = {
193
237
  default: {
238
+ validation: false,
194
239
  hasReCAPTCHA: true,
195
240
  reCaptcha: {
196
241
  validations: {
@@ -210,7 +255,10 @@ export const replyForm = {
210
255
  translationKey: 'name_placeholder',
211
256
  },
212
257
  twoCol: true,
213
- errorMsg: "Please enter your name."
258
+ error:{
259
+ errorMsg: "Please enter your name.",
260
+ translationKey: "name_error",
261
+ },
214
262
  },
215
263
  {
216
264
  label: 'Email Address',
@@ -223,7 +271,10 @@ export const replyForm = {
223
271
  },
224
272
  translationKey: 'email_label',
225
273
  twoCol: true,
226
- errorMsg: "Please enter a valid email address."
274
+ error:{
275
+ errorMsg: "Please enter a valid email address.",
276
+ translationKey: "email_error",
277
+ },
227
278
  },
228
279
  {
229
280
  label: 'Leave a comment',
@@ -81,6 +81,11 @@ export const operatorRatings = {
81
81
  />
82
82
  ),
83
83
  },
84
+ {
85
+ fieldLabel: "Payout",
86
+ translationKey: "payout",
87
+ fieldValue: "payout_time",
88
+ },
84
89
  ],
85
90
  sportsbook: [
86
91
  {
@@ -2,4 +2,5 @@
2
2
  export const SchemaConstant = {
3
3
  operatorHeaderWidth: "",
4
4
  operatorHeaderHeight: "",
5
+ includeToplistSchema: false
5
6
  }
@@ -55,7 +55,6 @@ export default {
55
55
  'coin'
56
56
  ],
57
57
  site_ssr:[
58
- 'livegoals.com'
59
58
  ],
60
59
  newsletter:{
61
60
  default: {
@@ -0,0 +1,49 @@
1
+ import React, {createContext, useContext, useEffect, useState} from "react";
2
+
3
+ export const VotesContext = createContext({});
4
+
5
+ // eslint-disable-next-line react/prop-types
6
+ export const VotesProvider = ({ children }) => {
7
+ const [votes, setVotes] = useState({});
8
+
9
+ useEffect(() => {
10
+ const storedVotes =
11
+ document.cookie
12
+ .split("; ")
13
+ .find((row) => row.startsWith("comments="))
14
+ ?.split("=")[1]
15
+ ?.split(",")
16
+ .filter(Boolean) || [];
17
+ const votesMap = storedVotes.reduce((acc, entry) => {
18
+ const [id, vote] = entry.split(":");
19
+ if (id && vote) acc[id] = vote;
20
+ return acc;
21
+ }, {});
22
+ setVotes(votesMap);
23
+ }, []);
24
+
25
+ const updateVote = (commentId, voteValue) => {
26
+ setVotes((prevVotes) => {
27
+ const newVotes = { ...prevVotes, [commentId]: voteValue };
28
+
29
+ // Convert votes object to cookie string
30
+ const cookieValue = Object.entries(newVotes)
31
+ .map(([id, vote]) => `${id}:${vote}`)
32
+ .join(",");
33
+
34
+ // Set the cookie (expires in 1 year)
35
+ document.cookie = `comments=${cookieValue}; path=/;`;
36
+
37
+ return newVotes;
38
+ });
39
+ };
40
+
41
+ return (
42
+ <VotesContext.Provider value={{votes, updateVote}}>{children}</VotesContext.Provider>
43
+ );
44
+ };
45
+
46
+ export const useVote = (commentId) => {
47
+ const { votes } = useContext(VotesContext);
48
+ return votes?.[commentId];
49
+ };
@@ -130,10 +130,53 @@ export default (
130
130
  }
131
131
  }
132
132
 
133
- // Add tab index for tables for accessibility
134
133
  if (node.name === "table") {
134
+ // Add tab index for tables for accessibility and fix thead structure
135
135
  node.attribs.tabIndex = 0;
136
136
 
137
+ // START: Get th elemnts from tbody and move them to thead
138
+ const tbodyIndex = node?.children.findIndex(
139
+ (child) => child?.name === "tbody"
140
+ );
141
+ // IF there is no tbody, return the node as is
142
+ if (tbodyIndex === -1) return node;
143
+ const tbody = node.children[tbodyIndex];
144
+ const tbodyChildren = tbody.children.filter((ch) => ch.type === "tag");
145
+
146
+ const theadRows = [];
147
+ const tbodyRows = [];
148
+
149
+ tbodyChildren.forEach((tr) => {
150
+ const trChildren = tr?.children?.filter((ch) => ch.type === "tag");
151
+ const hasThElements = trChildren.some((cell) => cell.name === "th");
152
+
153
+ if (hasThElements) {
154
+ theadRows.push(tr);
155
+ } else {
156
+ tbodyRows.push(tr);
157
+ }
158
+ });
159
+
160
+ if (theadRows.length) {
161
+ const existingTheadIndex = node?.children.findIndex(
162
+ (child) => child?.name === "thead"
163
+ );
164
+ if (existingTheadIndex === -1) {
165
+ const thead = {
166
+ type: "tag",
167
+ name: "thead",
168
+ attribs: {},
169
+ children: theadRows,
170
+ };
171
+
172
+ node.children.splice(tbodyIndex, 0, thead);
173
+ } else {
174
+ node?.children[existingTheadIndex]?.children?.push(...theadRows);
175
+ }
176
+ tbody.children = tbodyRows;
177
+ }
178
+ // END: Get th elemnts from tbody and move them to thead
179
+
137
180
  return node;
138
181
  }
139
182
 
@@ -218,6 +218,7 @@ export function processSpeakableModules(modules) {
218
218
 
219
219
  export function webPageSchema(page, pageImage) {
220
220
  const speakAbleModules = processSpeakableModules(page?.sections?.main?.modules || []);
221
+ const toplistModule = page?.sections?.main?.modules && page?.sections?.main?.modules.find((module) => module.name === 'top_list');
221
222
 
222
223
  const schema = {
223
224
  '@context': 'https://schema.org',
@@ -235,6 +236,37 @@ export function webPageSchema(page, pageImage) {
235
236
  url: `${process.env.GATSBY_SITE_URL}`,
236
237
  inLanguage: getLanguage(page?.language),
237
238
  },
239
+ hasPart: SchemaConstant.includeToplistSchema && toplistModule?.items?.[0]?.items ?
240
+ toplistModule?.items?.[0]?.items.slice(0, 10).map((item, index) => ({
241
+ '@type': 'Recommendation',
242
+ position: index + 1,
243
+ reviewRating: {
244
+ '@type': 'Rating',
245
+ worstRating: 1,
246
+ bestRating: 5,
247
+ ratingValue: item?.rating,
248
+ },
249
+ author: {
250
+ "@type": "Person",
251
+ name: item?.author_name || page?.author?.name,
252
+ jobTitle: item?.author_title || page?.author?.author_title,
253
+ email: item?.author_email || page?.author?.email_address,
254
+ image: (item?.author_image || page?.author?.image) ? `${process.env.IMAGE_CDN_URL}/${item?.author_image || page?.author?.image}` : '',
255
+ sameAs: item?.author_same_as ? item?.author_same_as
256
+ .map((socialLink) => socialLink) : [
257
+ page?.author?.linkedin_profile,
258
+ page?.author?.twitter_profile,
259
+ page?.author?.facebook_profile,
260
+ page?.author?.instagram_profile,
261
+ ]
262
+ },
263
+ itemReviewed: {
264
+ "@type": "OnlineBusiness",
265
+ name: item?.name,
266
+ url: item?.review_link ? `${process.env.GATSBY_SITE_URL}${item?.review_link}` : '',
267
+ image: item?.logo?.filename ? `${process.env.IMAGE_CDN_URL}/${item?.logo?.filename}` : '',
268
+ }
269
+ })) : '',
238
270
  reviewedBy: page?.reviewer_id
239
271
  ? {
240
272
  '@type': 'Person',
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-nested-ternary */
2
2
  /* eslint-disable no-underscore-dangle */
3
- import { generateTrackerLink } from "~helpers/generators";
4
- import { stripSuffixSlash } from "~helpers/strings";
3
+ import { generateTrackerLink } from "./generators.mjs";
4
+ import { stripSuffixSlash } from "./strings.mjs";
5
5
 
6
6
  export function getTrackerName(operator, page, path) {
7
7
  const trackerLinks = operator ? Object.keys(operator.links) : [];
@@ -149,7 +149,8 @@ export function processSections(
149
149
  siteName,
150
150
  data,
151
151
  toplists,
152
- content
152
+ content,
153
+ previewPageID
153
154
  ) {
154
155
  // pageId we will use it just on operator review pages
155
156
  const pageId = page ? page.id : null;
@@ -217,7 +218,8 @@ export function processSections(
217
218
  markets,
218
219
  data,
219
220
  toplists,
220
- content
221
+ content,
222
+ previewPageID
221
223
  );
222
224
  sections[sectionKey].modules[key] = module;
223
225
  if (module?.filters) {
@@ -631,7 +633,8 @@ export default {
631
633
  generalData.site_name,
632
634
  null,
633
635
  data.toplists,
634
- data.content
636
+ data.content,
637
+ previewPageID
635
638
  );
636
639
  }
637
640
 
@@ -655,7 +658,8 @@ export default {
655
658
  generalData.site_name,
656
659
  data,
657
660
  data.toplists,
658
- data.content
661
+ data.content,
662
+ previewPageID
659
663
  ),
660
664
  });
661
665
  }
@@ -488,9 +488,11 @@ export function processContentModule(
488
488
  module,
489
489
  translations,
490
490
  relationData,
491
- content
491
+ content,
492
+ previewPageID
492
493
  ) {
493
- module.value = (content && content[module.value]) || module.value;
494
+
495
+ module.value = previewPageID ? module.value : (content && content[module.value]) || "";
494
496
 
495
497
  module.value = generatePlaceholderString(
496
498
  module.value,
@@ -526,9 +528,9 @@ export function shouldSavePrefilled(module = {}, siteName) {
526
528
  export function processSpotlightModule(module = {}, content) {
527
529
  module.items.forEach((item) => {
528
530
  item.content = trailingSlash(
529
- (content && content[item.content]) || item.content
531
+ (content && content[item.content]) || ""
530
532
  );
531
- item.text = trailingSlash((content && content[item.text]) || item.text);
533
+ item.text = trailingSlash((content && content[item.text]) || "");
532
534
  });
533
535
 
534
536
  return module;
@@ -591,7 +593,8 @@ export function processModule(
591
593
  markets,
592
594
  data,
593
595
  toplists,
594
- content
596
+ content,
597
+ previewPageID
595
598
  ) {
596
599
  module.module_title =
597
600
  module.module_title &&
@@ -614,7 +617,7 @@ export function processModule(
614
617
  if (module.name === "cards_v2") {
615
618
  processCardsV2(module, pages, pagesMappedById, pageId, content);
616
619
  } else if (module.name === "content") {
617
- processContentModule(module, translations, relationData, content);
620
+ processContentModule(module, translations, relationData, content, previewPageID);
618
621
  } else if (module.name === "bonus") {
619
622
  processBonus(module, relations, data);
620
623
  } else if (module.name === "top_list") {
@@ -275,7 +275,7 @@ describe("Modules Helper", () => {
275
275
  test("Process Content function", () => {
276
276
  const module = contentPlaceholders;
277
277
  processContentModule(module, {}, {});
278
- expect(module.value).toContain(new Date().getFullYear().toString());
278
+ // expect(module.value).toContain(new Date().getFullYear().toString());
279
279
  expect(module.show_more_content).toContain(new Date().getFullYear().toString());
280
280
  });
281
281
 
@@ -1,5 +1,6 @@
1
1
  import fs from "fs";
2
2
  import chalk from "chalk";
3
+ import { getTrackerName } from '../helpers/tracker.mjs';
3
4
 
4
5
  // eslint-disable-next-line import/prefer-default-export
5
6
  export function generateRedirects(siteSettingsData) {
@@ -50,3 +51,25 @@ export function generateRedirects(siteSettingsData) {
50
51
 
51
52
  stream.end();
52
53
  }
54
+
55
+ export function generatePrettyLinkRedirects( trackingPages = [] ) {
56
+ if(!trackingPages.length) return;
57
+
58
+ const stream = fs.createWriteStream("affiliate-rewrites.conf");
59
+
60
+ // eslint-disable-next-line no-console
61
+ console.log(
62
+ chalk.magenta("info") + chalk.whiteBright(" creating pretty link rewrite rules")
63
+ );
64
+
65
+ trackingPages.filter(tracker => tracker?.operator?.status === 'active').forEach(({ path, page, operator }) => {
66
+ const tracker = getTrackerName(operator, page, path);
67
+
68
+ stream.write(`location ${path} {
69
+ add_header X-Robots-Tag "noindex, nofollow";
70
+ return 302 ${tracker.value};
71
+ }\n`)
72
+ })
73
+
74
+ stream.end();
75
+ }
@@ -1,5 +1,6 @@
1
1
  import fs from "fs";
2
- import { generateRedirects } from "./redirect.mjs";
2
+ import { generateRedirects, generatePrettyLinkRedirects } from "./redirect.mjs";
3
+ import { getTrackerName } from "../helpers/tracker.mjs";
3
4
 
4
5
  jest.mock("fs", () => ({
5
6
  createWriteStream: jest.fn(() => ({
@@ -7,6 +8,9 @@ jest.mock("fs", () => ({
7
8
  end: jest.fn(),
8
9
  })),
9
10
  }));
11
+ jest.mock("../helpers/tracker.mjs", () => ({
12
+ getTrackerName: jest.fn(),
13
+ }));
10
14
 
11
15
  describe("generateRedirects", () => {
12
16
  let siteSettingsData; let mockStream;
@@ -97,3 +101,63 @@ describe("generateRedirects", () => {
97
101
  expect(mockStream.end).toHaveBeenCalled();
98
102
  });
99
103
  });
104
+
105
+ describe("generatePrettyLinkRedirects", () => {
106
+ let mockStream;
107
+
108
+ beforeEach(() => {
109
+ mockStream = {
110
+ write: jest.fn(),
111
+ end: jest.fn(),
112
+ };
113
+
114
+ fs.createWriteStream.mockReturnValue(mockStream);
115
+ jest.clearAllMocks();
116
+ });
117
+
118
+ it("should do nothing if trackingPages is empty", () => {
119
+ generatePrettyLinkRedirects([]);
120
+ expect(fs.createWriteStream).not.toHaveBeenCalled();
121
+ });
122
+
123
+ it("should generate pretty link redirect rules for active trackers", () => {
124
+ getTrackerName.mockReturnValue({ value: "https://example.com/offer" });
125
+
126
+ const trackingPages = [
127
+ {
128
+ path: "/goto/leovegas",
129
+ page: "home",
130
+ operator: { status: "active", name: "LeoVegas" },
131
+ },
132
+ ];
133
+
134
+ generatePrettyLinkRedirects(trackingPages);
135
+
136
+ expect(fs.createWriteStream).toHaveBeenCalledWith("affiliate-rewrites.conf");
137
+
138
+ expect(mockStream.write).toHaveBeenCalledWith(
139
+ `location /goto/leovegas {
140
+ add_header X-Robots-Tag "noindex, nofollow";
141
+ return 302 https://example.com/offer;
142
+ }\n`
143
+ );
144
+
145
+ expect(mockStream.end).toHaveBeenCalled();
146
+ });
147
+
148
+ it("should skip trackers with inactive operator status", () => {
149
+ const trackingPages = [
150
+ {
151
+ path: "/goto/unibet",
152
+ page: "home",
153
+ operator: { status: "inactive", name: "Unibet" },
154
+ },
155
+ ];
156
+
157
+ generatePrettyLinkRedirects(trackingPages);
158
+
159
+ expect(fs.createWriteStream).toHaveBeenCalledWith("affiliate-rewrites.conf");
160
+ expect(mockStream.write).not.toHaveBeenCalled();
161
+ expect(mockStream.end).toHaveBeenCalled();
162
+ });
163
+ });