{"id":30902,"date":"2021-09-20T07:32:56","date_gmt":"2021-09-20T06:32:56","guid":{"rendered":"https:\/\/www.inovex.de\/?p=30902"},"modified":"2022-11-22T10:14:31","modified_gmt":"2022-11-22T09:14:31","slug":"testing-frontend-code-in-2021","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/","title":{"rendered":"Testing Frontend Code in 2021"},"content":{"rendered":"<p>Testing highly interactive web applications have evolved over the last decades. Some years ago, testing frontend code integrated with a browser environment was a big pain point. Nowadays, new utilities and libraries exist, best practices have been established and have evolved.<\/p>\n<p><!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Introduction\" >Introduction<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#TLDR\" >TLDR;<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Testing-history\" >Testing history<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#The-Testing-pyramid\" >The Testing pyramid<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Testing-strategies-Return-on-investment-ROI\" >Testing strategies: Return on investment (ROI)<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#The-Testing-Trophy-and-the-focus-on-integration-tests\" >The Testing Trophy and the focus on integration tests<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Example-with-React\" >Example with React<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#The-problem-False-confidence\" >The problem: False confidence<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Fix-the-problem-Lets-write-an-integration-test\" >Fix the problem: Let&#8217;s write an integration test<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Conclusion\" >Conclusion<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#Resources-and-further-notes\" >Resources and further notes<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Introduction\"><\/span>Introduction<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The first <a href=\"http:\/\/2016.stateofjs.com\/2016\/testing\/\">StateOfJS study in 2016<\/a> concluded that many developers struggled with testing and therefore avoided writing automated tests in general.<\/p>\n<p>Abstractions and frameworks like <a href=\"https:\/\/www.selenium.dev\/\">Selenium<\/a> and <a href=\"https:\/\/nightwatchjs.org\/\">Nightwatch<\/a> were helpful but also in their early days and even though those frameworks existed, it was still hard for frontend developers to write reliable, performant as well as refactor-friendly automated tests.<\/p>\n<p>The developers still had to write a lot of glue code and had to evolve their own best practices in their codebase. The overall experience for writing tests for frontend applications was not mature, but a lot has changed in the last four years.<\/p>\n<p>Frameworks and automated headless browser environments like <a href=\"https:\/\/www.cypress.io\/\">Cypress<\/a>, <a href=\"https:\/\/github.com\/microsoft\/playwright\">Playwright<\/a>, <a href=\"https:\/\/github.com\/puppeteer\/puppeteer\">Puppeteer<\/a> as well as utility frameworks like <a href=\"https:\/\/testing-library.com\/\">Testing-Library<\/a> and <a href=\"https:\/\/mswjs.io\/\">MSW<\/a> have been introduced and are trending in <a href=\"https:\/\/risingstars.js.org\/2020\/en#section-test-framework\">usage<\/a>. These changes also introduced a new perspective for frontend testing.<\/p>\n<p>Recent advances in end-to-end (e2e) and integration testing for frontend applications have shifted testing strategies from unit towards more integration and end-to-end testing.<\/p>\n<p>I think the main reason for this trend is that modern web applications got more complex and more developers got into testing. Thereby a lot of really great content, abstractions, and frameworks got created.<\/p>\n<p>As the latest <a href=\"https:\/\/2020.stateofjs.com\/\">StateOfJS<\/a> study in 2020 shows that more people are using and are satisfied with frameworks that are focused on (integration and e2e testing) <a href=\"https:\/\/2020.stateofjs.com\/en-US\/technologies\/testing\/\">like Cypress, Playwright, and helper utilities like Testing-Library<\/a>.<\/p>\n<figure id=\"attachment_30953\" aria-describedby=\"caption-attachment-30953\" style=\"width: 834px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-30953 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools.png\" alt=\"Testing frameworks and utility logos: Top Playwright, bottom Cypress, left Testing-Library and right Puppeteer\" width=\"834\" height=\"613\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools.png 834w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools-300x221.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools-768x564.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools-400x294.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tools-360x265.png 360w\" sizes=\"auto, (max-width: 834px) 100vw, 834px\" \/><figcaption id=\"caption-attachment-30953\" class=\"wp-caption-text\">Testing frameworks and utility logos: Top Playwright, bottom Cypress, left Testing-Library, and right Puppeteer<\/figcaption><\/figure>\n<p>In this blog post, I want to cover some historical aspects of testing with a focus on frontend applications and discuss the current state as well as some of the best practices of the current industry.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"TLDR\"><\/span>TLDR;<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li>Testing pyramid switches (trend) towards integration and e2e tests for frontend applications.<\/li>\n<li>With Cypress (<a href=\"https:\/\/www.npmtrends.com\/cypress-vs-puppeteer-vs-playwright\">first released 2015<\/a>), Playwright (<a href=\"https:\/\/github.com\/microsoft\/playwright\/graphs\/contributors\">first commit Nov 10, 2019<\/a>), Puppeteer (<a href=\"https:\/\/www.npmtrends.com\/cypress-vs-puppeteer-vs-playwright\">first released in 2017<\/a>), Codecept (<a href=\"https:\/\/github.com\/codeceptjs\/CodeceptJS\">released in 2016<\/a>) Testing Library (<a href=\"https:\/\/github.com\/testing-library\/react-testing-library\/releases\/tag\/v0.0.0\">released in 2018<\/a>) a lot of great tooling has been introduced in the last few years.<\/li>\n<li>Integration and end-to-end testing got more reliable and faster to execute because of better abstractions and new best practices.<\/li>\n<li>Also, integration and e2e tests provide more confidence that your app works as expected.<\/li>\n<\/ul>\n<h2><\/h2>\n<h2><span class=\"ez-toc-section\" id=\"Testing-history\"><\/span>Testing history<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>While several years ago many people would have suggested implementing a <a href=\"https:\/\/martinfowler.com\/bliki\/TestPyramid.html\">lot of unit tests<\/a>, several integration tests, and only some e2e tests as mentioned and referenced often by the testing pyramid principles, the testing strategy for frontend applications has shifted a bit.<\/p>\n<p>In general, this is still really good advice but the landscape has evolved and integration and e2e tests are faster to execute. <a href=\"https:\/\/glebbahmutov.com\/blog\/split-spec\/\">For example by using parallel and split testing<\/a> or the continuous updates to J<a href=\"https:\/\/jestjs.io\/blog\/2020\/01\/21\/jest-25\">est<\/a> and JSDOM abstraction. These types of tests are also easier to write with better <a href=\"https:\/\/testing-library.com\/docs\/queries\/about\">DOM queries<\/a> based on Testing-Library API and <a href=\"https:\/\/testing-library.com\/docs\/ecosystem-user-event\/\">user event<\/a> abstractions for handling user interactions.<\/p>\n<p>When speaking about testing in general we have to mention and talk about the so often referenced testing pyramid paradigm. So let&#8217;s take a look at the testing pyramid.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The-Testing-pyramid\"><\/span>The Testing pyramid<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The testing pyramid was first introduced by <a href=\"https:\/\/en.wikipedia.org\/wiki\/Mike_Cohn\">Mike Cohn<\/a> in the book <em>&#8222;Succeeding with agile&#8220;<\/em>. It describes three main layers of testing with a reference to how much testing you should do on each of these layers.<\/p>\n<ul>\n<li>Unit test<\/li>\n<li>Service test (also often described as integration-test)<\/li>\n<li>User interface test (also often described as end-to-end test)<\/li>\n<\/ul>\n<figure id=\"attachment_30957\" aria-describedby=\"caption-attachment-30957\" style=\"width: 560px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-30957 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/test-pyramid.png\" alt=\"Testing pyramid mentioned in this blog post by Martin fowler\" width=\"560\" height=\"300\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/test-pyramid.png 560w, https:\/\/www.inovex.de\/wp-content\/uploads\/test-pyramid-300x161.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/test-pyramid-400x214.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/test-pyramid-360x193.png 360w\" sizes=\"auto, (max-width: 560px) 100vw, 560px\" \/><figcaption id=\"caption-attachment-30957\" class=\"wp-caption-text\">Testing pyramid mentioned in this blog post by Martin fowler<\/figcaption><\/figure>\n<figure id=\"attachment_30959\" aria-describedby=\"caption-attachment-30959\" style=\"width: 481px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-30959 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/traditional-pyramid.png\" alt=\"Original testing pyramid from the book &quot;Succeeding with agile&quot;\" width=\"481\" height=\"277\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/traditional-pyramid.png 481w, https:\/\/www.inovex.de\/wp-content\/uploads\/traditional-pyramid-300x173.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/traditional-pyramid-400x230.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/traditional-pyramid-360x207.png 360w\" sizes=\"auto, (max-width: 481px) 100vw, 481px\" \/><figcaption id=\"caption-attachment-30959\" class=\"wp-caption-text\">Original testing pyramid from the book &#8222;Succeeding with agile&#8220;<\/figcaption><\/figure>\n<p>Many people adopted their own explanation for the different surface areas and adapted some terminology but most people would conclude that tests should follow the following principles<\/p>\n<p>While it is generally a good approach to have tests with <span data-token-index=\"1\" data-reactroot=\"\">different granularity,<\/span> the main purpose of testing is to<span data-token-index=\"3\" data-reactroot=\"\"> have a healthy, fast and maintainable test suite<\/span> which gives you the maximum confidence that your <span data-token-index=\"5\" data-reactroot=\"\">application works as you have expected<\/span>.<\/p>\n<p><a href=\"https:\/\/de.wikipedia.org\/wiki\/Martin_Fowler\">Martin Fowler<\/a> later referenced the testing pyramid in his <a href=\"https:\/\/martinfowler.com\/bliki\/TestPyramid.html\">blog post<\/a> from 2012 and shared his thoughts on why he prefers having more unit tests instead of slow-running UI (e2e) tests. But as a side note, he also mentioned that he prefers unit tests mainly because they are more reliable and fast to execute. I would argue that writing and mocking tests that run in a real browser environment got better in the execution time, the documentation, as well as the developer experience than it was back in 2012. As a\u00a0<a href=\"https:\/\/blog.checklyhq.com\/cypress-vs-selenium-vs-playwright-vs-puppeteer-speed-comparison\/\">comparison<\/a> to 2021 shows, are Playwright and Puppeteer generally faster in test execution than the industry standard selenium. While Cypress is slower, it provides an awesome developer experience <a href=\"https:\/\/github.com\/brunopulis\/awesome-cypress#webinars\">(as mentioned in several blog posts, webinars and podcasts)<\/a> and can be highly parallelized.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Testing-strategies-Return-on-investment-ROI\"><\/span>Testing strategies: Return on investment (ROI)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>One of the core decision drivers when writing tests is about the return on investment (<strong>ROI<\/strong>). There are several factors that we have to account for when evaluating ROI:<\/p>\n<ul>\n<li>Developer experience (DX)<\/li>\n<li>Confidence and preventing bugs that may get shipped<\/li>\n<li>Maintaining the codebase<\/li>\n<li>What kind of errors are you and your team mostly worried about and want to prevent to happen<\/li>\n<\/ul>\n<p>As I have mentioned, the tooling to create an integration and e2e test got much better in many different ways. Unit tests are very well suited to test application logic but can lead to false confidence. When we can assume that running an integration and e2e test has gotten and will get significantly better each year, we could argue that writing and maintaining those tests prevent most bugs and provides the best developer experience (as for example writing Cypress tests is a highly interactive experience).<\/p>\n<p>Modern tools like Cypress allow developers to write reliable and cheap to modify tests while contributing to more confidence and safety shipping your application to your users. Those tests give you much more confidence while with the new modern tools you do not lose a lot in developer experience and performance.<\/p>\n<p>In 2016 <a href=\"https:\/\/twitter.com\/rauchg?lang=de\">Guillermo Rauch<\/a> (CEO of Vercel) tweeted this and started a lot of discussions.<\/p>\n<figure id=\"attachment_30961\" aria-describedby=\"caption-attachment-30961\" style=\"width: 589px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-30961 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tweet.png\" alt=\"Guillermo Rauch CEO of Vercel quote: Write tests. Not too many. Mostly integration.\" width=\"589\" height=\"217\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tweet.png 589w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tweet-300x111.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tweet-400x147.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-tweet-360x133.png 360w\" sizes=\"auto, (max-width: 589px) 100vw, 589px\" \/><figcaption id=\"caption-attachment-30961\" class=\"wp-caption-text\"><a href=\"https:\/\/twitter.com\/rauchg\/status\/807626710350839808\">Guillermo Rauch CEO of Vercel quote<\/a>: Write tests. Not too many. Mostly integration.<\/figcaption><\/figure>\n<p>Later the creator of the Testing-Library <a href=\"https:\/\/kentcdodds.com\/\">Kent C. Dodds<\/a> responded to this quote and referenced this tweet in several discussions about testing frontend applications.<\/p>\n<p>Kent C Dodds a thought leader in testing afterward changed the testing pyramid construct and created the testing trophy. He shifted the testing principle towards writing more integration tests and added a new layer. The static testing layer describes the usage of Linters (ESLint), Types (TypeScript, Flow), and auto code formatting tools (Prettier).<\/p>\n<figure id=\"attachment_30997\" aria-describedby=\"caption-attachment-30997\" style=\"width: 679px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-30997 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-trophy.jpeg\" alt=\"Testing Trophy introduced by Kent C Dodds\" width=\"679\" height=\"688\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-trophy.jpeg 679w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-trophy-296x300.jpeg 296w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-trophy-400x405.jpeg 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/testing-trophy-360x365.jpeg 360w\" sizes=\"auto, (max-width: 679px) 100vw, 679px\" \/><figcaption id=\"caption-attachment-30997\" class=\"wp-caption-text\"><a href=\"https:\/\/kentcdodds.com\/blog\/the-testing-trophy-and-testing-classifications\">Testing Trophy<\/a> introduced by Kent C Dodds<\/figcaption><\/figure>\n<h2><span class=\"ez-toc-section\" id=\"The-Testing-Trophy-and-the-focus-on-integration-tests\"><\/span>The Testing Trophy and the focus on integration tests<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>There are several reasons why the testing trophy strategy got more attraction and popularity<\/p>\n<ul>\n<li>Attempting to refactor a codebase with a lot of unit tests is difficult, especially when implementation details get tested.<\/li>\n<li>Unit tests in frontend applications where you mock out a component can lose a lot of confidence.<\/li>\n<\/ul>\n<p>In reality, a well-tested and healthy codebase has all types of tests and also the distribution depends highly on the current status of the project as well as on the things you want to have tested (not everything needs to be tested). In most cases, if you want to test a user-facing frontend application, I would argue that the relation the testing trophy provides is a good one and satisfies business as well as developer needs.<\/p>\n<p>So let me sum up the points and the core reasons why the testing pyramid switches towards integration and e2e testing:<\/p>\n<p><strong>Why testing pyramid has shifted<\/strong><\/p>\n<ul>\n<li>Writing integration and e2e test got easier (tooling got better) Cypress, Testing-Library.<\/li>\n<li>More confidence for e2e and integration tests than unit tests.<\/li>\n<li>Users will use the frontend and interact with the DOM, not the actual code.<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"Example-with-React\"><\/span>Example with React<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>What does that actually mean in a codebase and what do people talk about when mentioning the problem of testing implementation details?<\/p>\n<p>I want to show an oversimplified example of what I mean when we test implementation details instead of real code shipped to the user and show why integration tests can lead to more confidence while keeping to the principles mentioned by this quote.<\/p>\n<p>While it is generally a good approach to have tests with <span data-token-index=\"1\" data-reactroot=\"\">different granularity,<\/span> the main purpose of testing is to<span data-token-index=\"3\" data-reactroot=\"\"> have a healthy, fast and maintainable test suite<\/span> which gives you the maximum confidence that your <span data-token-index=\"5\" data-reactroot=\"\">application works as you have expected<\/span>.<\/p>\n<p>Let&#8217;s say we have the following util function which prefixes a price value with a currency symbol.<\/p>\n<pre class=\"\"><code class=\"language-tsx\">\/\/ utils.ts\r\n\r\n\/**\r\n * This function prefixes the specified amount with a currency.\r\n * @param amount the amount value\r\n * @param currency the currency label\r\n * @returns prefixed currency value\r\n *\/\r\nconst prefixAmountWithCurrency = (amount, currency = \"$\")  =&gt;; {\r\n     return `${currency} ${amount}`;\r\n};\r\n\r\nprefixAmountWithCurrency(10.05); \/\/ $ 10.05\r\n\r\nexport { prefixAmountWithCurrency };\r\n<\/code><\/pre>\n<p>We want to use our <code>prefixAmountWithCurrency<\/code> function to format values in our frontend application. We want to make sure that it works properly. So let&#8217;s set up a basic Create-React-APP (CRA) project using that function and write a unit test for it.<\/p>\n<p>You can check out the code in this <a href=\"https:\/\/codesandbox.io\/s\/modern-testing-rc8vl?file=\/src\/App.tsx\">sandbox<\/a> or set up the files using CRA following these commands:<\/p>\n<pre class=\"\"><code class=\"language-bash\">npx create-react-app currency-formatter --template typescript &amp;&amp; cd currency-formatter\r\n<\/code><\/pre>\n<p>We then create a utils file as well as a test file.<\/p>\n<pre class=\"\"><code class=\"language-bash\">touch utils.ts &amp;&amp; touch utils.test.ts\r\n<\/code><\/pre>\n<p>In our <code>App.tsx<\/code> file, we import our utils function and use it to format a price.<\/p>\n<pre class=\"lang:js decode:true\">\/\/ App.tsx\r\n\r\nimport \".\/styles.css\";\r\nimport { prefixAmountWithCurrency } from \".\/utils\";\r\n\r\nconst App = () =&gt; {\r\n  const price = prefixAmountWithCurrency(10.05, \"$\");\r\n  return (<\/pre>\n<div>Price: {price}<\/div>\n<p>); }; export default App;<\/p>\n<p>Let&#8217;s write a short unit test for our utils function and run the tests with<br \/>\n<code>npm run test<\/code><\/p>\n<pre class=\"lang:default decode:true \" title=\"Utils test file\">\/\/ utils.test.ts\r\nimport { prefixAmountWithCurrency } from \".\/utils\";\r\n\r\ntest(\"prefixes amount with $ sign\", () =&gt; {\r\n  expect(prefixAmountWithCurrency(10.05, \"$\")).toEqual(\"$ 10.05\");\r\n});<\/pre>\n<p>As we can see, our App renders the price correctly and our function works as expected.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"The-problem-False-confidence\"><\/span>The problem: False confidence<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Let&#8217;s assume that another engineer steps in and wants to modify the price because he thinks that the value should have a character in between or adds a space accidentally. That is totally normal and, as we are humans, things like that happen. So an engineer takes the simplest route and adds a symbol after the dollar sign.<\/p>\n<pre class=\"lang:js decode:true\">\/\/ App.ts\r\n\r\nimport \".\/styles.css\";\r\nimport { prefixAmountWithCurrency } from \".\/utils\";\r\n\r\nconst App = () =&gt; {\r\n  const price = prefixAmountWithCurrency(10.05, \"$ -\");\r\n  return (<\/pre>\n<div>Price: {price}&amp;<\/div>\n<p>); }; export default App;<\/p>\n<p><strong>My question is, does the application still work as expected?<\/strong><\/p>\n<p>Our unit test still works well but is this really what we expect? Maybe but maybe not. At least as an engineer I want to get notified that I potentially broke some code.<\/p>\n<p>I actually tested the <strong>implementation detail<\/strong> of the above util function but not the real code shipped to the user.<\/p>\n<p>What makes it worse, my test did not warn me about my potential breaking change. This is a really small example to visualize the main idea but you hopefully get the idea and see how this can affect a larger codebase.<\/p>\n<p>I do not want to neglect the necessity and potentials of unit tests but you have to be aware of such behavior.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Fix-the-problem-Lets-write-an-integration-test\"><\/span>Fix the problem: Let&#8217;s write an integration test<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>One possible solution to this problem is to write tests that interact more directly with what the end-user is seeing and give you therefore more confidence that your application works as expected. Let&#8217;s add a test that makes sure that the rendered output HTML is the same as the user sees it. You can write such tests with <a href=\"https:\/\/testing-library.com\/docs\/react-testing-library\/intro\/\">react-testing-library<\/a>. This utility library gives you a jQuery-like abstraction layer for writing user-centric tests.<\/p>\n<pre class=\"lang:js decode:true\">\/\/ app.test.ts\r\nimport App from \".\/App\"\r\nimport { render, screen } from \"@testing-library\/react\";\r\n\r\ntest(\"prefixes amount with $ sign\", () =&gt; {\r\n\trender()\r\n\texpect(screen.toHaveTextValue(\/price: $ 10.05\/i))\r\n});<\/pre>\n<p>As you see, we now use the <span data-token-index=\"1\" data-reactroot=\"\">render<\/span> function of the <span data-token-index=\"3\" data-reactroot=\"\">@testing-library\/react<\/span> package to evaluate what the end-user will see when the App gets rendered. You now should see that this test is failing since we are missing the space in our test. We can now either adjust our test or our code and do not have to worry about shipping unexpected features to our users.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Unit tests are still important and should not be neglected, but as I mentioned integration and e2e test got easier to write. Because of newer and better tools and abstraction, I would argue that writing more integration tests gives you more confidence while you can faster iterate and test out new ideas. The react testing library provides you with a solid abstraction you can think of jQuery but for testing. With a unified API using react testing library, you do not have to invent the wheel of testing and get implicitly a more accessible UI.<\/p>\n<p>&nbsp;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Resources-and-further-notes\"><\/span>Resources and further notes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/testing-library\/testing-playground\">Testing-Library<\/a><\/li>\n<li><a href=\"https:\/\/kentcdodds.com\/blog\/common-mistakes-with-react-testing-library\">Kent C Dodds common mistakes with react-testing library<\/a><\/li>\n<li><a href=\"https:\/\/martinfowler.com\/articles\/practical-test-pyramid.html\">Martin Fowler: Practical test pyramid<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Testing highly interactive web applications have evolved over the last decades. Some years ago, testing frontend code integrated with a browser environment was a big pain point. Nowadays, new utilities and libraries exist, best practices have been established and have evolved.<\/p>\n","protected":false},"author":53,"featured_media":31728,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[377,69,54,70],"service":[444],"coauthors":[{"id":53,"display_name":"Jacob Cofman","user_nicename":"jcofman"}],"class_list":["post-30902","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-development","tag-digital-quality","tag-test","tag-web","service-frontend"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Testing Frontend Code in 2021 - inovex GmbH<\/title>\n<meta name=\"description\" content=\"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Testing Frontend Code in 2021 - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-20T06:32:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-11-22T09:14:31+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png\" \/>\n\t<meta property=\"og:image:width\" content=\"960\" \/>\n\t<meta property=\"og:image:height\" content=\"540\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Jacob Cofman\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png\" \/>\n<meta name=\"twitter:creator\" content=\"@jcofman\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jacob Cofman\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Jacob Cofman\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/\"},\"author\":{\"name\":\"Jacob Cofman\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/de25acdc07388388456ed0d03c8ade4d\"},\"headline\":\"Testing Frontend Code in 2021\",\"datePublished\":\"2021-09-20T06:32:56+00:00\",\"dateModified\":\"2022-11-22T09:14:31+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/\"},\"wordCount\":2091,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/testing-modern-frontend-code.png\",\"keywords\":[\"Development\",\"Digital Quality\",\"Test\",\"Web\"],\"articleSection\":[\"Applications\",\"English Content\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/\",\"name\":\"Testing Frontend Code in 2021 - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/testing-modern-frontend-code.png\",\"datePublished\":\"2021-09-20T06:32:56+00:00\",\"dateModified\":\"2022-11-22T09:14:31+00:00\",\"description\":\"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/testing-modern-frontend-code.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/testing-modern-frontend-code.png\",\"width\":960,\"height\":540,\"caption\":\"Illustration: Testing Modern Frontend Code by looking at every HTML element. Elements are hovering in a 3-dimensional space.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/testing-frontend-code-in-2021\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Testing Frontend Code in 2021\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/inovexde\",\"https:\\\/\\\/x.com\\\/inovexgmbh\",\"https:\\\/\\\/www.instagram.com\\\/inovexlife\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/inovex\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/de25acdc07388388456ed0d03c8ade4d\",\"name\":\"Jacob Cofman\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/jcofman_LThumb-96x79.jpge956e2771ef89c1ff0e79954c0d9e8c1\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/jcofman_LThumb-96x79.jpg\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2016\\\/07\\\/jcofman_LThumb-96x79.jpg\",\"caption\":\"Jacob Cofman\"},\"description\":\"Mein Name ist Jacob Cofman und ich bin Frontend-Entwickler bei inovex und liebe es, spannende Ideen in innovative Produkte zu verwandeln.\",\"sameAs\":[\"https:\\\/\\\/jcofman.de\",\"https:\\\/\\\/x.com\\\/jcofman\"],\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/author\\\/jcofman\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Testing Frontend Code in 2021 - inovex GmbH","description":"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/","og_locale":"de_DE","og_type":"article","og_title":"Testing Frontend Code in 2021 - inovex GmbH","og_description":"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.","og_url":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2021-09-20T06:32:56+00:00","article_modified_time":"2022-11-22T09:14:31+00:00","og_image":[{"width":960,"height":540,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","type":"image\/png"}],"author":"Jacob Cofman","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","twitter_creator":"@jcofman","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Jacob Cofman","Gesch\u00e4tzte Lesezeit":"11\u00a0Minuten","Written by":"Jacob Cofman"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/"},"author":{"name":"Jacob Cofman","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/de25acdc07388388456ed0d03c8ade4d"},"headline":"Testing Frontend Code in 2021","datePublished":"2021-09-20T06:32:56+00:00","dateModified":"2022-11-22T09:14:31+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/"},"wordCount":2091,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","keywords":["Development","Digital Quality","Test","Web"],"articleSection":["Applications","English Content","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/","url":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/","name":"Testing Frontend Code in 2021 - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","datePublished":"2021-09-20T06:32:56+00:00","dateModified":"2022-11-22T09:14:31+00:00","description":"This blog post covers some historical aspects of testing with a focus on frontend applications and discusses best practices of the industry.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/testing-modern-frontend-code.png","width":960,"height":540,"caption":"Illustration: Testing Modern Frontend Code by looking at every HTML element. Elements are hovering in a 3-dimensional space."},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/testing-frontend-code-in-2021\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Testing Frontend Code in 2021"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/de25acdc07388388456ed0d03c8ade4d","name":"Jacob Cofman","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/07\/jcofman_LThumb-96x79.jpge956e2771ef89c1ff0e79954c0d9e8c1","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/07\/jcofman_LThumb-96x79.jpg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/07\/jcofman_LThumb-96x79.jpg","caption":"Jacob Cofman"},"description":"Mein Name ist Jacob Cofman und ich bin Frontend-Entwickler bei inovex und liebe es, spannende Ideen in innovative Produkte zu verwandeln.","sameAs":["https:\/\/jcofman.de","https:\/\/x.com\/jcofman"],"url":"https:\/\/www.inovex.de\/de\/blog\/author\/jcofman\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/30902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=30902"}],"version-history":[{"count":6,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/30902\/revisions"}],"predecessor-version":[{"id":37032,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/30902\/revisions\/37032"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/31728"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=30902"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=30902"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=30902"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=30902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}