Skip to content

Commit

Permalink
WSTEAM1-112 - Enable Facebook Optimo embed (#10377)
Browse files Browse the repository at this point in the history
* Enable Facebook embeds on Optimo

* Style fixes, Storybook and tests

* CSP header updates

* AMP background colour fix

* Yarn and regex update

* Update Facebook script URL

* Yarn updates

* Remove custom AMP background colour

* Add Article embed fixture page

* Add check for Facebook script on mount and unmount

Co-authored-by: Andrew Bennett <[email protected]>
  • Loading branch information
amoore108 and andrewscfc authored Nov 2, 2022
1 parent 368df68 commit f9bacaa
Show file tree
Hide file tree
Showing 14 changed files with 1,427 additions and 5 deletions.
504 changes: 504 additions & 0 deletions data/pidgin/articles/c8pd7gx243po.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions src/app/legacy/containers/SocialEmbed/common/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,52 @@ export const tiktokBlockEmbed = {
],
},
};

export const facebookPostBlockEmbed = {
type: 'renditions',
model: {
locator: 'urn:bbc:optimo:social:d4ae3e6f-51cf-4899-bbd4-16d14882cbc7',
blocks: [
{
type: 'aresOEmbed',
model: {
oembed: {
author_name: 'Rick Astley',
author_url: 'https://www.facebook.com/RickAstley',
provider_url: 'https://www.facebook.com',
provider_name: 'Facebook',
html: '<div id="fb-root"></div>\n<script async="1" defer="1" crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&amp;version=v13.0" nonce="fPyyhrbz"></script><div class="fb-post" data-href="https://www.facebook.com/RickAstley/posts/545713756920775" data-width="552"><blockquote cite="https://graph.facebook.com/100044464658204/posts/545713756920775/" class="fb-xfbml-parse-ignore"><p>Had a fantastic time at &#064;thescriptofficial concert in LA this week, what a gig!! Have a great US tour guys! Don’t miss...</p>Posted by <a href="https://www.facebook.com/RickAstley">Rick Astley</a> on&nbsp;<a href="https://graph.facebook.com/100044464658204/posts/545713756920775/">Friday, April 1, 2022</a></blockquote></div>',
type: 'rich',
version: '1.0',
width: 552,
},
},
},
],
},
};

export const facebookVideoBlockEmbed = {
type: 'renditions',
model: {
locator: 'urn:bbc:optimo:social:d4ae3e6f-51cf-4899-bbd4-16d14882cbc7',
blocks: [
{
type: 'aresOEmbed',
model: {
oembed: {
author_name: 'Rick Astley',
author_url: 'https://www.facebook.com/RickAstley',
provider_url: 'https://www.facebook.com',
provider_name: 'Facebook',
height: 888,
html: '<div id="fb-root"></div>\n<script async="1" defer="1" crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&amp;version=v13.0" nonce="8pqnGEmE"></script><div class="fb-video" data-href="https://www.facebook.com/RickAstley/videos/1378590239249667/"><blockquote cite="https://www.facebook.com/RickAstley/videos/1378590239249667/" class="fb-xfbml-parse-ignore"><a href="https://www.facebook.com/RickAstley/videos/1378590239249667/"></a><p>Saw another great gig in LA this week, I went to see Inhaler in the &#064;belascola and they were fantastic! Have a great show in New York tomorrow guys! Rick x &#064;inhalerdublin</p>Posted by <a href="https://www.facebook.com/RickAstley">Rick Astley</a> on Saturday, April 2, 2022</blockquote></div>',
type: 'video',
version: '1.0',
width: 500,
},
},
},
],
},
};
1 change: 1 addition & 0 deletions src/app/legacy/containers/SocialEmbed/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const SocialEmbedContainer = ({ blocks, source }) => {
fallback={fallback}
skipLink={skipLink}
caption={caption}
source={source}
/>
) : (
<Lazyload offset={LAZYLOAD_OFFSET} once height={oEmbed?.height}>
Expand Down
38 changes: 38 additions & 0 deletions src/app/legacy/containers/SocialEmbed/index.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
instagramBlockNoEmbed,
youtubeBlockEmbed,
tiktokBlockEmbed,
facebookPostBlockEmbed,
facebookVideoBlockEmbed,
} from './common/fixtures';
import OptimoSocialEmbedContainer from '.';
import withContexts from './common/testHelper';
Expand Down Expand Up @@ -123,3 +125,39 @@ export const YoutubeWithConsentBannerAmp = props => (
/>
);
YoutubeWithConsentBannerAmp.decorators = [AmpDecorator];

export const FacebookPostCanonicalExample = props => (
<Component
blocks={[facebookPostBlockEmbed]}
source="https://www.facebook.com/RickAstley/posts/545713756920775"
{...props}
/>
);

export const FacebookPostAmpExample = props => (
<Component
isAmp
blocks={[facebookPostBlockEmbed]}
source="https://www.facebook.com/RickAstley/posts/545713756920775"
{...props}
/>
);
FacebookPostAmpExample.decorators = [AmpDecorator];

export const FacebookVideoCanonicalExample = props => (
<Component
blocks={[facebookVideoBlockEmbed]}
source="https://www.facebook.com/RickAstley/videos/1378590239249667"
{...props}
/>
);

export const FacebookVideoAmpExample = props => (
<Component
isAmp
blocks={[facebookVideoBlockEmbed]}
source="https://www.facebook.com/RickAstley/videos/1378590239249667"
{...props}
/>
);
FacebookVideoAmpExample.decorators = [AmpDecorator];
58 changes: 58 additions & 0 deletions src/app/legacy/containers/SocialEmbed/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
instagramBlock,
youtubeBlockEmbed,
tiktokBlockEmbed,
facebookPostBlockEmbed,
facebookVideoBlockEmbed,
} from './common/fixtures';

/* eslint-disable react/prop-types */
Expand Down Expand Up @@ -122,6 +124,62 @@ describe('SocialEmbedContainer', () => {
unmount();
});

it('should render a Facebook Post block and unmount correctly', () => {
const { container, unmount } = render(
<SocialEmbedContainer
blocks={[facebookPostBlockEmbed]}
source="https://www.facebook.com/RickAstley/posts/545713756920775"
/>,
{ service: 'news', isAmp: false, pageType: ARTICLE_PAGE },
);

expect(container.firstChild).toMatchSnapshot();
expect(
document.querySelector(
'head script[src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v15.0"]',
),
).toBeTruthy();
expect(loggerMock.info).toHaveBeenCalledTimes(1);
expect(loggerMock.info).toHaveBeenCalledWith(SOCIAL_EMBED_RENDERED, {
provider: 'facebook',
href: 'https://www.facebook.com/RickAstley/posts/545713756920775',
});
unmount();
expect(
document.querySelector(
'head script[src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v15.0"]',
),
).toBeFalsy();
});

it('should render a Facebook Video block and unmount correctly', () => {
const { container, unmount } = render(
<SocialEmbedContainer
blocks={[facebookVideoBlockEmbed]}
source="https://www.facebook.com/RickAstley/videos/1378590239249667"
/>,
{ service: 'news', isAmp: false, pageType: ARTICLE_PAGE },
);

expect(container.firstChild).toMatchSnapshot();
expect(
document.querySelector(
'head script[src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v15.0"]',
),
).toBeTruthy();
expect(loggerMock.info).toHaveBeenCalledTimes(1);
expect(loggerMock.info).toHaveBeenCalledWith(SOCIAL_EMBED_RENDERED, {
provider: 'facebook',
href: 'https://www.facebook.com/RickAstley/videos/1378590239249667',
});
unmount();
expect(
document.querySelector(
'head script[src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v15.0"]',
),
).toBeFalsy();
});

it('should render the correct skip link text when indexOfType is provided (means this is one of multiple e.g. Twitter embeds in the article)', () => {
render(
<SocialEmbedContainer
Expand Down
6 changes: 6 additions & 0 deletions src/app/legacy/containers/SocialEmbed/sourceHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const PROVIDERS = {
INSTAGRAM: 'instagram',
YOUTUBE: 'youtube',
TIKTOK: 'tiktok',
FACEBOOK: 'facebook',
UNKNOWN: 'unknown',
};

Expand All @@ -27,6 +28,9 @@ export const getProviderFromSource = source => {
if (source.match(/^https:\/\/www\.tiktok\.com/)) {
return PROVIDERS.TIKTOK;
}
if (source.match(/^https:\/\/www\.facebook\.com/)) {
return PROVIDERS.FACEBOOK;
}
return PROVIDERS.UNKNOWN;
};

Expand All @@ -42,6 +46,7 @@ export const getIdFromSource = source => {
youtube: /\/watch\?v=([0-9A-Z a-z_-]+)/,
instagram: /\/p\/([0-9A-Za-z_-]+)/,
tiktok: /\/video\/([0-9]+)/,
facebook: /\/(?:posts|videos)\/([0-9A-Za-z]+)/,
};
const NO_ID = '';
const provider = getProviderFromSource(source);
Expand All @@ -51,6 +56,7 @@ export const getIdFromSource = source => {
PROVIDERS.YOUTUBE,
PROVIDERS.INSTAGRAM,
PROVIDERS.TIKTOK,
PROVIDERS.FACEBOOK,
].includes(provider)
) {
const id = source.match(sourceIds[provider]);
Expand Down
14 changes: 14 additions & 0 deletions src/app/legacy/containers/SocialEmbed/sourceHelpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ describe('sourceHelpers', () => {
const YOUTUBE_SOURCE = 'https://www.youtube.com/watch?v=1e05_rwHvOM';
const TIKTOK_SOURCE =
'https://www.tiktok.com/@cuppymusic/video/7086167423639997701';
const FACEBOOK_POST_SOURCE =
'https://www.facebook.com/RickAstley/posts/545713756920775';
const FACEBOOK_VIDEO_SOURCE =
'https://www.facebook.com/RickAstley/videos/1378590239249667';
const UNKNOWN_SOURCE = 'https://www.randomSource.com/watch?v=XWxjmToNSjQ';

describe('getProviderFromSource', () => {
Expand Down Expand Up @@ -44,6 +48,16 @@ describe('sourceHelpers', () => {
expect(getIdFromSource(TIKTOK_SOURCE)).toEqual('7086167423639997701');
});

it('should return a social embed ID for a valid Facebook Post source', () => {
expect(getIdFromSource(FACEBOOK_POST_SOURCE)).toEqual('545713756920775');
});

it('should return a social embed ID for a valid Facebook Video source', () => {
expect(getIdFromSource(FACEBOOK_VIDEO_SOURCE)).toEqual(
'1378590239249667',
);
});

it('should return an empty string for an unknown or invalid source', () => {
expect(getIdFromSource(UNKNOWN_SOURCE)).toEqual('');
expect(getIdFromSource('https://twitter.com/BBCNews')).toEqual('');
Expand Down
34 changes: 34 additions & 0 deletions src/app/legacy/psammead/psammead-social-embed/src/Amp/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,38 @@ const TikTok = ({ id }) => (
</>
);

const Facebook = ({ source }) => {
const getEmbedType = () => {
switch (true) {
case source.includes('posts'):
return 'post';
case source.includes('videos'):
return 'video';
default:
return 'post';
}
};

return (
<>
<Helmet>
<script
async
custom-element="amp-facebook"
src="https://cdn.ampproject.org/v0/amp-facebook-0.1.js"
/>
</Helmet>
<amp-facebook
data-href={source}
data-embed-as={getEmbedType()}
height="1"
width="1"
layout="responsive"
/>
</>
);
};

const sharedPropTypes = {
id: string.isRequired,
};
Expand All @@ -68,10 +100,12 @@ Instagram.propTypes = sharedPropTypes;
Twitter.propTypes = sharedPropTypes;
YouTube.propTypes = sharedPropTypes;
TikTok.propTypes = sharedPropTypes;
Facebook.propTypes = { ...sharedPropTypes, source: string.isRequired };

export default {
instagram: memo(Instagram),
twitter: memo(Twitter),
youtube: memo(YouTube),
tiktok: memo(TikTok),
facebook: memo(Facebook),
};
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,37 @@ export const providers = provider =>
enrich: () => {},
onLibraryLoad: () => console.error(getOnRenderError('TikTok')),
},
facebook: {
script: 'https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v15.0',
styles: `
position: relative;
overflow: hidden;
.fb_iframe_widget {
position: unset;
> span {
position: unset;
}
}
iframe {
background-color: white;
left:0;
top:0;
height:100% !important;
width:100% !important;
position:absolute !important;
}
`,
enrich: () => {},
onLibraryLoad: () => console.error(getOnRenderError('Facebook')),
},
}[provider]);

const CanonicalEmbed = ({ provider, oEmbed, onRender }) => {
const { script, styles, enrich, onLibraryLoad } = providers(provider);
const hasLoadedLibrary = useScript(script);

useEffect(enrich);

useEffect(() => {
Expand Down
10 changes: 8 additions & 2 deletions src/app/legacy/psammead/psammead-social-embed/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const AmpSocialEmbed = ({
id,
caption,
fallback,
source,
}) => {
const { pageType } = useContext(RequestContext);
const embedCaption = getCaptionText({ pageType, caption, provider });
Expand All @@ -96,12 +97,12 @@ export const AmpSocialEmbed = ({
{embedCaption ? (
<CaptionWrapper service={service} {...embedCaption}>
<EmbedConsentBannerAmp provider={provider} id={id}>
<AmpElement id={id} />
<AmpElement id={id} source={source} />
</EmbedConsentBannerAmp>
</CaptionWrapper>
) : (
<EmbedConsentBannerAmp provider={provider} id={id}>
<AmpElement id={id} />
<AmpElement id={id} source={source} />
</EmbedConsentBannerAmp>
)}
</SkipLinkWrapper>
Expand Down Expand Up @@ -142,7 +143,12 @@ CanonicalSocialEmbed.propTypes = {
onRender: func,
};

AmpSocialEmbed.defaultProps = {
source: null,
};

AmpSocialEmbed.propTypes = {
...sharedPropTypes,
id: string.isRequired,
source: string,
};
Loading

0 comments on commit f9bacaa

Please sign in to comment.