{"componentChunkName":"component---src-templates-blog-jsx","path":"/blog/image-fallback-component","result":{"data":{"mdx":{"frontmatter":{"title":"A React image component with a fallback url","date":"2020-05-05","subtitle":"And how to test it with Jest and React Testing Library","coverCredit":"NeONBRAND","coverWebsite":"Unsplash","cover":{"publicURL":"/static/723a137b5c9d1b0500d22d142c8e2d2f/cover.jpg","childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAAB3TlaOcZ//8QAGBABAQEBAQAAAAAAAAAAAAAAAQIDABH/2gAIAQEAAQUCdoDPQup8nkNKZmVp7//EABgRAQEAAwAAAAAAAAAAAAAAAAEAAhIx/9oACAEDAQE/AQwDlqX/xAAWEQEBAQAAAAAAAAAAAAAAAAABABL/2gAIAQIBAT8BVbTf/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAAgMhEDFR/9oACAEBAAY/Agg4jEMdordTQ37x/8QAGxABAAMAAwEAAAAAAAAAAAAAAQARITFBUfD/2gAIAQEAAT8hXwTyXVTEJd4dxGgl+QAajTfvYvVoum5Z5n//2gAMAwEAAgADAAAAEKcv/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhQf/aAAgBAwEBPxC4ob8P/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAx/9oACAECAQE/EFtgr//EAB0QAQEAAgEFAAAAAAAAAAAAAAERACExQWGBkdH/2gAIAQEAAT8QegcToLzMBmgI/CKPrWVAAzbF+IkIiTEqSBKnnBaSdr9z/9k=","aspectRatio":1.5,"src":"/static/723a137b5c9d1b0500d22d142c8e2d2f/cf77e/cover.jpg","srcSet":"/static/723a137b5c9d1b0500d22d142c8e2d2f/8196e/cover.jpg 258w,\n/static/723a137b5c9d1b0500d22d142c8e2d2f/26313/cover.jpg 516w,\n/static/723a137b5c9d1b0500d22d142c8e2d2f/cf77e/cover.jpg 1032w,\n/static/723a137b5c9d1b0500d22d142c8e2d2f/7022b/cover.jpg 1548w,\n/static/723a137b5c9d1b0500d22d142c8e2d2f/14c55/cover.jpg 2064w,\n/static/723a137b5c9d1b0500d22d142c8e2d2f/9eda0/cover.jpg 4896w","sizes":"(max-width: 1032px) 100vw, 1032px"}}}},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"A React image component with a fallback url\",\n  \"author\": \"Patrick Passarella\",\n  \"date\": \"2020-05-05\",\n  \"subtitle\": \"And how to test it with Jest and React Testing Library\",\n  \"cover\": \"./cover.jpg\",\n  \"coverCredit\": \"NeONBRAND\",\n  \"coverWebsite\": \"Unsplash\",\n  \"published\": true\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"I am sure that you already found a website with an image not loading, maybe you don't really cared that much, but a lot of users care and find it very irritating. It's something incredible simple to solve, that adds a solid value to your application/website.\"), mdx(\"p\", null, \"What we will build, is a image component that can handle broken images, by having a fallback URL.\\nTo start off, let's build a simple Image React component with Typescript.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"interface Props {\\n  url: string;\\n};\\n\\nconst Image: React.FC<Props> = ({url, ...rest}) => (\\n  <img src={url} {...rest} />\\n);\\n\\n\")), mdx(\"p\", null, \"As you can see, it's just a component that returns a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"img\"), \" tag, now to add the fallback url we can use the property \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"onError\"), \" that the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"img\"), \" tag has and almost no one knows about it.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"interface Props {\\n  url: string;\\n  fallback?: string;\\n};\\n\\nconst handleImageError = fallback => event => event.target.src = fallback;\\n\\nconst Image: React.FC<Props> = ({url, fallback, ...rest}) => (\\n  <img src={url} onError={handleImageError(fallback)} {...rest} />\\n);\\n\\n\")), mdx(\"p\", null, \"So if the main url fails, it will change the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"src\"), \" from the image to the passed fallback url, which could be for example a default image. And it works! you can already try it, check the gif below on how to manually test it.\"), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"/3c20cb55dfa0de7920959a8c8a4c980c/fallback-image.gif\",\n    \"alt\": \"gif\"\n  }))), mdx(\"p\", null, \"Just change the URL to something non-existent and you will see that it will change the image source to the fallback one.\", mdx(\"br\", {\n    parentName: \"p\"\n  }), \"\\n\", \"Now, how to test it with Jest? After long and painful hours of trying to test it properly, I found (with the help of the community), a not-too-bad solution, it's not the best, but at least we can test it properly.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"import React from 'react';\\nimport '@testing-library/jest-dom/extend-expect';\\nimport { render, fireEvent, screen } from '@testing-library/react';\\nimport Image from '..';\\n\\nconst imageUrl = 'https://images.unsplash.com/photo-1531436107035-40b2e85b7a1b?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;w=1000&amp;q=80';\\nconst fallbackUrl = 'https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80';\\nconst imageErrorUrl = 'error://test';\\n\\ndescribe('Image', () => {\\n  it('should render the fallback image if the main one has an error', () => {\\n    render(\\n      <Image\\n        src={imageErrorUrl}\\n        fallback={fallbackUrl}\\n      />\\n    );\\n\\n    const image = screen.getByRole(\\\"img\\\");\\n    expect(image).toHaveAttribute('src', imageErrorUrl);\\n    fireEvent.error(image); // Here we trigger the error event\\n    expect(image).toHaveAttribute('src', fallbackUrl); // and check if the src changed\\n  });\\n});\\n\\n\")), mdx(\"p\", null, \"Remembering we need the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"@testing-library/jest-dom/extend-expect\"), \" to be able to use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"toHaveAttribute\"), \" property.\\nIt's a simple test, we are getting the image tag, forcing an error event to happen there, and checking if the image \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"src\"), \" has changed to the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"fallbackUrl\"), \".\"), mdx(\"p\", null, \"That's it! now you have a simple image component with a fallback, that you can reuse it in your application.\"));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"I am sure that you already found a website with an image not loading, maybe you don't really cared that much, but a lot of users care and…","fields":{"slug":"image-fallback-component"}}},"pageContext":{"slug":"image-fallback-component","previous":null,"next":{"fields":{"slug":"how-to-be-productive"}}}},"staticQueryHashes":["2337317332","3351591964"]}