bbc/psammead

View on GitHub
packages/components/psammead-social-embed/src/index.test.jsx

Summary

Maintainability
A
3 hrs
Test Coverage
/* eslint-disable no-console */
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { shouldMatchSnapshot } from '@bbc/psammead-test-helpers';
import { CanonicalSocialEmbed, AmpSocialEmbed } from './index';
import fixtures from './fixtures';
import * as useScript from './Canonical/useScript';

const useScriptSpy = jest.spyOn(useScript, 'default');
const mockOnRender = jest.fn();

describe('CanonicalSocialEmbed', () => {
  const { error } = global.console;

  beforeEach(() => {
    global.console.error = jest.fn();
  });

  afterEach(() => {
    global.console.error = error;
  });
  describe('Twitter', () => {
    const twitterSocialEmbed = (
      <CanonicalSocialEmbed
        provider={fixtures.twitter.source}
        oEmbed={fixtures.twitter.embed.oembed}
        skipLink={{
          text: 'Skip %provider_name% content',
          endTextId: 'skip-%provider%-content',
          endTextVisuallyHidden: 'End of %provider_name% content',
        }}
        fallback={{
          text: "Sorry but we're having trouble displaying this content",
          linkText: 'View content on %provider_name%',
          linkTextSuffixVisuallyHidden: ', external',
          linkHref: 'embed-url',
          warningText:
            'Warning: BBC is not responsible for third party content',
        }}
        service="news"
        onRender={mockOnRender}
      />
    );
    it('should render correctly for Twitter', async () => {
      const { container, unmount } = render(twitterSocialEmbed);
      expect(container.firstChild).toMatchSnapshot();
      expect(
        document.querySelector(
          'head script[src="https://platform.twitter.com/widgets.js"]',
        ),
      ).toBeTruthy();
      unmount();
      expect(
        document.querySelector(
          'head script[src="https://platform.twitter.com/widgets.js"]',
        ),
      ).toBeFalsy();
    });

    it('should call twitter api to enrich tweets after initial render', async () => {
      global.twttr = {
        widgets: {
          load: jest.fn(),
        },
      };

      render(twitterSocialEmbed);

      await waitFor(() => {
        expect(global.twttr.widgets.load).toHaveBeenCalled();
      });
    });

    it('should bind the onRender prop to the rendered event', async () => {
      useScriptSpy.mockReturnValueOnce(true);

      global.twttr = {
        widgets: {
          load: jest.fn(),
        },
        events: {
          bind: jest.fn(),
        },
      };
      global.twttr.ready = cb => cb(global.twttr);

      render(twitterSocialEmbed);

      await waitFor(() => {
        expect(global.twttr.widgets.load).toHaveBeenCalled();
        expect(global.twttr.events.bind).toHaveBeenCalledWith(
          'rendered',
          mockOnRender,
        );
      });
    });
  });

  describe('Instagram', () => {
    const instagramEmbed = (
      <CanonicalSocialEmbed
        provider={fixtures.instagram.source}
        oEmbed={fixtures.instagram.embed.oembed}
        skipLink={{
          text: 'Skip %provider_name% content',
          endTextId: 'skip-%provider%-content',
          endTextVisuallyHidden: 'End of %provider_name% content',
        }}
        fallback={{
          text: "Sorry but we're having trouble displaying this content",
          linkText: 'View content on %provider_name%',
          linkTextSuffixVisuallyHidden: ', external',
          linkHref: 'embed-url',
          warningText:
            'Warning: BBC is not responsible for third party content',
        }}
        service="news"
        onRender={mockOnRender}
      />
    );

    it('should render correctly for Instagram', async () => {
      const { container, unmount } = render(instagramEmbed);
      expect(container.firstChild).toMatchSnapshot();
      expect(
        document.querySelector(
          'head script[src="https://www.instagram.com/embed.js"]',
        ),
      ).toBeTruthy();
      unmount();
      expect(
        document.querySelector(
          'head script[src="https://www.instagram.com/embed.js"]',
        ),
      ).toBeFalsy();
    });

    it('should call instagram api to enrich instgram post after initial render', async () => {
      global.instgrm = {
        Embeds: {
          process: jest.fn(),
        },
      };

      render(instagramEmbed);

      await waitFor(() => {
        expect(global.instgrm.Embeds.process).toHaveBeenCalled();
      });
    });

    it('should not invoke the onRender prop and should log an error', async () => {
      useScriptSpy.mockReturnValueOnce(true);
      render(instagramEmbed);

      expect(console.error).toHaveBeenCalledWith(
        'onRender callback function not implemented for Instagram',
      );
      await waitFor(() => {
        expect(mockOnRender).not.toHaveBeenCalled();
      });
    });
  });

  describe('YouTube', () => {
    const youtubeEmbed = (
      <CanonicalSocialEmbed
        provider={fixtures.youtube.source}
        oEmbed={fixtures.youtube.embed.oembed}
        skipLink={{
          text: 'Skip %provider_name% content',
          endTextId: 'skip-%provider%-content',
          endTextVisuallyHidden: 'End of %provider_name% content',
        }}
        fallback={{
          text: "Sorry but we're having trouble displaying this content",
          linkText: 'View content on %provider_name%',
          linkTextSuffixVisuallyHidden: ', external',
          linkHref: 'embed-url',
          warningText:
            'Warning: BBC is not responsible for third party content',
        }}
        service="news"
        caption={{
          textPrefixVisuallyHidden: 'Video caption, ',
          text: 'Warning: Third party content may contain adverts',
        }}
        onRender={mockOnRender}
      />
    );

    it('should render correctly for YouTube', async () => {
      const { container } = render(youtubeEmbed);
      expect(container.firstChild).toMatchSnapshot();
    });

    it('should not invoke the onRender prop and should log an error', async () => {
      useScriptSpy.mockReturnValueOnce(true);
      render(youtubeEmbed);

      expect(console.error).toHaveBeenCalledWith(
        'onRender callback function not implemented for YouTube',
      );
      await waitFor(() => {
        expect(mockOnRender).not.toHaveBeenCalled();
      });
    });
  });

  shouldMatchSnapshot(
    'should render a notice when the provider is unsupported',
    <CanonicalSocialEmbed
      provider="unknown"
      oEmbed={fixtures.twitter.embed.oembed}
      skipLink={{
        text: 'Skip %provider_name% content',
        endTextId: 'skip-%provider%-content',
        endTextVisuallyHidden: 'End of %provider_name% content',
      }}
      fallback={{
        text: "Sorry but we're having trouble displaying this content",
        linkText: 'View content on %provider_name%',
        linkTextSuffixVisuallyHidden: ', external',
        linkHref: 'embed-url',
        warningText: 'Warning: BBC is not responsible for third party content',
      }}
      service="news"
    />,
  );

  shouldMatchSnapshot(
    'should render a notice when there is no oEmbed response',
    <CanonicalSocialEmbed
      provider={fixtures.twitter.source}
      skipLink={{
        text: 'Skip %provider_name% content',
        endTextId: 'skip-%provider%-content',
        endTextVisuallyHidden: 'End of %provider_name% content',
      }}
      fallback={{
        text: "Sorry but we're having trouble displaying this content",
        linkText: 'View content on %provider_name%',
        linkTextSuffixVisuallyHidden: ', external',
        linkHref: 'embed-url',
        warningText: 'Warning: BBC is not responsible for third party content',
      }}
      service="news"
    />,
  );
});

describe('AmpSocialEmbed', () => {
  Object.values(fixtures).forEach(fixture => {
    const { source: provider, id, embed } = fixture;
    const caption =
      provider === 'youtube'
        ? {
            text: 'Warning: Third party content may contain adverts',
          }
        : null;

    shouldMatchSnapshot(
      `should render correctly for ${embed.oembed.provider_name}`,
      <AmpSocialEmbed
        provider={provider}
        id={id}
        skipLink={{
          text: 'Skip %provider_name% content',
          endTextId: 'skip-%provider%-content',
          endTextVisuallyHidden: 'End of %provider_name% content',
        }}
        fallback={{
          text: "Sorry but we're having trouble displaying this content",
          linkText: 'View content on %provider_name%',
          linkHref: 'embed-url',
          warningText:
            'Warning: BBC is not responsible for third party content',
        }}
        service="news"
        caption={caption}
      />,
    );
  });

  shouldMatchSnapshot(
    'should render a notice when the provider is unsupported',
    <AmpSocialEmbed
      provider="unknown"
      id={fixtures.twitter.id}
      skipLink={{
        text: 'Skip %provider_name% content',
        endTextId: 'skip-%provider%-content',
        endTextVisuallyHidden: 'End of %provider_name% content',
      }}
      fallback={{
        text: "Sorry but we're having trouble displaying this content",
        linkText: 'View content on %provider_name%',
        linkHref: 'embed-url',
        warningText: 'Warning: BBC is not responsible for third party content',
      }}
      service="news"
    />,
  );

  shouldMatchSnapshot(
    'should render null when no social embed ID is provided',
    <AmpSocialEmbed
      provider="unknown"
      id={undefined}
      skipLink={{
        text: 'Skip %provider_name% content',
        endTextId: 'skip-%provider%-content',
        endTextVisuallyHidden: 'End of %provider_name% content',
      }}
      fallback={{
        text: "Sorry but we're having trouble displaying this content",
        linkText: 'View content on %provider_name%',
        linkHref: 'embed-url',
        warningText: 'Warning: BBC is not responsible for third party content',
      }}
      service="news"
    />,
  );
});