{"id":5934,"date":"2023-06-12T12:45:07","date_gmt":"2023-06-12T10:45:07","guid":{"rendered":"https:\/\/www.luklagroup.com\/uncategorized\/architecture-micro-frontends-communication-and-test-strategy\/"},"modified":"2025-02-06T17:10:58","modified_gmt":"2025-02-06T16:10:58","slug":"architecture-micro-frontends-communication-and-test-strategy","status":"publish","type":"post","link":"https:\/\/www.luklagroup.com\/en\/change-adopt-en\/architecture-micro-frontends-communication-and-test-strategy\/","title":{"rendered":"Architecture micro frontends &#8211; Communication and test strategy"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In a <a href=\"https:\/\/digiwin.fr\/actualites\/architecture-micro-frontends\/\">previous article<\/a>, we introduced the micro frontend architecture. If you&#8217;re not familiar with this type of architecture, I strongly recommend that you start by reading this one. In this article, we&#8217;ll look at several design points related to this type of architecture, including communication between micro frontends and test strategy.    <\/p>\n\n<h2 class=\"wp-block-heading\">Communication between micro frontends<\/h2>\n\n<p class=\"wp-block-paragraph\">The aim of micro front-end architecture is to decouple the different parts of an application as much as possible. But most of the time, certain parts need to interact with each other. They need to be able to communicate.  <\/p>\n\n<p class=\"wp-block-paragraph\">How can this be done, when each micro-frontend is potentially realized in a different technology?<\/p>\n\n<p class=\"wp-block-paragraph\">To do this, you can simply use url parameters, with all the limitations that implies. But there are other, more practical solutions, which we&#8217;ll look at below. <\/p>\n\n<h3 class=\"wp-block-heading\">Attributes + Properties<\/h3>\n\n<p class=\"wp-block-paragraph\">In the particular case of Web Components, data with attributes can be passed directly via the HTML code.<\/p>\n\n<pre class=\"wp-block-code\"><code>&lt;product-details product-id=\"1234567890\"&gt;&lt;\/product-details&gt;<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">The example uses a <code>properties<\/code> javascript product identifier to display product details.<\/p>\n\n<pre class=\"wp-block-code\"><code>const monWebComponent = document.getElementById(\"mon-web-component\")\n \nmonWebComponent.produit = {\n   id: \"1234567890\",\n   name: \"Mon produit\",\n   price: 30.5\n}\n<\/code><\/pre>\n\n<h4 class=\"wp-block-heading\">Benefits<\/h4>\n\n<p class=\"wp-block-paragraph\">The <code>attributes<\/code> approach is similar to the transfer of data from parent to child component in current SPA frameworks. So it&#8217;s an intuitive way for front-end developers. <\/p>\n\n<p class=\"wp-block-paragraph\">In the case of the <code>properties<\/code> approach, some libraries even simplify their use by passing data &#8211; even complex data &#8211; as <code>attributes<\/code>.<\/p>\n\n<h4 class=\"wp-block-heading\">Disadvantages<\/h4>\n\n<p class=\"wp-block-paragraph\">The data format passed to <code>attributes<\/code> remains rather limited, as it only accepts data in the form of character strings.<\/p>\n\n<p class=\"wp-block-paragraph\">This data is directly visible in the code, so don&#8217;t use it for sensitive data!<\/p>\n\n<h3 class=\"wp-block-heading\">Dom \/ Custom Events<\/h3>\n\n<p class=\"wp-block-paragraph\">In particular, the DOM is made up of an interface orchestrating the events that take place within the page, whether caused by the user (mouse click, key pressed, for example), or by other elements (paused video\/audio, for example).<\/p>\n\n<p class=\"wp-block-paragraph\">These events can be created and used to pass data via the <code>window<\/code> element.<\/p>\n\n<p class=\"wp-block-paragraph\">There are two main principles:<\/p>\n\n<ul class=\"wp-block-list\"><li>window.postMessage()<\/li><li>Custom Events.<\/li><\/ul>\n\n<pre class=\"wp-block-code\"><code>\/* emitter.js *\/\nconst message = {\n type: \"important\",\n content: \"Ce message est important\",\n};\n\n\/\/ DOM Event\nwindow.postMessage(message, \"https:\/\/url-destinataire.fr\");\n\n\/\/ Custom Event\nconst event = new CustomEvent(\"message.important\", {\n detail: message\n});\nwindow.dispatchEvent(event);\n\n\/* receiver.js *\/\nwindow.addEventListener(\"message.important\", handleMessage);\n \nfunction handleMessage(event) {\n   \/\/ la donn\u00e9e est accessible dans event.data ou event.detail\n}\n\n<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">It is preferable to use Custom Events instead of <code>window.postMessage(<\/code>) in all cases except for <code>iframe<\/code>, which can only be used with the latter method (due to their particular encapsulation).<\/p>\n\n<p class=\"wp-block-paragraph\">The <code>window.postMessage()<\/code> method can be called from and to any domain, so you need to be particularly careful when receiving it, for the sake of application security.<\/p>\n\n<h4 class=\"wp-block-heading\">Benefits<\/h4>\n\n<p class=\"wp-block-paragraph\">They are easy to use.<br\/>They ensure data reactivity between micro frontends on the same page.<\/p>\n\n<h4 class=\"wp-block-heading\">Disadvantages<\/h4>\n\n<p class=\"wp-block-paragraph\">Their use creates direct coupling between transmitting and receiving applications, which is precisely what we want to avoid.<\/p>\n\n<p class=\"wp-block-paragraph\">Managing the various events can quickly become complex, depending on their number.<\/p>\n\n<h3 class=\"wp-block-heading\">State Management<\/h3>\n\n<p class=\"wp-block-paragraph\">The component approach provided by frameworks such as React or Vue leads to parent-child dependencies for data passing.<\/p>\n\n<p class=\"wp-block-paragraph\">To avoid this complexity, Redux (for React), Vuex (for Vue) and NGRX (for Angular) state management solutions enable all components to have the same level of access and write access to the application&#8217;s shared data, made independent of the components.<\/p>\n\n<p class=\"wp-block-paragraph\">We can apply this concept to several micro frontends: one solution is to attach our read (selectors\/getters) and modify (actions) methods to the window.<\/p>\n\n<h4 class=\"wp-block-heading\">Benefits  <\/h4>\n\n<p class=\"wp-block-paragraph\">Shared data is available anywhere in the application, and independent of any micro frontends.<\/p>\n\n<p class=\"wp-block-paragraph\">It persists regardless of the life cycles of micro frontends.<\/p>\n\n<p class=\"wp-block-paragraph\">Using Vuex, Redux or Ngrx, you can keep your data up to date reactively.<\/p>\n\n<h4 class=\"wp-block-heading\">Disadvantages<\/h4>\n\n<p class=\"wp-block-paragraph\">However, this solution (via window) remains <strong>dangerous <\/strong>: anyone can access this element via the <strong>browser console<\/strong> and thus have read <strong>and write<\/strong> access to all common data.<\/p>\n\n<h3 class=\"wp-block-heading\">Session Storage \/ Local Storage \/ Cookies<\/h3>\n\n<p class=\"wp-block-paragraph\">Data communication within a micro-frontend architecture can also involve browser data storage solutions. Here are the 3 main ones: <\/p>\n\n<ul class=\"wp-block-list\"><li><code>sessionStorage<\/code>  stored data can only be accessed <strong>within a tab<\/strong>. It does not survive when the tab is closed. <\/li><li><code>localStorage<\/code>  stored data is shared by <strong>all<\/strong> browser <strong>tabs<\/strong> originating from the same source. It survives browser and system restarts. <\/li><li><code>cookies<\/code>  The stored data can be accessed by <strong>all<\/strong> browser <strong>tabs<\/strong> originating from the same source. The lifetime can be adjusted as required. <\/li><\/ul>\n\n<h4 class=\"wp-block-heading\">Benefits  <\/h4>\n\n<p class=\"wp-block-paragraph\">Like state management, the main advantage of these methods is that they provide read and write access to global data at any point in the application, and are totally independent of page changes.<\/p>\n\n<h4 class=\"wp-block-heading\">Disadvantages<\/h4>\n\n<p class=\"wp-block-paragraph\">The same disadvantages apply as before: this data can <strong>be accessed and modified by the user<\/strong> directly from the console, so beware of application security.<\/p>\n\n<p class=\"wp-block-paragraph\">Stored objects are in <strong>string<\/strong> format only.<\/p>\n\n<p class=\"wp-block-paragraph\">This data is &#8220;rigid&#8221;: a modification will not lead to a dynamic update in applications, but only to a refresh or page change.<br\/>The volume of data on <code>localStorage<\/code> is limited per application, depending on the browser. The same applies to cookies, where the limit is even lower. <\/p>\n\n<h2 class=\"wp-block-heading\">Communicating with an API<\/h2>\n\n<p class=\"wp-block-paragraph\">If we have separate teams working independently on each micro frontend, what about backend development?<\/p>\n\n<p class=\"wp-block-paragraph\">The advantage of full-stack teams is that they own the development of their application, from visual code to API development, and so on.<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>The model to be applied is the <a href=\"https:\/\/samnewman.io\/patterns\/architectural\/bff\/\" rel=\"nofollow\">BFF<\/a> pattern: Backend For Frontend.<\/strong><\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Each front-end application has a dedicated backend whose purpose is to meet the needs of that front-end only<\/strong> (originally this model was intended to have a backend for mobile, one for desktop, etc.).<\/p>\n\n<p class=\"wp-block-paragraph\">The BFF can be autonomous, with its own business logic and database, or it can be a service aggregator.<\/p>\n\n<p class=\"wp-block-paragraph\">The idea here is that <strong>the team building a micro frontend shouldn&#8217;t have to wait for other teams to build things for them<\/strong> (i.e. wait for a web service to be developed by the backend team and, in the meantime, use mocked-up data which, in the end, may not correspond exactly to the data issued by the service).<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>So, if every new feature added to a micro-interface also requires back-end modifications, it&#8217;s a solid case for a BFF, belonging to the same team.<\/strong><\/p>\n\n<p class=\"wp-block-paragraph\">On the other hand, if the micro frontend has only one API with which it exchanges, and this API is fairly stable, there may not be much point in creating a BFF.<\/p>\n\n<figure class=\"wp-block-image size-medium is-style-default\"><img decoding=\"async\" src=\"https:\/\/digiwin.fr\/wp-content\/uploads\/2023\/06\/image-900x410.png\" alt=\"Illustration of the Backend For Frontend pattern within a micro frontend architecture\" class=\"wp-image-4625\"\/><figcaption>The Backend For Frontend pattern<\/figcaption><\/figure>\n\n<p class=\"wp-block-paragraph\"><em>How should a user of a micro frontends application be authenticated and authorized with the server?<\/em><\/p>\n\n<p class=\"wp-block-paragraph\">Users should only have to authenticate once. As a result, authentication must belong to the container application. <\/p>\n\n<p class=\"wp-block-paragraph\">The container app probably has some kind of login form, through which we obtain an access token. This token should then belong to the container and could be injected into each micro frontend when it is initialized. <\/p>\n\n<p class=\"wp-block-paragraph\">Finally, the micro frontend can send the token with any request it sends to the server, and the server can perform the required validations.<\/p>\n\n<h2 class=\"wp-block-heading\">Test strategy<\/h2>\n\n<p class=\"wp-block-paragraph\">The micro-frontend architecture model creates technical complexity.<br\/>Technical complexity requires a solid harness of automated tests, without which our superb architecture risks being a fiasco.<\/p>\n\n<p class=\"wp-block-paragraph\">As a reminder, automated testing is mainly broken down into unit, integration and end-to-end tests (see OCTO article: <a href=\"https:\/\/blog.octo.com\/la-pyramide-des-tests-par-la-pratique-1-5\/\">The testing pyramid in practice<\/a>). <\/p>\n\n<ul class=\"wp-block-list\"><li>Unit tests verify the behavior of a portion of code, totally or partially isolated from its dependencies.<\/li><li>Integration tests verify that several components work together.<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\"><strong>As each micro frontend is an independent application, it must have its own unit and integration tests<\/strong>.<\/p>\n\n<p class=\"wp-block-paragraph\">In addition to these tests, we can add <a href=\"https:\/\/blog.octo.com\/la-pyramide-des-tests-par-la-pratique-4-5\/\">contract tests<\/a>, halfway between unitary and integration tests, independent of the micro frontends, which ensure that inter-application communication is operational by checking that interfaces are respected when data is sent and received.<br\/>So, if there is a breaking change, we know which micro frontend is responsible. Finally, end-to-end testing is used to check that a user journey is running smoothly from start to finish. <\/p>\n\n<p class=\"wp-block-paragraph\">It&#8217;s these tests that will ensure that the micro frontends work together coherently and that the application is usable.<\/p>\n\n<p class=\"wp-block-paragraph\">These tests take longer to run: the less interaction there is between the micro frontends, the more succinct the tests will be, and therefore faster to execute.<\/p>\n\n<p class=\"wp-block-paragraph\">However, a change to a micro frontend leads to a change in the overall application: our application&#8217;s CI must run end-to-end tests every time, and once again it&#8217;s in our interest to make the micro frontends as independent as possible.<\/p>\n\n<p class=\"wp-block-paragraph\">N.B.: the <a href=\"https:\/\/www.cypress.io\/\">Cypress<\/a> end-to-end testing framework has the advantage of being able to bypass Shadow encapsulation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a previous article, we introduced the micro frontend architecture. If you&#8217;re not familiar with this type of architecture, I strongly recommend that you start by reading this one. In this article, we&#8217;ll look at several design points related to this type of architecture, including communication between micro frontends and test strategy. Communication between micro [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":5468,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","footnotes":""},"categories":[109,105,115],"tags":[],"class_list":["post-5934","post","type-post","status-publish","format-standard","has-post-thumbnail","category-apps-data-en","category-change-adopt-en","category-web-marketing-en"],"_links":{"self":[{"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/posts\/5934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/comments?post=5934"}],"version-history":[{"count":2,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/posts\/5934\/revisions"}],"predecessor-version":[{"id":5936,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/posts\/5934\/revisions\/5936"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/media\/5468"}],"wp:attachment":[{"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/media?parent=5934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/categories?post=5934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.luklagroup.com\/en\/wp-json\/wp\/v2\/tags?post=5934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}