src/app/components/Image/index.test.tsx

Summary

Maintainability
B
5 hrs
Test Coverage
import React from 'react';
import { JSDOM } from 'jsdom';

import {
  render,
  screen,
  waitFor,
} from '../react-testing-library-with-providers';
import Image from '.';
import BASE64_PLACEHOLDER_IMAGE from './base64Placeholder';

import { SHADOW } from '../ThemeProvider/palette';

const removeStyles = (el: HTMLElement) => {
  const dom = new JSDOM(el.innerHTML.replace(/class=".+?"/gm, ''));

  return dom.window.document.body.firstChild;
};

const Fixture = ({ ...props }) => (
  <Image
    alt="Test image alt text"
    src="/test-image-500.jpg.webp"
    srcSet="/test-image-200.webp 200w, /test-image-500.webp 500w"
    mediaType="image/webp"
    fallbackSrcSet="/test-image-200.jpg 200w, /test-image-500.jpg 500w"
    fallbackMediaType="image/jpeg"
    sizes="(max-width: 600px) 480px, 800px"
    width={500}
    height={281}
    {...props}
  />
);

describe('Image - Canonical', () => {
  it('should preload when preload is true', async () => {
    render(<Fixture preload />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

      expect(linkEl).toHaveAttribute('rel', 'preload');
      expect(linkEl).toHaveAttribute('as', 'image');
      expect(linkEl).toHaveAttribute('href', '/test-image-500.jpg.webp');
      expect(linkEl).toHaveAttribute(
        'imagesrcset',
        '/test-image-200.webp 200w, /test-image-500.webp 500w',
      );
      expect(linkEl).toHaveAttribute(
        'imagesizes',
        '(max-width: 600px) 480px, 800px',
      );
    });
  });

  it('should not preload when preload is false', async () => {
    render(<Fixture preload={false} />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

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

  it('should not preload by default', async () => {
    render(<Fixture />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

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

  it('should lazy load when lazy load is true', () => {
    render(<Fixture lazyLoad />);

    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl).toHaveAttribute('loading', 'lazy');
  });

  it('should not lazy load when lazy load is false', () => {
    render(<Fixture lazyLoad={false} />);

    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl).not.toHaveAttribute('loading', 'lazy');
  });

  it('should not lazy load by default', () => {
    render(<Fixture />);

    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl).not.toHaveAttribute('loading', 'lazy');
  });

  it('should render the primary srcset and sizes', () => {
    render(<Fixture />);

    const sourceEl = screen.getByAltText('Test image alt text');
    expect(sourceEl).toHaveAttribute(
      'srcset',
      '/test-image-200.webp 200w, /test-image-500.webp 500w',
    );
    expect(sourceEl).toHaveAttribute(
      'sizes',
      '(max-width: 600px) 480px, 800px',
    );
  });

  it('should render image with correct width and height attributes', () => {
    render(<Fixture />);

    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl).toHaveAttribute('width', '500');
    expect(imageEl).toHaveAttribute('height', '281');
  });

  it('should render an image with an alt tag', () => {
    render(<Fixture />);
    expect(screen.getByAltText('Test image alt text')).toBeInTheDocument();
  });

  it('should render a placeholder image by default', () => {
    render(<Fixture />);
    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render a placeholder image when placeholder is true', () => {
    render(<Fixture />);
    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render a placeholder image when placeholder is true', () => {
    render(<Fixture darkPlaceholder />);
    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
      backgroundColor: SHADOW,
    });
  });

  it('should not render a placeholder image when placeholder is false', () => {
    render(<Fixture placeholder={false} />);
    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl.parentNode).not.toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render the container with an aspect ratio based on width and height', () => {
    render(<Fixture />);

    const imageEl = screen.getByAltText('Test image alt text');
    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '56.2%',
    });
  });

  it('should render the container with no fixed aspect ratio if no width, height or aspect ratio is provided', () => {
    render(<Fixture width={undefined} height={undefined} />);

    const imageEl = screen.getByAltText('Test image alt text');

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '0',
    });
  });

  it('should render the container with a custom aspect ratio when provided', () => {
    render(
      <Fixture aspectRatio={[4, 3]} width={undefined} height={undefined} />,
    );

    const imageEl = screen.getByAltText('Test image alt text');

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '75%',
    });
  });

  it('should render the container with a custom aspect ratio that overrides aspect ratio based on image width and height', () => {
    render(<Fixture aspectRatio={[4, 3]} />);

    const imageEl = screen.getByAltText('Test image alt text');

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '75%',
    });
  });

  it('should match markup for basic image', () => {
    const { container } = render(
      <Image
        alt="Test image alt text"
        src="/test-image-500.jpg"
        aspectRatio={[16, 9]}
      />,
    );

    expect(removeStyles(container)).toMatchInlineSnapshot(`
<div
  style="padding-bottom: 56.25%; overflow: hidden;"
>
  <img
    alt="Test image alt text"
    src="/test-image-500.jpg"
  />
</div>
`);
  });

  it('should match markup for a responsive image', () => {
    const { container } = render(
      <Image
        alt="Test image alt text"
        src="/test-image-500.jpg.webp"
        srcSet="/test-image-200.jpg.webp 200w, /test-image-500.jpg.webp 500w"
        aspectRatio={[16, 9]}
      />,
    );

    expect(removeStyles(container)).toMatchInlineSnapshot(`
      <div
        style="padding-bottom: 56.25%; overflow: hidden;"
      >
        <img
          alt="Test image alt text"
          src="/test-image-500.jpg.webp"
          srcset="/test-image-200.jpg.webp 200w, /test-image-500.jpg.webp 500w"
        />
      </div>
    `);
  });
});

describe('Image - AMP pages', () => {
  it('should preload when preload is true', async () => {
    render(<Fixture isAmp preload />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

      expect(linkEl).toHaveAttribute('rel', 'preload');
      expect(linkEl).toHaveAttribute('as', 'image');
      expect(linkEl).toHaveAttribute('href', '/test-image-500.jpg.webp');
      expect(linkEl).toHaveAttribute(
        'imagesrcset',
        '/test-image-200.webp 200w, /test-image-500.webp 500w',
      );
      expect(linkEl).toHaveAttribute(
        'imagesizes',
        '(max-width: 600px) 480px, 800px',
      );
    });
  });

  it('should not preload when preload is false', async () => {
    render(<Fixture isAmp preload={false} />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

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

  it('should not preload by default', async () => {
    render(<Fixture isAmp />);

    await waitFor(() => {
      const linkEl = document.head.querySelector('link');

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

  it('should render 2 nested amp-img tags both with alt text', () => {
    render(<Fixture isAmp />);

    const imageEls = screen.getAllByAltText('Test image alt text');
    expect(imageEls.length).toBe(1);
    expect(imageEls[0].nodeName).toBe('AMP-IMG');
  });

  it('should render jpg image', () => {
    render(<Fixture isAmp />);

    const imageEls = screen.getAllByAltText('Test image alt text');
    expect(imageEls[0]).toHaveAttribute(
      'srcset',
      '/test-image-200.webp 200w, /test-image-500.webp 500w',
    );
  });

  it('should render image with correct width and height attributes', () => {
    render(<Fixture isAmp />);

    const imageEl = screen.getAllByAltText('Test image alt text');
    expect(imageEl[0]).toHaveAttribute('width', '500');
    expect(imageEl[0]).toHaveAttribute('height', '281');
  });

  it('should render a placeholder image by default', () => {
    render(<Fixture isAmp />);
    const imageEl = screen.getAllByAltText('Test image alt text')[0];

    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render a placeholder image when placeholder is true', () => {
    render(<Fixture isAmp />);
    const imageEl = screen.getAllByAltText('Test image alt text')[0];
    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render a dark placeholder image when darkPlaceholder is true', () => {
    render(<Fixture isAmp darkPlaceholder />);
    const imageEl = screen.getAllByAltText('Test image alt text')[0];
    expect(imageEl.parentNode).toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
      backgroundColor: SHADOW,
    });
  });

  it('should not render a placeholder image when placeholder is false', () => {
    render(<Fixture placeholder={false} isAmp />);
    const imageEl = screen.getAllByAltText('Test image alt text')[0];
    expect(imageEl.parentNode).not.toHaveStyle({
      backgroundImage: `url(${BASE64_PLACEHOLDER_IMAGE})`,
    });
  });

  it('should render the container with an aspect ratio based on width and height', () => {
    render(<Fixture isAmp />);

    const imageEl = screen.getAllByAltText('Test image alt text')[0];

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '56.2%',
    });
  });

  it('should render the container with no fixed aspect ratio if no width, height or aspect ratio is provided', () => {
    render(<Fixture width={undefined} height={undefined} isAmp />);

    const imageEl = screen.getAllByAltText('Test image alt text')[0];

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: 0,
    });
  });

  it('should render the container with a custom aspect ratio when provided', () => {
    render(
      <Fixture
        aspectRatio={[4, 3]}
        width={undefined}
        height={undefined}
        isAmp
      />,
    );

    const imageEl = screen.getAllByAltText('Test image alt text')[0];

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '75%',
    });
  });

  it('should render the container with a custom aspect ratio that overrides aspect ratio based on image width and height', () => {
    render(<Fixture aspectRatio={[4, 3]} isAmp />);

    const imageEl = screen.getAllByAltText('Test image alt text')[0];

    expect(imageEl.parentNode).toHaveStyle({
      paddingBottom: '75%',
    });
  });

  it('should match markup for basic image', () => {
    const { container } = render(
      <Image
        isAmp
        alt="Test image alt text"
        src="/test-image-500.jpg"
        aspectRatio={[16, 9]}
      />,
    );

    expect(removeStyles(container)).toMatchInlineSnapshot(`
<div
  style="padding-bottom: 56.25%; overflow: hidden;"
>
  <amp-img
    alt="Test image alt text"
    fallback=""
    layout="fill"
    src="/test-image-500.jpg"
  />
</div>
`);
  });

  it('should match markup for a responsive image', () => {
    const { container } = render(
      <Image
        isAmp
        alt="Test image alt text"
        src="/test-image-500.jpg"
        srcSet="/test-image-200.jpg 200w, /test-image-500.jpg 500w"
        aspectRatio={[16, 9]}
      />,
    );

    expect(removeStyles(container)).toMatchInlineSnapshot(`
<div
  style="padding-bottom: 56.25%; overflow: hidden;"
>
  <amp-img
    alt="Test image alt text"
    fallback=""
    layout="fill"
    src="/test-image-500.jpg"
    srcset="/test-image-200.jpg 200w, /test-image-500.jpg 500w"
  />
</div>
`);
  });

  it('should match markup for a responsive jpg image', () => {
    const { container } = render(
      <Image
        isAmp
        alt="Test image alt text"
        src="/test-image-500.webp"
        srcSet="/test-image-200.webp 200w, /test-image-500.webp 500w"
        sizes="(max-width: 600px) 480px, 800px"
        mediaType="image/webp"
        fallbackSrcSet="/test-image-200.jpg 200w, /test-image-500.jpg 500w"
        fallbackMediaType="image/jpeg"
        aspectRatio={[16, 9]}
      />,
    );

    expect(removeStyles(container)).toMatchInlineSnapshot(`
<div
  style="padding-bottom: 56.25%; overflow: hidden;"
>
  <amp-img
    alt="Test image alt text"
    fallback=""
    layout="fill"
    sizes="(max-width: 600px) 480px, 800px"
    src="/test-image-500.webp"
    srcset="/test-image-200.webp 200w, /test-image-500.webp 500w"
  />
</div>
`);
  });
});