TDD with Static Image results in an Image Not Found Error Gatsby

Viewed 237

I have recently created a question previously regarding StaticImage appearing to now show up when using Jest and this project @testing-library/react. You can find my previous question here: StaticImage not showing up in test render in Gatsby As of writing this I haven't received a response which seems to indicate that I may have been pointing at the wrong problem.

To summarize, when attempting to follow TDD and make a test before implementing a solution, I attempted to make a test for rendering an image with StaticImage. I use the @testing-library/react to grab rendered react elements and ensure they are rendered correctly. However with StaticImage, it appears that the library does not render the image.

Originally in my first question, I believed that StaticImage from Gastby could've been a special component that for some reason didn't render when using the render method provided by @testing-library/react. However, upon understanding more about jest in general I determined that the jest-config.js file that I created as a part of Gastby's tutorial is actually redirecting any access attempts to image files and pointing them to '<rootDir>/__mocks__/file-mock.js'. Which makes me think when the StaticImage component starts rendering it attempts to access a .png file and that may trigger Jest to access the file-mock.js and attempt to resolve the image. However, in the console I get the warning 'Image could not be found.' I am currently using TypeScript and have attempted to follow the Gatsby's Guide to unit testing, but I haven't been successful thus far. Any help is appreciated!

The contents of my file-mock.js is:

export default 'test-file-stub';

This is from the Gatsby Guide on Unit Testing

My jest-config.js looks like this:

module.exports = {
  transform: {
    '^.+\\.[jt]sx?$': '<rootDir>/jest-preprocess.js',
  },
  moduleNameMapper: {
    '.+\\.(css|styl|less|sass|scss)$': `identity-obj-proxy`,
    '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `<rootDir>/__mocks__/file-mock.js`,
    '^gatsby-page-utils/(.*)$': `gatsby-page-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
    '^gatsby-core-utils/(.*)$': `gatsby-core-utils/dist/$1`, // Workaround for https://github.com/facebook/jest/issues/9771
    '^gatsby-plugin-utils/(.*)$': [`gatsby-plugin-utils/dist/$1`, `gatsby-plugin-utils/$1`], // Workaround for https://github.com/facebook/jest/issues/9771
  },
  testPathIgnorePatterns: [`node_modules`, `\\.cache`, `<rootDir>.*/public`],
  transformIgnorePatterns: [`node_modules/(?!(gatsby)/)`],
  globals: {
    __PATH_PREFIX__: ``,
  },
  testURL: `http://localhost`,
  setupFiles: [`<rootDir>/loadershim.js`],
  testEnvironment: `jsdom`,
  setupFilesAfterEnv: ['<rootDir>/setup-test-env.js'],
};

Here is my loadershim.js:

global.___loader = {
  enqueue: jest.fn(),
};

Here is my jest-preprocess.js:

const babelOptions = {
  presets: ["babel-preset-gatsby", "@babel/preset-typescript"],
};

module.exports = require("babel-jest").default.createTransformer(babelOptions);

Here is my gatsby-config.js

/** @type {import('gatsby').GatsbyConfig} */
module.exports = {
  siteMetadata: {
    title: `new`,
    siteUrl: `https://www.yourdomain.tld`,
  },
  plugins: [
    'gatsby-plugin-image',
    'gatsby-plugin-sitemap',
    `gatsby-plugin-sass`,
    'gatsby-plugin-dts-css-modules',
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        icon: 'src/images/icon.png',
      },
    },
    'gatsby-plugin-mdx',
    'gatsby-transformer-remark',
    'gatsby-plugin-sharp',
    'gatsby-transformer-sharp',
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'images',
        path: './src/images/',
      },
      __key: 'images',
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'pages',
        path: './src/pages/',
      },
      __key: 'pages',
    },
  ],
};
1 Answers

Thanks for the research and explanations on this. I had a similar issue, because even though I wasn't trying to verify images are present in tests, my test logs were filled up with annoying Image not loaded ../images/[my-filename] errors.

I'm not sure if it's the best solution, since it feels like what you have above enough should be sufficient without resorting to manual mocking ... but since it doesn't seem to be, I followed the advice in https://bradgarropy.com/blog/mocking-gatsby-image. I modified slightly, so I created a __mocks__/gatsby-plugin-image.js file, with this content:

const React = require("react")
const plugin = jest.requireActual("gatsby-plugin-image")

const mockImage = ({ imgClassName, ...props }) =>
  React.createElement("img", {
    ...props,
    className: imgClassName,
  })

module.exports = {
  ...plugin,
  GatsbyImage: jest.fn().mockImplementation(mockImage),
  StaticImage: jest.fn().mockImplementation(mockImage),
}

That makes the warnings go away, and it also can support assertions about the images in the tests.

Related