src/app/pages/OnDemandAudioPage/index.test.tsx

Summary

Maintainability
B
4 hrs
Test Coverage
import React from 'react';
import assocPath from 'ramda/src/assocPath';
import pashtoPageData from '#data/pashto/bbc_pashto_radio/w3ct0lz1.json';
import koreanPageData from '#data/korean/bbc_korean_radio/w3ct0kn5.json';
import zhongwenPageData from '#data/zhongwen/bbc_cantonese_radio/w172xf3r5x8hw4v.json';
import indonesiaPageData from '#data/indonesia/bbc_indonesian_radio/w172xh267fpn19l.json';
import afaanoromooPageData from '#data/afaanoromoo/bbc_afaanoromoo_radio/w13xttnw.json';
import arabicPodcastPageData from '#data/arabic/podcasts/p02pc9qc/p08wtg4d.json';
import persianPodcastBrandPageData from '#data/persian/bbc_persian_radio/p02pc9wf.json';
import indonesianBrandPageData from '#data/indonesia/bbc_indonesian_radio/w13xtt0s.json';
import persianDariEpisodePageData from '#data/persian/bbc_dari_radio/p0340v11.json';
import persianEpisodePageData from '#data/persian/bbc_persian_radio/p0340vyx.json';
import * as analyticsUtils from '#lib/analyticsUtils';
import getInitialData from '#app/routes/onDemandAudio/getInitialData';
import withMediaError from '#lib/utilities/episodeAvailability/withMediaError';
import { MEDIA_PAGE } from '#app/routes/utils/pageTypes';
import { Services, Variants } from '#app/models/types/global';
import { FetchMock } from 'jest-fetch-mock';
import * as MediaLoader from '#app/components/MediaLoader';
import {
  render,
  act,
  waitFor,
} from '../../components/react-testing-library-with-providers';
import koreanPageWithScheduleData from './fixtureData/korean.json';
import _OnDemandAudioPage, { OnDemandAudioProps } from './OnDemandAudioPage';

const OnDemandAudioPage = withMediaError(_OnDemandAudioPage);

const toggles = {
  recentAudioEpisodes: {
    enabled: false,
    value: 4,
  },
  recentPodcastEpisodes: {
    enabled: false,
    value: 8,
  },
  radioSchedule: {
    enabled: true,
  },
};

const fetchMock = fetch as FetchMock;

interface PageProps {
  pageData: OnDemandAudioProps['pageData'];
  service: Services;
  variant: Variants;
  lang: string;
}

const renderPage = async ({
  pageData,
  service,
  variant,
  lang = 'ko',
}: PageProps) => {
  let result;
  await act(async () => {
    result = render(
      <OnDemandAudioPage service={service} pageData={pageData} />,
      {
        service,
        variant,
        pageLang: lang,
        bbcOrigin: 'https://www.test.bbc.com',
        pageType: MEDIA_PAGE,
        derivedPageType: 'On Demand Radio',
        pathname: '/pathname',
        statusCode: 200,
        toggles,
      },
    );
  });

  return result;
};

(analyticsUtils.getAtUserId as jest.Mock) = jest.fn();

jest.mock('../../components/ChartbeatAnalytics', () => {
  const ChartbeatAnalytics = () => <div>chartbeat</div>;
  return ChartbeatAnalytics;
});

const { env } = process;

const getAvailableEpisode = assocPath(
  ['content', 'blocks', 0, 'availability'],
  'available',
);

describe('OnDemand Radio Page ', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    process.env = { ...env };
  });

  it('should match snapshot', async () => {
    const pashtoPageDataWithAvailableEpisode =
      getAvailableEpisode(pashtoPageData);
    fetchMock.mockResponse(JSON.stringify(pashtoPageDataWithAvailableEpisode));

    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });

    // @ts-expect-error partial data required for testing purposes
    const { container } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'pashto',
    });

    expect(container).toMatchSnapshot();
  });

  it('should show the brand title for OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(pashtoPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData: pageDataWithoutVideo } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required queries
    const { getByText, queryByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: pageDataWithoutVideo,
      service: 'pashto',
    });

    expect(getByText('ماښامنۍ خپرونه')).toBeInTheDocument();
    expect(
      queryByText('This podcast is also available on'),
    ).not.toBeInTheDocument();
  });

  it('should show the episode title when it is available', async () => {
    fetchMock.mockResponse(JSON.stringify(arabicPodcastPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-podcast-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'arabic',
    });
    const element = getByText(
      'التصويت عبر البريد في الانتخابات الرئاسية الأميركية',
    );

    expect(element.tagName).toEqual('SPAN');

    await waitFor(() => {
      const actual = document.querySelector('head > title')?.innerHTML;

      expect(actual).toEqual(
        'التصويت عبر البريد في الانتخابات الرئاسية الأميركية - BBC Xtra - Arabic - BBC News عربي',
      );
    });
  });

  it('should show the external links for podcast pages', async () => {
    fetchMock.mockResponse(JSON.stringify(arabicPodcastPageData));

    const { pageData } = await getInitialData({
      path: 'some-podcast-path',
      service: 'arabic',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'arabic',
    });

    expect(getByText('هذا البودكاست متاح عبر')).toBeInTheDocument();
  });

  it('should show the datestamp correctly for Pashto OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(pashtoPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'pashto',
    });

    expect(getByText('۱ می ۲۰۲۰')).toBeInTheDocument();
  });

  it('should show the datestamp correctly for Korean OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(koreanPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData: pageDataWithWithoutVideo } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: pageDataWithWithoutVideo,
      service: 'korean',
    });

    expect(getByText('2020년 5월 4일')).toBeInTheDocument();
  });

  it('should show the datestamp correctly for Indonesian OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(indonesiaPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData: pageDataWithoutVideo } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: pageDataWithoutVideo,
      service: 'indonesia',
    });

    expect(getByText('27 April 2020')).toBeInTheDocument();
  });

  it('should show the datestamp correctly for Zhongwen OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(zhongwenPageData));

    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });

    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      variant: 'trad',
      service: 'zhongwen',
    });

    expect(getByText('2020年6月6日')).toBeInTheDocument();
  });

  it('should show the summary for OnDemand Radio Pages', async () => {
    fetchMock.mockResponse(JSON.stringify(indonesiaPageData));

    // @ts-expect-error partial data required for testing purposes

    const { pageData: pageDataWithWithoutVideo } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: pageDataWithWithoutVideo,
      service: 'indonesia',
    });

    expect(
      getByText(
        'Berita terbaru dari seluruh dunia dan ulasan peristiwa dari Indonesia. Juga berita olahraga terbaru dan berbeda setiap harinya.',
      ),
    ).toBeInTheDocument();
  });

  it('should show the audio player', async () => {
    const koreanPageDataWithAvailableEpisode =
      getAvailableEpisode(koreanPageData);
    fetchMock.mockResponse(JSON.stringify(koreanPageDataWithAvailableEpisode));

    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { container } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'korean',
    });
    const audioPlayer = container.querySelector(
      '[data-e2e="media-loader__container"]',
    );

    expect(audioPlayer).toBeInTheDocument();
  });

  it('should show the expired content message if episode is expired', async () => {
    fetchMock.mockResponse(JSON.stringify(koreanPageData));
    // @ts-expect-error partial data required for testing purposes
    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { container, getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'korean',
    });
    const expiredMessageEl = getByText('더 이상 이용할 수 없는 콘텐츠입니다.');

    expect(expiredMessageEl).toBeInTheDocument();
    expect(container).toMatchSnapshot();
  });

  it("should show the 'content not yet available' message if episode is not yet available", async () => {
    const koreanPageDataWithNotYetAvailableEpisode = assocPath(
      ['content', 'blocks', 0, 'availability'],
      'future',
      koreanPageData,
    );

    fetchMock.mockResponse(
      JSON.stringify(koreanPageDataWithNotYetAvailableEpisode),
    );
    // @ts-expect-error partial data required for testing purposes

    const { pageData } = await getInitialData({
      path: 'some-ondemand-radio-path',
      pageType: MEDIA_PAGE,
      toggles,
    });
    // @ts-expect-error react testing library returns the required query
    const { container, getByText } = await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData,
      service: 'korean',
    });

    const notYetAvailableMessageEl = getByText(
      '아직 재생할 수 없는 프로그램입니다.',
    );

    expect(notYetAvailableMessageEl).toBeInTheDocument();
    expect(container).toMatchSnapshot();
  });

  it('should show the radio schedule for the On Demand radio page', async () => {
    await renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: koreanPageWithScheduleData,
      service: 'korean',
    });

    const scheduleWrapper = document.querySelector(
      '[data-e2e="radio-schedule"]',
    );

    expect(scheduleWrapper).toBeInTheDocument();
  });

  it('should not show the radio schedule for services without schedules', async () => {
    renderPage({
      // @ts-expect-error partial data required for testing purposes
      pageData: { ...koreanPageWithScheduleData, radioScheduleData: undefined },
      service: 'korean',
      lang: 'ko',
    });

    const scheduleWrapper = document.querySelector(
      '[data-e2e="radio-schedule"]',
    );

    expect(scheduleWrapper).not.toBeInTheDocument();
  });

  describe('Page Identifier Overrides ', () => {
    const afaanPageDataWithAvailableEpisode =
      getAvailableEpisode(afaanoromooPageData);

    it.each`
      path                          | data                                 | language | pageIdentifierOverride                                   | pageTitleOverride          | service          | description
      ${'some-podcast-radio-path'}  | ${persianPodcastBrandPageData}       | ${'fa'}  | ${'persian.bbc_persian_radio.podcasts.p0jrz542.page'}    | ${'پرگار'}                 | ${'persian'}     | ${'Persian Podcast'}
      ${'some-ondemand-radio-path'} | ${indonesianBrandPageData}           | ${'id'}  | ${'indonesia.bbc_indonesian_radio.w172ywztppckjfb.page'} | ${'Dunia Pagi Ini'}        | ${'indonesia'}   | ${'Indonesian Brand'}
      ${'some-ondemand-radio-path'} | ${persianDariEpisodePageData}        | ${'fa'}  | ${'persian.bbc_dari_radio.w3ct6lbh.page'}                | ${'مجله شامگاهی'}          | ${'persian'}     | ${'Persian Dari Episode'}
      ${'some-ondemand-radio-path'} | ${persianEpisodePageData}            | ${'fa'}  | ${'persian.bbc_persian_radio.w3ct2czp.page'}             | ${'چشم انداز بامدادی'}     | ${'persian'}     | ${'Persian Episode'}
      ${'some-ondemand-radio-path'} | ${afaanPageDataWithAvailableEpisode} | ${'om'}  | ${'afaanoromoo.bbc_afaanoromoo_radio.w3ct0l8r.page'}     | ${'Oduu BBC Afaan Oromoo'} | ${'afaanoromoo'} | ${'Afaan Oromoo Episode'}
      ${'some-ondemand-radio-path'} | ${pashtoPageData}                    | ${'ps'}  | ${'pashto.bbc_pashto_radio.w3ct0lz1.page'}               | ${'ماښامنۍ خپرونه'}        | ${'pashto'}      | ${'Pashto Brand'}
    `(
      'should use the derived page identifier to render the audio player for $description',
      async ({
        path,
        data,
        language,
        pageIdentifierOverride,
        pageTitleOverride,
        service,
      }) => {
        const mediaLoaderSpy = jest.spyOn(MediaLoader, 'default');

        fetchMock.mockResponse(JSON.stringify(data));
        // @ts-expect-error partial data required for testing purposes
        const { pageData } = await getInitialData({
          path,
          pageType: MEDIA_PAGE,
          toggles,
        });
        const expectedMediaOverrides = {
          model: {
            language,
            pageIdentifierOverride,
            pageTitleOverride,
          },
          type: 'mediaOverrides',
        };

        await renderPage({
          // @ts-expect-error partial data required for testing purposes
          pageData,
          service,
        });

        const mediaLoaderProps = mediaLoaderSpy.mock.calls[0][0];
        const { blocks } = mediaLoaderProps;

        expect(mediaLoaderSpy).toHaveBeenCalled();
        expect(blocks).toEqual(
          expect.arrayContaining([expectedMediaOverrides]),
        );
      },
    );
  });
});