Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f61b61e
Partial rendering and hydration of react on the client
oliverlloyd Oct 29, 2019
35ba0dd
Fix missing padding for revenue links
oliverlloyd Oct 29, 2019
23e2b35
Suppport reader revenue links in footer as well as header
oliverlloyd Oct 29, 2019
c76702f
Set geolocation cookie for Percy tests
oliverlloyd Oct 29, 2019
c82bb77
Move EditionDropdown to islands
oliverlloyd Oct 29, 2019
2f994f3
Restore set cookie call in Percy scripts
oliverlloyd Oct 29, 2019
9d7a707
Set correct cookie
oliverlloyd Oct 29, 2019
f7584c9
Replace all Portals with Islands
oliverlloyd Oct 30, 2019
22dbdc0
Fix key warning
oliverlloyd Oct 30, 2019
0bf0bb2
Use data attributes in place of ids to allow multiple instances of th…
oliverlloyd Oct 30, 2019
f145f6e
Remove unused root element
oliverlloyd Oct 30, 2019
2b5e730
Merge branch 'master' into oliver/partial-react
oliverlloyd Oct 31, 2019
e85482b
Fix merge regression
oliverlloyd Oct 31, 2019
3f49961
Added tests for Dropdown
oliverlloyd Oct 31, 2019
1cc049c
Merge branch 'master' into oliver/partial-react
oliverlloyd Oct 31, 2019
35d4d13
Added tests for pillar menu
oliverlloyd Nov 1, 2019
2fcda62
Merge branch 'oliver/partial-react' of https://github.com/guardian/do…
oliverlloyd Nov 1, 2019
941d394
Added tests for interactivity
oliverlloyd Nov 1, 2019
39f0135
Merge branch 'master' into oliver/partial-react
oliverlloyd Nov 1, 2019
d5c2fea
Mock the MostViewed api call to prevent the tabs suddenly dissapearing
oliverlloyd Nov 1, 2019
0e94eea
Remove only limit
oliverlloyd Nov 1, 2019
5de10cf
Define the order islands are hydrated
oliverlloyd Nov 1, 2019
9b05d1f
Merge branch 'master' into oliver/partial-react
oliverlloyd Nov 4, 2019
bf2db15
Merge branch 'master' into oliver/partial-react
oliverlloyd Nov 6, 2019
00f93e2
Merge branch 'master' into oliver/partial-react
oliverlloyd Nov 6, 2019
e85dad7
Mock fetch call properly
oliverlloyd Nov 6, 2019
141253d
Clearer naming: visitOptions > fetchPolyfill
oliverlloyd Nov 6, 2019
e295534
Merge branch 'oliver/partial-react' of https://github.com/guardian/do…
oliverlloyd Nov 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cypress/integration/e2e/article.e2e.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getPolyfill } from '../../lib/polyfill';
import { visitOptions } from '../../lib/config';
import { fetchPolyfill } from '../../lib/config';
import { articles, AMPArticles } from '../../lib/articles.js';
import { setupApiRoutes } from '../../lib/apiRoutes.js';

Expand All @@ -12,7 +12,7 @@ describe('E2E Page rendering', function() {
const { url, pillar, designType } = article;

it(`It should load ${designType} articles under the ${pillar} pillar`, function() {
cy.visit(`Article?url=${url}`, visitOptions);
cy.visit(`Article?url=${url}`, fetchPolyfill);
cy.contains('Sign in');

cy.wait('@getMostRead').then(xhr => {
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('E2E Page rendering', function() {
// Prevent the Privacy consent banner from obscuring snapshots
cy.setCookie('GU_TK', 'true');

cy.visit(`AMPArticle?url=${url}`, visitOptions);
cy.visit(`AMPArticle?url=${url}`, fetchPolyfill);
cy.contains('Opinion');
});
});
Expand Down
66 changes: 66 additions & 0 deletions cypress/integration/e2e/article.interactivity.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { getPolyfill } from '../../lib/polyfill';
import { mockApi } from '../../lib/mocks';
import { fetchPolyfill } from '../../lib/config';

const READER_REVENUE_TITLE_TEXT = 'Support The';
const articleUrl =
'https://www.theguardian.com/politics/2019/oct/29/tories-restore-party-whip-to-10-mps-who-sought-to-block-no-deal-brexit';

describe('Interactivity', function() {
describe('Verify elements have been hydrated', function() {
it('should open the edition dropdown menu when clicked', function() {
cy.visit(`/Article?url=${articleUrl}`);
cy.contains('Australian').should('not.be.visible');
cy.contains('edition').click();
cy.contains('Australian')
.parents('ul')
.should('be.visible');
});

it('should display the expanded pillar menu when More is clicked', function() {
cy.visit(`/Article?url=${articleUrl}`);
cy.contains('Crosswords').should('not.exist');
cy.contains('More').click();
cy.contains('Crosswords').should('be.visible');
});

it('should display the share count for an article', function() {
cy.visit(`/Article?url=${articleUrl}`);
cy.get('[data-cy=share-count]').should('exist');
});

it('should display all the rich links for an article', function() {
cy.visit(`/Article?url=${articleUrl}`);
cy.get('[data-link-name=rich-link]')
.should('exist')
.its('length')
// This count of rich links is dependent on the article that we're testing not changing
// If this assertion fails then it could be because a link was added or removed in
// which case this check should be updated
.should('be', 2);
});

describe('When most viewed is mocked', function() {
beforeEach(getPolyfill);
beforeEach(mockApi);
it('should change the list of most viewed items when a tab is clicked', function() {
cy.visit(`/Article?url=${articleUrl}`, fetchPolyfill);
cy.get('[data-cy=tab-body-0]').should('be.visible');
cy.get('[data-cy=tab-body-1]').should('not.be.visible');
cy.get('[data-cy=tab-heading-1]').click();
cy.get('[data-cy=tab-body-0]').should('not.be.visible');
cy.get('[data-cy=tab-body-1]').should('be.visible');
});
});

it('should render the reader revenue links in the header and footer', function() {
cy.visit(`/Article?url=${articleUrl}`);
cy.get('header')
.contains(READER_REVENUE_TITLE_TEXT)
.should('be.visible');
cy.get('footer')
.contains(READER_REVENUE_TITLE_TEXT)
.should('be.visible');
});
});
});
4 changes: 2 additions & 2 deletions cypress/integration/percy/article.amp.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getPolyfill } from '../../lib/polyfill';
import { fixTime } from '../../lib/time';
import { visitOptions } from '../../lib/config';
import { fetchPolyfill } from '../../lib/config';
import { AMPArticles } from '../../lib/articles.js';
import { mockApi } from '../../lib/mocks';

Expand All @@ -12,7 +12,7 @@ describe('For AMP', function() {
AMPArticles.map((article, index) => {
const { url, pillar, designType } = article;
it(`It should load ${designType} articles under the ${pillar} pillar`, function() {
cy.visit(`AMPArticle?url=${url}`, visitOptions);
cy.visit(`AMPArticle?url=${url}`, fetchPolyfill);
cy.percySnapshot(`AMP-${pillar}-${designType}-${index}`, {
widths: [375],
});
Expand Down
6 changes: 4 additions & 2 deletions cypress/integration/percy/article.web.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getPolyfill } from '../../lib/polyfill';
import { fixTime } from '../../lib/time';
import { visitOptions } from '../../lib/config';
import { fetchPolyfill } from '../../lib/config';
import { articles } from '../../lib/articles.js';
import { mockApi } from '../../lib/mocks';

Expand All @@ -14,7 +14,9 @@ describe('For WEB', function() {
it(`It should load ${designType} articles under the ${pillar} pillar`, function() {
// Prevent the Privacy consent banner from obscuring snapshots
cy.setCookie('GU_TK', 'true');
cy.visit(`Article?url=${url}`, visitOptions);
// Fix the location to UK (for edition)
cy.setCookie('GU_EDITION', 'UK');
cy.visit(`Article?url=${url}`, fetchPolyfill);
cy.percySnapshot(`WEB-${pillar}-${designType}-${index}`, {
widths: [739, 979, 1139, 1299, 1400],
});
Expand Down
2 changes: 1 addition & 1 deletion cypress/lib/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { polyfillFetch } from '../lib/polyfill';

export const visitOptions = {
export const fetchPolyfill = {
onBeforeLoad(win) {
polyfillFetch(win);
},
Expand Down
33 changes: 16 additions & 17 deletions src/web/browser/react/init.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import React from 'react';
import { hydrate as hydrateCSS } from 'emotion';
import { hydrate as hydrateApp } from 'react-dom';
import { Article } from '@root/src/web/pages/Article';
import { startup } from '@root/src/web/browser/startup';

const init = (): Promise<void> => {
const { cssIDs, data } = window.guardian.app;
const container = document.getElementById('app');
import { hydrateIslands } from '@frontend/web/islands/islands';

if (container) {
/**
* TODO: Remove conditional when Emotion's issue is resolved.
* We're having to prevent emotion hydrating styles in the browser
* in development mode to retain the sourceMap info. As detailed
* in the issue raised here https://github.com/emotion-js/emotion/issues/487
*/
if (process.env.NODE_ENV !== 'development') {
hydrateCSS(cssIDs);
}
const init = (): Promise<void> => {
const {
cssIDs,
data: { CAPI, config, NAV },
} = window.guardian.app;

hydrateApp(React.createElement(Article, { data }), container);
/**
* TODO: Remove conditional when Emotion's issue is resolved.
* We're having to prevent emotion hydrating styles in the browser
* in development mode to retain the sourceMap info. As detailed
* in the issue raised here https://github.com/emotion-js/emotion/issues/487
*/
if (process.env.NODE_ENV !== 'development') {
hydrateCSS(cssIDs);
}

hydrateIslands(CAPI, config, NAV);

return Promise.resolve();
};

Expand Down
3 changes: 1 addition & 2 deletions src/web/components/ArticleMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { css, cx } from 'emotion';
import { palette } from '@guardian/src-foundations';
import { between, until } from '@guardian/src-foundations/mq';

import { ShareCount } from './ShareCount';
import { Dateline } from './Dateline';
import { SharingIcons } from './ShareIcons';
import { Byline } from '@root/src/web/components/Byline';
Expand Down Expand Up @@ -65,7 +64,7 @@ export const ArticleMeta = ({ CAPI, config }: Props) => {
pillar={CAPI.pillar}
displayIcons={['facebook', 'twitter', 'email']}
/>
<ShareCount config={config} pageId={CAPI.pageId} />
<div data-island="share-count" />
</div>
</div>
</>
Expand Down
137 changes: 137 additions & 0 deletions src/web/components/Dropdown.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { Dropdown, Link } from './Dropdown';

const links: Link[] = [
{
url: '/preference/edition/uk',
title: 'UK edition',
isActive: true,
dataLinkName: 'linkname-UK',
},
{
url: '/preference/edition/us',
title: 'US edition',
dataLinkName: 'linkname-US',
},
{
url: '/preference/edition/au',
title: 'Australian edition',
dataLinkName: 'linkname-AU',
},
{
url: '/preference/edition/int',
title: 'International edition',
dataLinkName: 'linkname-INT',
},
];

const LABEL = 'Dropdown label';

/*
        interface Props {
            id: string;
            label: string;
            links: Link[];
            dataLinkName: string;
        }
*/

describe('Dropdown', () => {
it('should display the given label', () => {
const { getByText } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

expect(getByText(LABEL)).toBeInTheDocument();
});

it('should display link titles', () => {
const { getByText } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

expect(getByText(links[0].title)).toBeInTheDocument();
expect(getByText(links[1].title)).toBeInTheDocument();
expect(getByText(links[2].title)).toBeInTheDocument();
expect(getByText(links[3].title)).toBeInTheDocument();
});

it('should render the correct number of link items', () => {
const { container } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

const listItems = container.querySelectorAll('li');

expect(listItems.length).toEqual(links.length);
});

it('should expand the menu when clicked upon', () => {
const { container, getByRole } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

const ulElement = container.querySelector('ul');

expect(ulElement).toHaveStyle('display: none');
fireEvent.click(getByRole('button'));
expect(ulElement).toHaveStyle('display: block');
});

it('should close the expanded menu when they click away', () => {
const { container, getByRole } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

const ulElement = container.querySelector('ul');

fireEvent.click(getByRole('button'));
expect(ulElement).toHaveStyle('display: block');
container.click();
expect(ulElement).toHaveStyle('display: none');
});

it('should close the expanded menu when blurred', () => {
const { container, getByRole } = render(
<Dropdown
id="abc"
label={LABEL}
links={links}
dataLinkName="linkname"
/>,
);

const ulElement = container.querySelector('ul');

fireEvent.click(getByRole('button'));
expect(ulElement).toHaveStyle('display: block');
fireEvent.keyDown(container, { key: 'Escape', code: 'Escape' });
expect(ulElement).toHaveStyle('display: none');
});
});
8 changes: 1 addition & 7 deletions src/web/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { textSans, palette } from '@guardian/src-foundations';
import { from, until } from '@guardian/src-foundations/mq';

import { clearFix } from '@root/src/lib/mixins';
import { ReaderRevenueLinks } from '@root/src/web/components/ReaderRevenueLinks';
import { Pillars, pillarWidth, firstPillarWidth } from './Pillars';
import { BackToTop } from './BackToTop';

Expand Down Expand Up @@ -187,12 +186,7 @@ const FooterLinks: React.FC<{

const rrLinks = (
<div className={readerRevenueLinks}>
<ReaderRevenueLinks
urls={nav.readerRevenueLinks.footer}
edition={edition}
dataLinkNamePrefix={'footer : '}
noResponsive={true}
/>
<div data-island="reader-revenue-links-footer" />
</div>
);

Expand Down
Loading