@times-components/ts-components 1.36.0 → 1.36.3
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/CHANGELOG.md +33 -0
- package/dist/components/article-header/ArticleHeader.js +15 -14
- package/dist/components/article-header/__tests__/ArticleHeader.test.js +24 -170
- package/dist/components/carousel/GalleryCarousel.js +3 -2
- package/dist/components/carousel/__tests__/GalleryCarousel.test.js +3 -1
- package/dist/components/recommended-articles/RecommendedArticles.d.ts +1 -1
- package/dist/components/recommended-articles/RecommendedArticles.js +9 -2
- package/package.json +3 -3
- package/rnw.js +1 -1
- package/src/components/article-header/ArticleHeader.tsx +16 -16
- package/src/components/article-header/__tests__/ArticleHeader.test.tsx +23 -170
- package/src/components/carousel/GalleryCarousel.tsx +2 -1
- package/src/components/carousel/__tests__/GalleryCarousel.test.tsx +2 -0
- package/src/components/recommended-articles/RecommendedArticles.tsx +11 -1
- package/src/components/article-header/__tests__/__snapshots__/ArticleHeader.test.tsx.snap +0 -68
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import {
|
|
3
|
-
// parse,
|
|
4
|
-
format,
|
|
5
3
|
differenceInSeconds,
|
|
6
4
|
differenceInCalendarDays,
|
|
7
5
|
formatDistanceStrict
|
|
8
6
|
} from 'date-fns';
|
|
9
|
-
import {
|
|
10
|
-
// zonedTimeToUtc,
|
|
11
|
-
utcToZonedTime
|
|
12
|
-
} from 'date-fns-tz';
|
|
7
|
+
import { format, utcToZonedTime } from 'date-fns-tz';
|
|
13
8
|
|
|
14
9
|
import { BreakingArticleFlag } from '../article-flag/LiveArticleFlag';
|
|
15
10
|
import safeDecodeURIComponent from '../../utils/safeDecodeURIComponent';
|
|
@@ -38,19 +33,24 @@ const anchorString = (updateTxt = '', headlineTxt = '') => {
|
|
|
38
33
|
|
|
39
34
|
const ArticleHeader: React.FC<{
|
|
40
35
|
updated: string;
|
|
41
|
-
// date: string;
|
|
42
|
-
// time: string;
|
|
43
36
|
breaking?: string;
|
|
44
37
|
headline?: string;
|
|
45
38
|
}> = ({ updated, breaking, headline }) => {
|
|
39
|
+
const [timezone, setTimezone] = useState<string>('');
|
|
40
|
+
|
|
46
41
|
const currentDateTime = new Date();
|
|
42
|
+
const updatedDate = new Date(updated);
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// const updatedDate = zonedTimeToUtc(parsedDate, 'Europe/London');
|
|
44
|
+
const timeZone = 'Europe/London';
|
|
45
|
+
const parsedDate = utcToZonedTime(updatedDate, timeZone);
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const currentTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
49
|
+
|
|
50
|
+
if (currentTimezone !== timeZone) {
|
|
51
|
+
setTimezone(format(parsedDate, 'zzz', { timeZone }));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
54
|
|
|
55
55
|
const timeSincePublishing =
|
|
56
56
|
formatDistanceStrict(updatedDate, currentDateTime, {
|
|
@@ -92,12 +92,12 @@ const ArticleHeader: React.FC<{
|
|
|
92
92
|
<UpdatedTime
|
|
93
93
|
isLessThan13Hours={!isLessThan1Minute && isLessThan13Hours}
|
|
94
94
|
>
|
|
95
|
-
{format(parsedDate, 'h.mmaaa')}
|
|
95
|
+
{`${format(parsedDate, 'h.mmaaa')} ${timezone}`}
|
|
96
96
|
</UpdatedTime>
|
|
97
97
|
</UpdatedTimeItems>
|
|
98
98
|
|
|
99
99
|
{isDaysAgo ? (
|
|
100
|
-
<UpdatedDate>{format(parsedDate, 'MMMM d
|
|
100
|
+
<UpdatedDate>{format(parsedDate, 'MMMM d')}</UpdatedDate>
|
|
101
101
|
) : null}
|
|
102
102
|
</UpdatesContainer>
|
|
103
103
|
|
|
@@ -9,52 +9,52 @@ describe('ArticleHeader', () => {
|
|
|
9
9
|
describe('Same calendar day during GMT', () => {
|
|
10
10
|
afterEach(() => MockDate.reset());
|
|
11
11
|
|
|
12
|
-
const updated = '2021-12-31T06:30:
|
|
12
|
+
const updated = '2021-12-31T06:30:00+00:00';
|
|
13
13
|
|
|
14
14
|
it('Within a minute of updating', () => {
|
|
15
|
-
MockDate.set('2021-12-31T06:30:
|
|
15
|
+
MockDate.set('2021-12-31T06:30:10+00:00');
|
|
16
16
|
|
|
17
17
|
const { getByText, queryByTestId } = render(
|
|
18
18
|
<ArticleHeader updated={updated} />
|
|
19
19
|
);
|
|
20
20
|
|
|
21
|
-
expect(getByText(
|
|
21
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
22
22
|
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
it('Within an hour of updating', () => {
|
|
26
|
-
MockDate.set('2021-12-31T07:00:
|
|
26
|
+
MockDate.set('2021-12-31T07:00:00+00:00');
|
|
27
27
|
|
|
28
28
|
const { getByText } = render(<ArticleHeader updated={updated} />);
|
|
29
29
|
|
|
30
|
-
expect(getByText(
|
|
30
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
31
31
|
expect(getByText('30 minutes ago')).toBeVisible();
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('Between 1 and 12 hours after updating', () => {
|
|
35
|
-
MockDate.set('2021-12-31T08:30:
|
|
35
|
+
MockDate.set('2021-12-31T08:30:00+00:00');
|
|
36
36
|
|
|
37
37
|
const { getByText } = render(<ArticleHeader updated={updated} />);
|
|
38
38
|
|
|
39
|
-
expect(getByText(
|
|
39
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
40
40
|
expect(getByText('2 hours ago')).toBeVisible();
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
it('After 12 hours but same calendar day', () => {
|
|
44
|
-
MockDate.set('2021-12-20T20:30:
|
|
44
|
+
MockDate.set('2021-12-20T20:30:00+00:00');
|
|
45
45
|
|
|
46
46
|
const { getByText, queryByTestId } = render(
|
|
47
47
|
<ArticleHeader updated={updated} />
|
|
48
48
|
);
|
|
49
49
|
|
|
50
|
-
expect(getByText(
|
|
50
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
51
51
|
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it('With breaking flag and headline', () => {
|
|
55
|
-
MockDate.set('2021-12-31T07:00:
|
|
55
|
+
MockDate.set('2021-12-31T07:00:00+00:00');
|
|
56
56
|
|
|
57
|
-
const {
|
|
57
|
+
const { getByText } = render(
|
|
58
58
|
<ArticleHeader
|
|
59
59
|
updated={updated}
|
|
60
60
|
breaking="true"
|
|
@@ -62,22 +62,22 @@ describe('ArticleHeader', () => {
|
|
|
62
62
|
/>
|
|
63
63
|
);
|
|
64
64
|
|
|
65
|
-
expect(getByText(
|
|
65
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
66
66
|
expect(getByText('30 minutes ago')).toBeVisible();
|
|
67
67
|
expect(getByText('BREAKING')).toBeVisible();
|
|
68
68
|
expect(getByText('This is the headline')).toBeVisible();
|
|
69
69
|
|
|
70
|
-
expect(baseElement).toMatchSnapshot();
|
|
70
|
+
// expect(baseElement).toMatchSnapshot();
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
it('With breaking flag expired', () => {
|
|
74
|
-
MockDate.set('2021-12-31T08:30:
|
|
74
|
+
MockDate.set('2021-12-31T08:30:00+00:00');
|
|
75
75
|
|
|
76
76
|
const { getByText, queryByText } = render(
|
|
77
77
|
<ArticleHeader updated={updated} breaking="true" />
|
|
78
78
|
);
|
|
79
79
|
|
|
80
|
-
expect(getByText(
|
|
80
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
81
81
|
expect(getByText('2 hours ago')).toBeVisible();
|
|
82
82
|
expect(queryByText('BREAKING')).toBeFalsy();
|
|
83
83
|
});
|
|
@@ -95,7 +95,7 @@ describe('ArticleHeader', () => {
|
|
|
95
95
|
<ArticleHeader updated={updated} />
|
|
96
96
|
);
|
|
97
97
|
|
|
98
|
-
expect(getByText(
|
|
98
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
99
99
|
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -104,7 +104,7 @@ describe('ArticleHeader', () => {
|
|
|
104
104
|
|
|
105
105
|
const { getByText } = render(<ArticleHeader updated={updated} />);
|
|
106
106
|
|
|
107
|
-
expect(getByText(
|
|
107
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
108
108
|
expect(getByText('30 minutes ago')).toBeVisible();
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -113,7 +113,7 @@ describe('ArticleHeader', () => {
|
|
|
113
113
|
|
|
114
114
|
const { getByText } = render(<ArticleHeader updated={updated} />);
|
|
115
115
|
|
|
116
|
-
expect(getByText(
|
|
116
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
117
117
|
expect(getByText('2 hours ago')).toBeVisible();
|
|
118
118
|
});
|
|
119
119
|
|
|
@@ -124,7 +124,7 @@ describe('ArticleHeader', () => {
|
|
|
124
124
|
<ArticleHeader updated={updated} />
|
|
125
125
|
);
|
|
126
126
|
|
|
127
|
-
expect(getByText(
|
|
127
|
+
expect(getByText(/6.30am/i)).toBeVisible();
|
|
128
128
|
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
129
129
|
});
|
|
130
130
|
});
|
|
@@ -132,163 +132,16 @@ describe('ArticleHeader', () => {
|
|
|
132
132
|
describe('Different calendar days', () => {
|
|
133
133
|
afterEach(() => MockDate.reset());
|
|
134
134
|
|
|
135
|
-
const updated = '2021-12-31T22:30:
|
|
135
|
+
const updated = '2021-12-31T22:30:00+00:00';
|
|
136
136
|
|
|
137
137
|
it('Between 1 and 12 hours after updating', () => {
|
|
138
|
-
MockDate.set('2022-01-01T02:30:
|
|
138
|
+
MockDate.set('2022-01-01T02:30:00+00:00');
|
|
139
139
|
|
|
140
140
|
const { getByText } = render(<ArticleHeader updated={updated} />);
|
|
141
141
|
|
|
142
|
-
expect(getByText(
|
|
142
|
+
expect(getByText(/10.30pm/i)).toBeVisible();
|
|
143
143
|
expect(getByText('4 hours ago')).toBeVisible();
|
|
144
|
-
expect(getByText('December 31
|
|
144
|
+
expect(getByText('December 31')).toBeVisible();
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
|
-
|
|
149
|
-
/*
|
|
150
|
-
describe('ArticleHeader', () => {
|
|
151
|
-
describe('Same calendar day during GMT', () => {
|
|
152
|
-
afterEach(() => MockDate.reset());
|
|
153
|
-
|
|
154
|
-
const date = '31/12/2021';
|
|
155
|
-
const time = '06:30';
|
|
156
|
-
|
|
157
|
-
it('Within a minute of updating', () => {
|
|
158
|
-
MockDate.set('2021-12-31T06:30:10Z');
|
|
159
|
-
|
|
160
|
-
const { getByText, queryByTestId } = render(
|
|
161
|
-
<ArticleHeader date={date} time={time} />
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
165
|
-
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('Within an hour of updating', () => {
|
|
169
|
-
MockDate.set('2021-12-31T07:00:00Z');
|
|
170
|
-
|
|
171
|
-
const { getByText } = render(<ArticleHeader date={date} time={time} />);
|
|
172
|
-
|
|
173
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
174
|
-
expect(getByText('30 minutes ago')).toBeVisible();
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('Between 1 and 12 hours after updating', () => {
|
|
178
|
-
MockDate.set('2021-12-31T08:30:00Z');
|
|
179
|
-
|
|
180
|
-
const { getByText } = render(<ArticleHeader date={date} time={time} />);
|
|
181
|
-
|
|
182
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
183
|
-
expect(getByText('2 hours ago')).toBeVisible();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('After 12 hours but same calendar day', () => {
|
|
187
|
-
MockDate.set('2021-12-20T20:30:00Z');
|
|
188
|
-
|
|
189
|
-
const { getByText, queryByTestId } = render(
|
|
190
|
-
<ArticleHeader date={date} time={time} />
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
194
|
-
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('With breaking flag and headline', () => {
|
|
198
|
-
MockDate.set('2021-12-31T07:00:00Z');
|
|
199
|
-
|
|
200
|
-
const { baseElement, getByText } = render(
|
|
201
|
-
<ArticleHeader
|
|
202
|
-
date={date}
|
|
203
|
-
time={time}
|
|
204
|
-
breaking="true"
|
|
205
|
-
headline="This%20is%20the%20headline"
|
|
206
|
-
/>
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
210
|
-
expect(getByText('30 minutes ago')).toBeVisible();
|
|
211
|
-
expect(getByText('BREAKING')).toBeVisible();
|
|
212
|
-
expect(getByText('This is the headline')).toBeVisible();
|
|
213
|
-
|
|
214
|
-
expect(baseElement).toMatchSnapshot();
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('With breaking flag expired', () => {
|
|
218
|
-
MockDate.set('2021-12-31T08:30:00Z');
|
|
219
|
-
|
|
220
|
-
const { getByText, queryByText } = render(
|
|
221
|
-
<ArticleHeader date={date} time={time} breaking="true" />
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
225
|
-
expect(getByText('2 hours ago')).toBeVisible();
|
|
226
|
-
expect(queryByText('BREAKING')).toBeFalsy();
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
describe('Same calendar day during BST', () => {
|
|
231
|
-
afterEach(() => MockDate.reset());
|
|
232
|
-
|
|
233
|
-
const date = '20/04/2022';
|
|
234
|
-
const time = '06:30';
|
|
235
|
-
|
|
236
|
-
it('Within a minute of updating', () => {
|
|
237
|
-
MockDate.set('2022-04-20T06:30:10+01:00');
|
|
238
|
-
|
|
239
|
-
const { getByText, queryByTestId } = render(
|
|
240
|
-
<ArticleHeader date={date} time={time} />
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
244
|
-
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('Within an hour of updating', () => {
|
|
248
|
-
MockDate.set('2022-04-20T07:00:00+01:00');
|
|
249
|
-
|
|
250
|
-
const { getByText } = render(<ArticleHeader date={date} time={time} />);
|
|
251
|
-
|
|
252
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
253
|
-
expect(getByText('30 minutes ago')).toBeVisible();
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('Between 1 and 12 hours after updating', () => {
|
|
257
|
-
MockDate.set('2022-04-20T08:30:00+01:00');
|
|
258
|
-
|
|
259
|
-
const { getByText } = render(<ArticleHeader date={date} time={time} />);
|
|
260
|
-
|
|
261
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
262
|
-
expect(getByText('2 hours ago')).toBeVisible();
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('After 12 hours but same calendar day', () => {
|
|
266
|
-
MockDate.set('2022-04-20T20:30:00+01:00');
|
|
267
|
-
|
|
268
|
-
const { getByText, queryByTestId } = render(
|
|
269
|
-
<ArticleHeader date={date} time={time} />
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
expect(getByText('6.30am')).toBeVisible();
|
|
273
|
-
expect(queryByTestId('TimeSincePublishing')).toBeFalsy();
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
describe('Different calendar days', () => {
|
|
278
|
-
afterEach(() => MockDate.reset());
|
|
279
|
-
|
|
280
|
-
const date = '31/12/2021';
|
|
281
|
-
const time = '22:30';
|
|
282
|
-
|
|
283
|
-
it('Between 1 and 12 hours after updating', () => {
|
|
284
|
-
MockDate.set('2022-01-01T02:30:00Z');
|
|
285
|
-
|
|
286
|
-
const { getByText } = render(<ArticleHeader date={date} time={time} />);
|
|
287
|
-
|
|
288
|
-
expect(getByText('10.30pm')).toBeVisible();
|
|
289
|
-
expect(getByText('4 hours ago')).toBeVisible();
|
|
290
|
-
expect(getByText('December 31 2021')).toBeVisible();
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
*/
|
|
@@ -153,7 +153,8 @@ export const GalleryCarousel: React.FC<GalleryCarouselProps> = ({
|
|
|
153
153
|
fireAnalyticsEvent({
|
|
154
154
|
attrs: {
|
|
155
155
|
event_navigation_name: `button : ${buttonLabel}`,
|
|
156
|
-
component_name: headline
|
|
156
|
+
component_name: headline,
|
|
157
|
+
event_navigation_browsing_method: 'click'
|
|
157
158
|
}
|
|
158
159
|
});
|
|
159
160
|
}
|
|
@@ -179,6 +179,7 @@ describe('GalleryCarousel', () => {
|
|
|
179
179
|
component_type: 'in-article component : gallery : interactive',
|
|
180
180
|
eventTime: '2021-05-03T00:00:00.000Z',
|
|
181
181
|
event_navigation_action: 'navigation',
|
|
182
|
+
event_navigation_browsing_method: 'click',
|
|
182
183
|
event_navigation_name: 'button : left',
|
|
183
184
|
section_details: 'Section'
|
|
184
185
|
},
|
|
@@ -212,6 +213,7 @@ describe('GalleryCarousel', () => {
|
|
|
212
213
|
eventTime: '2021-05-03T00:00:00.000Z',
|
|
213
214
|
event_navigation_action: 'navigation',
|
|
214
215
|
event_navigation_name: 'button : right',
|
|
216
|
+
event_navigation_browsing_method: 'click',
|
|
215
217
|
section_details: 'Section'
|
|
216
218
|
},
|
|
217
219
|
component: 'ArticleSkeleton',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import RelatedArticles from '@times-components/related-articles';
|
|
4
4
|
import { GetRecommendedArticles } from '@times-components/provider';
|
|
@@ -18,6 +18,16 @@ export const RecommendedArticles = ({
|
|
|
18
18
|
section,
|
|
19
19
|
analyticsStream
|
|
20
20
|
}: RecommendedArticlesProps) => {
|
|
21
|
+
const [isReady, setIsReady] = useState<boolean>(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
setIsReady(true);
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
if (!isReady) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
return (
|
|
22
32
|
<GetRecommendedArticles
|
|
23
33
|
publisher={'TIMES'}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`ArticleHeader Same calendar day during GMT With breaking flag and headline 1`] = `
|
|
4
|
-
<body>
|
|
5
|
-
<div>
|
|
6
|
-
<div
|
|
7
|
-
class="sc-VigVT esKZlx"
|
|
8
|
-
id="u_20211231063000T222"
|
|
9
|
-
>
|
|
10
|
-
<div
|
|
11
|
-
class="sc-jTzLTM hsNKrf"
|
|
12
|
-
>
|
|
13
|
-
<div
|
|
14
|
-
class="sc-cSHVUG jdArUK"
|
|
15
|
-
>
|
|
16
|
-
<div
|
|
17
|
-
class="sc-kpOJdX pPyiu"
|
|
18
|
-
>
|
|
19
|
-
<div
|
|
20
|
-
class="sc-EHOje cfBXHC"
|
|
21
|
-
>
|
|
22
|
-
<div
|
|
23
|
-
class="sc-bdVaJa bkSKmo"
|
|
24
|
-
>
|
|
25
|
-
<div
|
|
26
|
-
class="sc-htpNat jcRSar"
|
|
27
|
-
>
|
|
28
|
-
<div
|
|
29
|
-
class="sc-bxivhb hTEbzV"
|
|
30
|
-
/>
|
|
31
|
-
</div>
|
|
32
|
-
<span
|
|
33
|
-
class="sc-bwzfXH hBgZUv"
|
|
34
|
-
>
|
|
35
|
-
BREAKING
|
|
36
|
-
</span>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
<div
|
|
41
|
-
class="sc-fjdhpX eXIoUS"
|
|
42
|
-
>
|
|
43
|
-
<div
|
|
44
|
-
class="sc-jzJRlG ektXhQ"
|
|
45
|
-
data-testid="TimeSincePublishing"
|
|
46
|
-
>
|
|
47
|
-
30 minutes ago
|
|
48
|
-
</div>
|
|
49
|
-
<div
|
|
50
|
-
class="sc-kgoBCf gsnOug"
|
|
51
|
-
/>
|
|
52
|
-
</div>
|
|
53
|
-
<div
|
|
54
|
-
class="sc-kAzzGY cABvZX"
|
|
55
|
-
>
|
|
56
|
-
6.30am
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<h2
|
|
61
|
-
class="sc-kGXeez crUIWF"
|
|
62
|
-
>
|
|
63
|
-
This is the headline
|
|
64
|
-
</h2>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
</body>
|
|
68
|
-
`;
|