{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Esteban Hern\u00e1ndez","description":"The latest articles on DEV Community by Esteban Hern\u00e1ndez (@lysofdev).","link":"https:\/\/dev.to\/lysofdev","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F99912%2F5d66fca5-1503-432d-ad77-2cc88f01f8ae.jpg","title":"DEV Community: Esteban Hern\u00e1ndez","link":"https:\/\/dev.to\/lysofdev"},"language":"en","item":[{"title":"Gibson - An English-2-Shell CLI demo with OpenAI","pubDate":"Fri, 20 Jan 2023 21:39:58 +0000","link":"https:\/\/dev.to\/lysofdev\/gibson-an-english-2-shell-cli-demo-with-openai-2g17","guid":"https:\/\/dev.to\/lysofdev\/gibson-an-english-2-shell-cli-demo-with-openai-2g17","description":"<p>Shell commands are esoteric. Most commands were invented decades ago and it almost feels like a language only the nerdiest of hackers are fluent in. I always end up googling reference materials even for the most basic of shell commands.<\/p>\n\n<p>That changes today. The future is now. What a time to be alive.<\/p>\n\n<p>Let's build a REPL CLI tool using Python that receives our intent in plain English and employs the OpenAI API to translate that into a <br>\nShell command which is then executed as part of the Python process.<\/p>\n<h2>\n  \n  \n  Abbreviations\n<\/h2>\n\n<ul>\n<li>REPL - Read-Evaluate-Print Loop<\/li>\n<li>CLI - Command Line Interface<\/li>\n<li>API - Application Programming Interface<\/li>\n<\/ul>\n<h2>\n  \n  \n  OpenAI API Requirements\n<\/h2>\n\n<p>OpenAI requires an account and payment method with a minimum of $10 to use their API. However, new users receive a $10 credit upon sign up and the cost is based on the amount of tokens in the prompt and completion, and the model used. <a href=\"https:\/\/openai.com\/api\/pricing\/\" rel=\"noopener noreferrer\">See here for additional billing information<\/a>.<\/p>\n\n<p>Setup your Personal account and copy your API key somewhere safe. Remember not to commit your API key to any public code repository (or any repository for that matter) as someone could use it to steal your credits and run up your bill. <strong>Keep your API key secret.<\/strong><\/p>\n<h2>\n  \n  \n  OpenAI Python Library\n<\/h2>\n\n<p>Create a development directory and name it <strong>gibson<\/strong> in honor of the writer William Gibson who pioneered the AI and Cyberpunk Science Fiction subgenres. Install the <strong>openai<\/strong> package and create a text file named <strong>gibson.py<\/strong>.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">mkdir <\/span>gibson\n<span class=\"nb\">cd <\/span>gibson\npip <span class=\"nb\">install<\/span> <span class=\"nt\">--upgrade<\/span> openai\n<span class=\"nb\">touch <\/span>gibson.py\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Gibson REPL CLI\n<\/h2>\n\n<p>Add the following to <strong>gibson.py<\/strong> and replace the placeholder <code>OPENAI_API_KEY<\/code> with the API key from the previous steps. Change the <strong>OS<\/strong> variable to reflect whatever operating system the script will be executing the commands on.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"c1\">#! \/c\/Python310\/python\n<\/span><span class=\"kn\">import<\/span> <span class=\"n\">os<\/span>\n<span class=\"kn\">import<\/span> <span class=\"n\">openai<\/span>\n\n<span class=\"c1\"># Set your OS to get the correct Shell commands. Windows, Mac, Linx, etc.\n<\/span><span class=\"n\">OS<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">Windows<\/span><span class=\"sh\">'<\/span>\n\n<span class=\"c1\"># Set the OpenAI API Key\n<\/span><span class=\"n\">openai<\/span><span class=\"p\">.<\/span><span class=\"n\">api_key<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">OPENAI_API_KEY<\/span><span class=\"sh\">'<\/span>\n\n<span class=\"c1\"># Keep prompting for more input.\n<\/span><span class=\"k\">while<\/span> <span class=\"bp\">True<\/span><span class=\"p\">:<\/span>\n    <span class=\"c1\"># Capture the user's intent in plain English\n<\/span>    <span class=\"n\">intent<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">input<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">$ <\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"c1\"># Exit the Python process if the user types 'exit'\n<\/span>    <span class=\"k\">if<\/span> <span class=\"n\">intent<\/span> <span class=\"o\">==<\/span> <span class=\"sh\">'<\/span><span class=\"s\">exit<\/span><span class=\"sh\">'<\/span><span class=\"p\">:<\/span>\n        <span class=\"nf\">exit<\/span><span class=\"p\">()<\/span>\n    <span class=\"c1\"># Interpolate the user's intent and OS into the OpenAI prompt.\n<\/span>    <span class=\"n\">prompt<\/span> <span class=\"o\">=<\/span> <span class=\"sa\">f<\/span><span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n        Translate this English statement to a Shell command for the OS.\n        OS: <\/span><span class=\"si\">{<\/span><span class=\"n\">OS<\/span><span class=\"si\">}<\/span><span class=\"s\">\n        English: <\/span><span class=\"si\">{<\/span><span class=\"n\">intent<\/span><span class=\"si\">}<\/span><span class=\"s\">\n        Shell:\n    <\/span><span class=\"sh\">\"\"\"<\/span>\n    <span class=\"c1\"># Fetch the prompt completion using the OpenAI library.\n<\/span>    <span class=\"n\">completion<\/span> <span class=\"o\">=<\/span> <span class=\"n\">openai<\/span><span class=\"p\">.<\/span><span class=\"n\">Completion<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">prompt<\/span><span class=\"o\">=<\/span><span class=\"n\">prompt<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">(),<\/span> <span class=\"c1\"># Always remove surrounding whitespace for performance reasons on OpenAI.\n<\/span>        <span class=\"n\">engine<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">text-davinci-003<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"c1\"># The OpenAI model.\n<\/span>        <span class=\"n\">temperature<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"c1\"># How \"creative\". Lower means less creative.\n<\/span>        <span class=\"n\">max_tokens<\/span><span class=\"o\">=<\/span><span class=\"mi\">256<\/span> <span class=\"c1\"># Max of 256 tokens including prompt and completion.\n<\/span>    <span class=\"p\">)<\/span>\n    <span class=\"c1\"># Execute the completion text as a Shell statement\n<\/span>    <span class=\"n\">os<\/span><span class=\"p\">.<\/span><span class=\"nf\">system<\/span><span class=\"p\">(<\/span><span class=\"n\">completion<\/span><span class=\"p\">.<\/span><span class=\"n\">choices<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"n\">text<\/span><span class=\"p\">.<\/span><span class=\"nf\">strip<\/span><span class=\"p\">())<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The OpenAI Create Completion request will take the full <strong>prompt<\/strong> as an argument along with the name of the <strong>model<\/strong> to process it with. Use the OpenAI playground to try out the different models. The \"dumber\" the model, the cheaper it is to use. The <em>davincii<\/em> model is the most \"intelligent\" model at this time so it is also the most expensive but will give us the best results. It's great for creating proofs of concept and demos but you'll want to fine-tune a new model for a specific use-case in a production environment. The <em>ada<\/em> model is the cheapest and might be able to solve your use-case for a much lower price and faster execution time. <\/p>\n\n<p>The <strong>temperature<\/strong> value refers to what <em>sampling temperature<\/em> to use. Higher values means the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer. In this case, a low <strong>temperature<\/strong> is best since the completion is expected to be constant given the same prompt.<\/p>\n\n<p>The <strong>max_tokens<\/strong> value sets a limit on the prompt and completion size. You can think of tokens as words but more complex words may have multiple tokens. This can help with rate limiting but also runs the risk that the completion will be missing text if the prompt takes up too many tokens. <a href=\"https:\/\/help.openai.com\/en\/articles\/4936856-what-are-tokens-and-how-to-count-them\" rel=\"noopener noreferrer\">See this article for more detail on how to count tokens<\/a>. In this case, 256 is more than enough.<\/p>\n\n<h2>\n  \n  \n  Limitations\n<\/h2>\n\n<ol>\n<li>Security\nExecuting commands without reviewing them is reckless so this script should never be run with Administrator privileges. Further, the AI can make mistakes and provide an incorrect command so be careful when deleting or making destructive actions.<\/li>\n<li>Error Handling\nThe script doesn't check if the command succeeded or not. In the case of an error, the message will be printed to screen and the script will prompt for a new input. This is a great opportunity to use OpenAI to translate the Shell error text to plain English so as to provide us with a better understanding of what went wrong.<\/li>\n<\/ol>\n\n","category":["openai","cli","ai","shell"]},{"title":"Spring Boot: Conditional Caching in 6 lines of code.","pubDate":"Sun, 22 Nov 2020 18:07:02 +0000","link":"https:\/\/dev.to\/lysofdev\/spring-boot-conditional-caching-in-6-lines-of-code-2f5h","guid":"https:\/\/dev.to\/lysofdev\/spring-boot-conditional-caching-in-6-lines-of-code-2f5h","description":"<p>The Spring Boot framework includes a simple, server-side caching solution which is easy to enable and see immediate results and even easier to extend using robust caching solutions all through an Annotation based interface that makes it all feel like configuration rather than implementation.<\/p>\n\n<p>When you work with different sources of data, your cache control rules may vary and conditions may need to be evaluated before performing caching operations. With this requirement, we risk polluting our business code with caching logic. Spring Boot's <a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/current\/javadoc-api\/org\/springframework\/cache\/annotation\/Cacheable.html\"><code>@Cacheable<\/code><\/a> interface handles this elegantly by employing Java Annotations and the <a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/3.0.x\/reference\/expressions.html\">Spring Expression Language (SpEL)<\/a>.<\/p>\n\n<h1>\n  \n  \n  Use Case\n<\/h1>\n\n<p>The Demo application serves as Backend-For-Frontend service for Typicode's <a href=\"https:\/\/jsonplaceholder.typicode.com\/\">JSONPlaceholder<\/a> which serves RESTful JSON samples which can then be used for demos and tests concerning external APIs.<\/p>\n\n<p>For the sake of this tutorial, the JSONPlaceholder API has a significant network latency of 3 seconds in every call to read collections and records. We could cache every single endpoint but the stakeholders have stated an additional requirement. We can only cache the <code>\/users\/<\/code>, <code>\/albums<\/code> and <code>\/photos<\/code> endpoints. All the others endpoints contain data that cannot be cached for reasons. The Front-End team will implement a loading screen for those endpoints instead.<\/p>\n\n<h1>\n  \n  \n  Starter Template\n<\/h1>\n\n<p>To setup the demo, clone the <a href=\"https:\/\/github.com\/LySofDev\/java-spring-conditional-caching-demo.git\">Github repo<\/a> and checkout the 1.0 tag as a new branch.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nv\">$ <\/span>git clone https:\/\/github.com\/LySofDev\/java-spring-conditional-caching-demo.git <span class=\"nb\">.<\/span>\n\n<span class=\"nv\">$ <\/span><span class=\"nb\">cd <\/span>java-spring-conditional-caching-demo\n\n<span class=\"nv\">$ <\/span>git checkout tags\/1.0 <span class=\"nt\">-b<\/span> demo\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h1>\n  \n  \n  Implementation Details\n<\/h1>\n\n<p>The <code>PlaceholderController<\/code> will pass along the arguments from the request URL and the application configuration to the <code>JSONPlaceholder<\/code> service which will perform the REST call to the JSONPlaceholder API.<\/p>\n\n<p><code>src\/main\/java\/com\/example\/conditionalcachingdemo\/controllers\/PlaceholderController.java<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight java\"><code><span class=\"nd\">@GetMapping<\/span><span class=\"o\">(<\/span><span class=\"s\">\"\/{name}\"<\/span><span class=\"o\">)<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONArray<\/span> <span class=\"nf\">getCollection<\/span><span class=\"o\">(<\/span><span class=\"nd\">@PathVariable<\/span> <span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">placeholderService<\/span><span class=\"o\">.<\/span><span class=\"na\">getCollection<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">);<\/span>\n<span class=\"o\">}<\/span>\n\n<span class=\"nd\">@GetMapping<\/span><span class=\"o\">(<\/span><span class=\"s\">\"\/{name}\/{id}\"<\/span><span class=\"o\">)<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONObject<\/span> <span class=\"nf\">getRecord<\/span><span class=\"o\">(<\/span><span class=\"nd\">@PathVariable<\/span> <span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"nd\">@PathVariable<\/span> <span class=\"kt\">int<\/span> <span class=\"n\">id<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">placeholderService<\/span><span class=\"o\">.<\/span><span class=\"na\">getRecord<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"n\">id<\/span><span class=\"o\">);<\/span>\n<span class=\"o\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>src\/main\/java\/com\/example\/conditionalcachingdemo\/services\/PlaceholderServiceImpl.java<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight java\"><code><span class=\"nd\">@Override<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONArray<\/span> <span class=\"nf\">getCollection<\/span><span class=\"o\">(<\/span><span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">try<\/span> <span class=\"o\">{<\/span>\n        <span class=\"nc\">JSONArray<\/span> <span class=\"n\">collection<\/span> <span class=\"o\">=<\/span> <span class=\"n\">restTemplate<\/span><span class=\"o\">.<\/span><span class=\"na\">getForObject<\/span><span class=\"o\">(<\/span><span class=\"n\">collectionUrl<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">),<\/span> <span class=\"nc\">JSONArray<\/span><span class=\"o\">.<\/span><span class=\"na\">class<\/span><span class=\"o\">);<\/span>\n        <span class=\"nc\">Thread<\/span><span class=\"o\">.<\/span><span class=\"na\">sleep<\/span><span class=\"o\">(<\/span><span class=\"mi\">3000<\/span><span class=\"o\">);<\/span> <span class=\"c1\">\/\/ Simulating a slow network.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">collection<\/span><span class=\"o\">;<\/span>\n    <span class=\"o\">}<\/span> <span class=\"k\">catch<\/span> <span class=\"o\">(<\/span><span class=\"nc\">HttpClientErrorException<\/span><span class=\"o\">.<\/span><span class=\"na\">NotFound<\/span> <span class=\"o\">|<\/span> <span class=\"nc\">InterruptedException<\/span> <span class=\"n\">e<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n        <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"nf\">CollectionNotFoundException<\/span><span class=\"o\">();<\/span>\n    <span class=\"o\">}<\/span>\n<span class=\"o\">}<\/span>\n\n<span class=\"nd\">@Override<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONObject<\/span> <span class=\"nf\">getRecord<\/span><span class=\"o\">(<\/span><span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"kt\">int<\/span> <span class=\"n\">id<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">try<\/span> <span class=\"o\">{<\/span>\n        <span class=\"nc\">JSONObject<\/span> <span class=\"n\">record<\/span> <span class=\"o\">=<\/span> <span class=\"n\">restTemplate<\/span><span class=\"o\">.<\/span><span class=\"na\">getForObject<\/span><span class=\"o\">(<\/span><span class=\"n\">recordUrl<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"n\">id<\/span><span class=\"o\">),<\/span> <span class=\"nc\">JSONObject<\/span><span class=\"o\">.<\/span><span class=\"na\">class<\/span><span class=\"o\">);<\/span>\n        <span class=\"nc\">Thread<\/span><span class=\"o\">.<\/span><span class=\"na\">sleep<\/span><span class=\"o\">(<\/span><span class=\"mi\">3000<\/span><span class=\"o\">);<\/span> <span class=\"c1\">\/\/ Simulating a slow network.<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">record<\/span><span class=\"o\">;<\/span>\n    <span class=\"o\">}<\/span> <span class=\"k\">catch<\/span> <span class=\"o\">(<\/span><span class=\"nc\">HttpClientErrorException<\/span><span class=\"o\">.<\/span><span class=\"na\">NotFound<\/span> <span class=\"o\">|<\/span> <span class=\"nc\">InterruptedException<\/span> <span class=\"n\">e<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n        <span class=\"k\">throw<\/span> <span class=\"k\">new<\/span> <span class=\"nf\">RecordNotFoundException<\/span><span class=\"o\">();<\/span>\n    <span class=\"o\">}<\/span>\n<span class=\"o\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>These two code excerpts cover the meat of the application. Everything else in the repository is built to provide this functionality to the end user. Feel free to take a moment to look at the rest of the repo as most files are brief.<\/p>\n\n<p>To simulate the JSONPlaceholder API's network latency, we'll include a 3 second wait period in our code after fetching data from the API.<\/p>\n\n<h1>\n  \n  \n  Enabling the Cache\n<\/h1>\n\n<p><code>src\/main\/java\/com\/example\/conditionalcachingdemo\/ConditionalCachingDemoApplication.java<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight java\"><code><span class=\"nd\">@SpringBootApplication<\/span>\n<span class=\"nd\">@EnableCaching<\/span>\n<span class=\"kd\">public<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">ConditionalCachingDemoApplication<\/span> <span class=\"o\">{<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The implementation of the cache is based on the <code>CacheManager<\/code> interface. The Spring framework includes a simple implementation which stores cache data in memory. This is fine for development but, in production, we'll want to use an external caching solution like Redis or Cassandra. Replacing the default implementation is as simple as providing an alternative implementation of the <code>CacheManager<\/code> interface.<\/p>\n\n<h1>\n  \n  \n  Cache Configuration\n<\/h1>\n\n<p>We'll update the application configuration to include a list of the cacheable endpoints.<\/p>\n\n<p><code>src\/main\/resources\/application.properties<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight java\"><code><span class=\"n\">api<\/span><span class=\"o\">.<\/span><span class=\"na\">url<\/span><span class=\"o\">=<\/span><span class=\"nl\">https:<\/span><span class=\"c1\">\/\/jsonplaceholder.typicode.com\/<\/span>\n<span class=\"n\">api<\/span><span class=\"o\">.<\/span><span class=\"na\">cacheables<\/span><span class=\"o\">=<\/span><span class=\"n\">users<\/span><span class=\"o\">,<\/span><span class=\"n\">albums<\/span><span class=\"o\">,<\/span><span class=\"n\">photos<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Then, we'll add the <code>@Cacheable<\/code> annotations to the <code>PlaceholderController<\/code> and update the method signatures to include the <code>api.cacheables<\/code> configuration values.<\/p>\n\n<p><code>src\/main\/java\/com\/example\/conditionalcachingdemo\/controllers\/PlaceholderController.java<\/code><br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight java\"><code><span class=\"nd\">@GetMapping<\/span><span class=\"o\">(<\/span><span class=\"s\">\"\/{name}\"<\/span><span class=\"o\">)<\/span>\n<span class=\"nd\">@Cacheable<\/span><span class=\"o\">(<\/span><span class=\"n\">value<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"collections\"<\/span><span class=\"o\">,<\/span> <span class=\"n\">condition<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"#cacheables.contains(#name)\"<\/span><span class=\"o\">)<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONArray<\/span> <span class=\"nf\">getCollection<\/span><span class=\"o\">(<\/span><span class=\"nd\">@PathVariable<\/span> <span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"nd\">@Value<\/span><span class=\"o\">(<\/span><span class=\"s\">\"${api.cacheables}\"<\/span><span class=\"o\">)<\/span> <span class=\"nc\">List<\/span><span class=\"o\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">cacheables<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">placeholderService<\/span><span class=\"o\">.<\/span><span class=\"na\">getCollection<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">);<\/span>\n<span class=\"o\">}<\/span>\n\n<span class=\"nd\">@GetMapping<\/span><span class=\"o\">(<\/span><span class=\"s\">\"\/{name}\/{id}\"<\/span><span class=\"o\">)<\/span>\n<span class=\"nd\">@Cacheable<\/span><span class=\"o\">(<\/span><span class=\"n\">value<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"records\"<\/span><span class=\"o\">,<\/span> <span class=\"n\">key<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"#name + #id\"<\/span><span class=\"o\">,<\/span> <span class=\"n\">condition<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"#cacheables.contains(#name)\"<\/span><span class=\"o\">)<\/span>\n<span class=\"kd\">public<\/span> <span class=\"nc\">JSONObject<\/span> <span class=\"nf\">getRecord<\/span><span class=\"o\">(<\/span><span class=\"nd\">@PathVariable<\/span> <span class=\"nc\">String<\/span> <span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"nd\">@PathVariable<\/span> <span class=\"kt\">int<\/span> <span class=\"n\">id<\/span><span class=\"o\">,<\/span> <span class=\"nd\">@Value<\/span><span class=\"o\">(<\/span><span class=\"s\">\"${api.cacheables}\"<\/span><span class=\"o\">)<\/span> <span class=\"nc\">List<\/span><span class=\"o\">&lt;<\/span><span class=\"nc\">String<\/span><span class=\"o\">&gt;<\/span> <span class=\"n\">cacheables<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">placeholderService<\/span><span class=\"o\">.<\/span><span class=\"na\">getRecord<\/span><span class=\"o\">(<\/span><span class=\"n\">name<\/span><span class=\"o\">,<\/span> <span class=\"n\">id<\/span><span class=\"o\">);<\/span>\n<span class=\"o\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That's it. Run the Spring Boot application and hit the cacheable endpoints. The first time we hit an endpoint, it will take 3 seconds to respond since the cache hasn't yet been hydrated. Once the data from JSONPlaceholder is loaded into the cache, subsequent requests to the endpoint will be served almost immediately since the data is coming from memory and not the network.<\/p>\n\n<h1>\n  \n  \n  Solution Analysis\n<\/h1>\n\n<p>The <code>@Cacheable<\/code> annotation includes two arguments in the <code>getCollection<\/code> method. The <code>value<\/code> argument indicates the cache name for the collection. This allows us to set different configurations per cache such as expiry times, etc. The <code>condition<\/code> argument validates that the <code>name<\/code> of the endpoint provided in the URL is included in the <code>api.cacheables<\/code> configuration.<\/p>\n\n<p>You might be wondering why we include the <code>cacheables<\/code> value in the controller method signature instead of making it part of the class itself. The SpEL only interacts with the variables that are declared static but the <code>@Value<\/code> annotation can only be applied on an instance variable or a method parameter. Therefore, to provide the configuration values <code>api.cacheables<\/code> to the <code>@Cacheable<\/code> <code>condition<\/code>, we'll include them as part of the method signature <code>List&lt;String&gt; cacheables<\/code> and let the <code>@Value<\/code> annotation fill the values in during runtime.<\/p>\n\n<p>In the <code>getRecord<\/code> method, we also use the <code>key<\/code> argument to add a mapping expression <code>#name + #id<\/code> to generate the key for this record in cache from the collection name and record id. In the <code>getCollections<\/code> method, the key will default to the value of the <code>name<\/code> variable.<\/p>\n\n<h1>\n  \n  \n  Conclusion\n<\/h1>\n\n<p>The Spring Boot application now satisfies the caching requirement and can be pushed to a UAT environment for demonstration to the stakeholders while the underlying caching solution for the production environment is developed.<\/p>\n\n","category":["java","spring","rest","web"]},{"title":"Unreliable API? Not a problem with Angular and RxJs","pubDate":"Sat, 20 Jun 2020 18:42:31 +0000","link":"https:\/\/dev.to\/lysofdev\/unreliable-api-not-a-problem-with-angular-and-rxjs-1b1d","guid":"https:\/\/dev.to\/lysofdev\/unreliable-api-not-a-problem-with-angular-and-rxjs-1b1d","description":"<p>I was tasked with integrating a really old, internal API which had a particular quirk. This API seemed to fail, at random. After asking around, it seemed that handling random errors was going to be a part of this task.<\/p>\n\n<p>We spent some time testing the API by sending the same exact request multiple times until we could reliably predict the failure rate. Our most conservative estimate was that the API would fail for no apparent reason at least one out of every ten requests.<\/p>\n\n<p>We decided that the simplest solution was to retry the request up to three times if we encountered an Internal Server Error. Any request which failed more than three times would be considered invalid, and the app would rely on the user to fix the request by altering their inputs.<\/p>\n\n<p>The app had to query a few different endpoints from the unreliable API so our solution had to work on every request. We chose to house the solution in an interceptor as this is Angular's way of modifying HTTP requests\/responses for the app as a whole.<\/p>\n\n<h1>\n  \n  \n  Setup\n<\/h1>\n\n<p>I've created a demo application with a mock server that emulates the failure rate of the unreliable API we integrated. The repository also has a Cypress e2e specification which tests the app agains the mock server. Below the environment setup steps:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>git clone https:\/\/github.com\/LySofDev\/retry-on-internal-server-error-demo.git demo\n<span class=\"nb\">cd <\/span>demo\nnpm i\n<span class=\"nb\">cd<\/span> .\/server\nnpm i\n<span class=\"nb\">cd<\/span> ..\nnpm run dev\n<\/code><\/pre><\/div>\n\n\n\n<p>You should now have the Angular application listening on port 4200, the Cypress test runner open and displaying two spec files, and the mock server listening on port 3000. I recommend using the Cypress test runner to experiment with the application since we have to fill in a form for each request.<\/p>\n\n<h1>\n  \n  \n  Integration Test Failures\n<\/h1>\n\n<p>Run the <code>internal_server_error_spec<\/code> in Cypress to see the app interacting with the server without the random error handler. We should see at least one or two test runs failing.<\/p>\n\n<p>We can manipulate the failure rate of the server in the <code>server\/src\/index.ts<\/code> file by changing the value of the <code>RANDOM_INTERNAL_SERVER_ERROR_CHANCE<\/code> variable. See the inline documentation for details on how this affects the rate of failure.<\/p>\n\n<h1>\n  \n  \n  Unit Test Failures\n<\/h1>\n\n<p>Let's add a specification file for the interceptor that we'll be developing. Create a file <code>src\/app\/retry-on-internal-server-error.interceptor.ts<\/code> and add the following boilerplate code.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">HttpInterceptor<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpRequest<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpHandler<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpEvent<\/span>\n<span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/common\/http<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Observable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span> <span class=\"k\">implements<\/span> <span class=\"nx\">HttpInterceptor<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">intercept<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">request<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpRequest<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">any<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">next<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpHandler<\/span>\n  <span class=\"p\">):<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">HttpEvent<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">any<\/span><span class=\"o\">&gt;&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">next<\/span><span class=\"p\">.<\/span><span class=\"nx\">handle<\/span><span class=\"p\">(<\/span><span class=\"nx\">request<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>The above implementation essentially does nothing. It receives every request returns the observable result of the request being called with the handler. That is the minimum definition of the Angular interceptor so we are all set. Let's add it to our <code>src\/app\/app.module.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">BrowserModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/platform-browser<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NgModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">HttpClientModule<\/span><span class=\"p\">,<\/span> <span class=\"nx\">HTTP_INTERCEPTORS<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/common\/http<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AppComponent<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/app.component<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">BrowserAnimationsModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/platform-browser\/animations<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatToolbarModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/toolbar<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatFormFieldModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/form-field<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatInputModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/input<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">ReactiveFormsModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/forms<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatButtonModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/button<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatCardModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/card<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatProgressSpinnerModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/progress-spinner<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">MatSnackBarModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/material\/snack-bar<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/retry-on-internal-server-errror.interceptor<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">NgModule<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">declarations<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">AppComponent<\/span><span class=\"p\">],<\/span>\n  <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nx\">BrowserModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">BrowserAnimationsModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatToolbarModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatFormFieldModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatInputModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">ReactiveFormsModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatButtonModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatCardModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatProgressSpinnerModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">MatSnackBarModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">HttpClientModule<\/span><span class=\"p\">,<\/span>\n  <span class=\"p\">],<\/span>\n  <span class=\"na\">providers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"na\">provide<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HTTP_INTERCEPTORS<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">useClass<\/span><span class=\"p\">:<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">multi<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">],<\/span>\n  <span class=\"na\">bootstrap<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">AppComponent<\/span><span class=\"p\">],<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">AppModule<\/span> <span class=\"p\">{}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>The new interceptor is now part of the stack of HTTP interceptors that every request\/response will go through. Given the amazing developers that we are, we're going to go ahead and add a spec file with some tests for our interceptor. Create a file <code>src\/app\/retry-on-internal-server-error.interceptor.spec.ts<\/code> and add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">HttpClientTestingModule<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">TestRequest<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/common\/http\/testing<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">HttpClient<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HTTP_INTERCEPTORS<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpErrorResponse<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/common\/http<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Observable<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Subject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">TestBed<\/span><span class=\"p\">,<\/span> <span class=\"k\">async<\/span><span class=\"p\">,<\/span> <span class=\"nx\">fakeAsync<\/span><span class=\"p\">,<\/span> <span class=\"nx\">inject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core\/testing<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/retry-on-internal-server-error.interceptor<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"kd\">class<\/span> <span class=\"nx\">MockService<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"k\">private<\/span> <span class=\"nx\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpClient<\/span><span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n  <span class=\"nx\">mockRequest<\/span><span class=\"p\">():<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">any<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">RetryOnInternalServerErrorInterceptor<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">let<\/span> <span class=\"na\">testRequest<\/span><span class=\"p\">:<\/span> <span class=\"nx\">TestRequest<\/span><span class=\"p\">;<\/span>\n  <span class=\"kd\">let<\/span> <span class=\"na\">testNext<\/span><span class=\"p\">:<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">Mock<\/span><span class=\"p\">;<\/span>\n  <span class=\"kd\">let<\/span> <span class=\"na\">testError<\/span><span class=\"p\">:<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">Mock<\/span><span class=\"p\">;<\/span>\n  <span class=\"kd\">let<\/span> <span class=\"na\">testComplete<\/span><span class=\"p\">:<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">Mock<\/span><span class=\"p\">;<\/span>\n\n  <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"k\">async<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">testNext<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">fn<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">testError<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">fn<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">testComplete<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">jest<\/span><span class=\"p\">.<\/span><span class=\"nx\">fn<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">TestBed<\/span><span class=\"p\">.<\/span><span class=\"nx\">configureTestingModule<\/span><span class=\"p\">({<\/span>\n      <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">HttpClientTestingModule<\/span><span class=\"p\">],<\/span>\n      <span class=\"na\">providers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n        <span class=\"p\">{<\/span>\n          <span class=\"na\">provide<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HTTP_INTERCEPTORS<\/span><span class=\"p\">,<\/span>\n          <span class=\"na\">useClass<\/span><span class=\"p\">:<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span><span class=\"p\">,<\/span>\n          <span class=\"na\">multi<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span><span class=\"p\">,<\/span>\n        <span class=\"p\">},<\/span>\n        <span class=\"nx\">MockService<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">],<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">}));<\/span>\n\n  <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">[<\/span><span class=\"nx\">MockService<\/span><span class=\"p\">,<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n    <span class=\"p\">(<\/span><span class=\"na\">mockService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">MockService<\/span><span class=\"p\">,<\/span> <span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">mockService<\/span><span class=\"p\">.<\/span><span class=\"nx\">mockRequest<\/span><span class=\"p\">().<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">({<\/span>\n        <span class=\"na\">next<\/span><span class=\"p\">:<\/span> <span class=\"nx\">testNext<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">error<\/span><span class=\"p\">:<\/span> <span class=\"nx\">testError<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">complete<\/span><span class=\"p\">:<\/span> <span class=\"nx\">testComplete<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">});<\/span>\n      <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">));<\/span>\n\n  <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when receiving a 200 response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">beforeEach<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">flush<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">forwards the response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">completes<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt throw an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">});<\/span>\n\n  <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when receiving a 400 response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">beforeEach<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Bad Request<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n        <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">400<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Bad Request<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt forward any response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt complete<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">throws an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">});<\/span>\n\n  <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when receiving a 401 response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">beforeEach<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Unauthorized<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n        <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">401<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Unauthorized<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt forward any response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt complete<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">throws an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">});<\/span>\n\n  <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when receiving a 500 error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">beforeEach<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n        <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">500<\/span><span class=\"p\">,<\/span>\n        <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">retries the request<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n      <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n      <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">));<\/span>\n\n    <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the retry succeeds<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n        <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n        <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n          <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">flush<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">));<\/span>\n\n      <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">forwards the response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n      <span class=\"p\">});<\/span>\n\n      <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">completes<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n      <span class=\"p\">});<\/span>\n\n      <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt throw an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the retry fails<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n        <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n        <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n          <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n            <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">500<\/span><span class=\"p\">,<\/span>\n            <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n          <span class=\"p\">});<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">));<\/span>\n\n      <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">retries the request again<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n        <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n        <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">));<\/span>\n\n      <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the second retry succeeds<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n          <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n          <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n            <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">flush<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n          <span class=\"p\">}<\/span>\n        <span class=\"p\">));<\/span>\n\n        <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">forwards the response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">});<\/span>\n\n        <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">completes<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n        <span class=\"p\">});<\/span>\n\n        <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt throw an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n        <span class=\"p\">});<\/span>\n      <span class=\"p\">});<\/span>\n\n      <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the second retry fails<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n          <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n          <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n            <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n              <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">500<\/span><span class=\"p\">,<\/span>\n              <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n            <span class=\"p\">});<\/span>\n          <span class=\"p\">}<\/span>\n        <span class=\"p\">));<\/span>\n\n        <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">retries the request again<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n          <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n          <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n          <span class=\"p\">}<\/span>\n        <span class=\"p\">));<\/span>\n\n        <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the third retry succeeds<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n            <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n            <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n              <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n              <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">flush<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n            <span class=\"p\">}<\/span>\n          <span class=\"p\">));<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">forwards the response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n          <span class=\"p\">});<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">completes<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n          <span class=\"p\">});<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt throw an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n          <span class=\"p\">});<\/span>\n        <span class=\"p\">});<\/span>\n\n        <span class=\"nx\">describe<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">when the third retry fails<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span><span class=\"nx\">inject<\/span><span class=\"p\">(<\/span>\n            <span class=\"p\">[<\/span><span class=\"nx\">HttpTestingController<\/span><span class=\"p\">],<\/span>\n            <span class=\"p\">(<\/span><span class=\"na\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpTestingController<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n              <span class=\"nx\">testRequest<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"nx\">expectOne<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">\/mock<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n              <span class=\"nx\">testRequest<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"k\">new<\/span> <span class=\"nx\">ErrorEvent<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">),<\/span> <span class=\"p\">{<\/span>\n                <span class=\"na\">status<\/span><span class=\"p\">:<\/span> <span class=\"mi\">500<\/span><span class=\"p\">,<\/span>\n                <span class=\"na\">statusText<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Internal Server Error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n              <span class=\"p\">});<\/span>\n            <span class=\"p\">}<\/span>\n          <span class=\"p\">));<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt forward any response<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testNext<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n          <span class=\"p\">});<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">doesnt complete<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testComplete<\/span><span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n          <span class=\"p\">});<\/span>\n\n          <span class=\"nx\">it<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">throws an error<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span><span class=\"nx\">testError<\/span><span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n          <span class=\"p\">});<\/span>\n        <span class=\"p\">});<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">});<\/span>\n<span class=\"p\">});<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Take a moment to run the above spec file with the following command:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>npm run <span class=\"nb\">test<\/span> <span class=\"nt\">--<\/span> retry-on-internal-server-error.interceptor\n<\/code><\/pre><\/div>\n\n\n\n<p>The first few tests should pass as we don't want to modify the behavior of the request\/response chain if the error is not an Internal Server Error. The only failures we should see are with the last few tests focused on the 500 error codes.<\/p>\n\n<p>Our test will attempt to make several requests which will be mocked with responses containing a 500 error code. We will test that the interceptor retries the request up to three times before passing the failure on down the request\/response chain.<\/p>\n\n<h1>\n  \n  \n  Solution\n<\/h1>\n\n<p>Let's just look at the solution since it's only a few lines of code.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">HttpInterceptor<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpRequest<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpHandler<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpEvent<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">HttpErrorResponse<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/common\/http<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Observable<\/span><span class=\"p\">,<\/span> <span class=\"k\">of<\/span><span class=\"p\">,<\/span> <span class=\"nx\">throwError<\/span><span class=\"p\">,<\/span> <span class=\"nx\">isObservable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">catchError<\/span><span class=\"p\">,<\/span> <span class=\"nx\">flatMap<\/span><span class=\"p\">,<\/span> <span class=\"nx\">retry<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs\/operators<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Inject<\/span><span class=\"p\">,<\/span> <span class=\"nx\">InjectionToken<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"cm\">\/**\n * Upper limit of retry attempts for a request with an Internal Server Error response.\n *\/<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">INTERNAL_SERVER_ERROR_RETRY_LIMIT<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">InjectionToken<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">number<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span>\n  <span class=\"dl\">'<\/span><span class=\"s1\">INTERNAL_SERVER_ERROR_RETRY_LIMIT<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"p\">{<\/span> <span class=\"na\">factory<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"mi\">3<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">);<\/span>\n<span class=\"cm\">\/**\n * Retries a request up to [INTERNAL_SERVER_ERROR_RETRY_LIMIT] times\n * if the response contained an Internal Server Error with status code 500.\n * Otherwise, it forwards the response.\n *\/<\/span>\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">RetryOnInternalServerErrorInterceptor<\/span> <span class=\"k\">implements<\/span> <span class=\"nx\">HttpInterceptor<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">@<\/span><span class=\"nd\">Inject<\/span><span class=\"p\">(<\/span><span class=\"nx\">INTERNAL_SERVER_ERROR_RETRY_LIMIT<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">private<\/span> <span class=\"k\">readonly<\/span> <span class=\"nx\">retryLimit<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span>\n  <span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n  <span class=\"nx\">intercept<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">request<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpRequest<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">any<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">next<\/span><span class=\"p\">:<\/span> <span class=\"nx\">HttpHandler<\/span>\n  <span class=\"p\">):<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">HttpEvent<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">any<\/span><span class=\"o\">&gt;&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">next<\/span><span class=\"p\">.<\/span><span class=\"nx\">handle<\/span><span class=\"p\">(<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span>\n      <span class=\"nx\">catchError<\/span><span class=\"p\">((<\/span><span class=\"na\">error<\/span><span class=\"p\">:<\/span> <span class=\"kr\">any<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">error$<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">throwError<\/span><span class=\"p\">(<\/span><span class=\"nx\">error<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">error<\/span> <span class=\"k\">instanceof<\/span> <span class=\"nx\">HttpErrorResponse<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">error<\/span><span class=\"p\">.<\/span><span class=\"nx\">status<\/span> <span class=\"o\">===<\/span> <span class=\"mi\">500<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">return<\/span> <span class=\"nx\">error$<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">}<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">of<\/span><span class=\"p\">(<\/span><span class=\"nx\">error$<\/span><span class=\"p\">);<\/span>\n      <span class=\"p\">}),<\/span>\n      <span class=\"nx\">retry<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">retryLimit<\/span><span class=\"p\">),<\/span>\n      <span class=\"nx\">flatMap<\/span><span class=\"p\">((<\/span><span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"kr\">any<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span><span class=\"nx\">isObservable<\/span><span class=\"p\">(<\/span><span class=\"nx\">value<\/span><span class=\"p\">)<\/span> <span class=\"p\">?<\/span> <span class=\"nx\">value<\/span> <span class=\"p\">:<\/span> <span class=\"k\">of<\/span><span class=\"p\">(<\/span><span class=\"nx\">value<\/span><span class=\"p\">)))<\/span>\n    <span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Let's break it down. We added a dependency to our interceptor with the token <code>INTERNAL_SERVER_ERROR_RETRY_LIMIT<\/code> which will be the number of times we want to retry any particular request. This dependency will automatically be resolved to three, as per our earlier specification. But we can change it to another number in the <code>app.module.ts<\/code> if we find that three isn't quite the perfect value.<\/p>\n\n<p>Next, the actual interceptor. We immediately pass the request to the handler so that it can be transacted over the network. We'll use a pipe to listen for the response notifications. Here's where it gets a bit complicated but bare with me.<\/p>\n\n<p>If the response is emitted in the form of an error notification, the <code>catchError<\/code> operator will receive the notification. Within the operator's projection function, we identify whether the error is an HTTP Error and not some other runtime error, and we validate that the status code is in fact 500. We also wrap the error in a new observable which will immediately emit the error again. Why? Hold on.<\/p>\n\n<p>If the previously mentioned conditions are true, then the <code>catchError<\/code> operator will emit the error notification containing the 500 error. This will trigger the next operator in the pipe, the <code>retry<\/code> operator. The <code>retry<\/code> operator is very simple, given an error notification, it will resubscribe to the source up to N times. In our case, N will be the <code>retryLimit<\/code>. So, there's the retry mechanic in action but we have to take a few extra steps to prevent other errors from being retried. After all, we're only interested in retrying Internal Server Errors.<\/p>\n\n<p>With that in mind, if the error notification is not an Internal Server Error, we will wrap the error in a <code>throwError<\/code> observable and then an <code>of<\/code> observable. Essentially, it's an error notification inside an error observable inside a normal, high-order observable. Wait, wait, for what?<\/p>\n\n<p>This is how we skip the <code>retry<\/code> operator with the other error notifications. The high-order observable containing the error observable, will be ignored by the <code>retry<\/code> operator. It will then activate the <code>flatMap<\/code> operator whose projector function will receive the error observable and verify that it is, in fact, an observable, and not a scalar notification. It will then flatten the observable into the top-level observable stream. What is it flattening? Well, the error observable, which will cause the error to flow down the stream to the observers, as we would expect.<\/p>\n\n<p>Ok, but what about normal notifications which just need to go through? Simple, the <code>flatMap<\/code> operator will also pass these on by flattening them into the top-level observable stream as well.<\/p>\n\n<h1>\n  \n  \n  Conclusion\n<\/h1>\n\n<p>So, that's it. Some might say that <code>retryWhen<\/code> is a better operator for this case but I couldn't quite get it to work the same way. Not with the same level of simplicity, at least.<\/p>\n\n<p>These Observables may seem complicated at first but think about all that we achieved in some fairly concise code. Could we really achieve the same result without taking advantage of RxJs?<\/p>\n\n","category":["javascript","angular","rxjs","typescript"]},{"title":"Angular - NGRX-Data - AG Grid - Pt. 1","pubDate":"Tue, 24 Dec 2019 20:45:07 +0000","link":"https:\/\/dev.to\/lysofdev\/angular-ngrx-data-ag-grid-pt-1-1djc","guid":"https:\/\/dev.to\/lysofdev\/angular-ngrx-data-ag-grid-pt-1-1djc","description":"<h2>\n  \n  \n  Introduction\n<\/h2>\n\n<p>I've been building a Dashboard-style monitoring application for a client for the last few weeks. The application requires CRUD functionality across a series of resources. Although there is a lot of shared functionality across these different resources, each one has a set of business rules when it comes to creating, updating and destroying these resources. When starting out, I had to select a few libraries that would help me avoid having to write all of the common CRUD functionality while allowing me to easily insert the business logic at any point.<\/p>\n\n<p>After some research, I settled on NGRX-Data for state management and AG Grid for the resource views. You might've heard some criticism around NGRX on how much boilerplate it requires but I want to clarify that NGRX Data is an additional layer of abstraction on top of the basic NGRX Store library which helps the developer avoid the common boilerplate code. In fact, I found myself writting very little code beyond configuration to get the majority of the necessary functionality going.<\/p>\n\n<p>As for the UI, I chose AG Grid since it comes with tons of functionality out of the box and is very easy to extend. It comes with sensible defaults while also offering tons of extension points. I have yet to find any significant limitation on this library and I definetly recommend it's use for an application requiring anything beyond a trivial data table.<\/p>\n\n<p>Finally, we'll be leveraging the Angular 2+ web application framework and the RxJs library. Be sure to understand both of these tools to follow along although this post will be more focused on NGRX Data and AG Grid.<\/p>\n\n<h2>\n  \n  \n  Demo Data\n<\/h2>\n\n<p>I'll be using data from <a href=\"https:\/\/jsonplaceholder.typicode.com\/\">JSON Placeholder<\/a> which is a free-to-use, mock API. It doesn't belong to me so much gratitude to <a href=\"https:\/\/github.com\/typicode\">Typicode<\/a> for making this awesome tool available.<\/p>\n\n<h2>\n  \n  \n  Installation\n<\/h2>\n\n<h3>\n  \n  \n  Creating an Angular project\n<\/h3>\n\n<p>Let's get our application setup. First, start a new Angular 2+ project. If you don't already have the <code>@angular\/cli<\/code> installed, run the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>npm i <span class=\"nt\">-g<\/span> @angular\/cli\n<\/code><\/pre><\/div>\n\n\n\n<p>Be sure to include routing and SCSS in the Angular application prompts.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>ng new ngrx-data-ag-grid-demo\n<span class=\"nb\">cd <\/span>ngrx-data-ag-grid-demo\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Install AG Grid:\n<\/h3>\n\n\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>npm <span class=\"nb\">install<\/span> <span class=\"nt\">--save<\/span> ag-grid-community ag-grid-angular\n<\/code><\/pre><\/div>\n\n\n\n<p>We need to add some styles for AG Grid to our <code>styles.scss<\/code> file.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight scss\"><code><span class=\"k\">@import<\/span> <span class=\"s2\">\"~ag-grid-community\/dist\/styles\/ag-grid.css\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">@import<\/span> <span class=\"s2\">\"~ag-grid-community\/dist\/styles\/ag-theme-balham.css\"<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Install NGRX Data\n<\/h3>\n\n\n\n<div class=\"highlight\"><pre class=\"highlight shell\"><code>npm i <span class=\"nt\">--save<\/span> @ngrx\/data @ngrx\/store @ngrx\/entity @ngrx\/effects\n<\/code><\/pre><\/div>\n\n\n\n<p>NGRX Data still requires NGRX Store, Effects and Entities. It does however add a lot of the functionality for CRUD actions freeing up developers to focus on the business domain. Create an <code>app-store.module.ts<\/code> file and add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NgModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">CommonModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/common<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">StoreModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@ngrx\/store<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">EffectsModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@ngrx\/effects<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">EntityDataModule<\/span><span class=\"p\">,<\/span> <span class=\"nx\">DefaultDataServiceConfig<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@ngrx\/data<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PostCollectionService<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts\/post-collection.service<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">fromPosts<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">NGRX_STORE_CONFIGURATION<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{};<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">REGISTERED_EFFECTS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">ENTITY_METADATA<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{};<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">ENTITY_PLURAL_NAMES<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{};<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">NGRX_DATA_SERVICE_CONFIGURATION<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{};<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">NgModule<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nx\">CommonModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">StoreModule<\/span><span class=\"p\">.<\/span><span class=\"nx\">forRoot<\/span><span class=\"p\">(<\/span><span class=\"nx\">NGRX_STORE_CONFIGURATION<\/span><span class=\"p\">),<\/span>\n    <span class=\"nx\">EffectsModule<\/span><span class=\"p\">.<\/span><span class=\"nx\">forRoot<\/span><span class=\"p\">(<\/span><span class=\"nx\">REGISTERED_EFFECTS<\/span><span class=\"p\">),<\/span>\n    <span class=\"nx\">EntityDataModule<\/span><span class=\"p\">.<\/span><span class=\"nx\">forRoot<\/span><span class=\"p\">({<\/span>\n      <span class=\"na\">entityMetadata<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ENTITY_METADATA<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">pluralNames<\/span><span class=\"p\">:<\/span> <span class=\"nx\">ENTITY_PLURAL_NAMES<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">],<\/span>\n  <span class=\"na\">providers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"na\">provide<\/span><span class=\"p\">:<\/span> <span class=\"nx\">DefaultDataServiceConfig<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">useValue<\/span><span class=\"p\">:<\/span> <span class=\"nx\">NGRX_DATA_SERVICE_CONFIGURATION<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">PostCollectionService<\/span>\n  <span class=\"p\">]<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">AppStoreModule<\/span> <span class=\"p\">{}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Configuring the API endpoint\n<\/h3>\n\n<p>Configure the API address by providing a <code>DefaultDataServiceConfig<\/code> object. Add the following to <code>app-store.module.ts<\/code>:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"p\">...<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">NGRX_DATA_SERVICE_CONFIGURATION<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"na\">root<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">https:\/\/jsonplaceholder.typicode.com\/<\/span><span class=\"dl\">\"<\/span>\n<span class=\"p\">};<\/span>\n<span class=\"p\">...<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Add the Store to the App\n<\/h3>\n\n<p>Import the <code>AppStoreModule<\/code> within the <code>app.module.ts<\/code>:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">BrowserModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/platform-browser<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NgModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AppRoutingModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/app-routing.module<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AppStoreModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/app-store.module<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AppComponent<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/app.component<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">NgModule<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">declarations<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">AppComponent<\/span><span class=\"p\">],<\/span>\n  <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">BrowserModule<\/span><span class=\"p\">,<\/span> <span class=\"nx\">AppStoreModule<\/span><span class=\"p\">,<\/span> <span class=\"nx\">AppRoutingModule<\/span><span class=\"p\">],<\/span>\n  <span class=\"na\">providers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[],<\/span>\n  <span class=\"na\">bootstrap<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">AppComponent<\/span><span class=\"p\">]<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">AppModule<\/span> <span class=\"p\">{}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h2>\n  \n  \n  Configuring the first Entity Collection\n<\/h2>\n\n<p>NGRX Data is focused on entities which are just collections of JS objects. It'll handle the synchronization of a local cache and a remote endpoint by default with pessimistic strategies. It can however be configured to use optimistic strategies, multiple endpoints, etc. All defaults can be overriden.<\/p>\n\n<h3>\n  \n  \n  Define the Entity state and configuration\n<\/h3>\n\n<p>The first entity will be the <code>Post<\/code> entity. Start by creating a <code>posts<\/code> directory and a <code>state.ts<\/code> file and an <code>index.ts<\/code> file. Add the following to <code>state.ts<\/code>:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">entityCollectionName<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Post<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">pluralizedEntityName<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">posts<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">const<\/span> <span class=\"nx\">entityCollectionEndpoint<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">pluralizedEntityName<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kr\">interface<\/span> <span class=\"nx\">Post<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">id<\/span><span class=\"p\">:<\/span> <span class=\"nx\">number<\/span><span class=\"p\">;<\/span>\n  <span class=\"nl\">userId<\/span><span class=\"p\">:<\/span> <span class=\"nx\">number<\/span><span class=\"p\">;<\/span>\n  <span class=\"nl\">title<\/span><span class=\"p\">:<\/span> <span class=\"nx\">string<\/span><span class=\"p\">;<\/span>\n  <span class=\"nl\">body<\/span><span class=\"p\">:<\/span> <span class=\"nx\">string<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Export the Entity state and configuration\n<\/h3>\n\n<p>And, <code>index.ts<\/code>:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">export<\/span> <span class=\"o\">*<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/state<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Configure the Entity in the Store\n<\/h3>\n\n<p>The <code>app-store.module.ts<\/code> needs to be updated with the <code>Post<\/code> entity collection configuration:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"p\">...<\/span>\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">fromPosts<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/posts<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">...<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">ENTITY_METADATA<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"p\">[<\/span><span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">entityCollectionName<\/span><span class=\"p\">]:<\/span> <span class=\"p\">{}<\/span>\n<span class=\"p\">};<\/span>\n<span class=\"p\">...<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">ENTITY_PLURAL_NAMES<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n  <span class=\"p\">[<\/span><span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">entityCollectionName<\/span><span class=\"p\">]:<\/span> <span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">pluralizedEntityName<\/span>\n<span class=\"p\">};<\/span>\n<span class=\"p\">...<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>NGRX Data has a default pluralization feature based on the collection name but we found it to be very unreliable. We decided to always provide the pluralNames from configuration instead. This also makes mapping application routes to API calls more reliable.<\/p>\n\n<h3>\n  \n  \n  Creating the Entity Collection Service\n<\/h3>\n\n<p>NGRX Data provides the <code>EntityCollectionServiceBase<\/code> class which provides the high-level implementation for the observable state and actions of the Entity store. Each Entity will have a dedicated service that extends this class.<\/p>\n\n<p>Create a file within the <code>posts<\/code> directory named <code>post-collection.service.ts<\/code> and add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">EntityCollectionServiceBase<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@ngrx\/data<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">EntityCollectionServiceElementsFactory<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@ngrx\/data<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">fromPosts<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">PostCollectionService<\/span> <span class=\"kd\">extends<\/span> <span class=\"nx\">EntityCollectionServiceBase<\/span><span class=\"o\">&lt;<\/span>\n  <span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">Post<\/span>\n<span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">readonly<\/span> <span class=\"na\">elementsFactory<\/span><span class=\"p\">:<\/span> <span class=\"nx\">EntityCollectionServiceElementsFactory<\/span>\n  <span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">super<\/span><span class=\"p\">(<\/span><span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">entityCollectionName<\/span><span class=\"p\">,<\/span> <span class=\"nx\">elementsFactory<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h3>\n  \n  \n  Display the data with AG Grid\n<\/h3>\n\n<p>Create a directory within the <code>posts<\/code> directory named <code>posts-list<\/code> and add a <code>posts-list.component.ts<\/code> file. Add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Component<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">concat<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">startWith<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">FirstDataRenderedEvent<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">ag-grid-community<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PostCollectionService<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">..\/post-collection.service<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Component<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">selector<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">app-posts-list<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">template<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`\n    &lt;h1&gt;Posts&lt;\/h1&gt;\n    &lt;hr \/&gt;\n    &lt;ag-grid-angular\n      class=\"ag-theme-balham grid\"\n      [columnDefs]=\"columns\"\n      [rowData]=\"rows$ | async\"\n      [pagination]=\"true\"\n      [paginationAutoPageSize]=\"true\"\n      (firstDataRendered)=\"onFirstDataRendered($event)\"\n    &gt;&lt;\/ag-grid-angular&gt;\n  `<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">styles<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"s2\">`\n      :host {\n        display: flex;\n        flex-direction: column;\n        justify-content: center;\n        padding-left: 5vw;\n      }\n\n      .grid {\n        height: 80vh;\n        width: 90vw;\n      }\n    `<\/span>\n  <span class=\"p\">]<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">PostListComponent<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kr\">private<\/span> <span class=\"nx\">columnDefaults<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"na\">resizable<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">sortable<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">filter<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span>\n  <span class=\"p\">};<\/span>\n\n  <span class=\"nx\">readonly<\/span> <span class=\"nx\">columns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"p\">...<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">columnDefaults<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">headerName<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">ID<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">field<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">id<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">resizable<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"p\">...<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">columnDefaults<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">headerName<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Title<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">field<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">title<\/span><span class=\"dl\">\"<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"p\">{<\/span>\n      <span class=\"p\">...<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">columnDefaults<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">headerName<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Body<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n      <span class=\"na\">field<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">body<\/span><span class=\"dl\">\"<\/span>\n    <span class=\"p\">}<\/span>\n  <span class=\"p\">];<\/span>\n\n  <span class=\"nx\">readonly<\/span> <span class=\"nx\">rows$<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">concat<\/span><span class=\"p\">(<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">postCollectionService<\/span><span class=\"p\">.<\/span><span class=\"nx\">getAll<\/span><span class=\"p\">(),<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">postCollectionService<\/span><span class=\"p\">.<\/span><span class=\"nx\">entities$<\/span>\n  <span class=\"p\">).<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">startWith<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">));<\/span>\n\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kr\">private<\/span> <span class=\"nx\">postCollectionService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">PostCollectionService<\/span><span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n  <span class=\"nx\">onFirstDataRendered<\/span><span class=\"p\">({<\/span> <span class=\"nx\">columnApi<\/span> <span class=\"p\">}:<\/span> <span class=\"nx\">FirstDataRenderedEvent<\/span><span class=\"p\">):<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">columnApi<\/span><span class=\"p\">.<\/span><span class=\"nx\">autoSizeAllColumns<\/span><span class=\"p\">();<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h2>\n  \n  \n  Setup lazy loading for Feature modules\n<\/h2>\n\n<p>This is a great opportunity to setup lazy-loading of each feature module. We'll load the proper presentation components based on the current route.<\/p>\n\n<p>First, create a <code>posts-routing.module.ts<\/code> and add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NgModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">RouterModule<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Routes<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/router<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PostListComponent<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts-list\/posts-list.component<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">routes<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Routes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n  <span class=\"p\">{<\/span>\n    <span class=\"na\">path<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">component<\/span><span class=\"p\">:<\/span> <span class=\"nx\">PostListComponent<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">];<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">NgModule<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">RouterModule<\/span><span class=\"p\">.<\/span><span class=\"nx\">forChild<\/span><span class=\"p\">(<\/span><span class=\"nx\">routes<\/span><span class=\"p\">)],<\/span>\n  <span class=\"na\">exports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">RouterModule<\/span><span class=\"p\">]<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">PostsRoutingModule<\/span> <span class=\"p\">{}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Second, create a <code>posts.module.ts<\/code> and add the following:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NgModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">CommonModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/common<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AgGridModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">ag-grid-angular<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PostsRoutingModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts-routing.module<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PostListComponent<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts-list\/posts-list.component<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">AG_GRID_CUSTOM_COMPONENTS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">NgModule<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n    <span class=\"nx\">CommonModule<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">AgGridModule<\/span><span class=\"p\">.<\/span><span class=\"nx\">withComponents<\/span><span class=\"p\">(<\/span><span class=\"nx\">AG_GRID_CUSTOM_COMPONENTS<\/span><span class=\"p\">),<\/span>\n    <span class=\"nx\">PostsRoutingModule<\/span>\n  <span class=\"p\">],<\/span>\n  <span class=\"na\">declarations<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">PostListComponent<\/span><span class=\"p\">]<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">PostsModule<\/span> <span class=\"p\">{}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Next, add the router outlet to the <code>app.component.html<\/code> file:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight html\"><code><span class=\"nt\">&lt;router-outlet&gt;&lt;\/router-outlet&gt;<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Finally, add the first route to the <code>app-routing.module.ts<\/code>:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"p\">...<\/span>\n<span class=\"k\">import<\/span> <span class=\"o\">*<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">fromPosts<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/posts<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">...<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">routes<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Routes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n  <span class=\"p\">{<\/span>\n    <span class=\"na\">path<\/span><span class=\"p\">:<\/span> <span class=\"nx\">fromPosts<\/span><span class=\"p\">.<\/span><span class=\"nx\">entityCollectionEndpoint<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">loadChildren<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">import<\/span><span class=\"p\">(<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">.\/posts\/posts.module<\/span><span class=\"dl\">\"<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span><span class=\"nx\">m<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">m<\/span><span class=\"p\">.<\/span><span class=\"nx\">PostsModule<\/span><span class=\"p\">)<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">];<\/span>\n<span class=\"p\">...<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>We should now be able to navigate in our browser to <code>http:\/\/localhost:4200\/posts<\/code> and see a grid populated with data from JSONPlaceholder. Not bad for how little code we've had to write.<\/p>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>For Part 2, we'll be adding the <code>User<\/code> entity and interpolating the author's name into each of the <code>Post<\/code> entries in the AG Grid.<\/p>\n\n","category":["angular","ngrx","aggrid","javascript"]},{"title":"[Solved] ag-Grid: Looking for component [agSetColumnFilter] but it wasn't found.","pubDate":"Fri, 20 Dec 2019 16:08:51 +0000","link":"https:\/\/dev.to\/lysofdev\/solved-ag-grid-looking-for-component-agsetcolumnfilter-but-it-wasn-t-found-393n","guid":"https:\/\/dev.to\/lysofdev\/solved-ag-grid-looking-for-component-agsetcolumnfilter-but-it-wasn-t-found-393n","description":"<p>We use AgGrid extensively in our Dashboard-style web application to show the user large datasets. The community version of Ag Grid contains the majority of its popular features but we ended up buying the enterprise version for the Set Filter, among other reasons.<\/p>\n\n<p>However, when trying to use the Set Filter we ran into a confusing bug. Upon clicking on the filter button, we would be presented with the following error message in the console and no Set Filter to be found.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>userComponentRegistry.js:215 ag-Grid: Looking for component [agSetColumnFilter] but it wasn't found.\ncore.js:15724 ERROR TypeError: Cannot read property 'componentFromFramework' of null\n    at UserComponentFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/components\/framework\/userComponentFactory.js.UserComponentFactory.lookupComponentClassDef (userComponentFactory.js:283)\n    at UserComponentFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/components\/framework\/userComponentFactory.js.UserComponentFactory.createComponentInstance (userComponentFactory.js:343)\n    at UserComponentFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/components\/framework\/userComponentFactory.js.UserComponentFactory.createAndInitUserComponent (userComponentFactory.js:110)\n    at UserComponentFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/components\/framework\/userComponentFactory.js.UserComponentFactory.newFilterComponent (userComponentFactory.js:73)\n    at FilterManager.push..\/node_modules\/ag-grid-community\/dist\/lib\/filter\/filterManager.js.FilterManager.createFilterInstance (filterManager.js:421)\n    at FilterManager.push..\/node_modules\/ag-grid-community\/dist\/lib\/filter\/filterManager.js.FilterManager.createFilterWrapper (filterManager.js:453)\n    at FilterManager.push..\/node_modules\/ag-grid-community\/dist\/lib\/filter\/filterManager.js.FilterManager.getOrCreateFilterWrapper (filterManager.js:383)\n    at StandardMenuFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/headerRendering\/standardMenu.js.StandardMenuFactory.showPopup (standardMenu.js:54)\n    at StandardMenuFactory.push..\/node_modules\/ag-grid-community\/dist\/lib\/headerRendering\/standardMenu.js.StandardMenuFactory.showMenuAfterButtonClick (standardMenu.js:45)\n    at HeaderComp.push..\/node_modules\/ag-grid-community\/dist\/lib\/headerRendering\/header\/headerComp.js.HeaderComp.showMenu (headerComp.js:147)\n<\/code><\/pre><\/div>\n\n\n\n<p>We googled and googled and googled and googled but found no solution. There's a single question replicating this issue in Stack Overflow but the answer simply states that one should try using a custom filter instead. Wrong answer.<\/p>\n\n<p>After reading through the extensive Ag Grid documentation, we came upon a solution so simple we questioned whether we truly deserved to be called software developers. It turns out we had forgotten to import the Ag Grid Enterprise package into our project.<\/p>\n\n<p>To resolve the above error, simply add the following line to your <code>main.ts<\/code> file.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight javascript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">enableProdMode<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">platformBrowserDynamic<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/platform-browser-dynamic<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">ag-grid-enterprise<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ &lt;-- This will fix it.<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AppModule<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/app\/app.module<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">environment<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/environments\/environment<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">environment<\/span><span class=\"p\">.<\/span><span class=\"nx\">production<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">enableProdMode<\/span><span class=\"p\">();<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">platformBrowserDynamic<\/span><span class=\"p\">()<\/span>\n  <span class=\"p\">.<\/span><span class=\"nx\">bootstrapModule<\/span><span class=\"p\">(<\/span><span class=\"nx\">AppModule<\/span><span class=\"p\">)<\/span>\n  <span class=\"p\">.<\/span><span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">error<\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">));<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>I hope this post can save you the wasted hours we spent trying to figure out why the Set Filter was missing.<\/p>\n\n","category":["aggrid","angular","javascript"]},{"title":"NgNotes - Don't ever subscribe!","pubDate":"Wed, 04 Dec 2019 01:21:36 +0000","link":"https:\/\/dev.to\/lysofdev\/ngnotes-don-t-ever-subscribe-3iic","guid":"https:\/\/dev.to\/lysofdev\/ngnotes-don-t-ever-subscribe-3iic","description":"<h3>\n  \n  \n  Update\n<\/h3>\n\n<p>Shout out to Andrei Gatej for an additional improvement that I've added as a final iteration below.<\/p>\n\n\n\n\n<p>Let me start off by saying that there's always going to be exceptions and you should not refactor your current Angular source code. Rather take into consideration my notes and continue improving your style.<\/p>\n\n<p>Observables and Subscriptions are a big part of the Angular 2+ web framework. The theory behind it can be a bit confusing at first and many Angular developers avoid Observables unless absolutely necessary. In my own experience, I've encountered production code bases where Observables were avoided like the plague and badly coerced into behaving in incorrect ways. This lead to memory-intensive applications that ran like a turtle after eating at a buffet.<\/p>\n\n<p>Learning more about the RxJs API and Observables can lead to leaner applications that express and achieve a lot more in less code. Also, the Angular team recommends the <em>smart<\/em> use of Observables where possible.<\/p>\n\n<p>Rather than go into an abstract discussion about Observables and Streams and Functional Programming and all that jazz, I'm going to illustrate a common mistake made by many developers when starting out with RxJs and Angular 2+. The first example implements a naive implementation of a numeric counter.<\/p>\n\n<p>Below is a naive implementation which demonstrates quite a few initial misconceptions of RxJs and Angular. If you've been working with Angular for a while, you've probably encountered code similar to this, maybe even written it yourself. Don't worry, this is a no shame zone.<\/p>\n\n<p><code>naive-counter.service.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">ReplaySubject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">first<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">counter$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ReplaySubject<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">number<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"kd\">constructor<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">increment<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">first<\/span><span class=\"p\">())<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">((<\/span><span class=\"na\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"nx\">counter<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">));<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">decrement<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">first<\/span><span class=\"p\">())<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">((<\/span><span class=\"na\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"nx\">counter<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">));<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre><\/div>\n\n\n\n<p><code>naive-counter.component.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Component<\/span><span class=\"p\">,<\/span> <span class=\"nx\">OnInit<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/naive-counter.service<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Component<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">selector<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">app-naive-counter<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">template<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`\n    Counter: &lt;strong&gt;{{ counter }}&lt;\/strong&gt;\n    &lt;button (click)=\"naiveCounterService.increment()\"&gt;Increment&lt;\/button&gt;\n    &lt;button (click)=\"naiveCounterService.decrement()\"&gt;Decrement&lt;\/button&gt;\n  `<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterComponent<\/span> <span class=\"k\">implements<\/span> <span class=\"nx\">OnInit<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">;<\/span>\n\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"k\">readonly<\/span> <span class=\"nx\">naiveCounterService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">NaiveCounterService<\/span><span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n  <span class=\"nx\">ngOnInit<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">naiveCounterService<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span>\n      <span class=\"p\">(<\/span><span class=\"na\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">counter<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre><\/div>\n\n\n\n<p>Let's identify every area of improvement. Biggest red flag, in my opinion, is the fact that we have a subscription which is not being disposed of when the component unmounts. This leads to memory leaks as these subscriptions could potentially continue running until the web application navigates away. Even worse, if the component is mounted and unmounted repeatedly, that's an additional, long running subscription added per life-cycle.<\/p>\n\n<p>The simples way to solve this issue, and perhaps the most pragmatic, is to bind the observable itself to the template using the <strong>async pipe<\/strong>. Let's refactor.<\/p>\n\n<p><code>naive-counter.component.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Component<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/naive-counter.service<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Component<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">selector<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">app-naive-counter<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">template<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`\n    Counter: &lt;strong&gt;{{ naiveCounterService.counter$ | async }}&lt;\/strong&gt;\n    &lt;button (click)=\"naiveCounterService.increment()\"&gt;Increment&lt;\/button&gt;\n    &lt;button (click)=\"naiveCounterService.decrement()\"&gt;Decrement&lt;\/button&gt;\n  `<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterComponent<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"k\">readonly<\/span> <span class=\"nx\">naiveCounterService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">NaiveCounterService<\/span><span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>With this improvement, the responsibility over managing subscriptions is delegated from the developers to \"Angular\", or the Angular developers. The <em>async pipe<\/em>, as demonstrated above, subscribes to the observable and updates the UI with each notification received. Once the component unmounts, the <em>async pipe<\/em> unsubscribes from the observable automatically. The risk of long living subscriptions has been removed.<\/p>\n\n<p>The above design illustrates a common pattern in Angular to provide long-living state for a component, or series of components, that will mount and unmount repeatedly throughout the application's usage. You should definitely <em>not<\/em> be creating long-living state where you don't really need it as this is the main cause of memory consumption over time.<\/p>\n\n<p>The next step to improving this design is in the service. Here it is once again.<\/p>\n\n<p><code>naive-counter.service.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">ReplaySubject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">first<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">counter$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ReplaySubject<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">number<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"kd\">constructor<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">increment<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">first<\/span><span class=\"p\">())<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">((<\/span><span class=\"na\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"nx\">counter<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">));<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">decrement<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">first<\/span><span class=\"p\">())<\/span>\n      <span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">((<\/span><span class=\"na\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">counter$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"nx\">counter<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">));<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>The first issue to address is the <code>increment()<\/code> and <code>decrement()<\/code> methods. The original implementation attempts to read the last emitted notification by subscribing with a <code>first()<\/code> pipe which completes the observable once a single notification is received. Further, this implementation is relying on a <code>ReplaySubject<\/code> in order to receive a cached value immediately after subscribing.<\/p>\n\n<p>The simplest solution is to replace the <code>ReplaySubject<\/code> with a <code>BehaviorSubject<\/code> which includes an initial value and a <code>getValue<\/code> method that returns the cached value synchronously. This solution, however, misses the point. <\/p>\n\n<p>The current design doesn't consider the calling of the <code>increment()<\/code> and <code>decrement()<\/code> methods as notifications that affect the stream. For this reason, the calculation of the next notification falls outside of the stream. The stream is itself only being used to push a value to its observers. The best approach is to replace the <code>ReplaySubject<\/code> with a multi-casting observable.<\/p>\n\n<p>The <code>publishBehavior(initialNotification)<\/code> operator will convert the observable into a <code>ConnectableObservable<\/code>. This <code>ConnectableObservable<\/code> will begin emitting notifications when its <code>connect()<\/code> method is called. To avoid this additional step, the <code>refCount()<\/code> operator can be added right after which will begin emitting notifications as soon as a single observer subscribes and will unsubscribe from the source if no observers remain subscribed. Further, it will re-subscribe to the source if a new observer subscribes and the source is has not finalized.<\/p>\n\n<p>With a bit of refactoring,<\/p>\n\n<p><code>naive-counter.service.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Subject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">scan<\/span><span class=\"p\">,<\/span> <span class=\"nx\">publishBehavior<\/span><span class=\"p\">,<\/span> <span class=\"nx\">refCount<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">private<\/span> <span class=\"nx\">change$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Subject<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">number<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">();<\/span>\n\n  <span class=\"k\">readonly<\/span> <span class=\"nx\">counter$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span><span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">scan<\/span><span class=\"p\">((<\/span><span class=\"nx\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">,<\/span> <span class=\"nx\">change<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">counter<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">change<\/span><span class=\"p\">),<\/span>\n    <span class=\"nx\">publishBehavior<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">),<\/span>\n    <span class=\"nx\">refCount<\/span><span class=\"p\">()<\/span>\n  <span class=\"p\">);<\/span>\n\n  <span class=\"nx\">increment<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">decrement<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n\n<\/code><\/pre><\/div>\n\n\n\n<p>The above design has replaced the <code>ReplaySubject<\/code> with a <code>ConnectableObservable<\/code> that behaves similar to a <code>BehaviorSubject<\/code> in that it has an initial notification, specifically <code>0<\/code>, and the last notification is immediately emitted to each new subscriber. Subscriptions are managed automatically by the <code>refCount()<\/code> pipe. Yet, it receives all consecutive values from the observable stream.<\/p>\n\n<p>The <code>increment()<\/code> and <code>decrement()<\/code> methods now act as proxy methods for dispatching notifications on the <code>change$<\/code> stream which is an <code>Subject<\/code>. Finally, the state of the <code>counter<\/code> is calculated with each notification from <code>change$<\/code> and the previously emitted notification.<\/p>\n\n<p>One problem that might arise from this design is caused by the <code>refCount()<\/code> operator. If all observers unsubscribe, the subject will unsubscribe from the source. This is fine in most cases but one caveat is that there wont be a cached value for a new observer. The next observer to subscribe will have to wait until the source emits a new notification to receive its first notification. This could be a problem if the UI is trying to mount again with the last notification as its current state.<\/p>\n\n<p>A <code>BehaviorSubject<\/code> and the <code>asObservable()<\/code> method provide an even better solution. Here is the latest iteration:<\/p>\n\n<p><code>naive-counter.service.ts<\/code><br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Injectable<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">@angular\/core<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">scan<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">BehaviorSubject<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Injectable<\/span><span class=\"p\">()<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">NaiveCounterService<\/span> <span class=\"p\">{<\/span>\n  <span class=\"k\">private<\/span> <span class=\"k\">readonly<\/span> <span class=\"nx\">change$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">BehaviorSubject<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">number<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">);<\/span>\n\n  <span class=\"k\">readonly<\/span> <span class=\"nx\">counter$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">asObservable<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">scan<\/span><span class=\"p\">((<\/span><span class=\"nx\">counter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">,<\/span> <span class=\"nx\">change<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">counter<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">change<\/span><span class=\"p\">));<\/span>\n\n  <span class=\"nx\">increment<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n\n  <span class=\"nx\">decrement<\/span><span class=\"p\">():<\/span> <span class=\"k\">void<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">change$<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>The above improvement relies on the <code>BehaviorSubject<\/code> to receive and cache new notifications. The <code>asObservable()<\/code> method returns an observable that conceals the <code>BehaviorSubject<\/code> so that external actors cannot push notifications into the stream. The stream logic is attached to the returned observable.<\/p>\n\n","category":["angular","rxjs","ngrx","javascript"]},{"title":"Angular Concepts in React: The Async Pipe","pubDate":"Sat, 14 Sep 2019 22:28:07 +0000","link":"https:\/\/dev.to\/lysofdev\/angular-concepts-in-react-the-async-pipe-16ej","guid":"https:\/\/dev.to\/lysofdev\/angular-concepts-in-react-the-async-pipe-16ej","description":"<p>One of my favorite tools in the Angular framework is the Async pipe. It allows me to render the latest value of an Observable to the screen. The component will then re-render to display the next value of the observable each time it receives a new notification. Finally, the subscription to the observable will be disposed of as soon as the component dismouns. Automatically! It allows me to build my asynchronous code in neat, RxJs streams.<\/p>\n\n<p>A common use would be to synchronize some value from a data store like NgRx and display it in a component with some adjustments such as formatting. I don't have to use the OnInit life cycle method to start the subscription, nor do I need to use the OnDestroy life cycle method to unsubscribe.<\/p>\n\n<p>Now, I'm not here to tell you that you should be using RxJs with React. I know I can certainly build a simpler app without it but if I find myself working with many APIs and having tons of Promises to take care of, then I think RxJs is merited. For this reason, I'd like to share with you my personal implementation of the Async pipe from Angular as a React component.<\/p>\n\n<h1>\n  \n  \n  A Simple Example Problem - Stock Prices\n<\/h1>\n\n<p>We'll build a theoretical, stock monitoring tool which receives a feed of stock prices that we can filter by each stock's ticker. We need a component which displays the ticker and the latest price for this stock. Let's assume that we have a service which provides this value as an Observable stream of number values which we need to reformat as a string with the dollar sign and a two point precision. Simple enough, right?<\/p>\n\n<h1>\n  \n  \n  The Async pipe in Angular 2+\n<\/h1>\n\n<p>Our Angular component will consume the API from a service, format the latest value and print them to the screen.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Component<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Input<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@angular\/core<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">StockPricesService<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">.\/stock-prices.service<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">map<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">rxjs\/operators<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"p\">@<\/span><span class=\"nd\">Component<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">selector<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">app-stock-price<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">templateUrl<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">stock-price.component.html<\/span><span class=\"dl\">'<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"k\">export<\/span> <span class=\"kd\">class<\/span> <span class=\"nx\">StockPriceComponent<\/span> <span class=\"p\">{<\/span>\n  <span class=\"p\">@<\/span><span class=\"nd\">Input<\/span><span class=\"p\">()<\/span> <span class=\"nx\">ticker<\/span><span class=\"p\">:<\/span> <span class=\"nx\">string<\/span><span class=\"p\">;<\/span>\n\n  <span class=\"nx\">price$<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">stockPrices<\/span><span class=\"p\">.<\/span><span class=\"nx\">getStockPrice<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">ticker<\/span><span class=\"p\">).<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">map<\/span><span class=\"p\">((<\/span><span class=\"nx\">price<\/span><span class=\"p\">:<\/span> <span class=\"nx\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s2\">`$<\/span><span class=\"p\">${<\/span><span class=\"nx\">price<\/span><span class=\"p\">.<\/span><span class=\"nx\">toFixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)}<\/span><span class=\"s2\">`<\/span><span class=\"p\">)<\/span>\n  <span class=\"p\">);<\/span>\n\n  <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span><span class=\"kr\">private<\/span> <span class=\"nx\">stockPrices<\/span><span class=\"p\">:<\/span> <span class=\"nx\">StockPricesService<\/span><span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>Our Component's HTML will look something like this:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight html\"><code><span class=\"nt\">&lt;article&gt;<\/span>\n  <span class=\"nt\">&lt;section&gt;<\/span>{{ ticker }}<span class=\"nt\">&lt;\/section&gt;<\/span>\n  <span class=\"nt\">&lt;section&gt;<\/span>{{ price$ | async }}<span class=\"nt\">&lt;\/section&gt;<\/span>\n<span class=\"nt\">&lt;\/article&gt;<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Finally, we might use this component like this:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight html\"><code><span class=\"nt\">&lt;app-stock-price<\/span> <span class=\"na\">[ticker]=<\/span><span class=\"s\">\"'GE'\"<\/span><span class=\"nt\">&gt;&lt;\/app-stock-price&gt;<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<h1>\n  \n  \n  The React version of the Stock Price Component\n<\/h1>\n\n<p>Here's how we might implement this same component in React:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useMemo<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">map<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs\/operators<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Async<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/async<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">useStockPrices<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">.\/use-stock-prices<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kr\">interface<\/span> <span class=\"nx\">StockPriceProps<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nl\">ticker<\/span><span class=\"p\">:<\/span> <span class=\"nx\">string<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">StockPrice<\/span><span class=\"p\">({<\/span> <span class=\"nx\">ticker<\/span> <span class=\"p\">}:<\/span> <span class=\"nx\">StockPriceProps<\/span><span class=\"p\">):<\/span> <span class=\"nx\">JSX<\/span><span class=\"p\">.<\/span><span class=\"nx\">Element<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">getStockPrice<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useStockPrices<\/span><span class=\"p\">();<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"nx\">price$<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useMemo<\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">getStockPrice<\/span><span class=\"p\">(<\/span><span class=\"nx\">ticker<\/span><span class=\"p\">).<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">map<\/span><span class=\"p\">((<\/span><span class=\"nx\">price<\/span><span class=\"p\">:<\/span> <span class=\"nx\">number<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"s2\">`$<\/span><span class=\"p\">${<\/span><span class=\"nx\">price<\/span><span class=\"p\">.<\/span><span class=\"nx\">toFixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)}<\/span><span class=\"s2\">`<\/span><span class=\"p\">)),<\/span>\n    <span class=\"p\">[<\/span><span class=\"nx\">ticker<\/span><span class=\"p\">]<\/span>\n  <span class=\"p\">);<\/span>\n  <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n    <span class=\"o\">&lt;<\/span><span class=\"nx\">article<\/span><span class=\"o\">&gt;<\/span>\n      <span class=\"o\">&lt;<\/span><span class=\"nx\">section<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">ticker<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/section<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"nx\">section<\/span><span class=\"o\">&gt;<\/span>\n        <span class=\"o\">&lt;<\/span><span class=\"nx\">Async<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">price$<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/Async<\/span><span class=\"err\">&gt;\n<\/span>      <span class=\"o\">&lt;<\/span><span class=\"sr\">\/section<\/span><span class=\"err\">&gt;\n<\/span>    <span class=\"o\">&lt;<\/span><span class=\"sr\">\/article<\/span><span class=\"err\">&gt;\n<\/span>  <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>Obviously, the <code>Async<\/code> component doesn't exist yet so we'll have to implement it to get the desired effect. Here's how I did it:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"nx\">React<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">PropsWithChildren<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useState<\/span><span class=\"p\">,<\/span> <span class=\"nx\">useEffect<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">react<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">Observable<\/span><span class=\"p\">,<\/span> <span class=\"nx\">isObservable<\/span><span class=\"p\">,<\/span> <span class=\"nx\">Subscription<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">rxjs<\/span><span class=\"dl\">\"<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nx\">type<\/span> <span class=\"nx\">AsyncProps<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span><span class=\"o\">&gt;<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">PropsWithChildren<\/span><span class=\"o\">&lt;<\/span><span class=\"p\">{<\/span> <span class=\"nx\">observable<\/span><span class=\"p\">?:<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">}<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">export<\/span> <span class=\"kd\">function<\/span> <span class=\"nx\">Async<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">any<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">({<\/span>\n  <span class=\"nx\">observable<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">children<\/span>\n<span class=\"p\">}:<\/span> <span class=\"nx\">AsyncProps<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">):<\/span> <span class=\"nx\">JSX<\/span><span class=\"p\">.<\/span><span class=\"nx\">Element<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kd\">const<\/span> <span class=\"p\">[<\/span><span class=\"nx\">value<\/span><span class=\"p\">,<\/span> <span class=\"nx\">setValue<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">useState<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">null<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n  <span class=\"nx\">useEffect<\/span><span class=\"p\">(()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kd\">let<\/span> <span class=\"na\">subscription<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Subscription<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">isObservable<\/span><span class=\"p\">(<\/span><span class=\"nx\">observable<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">subscription<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">observable<\/span><span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span><span class=\"nx\">setValue<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">isObservable<\/span><span class=\"p\">(<\/span><span class=\"nx\">children<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">subscription<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">children<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"nx\">T<\/span><span class=\"o\">&gt;<\/span><span class=\"p\">).<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span><span class=\"nx\">setValue<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">subscription<\/span><span class=\"p\">.<\/span><span class=\"nx\">unsubscribe<\/span><span class=\"p\">();<\/span>\n  <span class=\"p\">},<\/span> <span class=\"p\">[<\/span><span class=\"nx\">observable<\/span><span class=\"p\">,<\/span> <span class=\"nx\">children<\/span><span class=\"p\">]);<\/span>\n  <span class=\"k\">return<\/span> <span class=\"o\">&lt;&gt;<\/span><span class=\"p\">{<\/span><span class=\"nx\">value<\/span><span class=\"p\">}<\/span><span class=\"o\">&lt;<\/span><span class=\"sr\">\/&gt;<\/span><span class=\"err\">;\n<\/span><span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Notice that we can also pass the observable as a prop like so:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>&lt;Async observable={price$} \/&gt;\n<\/code><\/pre><\/div>\n\n\n\n<h1>\n  \n  \n  Is this even useful?\n<\/h1>\n\n<p>If you're a skeptical developer like I am, you may have noticed that this hardly saves us any trouble from just performing the deliberate subscription on the Stock Price component. We still need to use the <code>useMemo<\/code> hook to apply the pipe transformation on the observable. It all comes down to how many observable s you want to synchronize your component to. If you only have one, then it's probably not worth it, but if you have more than one or two, or if you're just trying to display the observable directly without transformation, then it may very well be worth it.<\/p>\n\n<p>What do you think?<\/p>\n\n","category":["javascript","react","angular","webdev"]},{"title":"Redux + RxJs: Observable Actions","pubDate":"Tue, 09 Jul 2019 19:03:02 +0000","link":"https:\/\/dev.to\/lysofdev\/redux-rxjs-observable-actions-31di","guid":"https:\/\/dev.to\/lysofdev\/redux-rxjs-observable-actions-31di","description":"<p><a href=\"https:\/\/rxjs-dev.firebaseapp.com\/\">RxJs<\/a> is one of my favorite Javascript libraries. It's almost an update to the language itself. In a recent role, we built an awesome data pipeline that handled sorting, filtering, aggregating and paginating for multiple large datasets in the user's device using RxJs. We also used a <a href=\"https:\/\/redux.js.org\/\">Redux<\/a> store to maintain the application's state and <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/IndexedDB_API\">IndexedDB<\/a> to store the large datasets in the user's device. With this and a few other tricks we were able to deliver a progressive web application that worked offline.<\/p>\n\n<p>In this posts, I'd like to share with you a custom Redux middleware function that we developed to easily handle <a href=\"http:\/\/reactivex.io\/documentation\/observable.html\">Observables<\/a> within Redux actions. There are a few libraries in <a href=\"https:\/\/www.npmjs.com\/\">NPM<\/a> that advertise the ability to do this but we found that the solution was simple enough that a security audit of a third-party library was just a waste of time. <\/p>\n\n<p>We wanted to keep our <a href=\"https:\/\/reactjs.org\/\">React<\/a> view layer pure by keeping all business logic out of it. The application rendered the state of the Redux store which included the query necessary to extract the visible records from IndexedDB. Any actions from the user where mapped to a dispatch to the store which could be a simple action or an observable action. We skipped accepting functions as a thunk action since this is basically the same thing as an observable action but the middleware actually ignores these as well so it's safe to combine with <a href=\"https:\/\/github.com\/reduxjs\/redux-thunk\">Redux-Thunk<\/a>.<\/p>\n\n<p>We determined that there existed two types of logic that we wanted to store in observables.<\/p>\n\n<ul>\n<li>Business<\/li>\n<li>Asynchronous<\/li>\n<\/ul>\n\n<p>That's really what RxJs is all about. Rather than have complex or several middlewares, intermediate actions and complex reducers to handle network requests and other business tasks, we delegated all of this to RxJs which allows us to isolate logic and compose it seamlessly. The Redux store focuses on mapping actions to state and notifying the React application of changes in state. With RxJs we can map a user dispatched action to a write to the Redux store all within a single observable interface which seamlessly hides away the asynchronous scheduling and the several intermediate tasks.<\/p>\n\n<p>Ok, so enough talk. Here's a working example:<\/p>\n\n\n<div class=\"ltag__replit\">\n  <iframe height=\"550px\" src=\"https:\/\/repl.it\/@EstebanHernande\/LargeLuxuriousNumerators?lite=true\"><\/iframe>\n<\/div>\n\n\n<p>The above is a simple script that uses a Redux store to add numbers together and return the total sum. It also keeps track of errors and has a loading flag so that the user wont receive intermediate values.<\/p>\n\n<p>If you take a look at the <code>counterReducer<\/code>, we have four action types to keep in mind. The <code>_RESET<\/code> action type is emitted synchronously so the reducer will receive this notification before any of the notifications from the observable. This can be used to reset some state such as clearing the errors, clearing the counter, and setting the loading flat to <code>true<\/code>.<\/p>\n\n<p>The <code>observerMiddleware<\/code> will handle observable actions.<\/p>\n\n<p>By default, an Observable will attempt to execute synchronously and switch to asynchronous processing once it encounters a Promise or any other type of asynchronous operation. This might lead to the <code>_NEXT<\/code>, <code>_ERROR<\/code> and <code>_COMPLETE<\/code> notifications being emitted before the <code>_RESET<\/code> which might cause the <code>_RESET<\/code> notification to clear out the state after we've updated it. We need to change the default <a href=\"http:\/\/reactivex.io\/documentation\/scheduler.html\">scheduler<\/a> on the Observable to prevent this. Luckily for us, RxJs provides a very simple way to guarantee that an observable is processed asynchronously. All we have to do is apply the <code>observeOn<\/code> <a href=\"http:\/\/reactivex.io\/documentation\/operators.html\">operator<\/a> with the <code>asapScheduler<\/code> to the observable and presto!<\/p>\n\n<p>Now, our observable will begin processing after the <code>_RESET<\/code> notification and will emit every value as a <code>_NEXT<\/code> notification. Our reducer will update the state of the counter for each of these notifications.<\/p>\n\n<p>Finally, if the observable emits an <code>_ERROR<\/code> notification, our reducer will update the state with the error. Otherwise, the observable will emit a <code>_COMPLETE<\/code> notification which our reducer will process to set the loading flag to <code>false<\/code>. Now our user-facing application can remove the loading indicator and display the total sum (or the error message).<\/p>\n\n<p>We'll test this out by creating an action generator named <code>addNumbers<\/code> that receives any amount of numbers as arguments and dispatches an action with an observable payload that emits these numbers in sequence before completing. Given the numbers 1 through 4, we expect a sum of 10. If we run the above script, we can see that once the loading flat is set to <code>false<\/code> and the value of <code>counter<\/code> will be set informing us that the process has finished loading and the total sum is <code>10<\/code>.<\/p>\n\n","category":["javascript","react","redux","rxjs"]},{"title":"Need help - Losing faith in my team","pubDate":"Mon, 01 Apr 2019 21:49:57 +0000","link":"https:\/\/dev.to\/lysofdev\/need-help-losing-faith-in-my-team-em3","guid":"https:\/\/dev.to\/lysofdev\/need-help-losing-faith-in-my-team-em3","description":"<p>Hey Dev.to,<\/p>\n\n<p>I need some serious career advice as I face total burnout. <\/p>\n\n<p>I joined a web development team about 6 months ago hoping to learn all about working in a team.<\/p>\n\n<p>Instead, I've become the senior developer by default for the entire team as almost no one on the team is familiar with the web framework we use.<\/p>\n\n<p>My team members constantly submit work that I consider to be absolutely unacceptable. Illegible, buggy, incorrectly tested and just sloppy in general.<\/p>\n\n<p>I take my coding style very seriously and write everything with legibility in mind. I constantly apply techniques to make my code easy to read and easy to work with. My test coverage is almost a perfect 100% where the standard is 80% and this is all easy to me.<\/p>\n\n<p>However, this all seems to be completely alien to my teammates. Not only is their code illegible, it's misguided and convoluted. Full of unnecessary logic and \"reinvent the wheel\" type of problems. Most of them seem to refuse to use the framework and have built buggy versions of features that are already built into the framework.<\/p>\n\n<p>I've tried to improve team knowledge of the framework by posting links to docs, articles, and videos on the team chat which I'm sure only one developer has bothered opening.<\/p>\n\n<p>My manager constantly interrupts me to request that I \"help out\" other developers which basically ends up with me giving basic coding lessons to the other developers and basically doing everything other than typing for them.<\/p>\n\n<p>Sometimes I feel that they know I have no choice but to help.<\/p>\n\n<p>I'm seriously considering leaving the team either by requesting that I be reassigned or leaving the company entirely. I feel burned out everyday having to spend weeks reverse engineering terrible implementations to add basic features that should take hours to complete.<\/p>\n\n<p>Have you faced a similar situation? How did you handle it?<\/p>\n\n","category":"discuss"},{"title":"Interest in a DIY micro-service system?","pubDate":"Tue, 05 Feb 2019 13:44:53 +0000","link":"https:\/\/dev.to\/lysofdev\/discuss-interest-in-a-diy-micro-service-system-4bm4","guid":"https:\/\/dev.to\/lysofdev\/discuss-interest-in-a-diy-micro-service-system-4bm4","description":"<p>Hello, everyone. I've been having fun these last few days building the more common components of a micro-service system out of anything I can think of. For example, I built an API Gateway with Phoenix and Elixir and a configuration server in Python.<\/p>\n\n<p>Is there any interest in a tutorial or series following these lessons? The main point of the tutorial would be to demonstrate how a micro-service system can be developed by composing simple, stack-agnostic services. I will avoid using pre-built solutions and instead opt for building each component myself either with a few libraries or a popular framework. I find that this technique of learning is especially helpful at demystifying the more complicated aspects of any technology.<\/p>\n\n<p>I would be using Docker and Docker-Compose for development and K8s for a simulated deployment.<\/p>\n\n<p>Let me know in the comments if this sounds interesting.<\/p>\n\n","category":["devops","docker","kubernetes","discuss"]},{"title":"Reactive Cookies with RxJs","pubDate":"Mon, 26 Nov 2018 16:51:10 +0000","link":"https:\/\/dev.to\/lysofdev\/reactive-cookies-with-rxjs-1g9m","guid":"https:\/\/dev.to\/lysofdev\/reactive-cookies-with-rxjs-1g9m","description":"<p>We need to store data on the client's device securely and, for that, we have cookies. The NPM package <code>js-cookie<\/code> provides us with a simple interface to store and retrieve cookies. Let's build a wrapper for this interface to make our cookies reactive.<\/p>\n\n<p>A reactive cookie will be created with a key.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>import { of, Subject } from 'rxjs';\n\nclass ReactiveCookie {\n\n    constructor(key) {\n        this.key = key;\n    }\n\n}\n<\/code><\/pre><\/div>\n\n\n\n<p>Let's add getters and setters for the value.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>constructor() {\n    ...\n    this.value = new Subject();\n}\n\ngetValue() {\n    return this.value;\n}\n\nsetValue(value) {\n    this.value.next(value);\n}\n<\/code><\/pre><\/div>\n\n\n\n<p>Great! We want the stored cookie to be updated every time we set the value so that it's always in sync. We'll subscribe to the <code>value<\/code> subject and set the cookie on each value.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>constructor() {\n    ...\n    this.synchronize();\n}\n\nsynchronize() {\n    this.getValue().subscribe((value) =&gt; { Cookies.set(this.key, value); });\n}\n<\/code><\/pre><\/div>\n\n\n\n<p>Alright, what about when there is already a stored value. We want this stored value to be set as the initial value so we'll add that as well to the constructor.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>constructor() {\n    this.retrieveStoredValue();\n}\n\ngetStoredValue() {\n    return of(Cookies.get(this.key));\n}\n\nretrieveStoredValue() {\n    this.getStoredValue().subscribe((value) =&gt; { this.value.next(value) });\n}\n<\/code><\/pre><\/div>\n\n\n\n<p>Woo! Now, whenever we create a Cookie with a key that already has a value stored, that value will automatically be loaded into the ReactiveCookie <code>value<\/code>. Furthermore, setting a new value will immediately update the value of the stored cookie. Finally, lets add <code>clear()<\/code> and <code>remove()<\/code> methods to complete our functionality.<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight plaintext\"><code>clear() {\n    this.setValue(null);\n}\n\nremove() {\n    Cookies.delete(this.key);\n    this.value.complete();\n}\n<\/code><\/pre><\/div>\n\n\n\n<p>Now, go out and store some values!<\/p>\n\n","category":["javascript","observables","webdev"]},{"title":"An Angular Testing Cheatsheet","pubDate":"Mon, 22 Oct 2018 16:04:50 +0000","link":"https:\/\/dev.to\/lysofdev\/an-angular-testing-cheatsheet-5hj2","guid":"https:\/\/dev.to\/lysofdev\/an-angular-testing-cheatsheet-5hj2","description":"<h2>\n  \n  \n  Personal note\n<\/h2>\n\n<p>This is a redacted version of an internal document I prepared for a client. It is based off the most recent revision and is not identical to the client's version.<\/p>\n\n<h1>\n  \n  \n  Angular Unit Testing Cheat Sheet\n<\/h1>\n\n<p>The following is a quick reference to code examples of common Angular testing scenarios and some tips to improve our testing practices. Remember to test first!<\/p>\n\n<h3>\n  \n  \n  Testing Scenarios\n<\/h3>\n\n<ul>\n<li>Isolating Logic<\/li>\n<li>Async Behavior<\/li>\n<li>Spies and Mocks<\/li>\n<li>User Input Events<\/li>\n<li>Inherited Functionality<\/li>\n<li>Application Events<\/li>\n<li>Services<\/li>\n<li>Input Variables<\/li>\n<li>Output Variables<\/li>\n<li>Life Cycle Methods<\/li>\n<li>Mock Method Chains<\/li>\n<li>HTTP Calls<\/li>\n<\/ul>\n\n\n\n\n<h2>\n  \n  \n  Isolating Logic\n<\/h2>\n\n<p>Use helper functions to encapsulate logic from the rest of the application. Avoid placing logic within life cycle methods and other hooks. Avoid referencing the component's state from within a helper method despite it being available. This will make it easier to test in isolation.<\/p>\n\n<h4>\n  \n  \n  Bad\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">ngOnInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"p\">...<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">clientPhoneNumbers<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">allClients<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">undefined<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">map<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"na\">phone<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">...<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The above code example is hard to test. We have provide and\/or mock every dependency of every operation within the <code>ngOnInit<\/code> method to test just three lines of code.<\/p>\n\n<h4>\n  \n  \n  Better\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">ngOnInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"p\">...<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">collectClientPhoneNumbers<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">...<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">collectClientPhoneNumbers<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">clientPhoneNumbers<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">allClients<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">undefined<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">map<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"na\">phone<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In our improved example, we no longer need to ensure that all other operations in <code>ngOnInit<\/code> are successful since we are only testing the <code>collectClientPhoneNumbers<\/code> method. However, we still have to mock or provide the component's state for the allClients field.<\/p>\n\n<h4>\n  \n  \n  Best\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">ngOnInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"p\">...<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">clientPhoneNumbers<\/span> <span class=\"o\">=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">collectClientPhoneNumbers<\/span><span class=\"p\">(<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">allClients<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">...<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">collectClientPhoneNumbers<\/span><span class=\"p\">(<\/span> <span class=\"nx\">clients<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span><span class=\"p\">[]<\/span> <span class=\"p\">):<\/span> <span class=\"nb\">Object<\/span><span class=\"p\">[]<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">clients<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">undefined<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nx\">map<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">client<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Client<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"na\">phone<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In our best implementation, the logic is completely independent of the component's state. We don't need to mock anything if our component compiles, just provide vanilla JS input.<\/p>\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When collectClientPhoneNumbers receives a list of Clients, then it should return a list of phone numbers<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Load test data and define expected results.<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">clients<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">loadFromMockData<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">valid-clients<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">firstClientPhoneNumber<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"na\">phone<\/span><span class=\"p\">:<\/span> <span class=\"nx\">client<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"kr\">number<\/span> <span class=\"p\">};<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">clientsWithPhoneNumbers<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">clients<\/span><span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">undefined<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">client<\/span><span class=\"p\">.<\/span><span class=\"nx\">phone<\/span> <span class=\"o\">!==<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Perform the operation and capture results.<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">filteredClients<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">collectClientPhoneNumbers<\/span><span class=\"p\">(<\/span> <span class=\"nx\">clients<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Compare results with expected values.<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">filteredClients<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">clientsWithPhoneNumbers<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">filteredClients<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">firstClientPhoneNumber<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h1>\n  \n  \n  Async Behavior\n<\/h1>\n\n<p>The Angular Testing module provides two utilities for testing asynchronous operations.<\/p>\n\n<h4>\n  \n  \n  Notes on Async Testing Tools\n<\/h4>\n\n<ul>\n<li>\n<strong>async<\/strong>: The test will wait until all asynchronous behavior has resolved before finishing. Best to test simple async behavior that shouldn't block for much time. Avoid using with async behavior that could hang or last a long time before resolving.<\/li>\n<li>\n<strong>fakeAsync<\/strong>: The test will intercept async behavior and perform it synchronously. Best for testing chains of async behavior or unreliable async behavior that might hang or take a long time to resolve.<\/li>\n<li>\n<strong>tick<\/strong>: Simulate the passage of time in a <em>fakeAsync<\/em> test. Expects a numeric argument representing elapsed time in milliseconds.<\/li>\n<li>\n<strong>flushMicrotasks<\/strong>: Force the completion of all pending <strong>microtasks<\/strong> such as <em>Promises<\/em> and <em>Observables<\/em>.<\/li>\n<li>\n<strong>flush<\/strong>: Force the completion of all pending <strong>macrotasks<\/strong> such as <em>setInterval<\/em>, <em>setTimeout<\/em>, etc.\n#### Code to Test\n<\/li>\n<\/ul>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">SlowService<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nl\">names<\/span><span class=\"p\">:<\/span> <span class=\"nx\">BehaviorSubject<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">string<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">BehaviorSubject<\/span><span class=\"o\">&lt;&gt;<\/span><span class=\"p\">(<\/span> <span class=\"p\">[]<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"nx\">getNames<\/span><span class=\"p\">():<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">string<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">updateNames<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[]<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">setTimeout<\/span><span class=\"p\">(<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">),<\/span> <span class=\"mi\">3000<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">class<\/span> <span class=\"nx\">SlowComponent<\/span> <span class=\"k\">implements<\/span> <span class=\"nx\">OnInit<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nl\">names<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[];<\/span>\n\n    <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span> <span class=\"k\">private<\/span> <span class=\"nx\">slowService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">SlowService<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n    <span class=\"nx\">ngOnInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">slowService<\/span><span class=\"p\">.<\/span><span class=\"nx\">getNames<\/span><span class=\"p\">().<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">names<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[]<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">names<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example <code>async()<\/code>\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When updatedNames is passed a list of names, Then the subscription will update with a list of names<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"k\">async<\/span><span class=\"p\">(<\/span> \n    <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span> <span class=\"p\">[<\/span><span class=\"nx\">SlowService<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">slowService<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Create test data, initialize component and assert component's initial state<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Bob<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Mark<\/span><span class=\"dl\">\"<\/span> <span class=\"p\">];<\/span>\n    <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">ngOnInit<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">whenStable<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBeDefined<\/span><span class=\"p\">();<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">);<\/span>\n\n        <span class=\"c1\">\/\/ WHEN - Simulate an update in the service's state and wait for asynchronous operations to complete<\/span>\n        <span class=\"nx\">slowService<\/span><span class=\"p\">.<\/span><span class=\"nx\">updateNames<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">);<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">whenStable<\/span><span class=\"p\">();<\/span>\n    <span class=\"p\">}<\/span> <span class=\"p\">)<\/span>\n    <span class=\"p\">.<\/span><span class=\"nx\">then<\/span><span class=\"p\">(<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ THEN - Assert changes in component's state<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">);<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  TestExample <code>fakeAsync()<\/code>, <code>tick()<\/code>, <code>flush()<\/code>, <code>flushMicrotasks()<\/code>\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When updatedNames is passed a list of names, Then the subscription will update with a list of names<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">fakeAsync<\/span><span class=\"p\">(<\/span> \n    <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span> <span class=\"p\">[<\/span><span class=\"nx\">SlowService<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">slowService<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Create test data, initialize component and assert component's initial state<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Bob<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Mark<\/span><span class=\"dl\">\"<\/span> <span class=\"p\">];<\/span>\n    <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">ngOnInit<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">flushMicrotasks<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBeDefined<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Simulate an update in the service's state and wait for asynchronous operations to complete<\/span>\n    <span class=\"nx\">slowService<\/span><span class=\"p\">.<\/span><span class=\"nx\">updateNames<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">tick<\/span><span class=\"p\">(<\/span> <span class=\"mi\">3001<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert changes in component's state<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">names<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Spies and Mocks\n<\/h2>\n\n<p>Spying on functions allows us to validate that interactions between components are ocurring under the right conditions. We use mock objects to reduce the amount of code that is being tested. Jasmine provides the <code>spyOn()<\/code> function which let's us manage spies and mocks. <\/p>\n\n<h4>\n  \n  \n  Case 1: Assert that a method was called.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">obj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">method<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">method<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">method<\/span><span class=\"p\">();<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">method<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><strong>Warning<\/strong>: Spying on a method will prevent the method from actually being executed.<\/p>\n\n<h4>\n  \n  \n  Case 2: Assert that a method was called and execute method.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">obj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">getName<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Sam<\/span><span class=\"dl\">'<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">getName<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">callThrough<\/span><span class=\"p\">();<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span><span class=\"p\">()<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Sam<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 3: Assert that a method was called and execute a function.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">obj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">getName<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Sam<\/span><span class=\"dl\">'<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">getName<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">callFake<\/span><span class=\"p\">((<\/span><span class=\"nx\">args<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">args<\/span><span class=\"p\">));<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span><span class=\"p\">()<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Sam<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">getName<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 4: Mock a response for an existing method.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">obj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">mustBeTrue<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"kc\">false<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">mustBeTrue<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"kc\">true<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">mustBeTrue<\/span><span class=\"p\">()<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBe<\/span><span class=\"p\">(<\/span> <span class=\"kc\">true<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 5: Mock several responses for an existing method.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">iterator<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">next<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">iterator<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">next<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValues<\/span><span class=\"p\">(<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">iterator<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">iterator<\/span><span class=\"p\">.<\/span><span class=\"nx\">next<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 6: Assert that a method was called more than once.\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">obj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">method<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"kc\">null<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">method<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"k\">for<\/span> <span class=\"p\">(<\/span> <span class=\"kd\">let<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">3<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span><span class=\"o\">++<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">method<\/span><span class=\"p\">();<\/span>\n<span class=\"p\">}<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">.<\/span><span class=\"nx\">method<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledTimes<\/span><span class=\"p\">(<\/span> <span class=\"mi\">3<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 7: Assert that a method was called with arguments\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">calculator<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">add<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span> <span class=\"na\">x<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span><span class=\"p\">,<\/span> <span class=\"na\">y<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">x<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">y<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">calculator<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">add<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">callThrough<\/span><span class=\"p\">();<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">calculator<\/span><span class=\"p\">.<\/span><span class=\"nx\">add<\/span><span class=\"p\">(<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span> <span class=\"p\">)<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">7<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">calculator<\/span><span class=\"p\">.<\/span><span class=\"nx\">add<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Case 8: Assert that a method was called with arguments several times\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">const<\/span> <span class=\"nx\">ids<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">ABC123<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">DEF456<\/span><span class=\"dl\">'<\/span> <span class=\"p\">];<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">db<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">store<\/span><span class=\"p\">:<\/span> <span class=\"p\">(<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"k\">void<\/span> <span class=\"p\">};<\/span>\n<span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">store<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">ids<\/span><span class=\"p\">.<\/span><span class=\"nx\">forEach<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">id<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"nx\">store<\/span><span class=\"p\">(<\/span> <span class=\"nx\">id<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"nx\">store<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">ABC123<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"nx\">store<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">DEF456<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  User Input Events\n<\/h2>\n\n<p>We can simulate user input without having to interact with the DOM by simulating events on the <code>DebugElement<\/code>. The <code>DebugElement<\/code> is a browser-agnostic rendering of the Angular Component as an <code>HTMLElement<\/code>. This means we can test elements without a browser to render the actual HTML.<\/p>\n\n<h4>\n  \n  \n  Component to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"p\">@<\/span><span class=\"nd\">Component<\/span><span class=\"p\">({<\/span>\n    <span class=\"na\">selector<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">simple-button<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"na\">template<\/span><span class=\"p\">:<\/span> <span class=\"s2\">`\n        &lt;div class=\"unnecessary-container\"&gt;\n            &lt;button (click)=\"increment()\"&gt;Click Me!&lt;\/button&gt;\n        &lt;\/div&gt;\n    `<\/span>\n<span class=\"p\">})<\/span>\n<span class=\"kd\">class<\/span> <span class=\"nx\">SimpleButtonComponent<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nl\">clickCounter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"nx\">increment<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">clickCounter<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When the button is clicked, then click counter should increment<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Capture reference to DebugElement not NativeElement and verify initial state<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">buttonDE<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">debugElement<\/span><span class=\"p\">.<\/span><span class=\"nx\">find<\/span><span class=\"p\">(<\/span> <span class=\"nx\">By<\/span><span class=\"p\">.<\/span><span class=\"nx\">css<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">button<\/span><span class=\"dl\">'<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">clickCounter<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Simulate the user input event and detect changes.<\/span>\n    <span class=\"nx\">buttonDE<\/span><span class=\"p\">.<\/span><span class=\"nx\">triggerEventHandler<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">click<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">{}<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">detectChanges<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert change in component's state<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">clickCounter<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Inherited Functionality\n<\/h2>\n\n<p>We shouldn't test a parent class's functionality in it's inheriting children. Instead, this inherited functionality should be mocked.<\/p>\n\n<h4>\n  \n  \n  Parent Class\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">ResourceComponent<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"k\">protected<\/span> <span class=\"nx\">getAllResources<\/span><span class=\"p\">(<\/span> <span class=\"nx\">resourceName<\/span> <span class=\"p\">):<\/span> <span class=\"nx\">Resource<\/span><span class=\"p\">[]<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">externalSource<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span> <span class=\"nx\">resourceName<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Child Class\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">ContactsComponent<\/span> <span class=\"kd\">extends<\/span> <span class=\"nx\">ResourceComponent<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nx\">getAvailableContacts<\/span><span class=\"p\">():<\/span> <span class=\"nx\">Contact<\/span><span class=\"p\">[]<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">getAllResources<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">contacts<\/span><span class=\"dl\">'<\/span> <span class=\"p\">)<\/span>\n            <span class=\"p\">.<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">contact<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Contact<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">contact<\/span><span class=\"p\">.<\/span><span class=\"nx\">available<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When the getAvailableContacts method is called, Then it should return contacts where available is true<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Intercept call to inherited method and return a mocked response.<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">getAllResources<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"p\">[<\/span> \n        <span class=\"p\">{<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Charles McGill<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">available<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Tom Tso<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">available<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Ruben Blades<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">available<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span> <span class=\"p\">}<\/span>\n    <span class=\"p\">]<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Perform operation on inheriting class<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">contacts<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">getAvailableContacts<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert that interaction between inherited and inheriting is correctly applied.<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">getAllResources<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">contacts<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">contacts<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">2<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">contacts<\/span><span class=\"p\">.<\/span><span class=\"kr\">any<\/span><span class=\"p\">(<\/span> <span class=\"nx\">c<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"nx\">name<\/span> <span class=\"o\">===<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Charles McGill<\/span><span class=\"dl\">'<\/span> <span class=\"p\">)<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBe<\/span><span class=\"p\">(<\/span> <span class=\"kc\">false<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Services\n<\/h2>\n\n<p>Service objects are tested with the <code>inject()<\/code> function. <code>TestBed<\/code> will inject a new instance of the service object for each test. Use the <code>async()<\/code> function when testing asynchronous behavior such as Observables and Promises. Use <code>of()<\/code> to mock observables.<\/p>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">NameService<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span> <span class=\"k\">private<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">:<\/span> <span class=\"nx\">CacheService<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n    <span class=\"nx\">getNames<\/span><span class=\"p\">():<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">string<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">names<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When getNames is called Then return an observable list of strings<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"k\">async<\/span><span class=\"p\">(<\/span> \n    <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span> <span class=\"p\">[<\/span><span class=\"nx\">CacheService<\/span><span class=\"p\">,<\/span> <span class=\"nx\">NameService<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">,<\/span> <span class=\"nx\">nameService<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Mock service dependencies with expected value<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">testNames<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"dl\">\"<\/span><span class=\"s2\">Raul<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Fareed<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">Mark<\/span><span class=\"dl\">\"<\/span><span class=\"p\">];<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">get<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"k\">of<\/span><span class=\"p\">(<\/span> <span class=\"nx\">testNames<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Subscribe to observable returned by service method<\/span>\n    <span class=\"nx\">nameService<\/span><span class=\"p\">.<\/span><span class=\"nx\">getNames<\/span><span class=\"p\">().<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"na\">names<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[]<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ THEN - Assert result matches expected value<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">names<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toMatch<\/span><span class=\"p\">(<\/span> <span class=\"nx\">testNames<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Input Variables\n<\/h2>\n\n<p>As of Angular 5, Component inputs behave just like normal properties. We can test changes using the fixture change detection.<\/p>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">CounterComponent<\/span> <span class=\"k\">implements<\/span> <span class=\"nx\">OnChanges<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"p\">@<\/span><span class=\"nd\">Input<\/span><span class=\"p\">()<\/span> <span class=\"nx\">value<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">;<\/span>\n    <span class=\"nl\">changeCounter<\/span><span class=\"p\">:<\/span> <span class=\"kr\">number<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"nx\">ngOnChanges<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">changeCounter<\/span><span class=\"o\">++<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When the value input is changed, the changeCounter incrementsByOne<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Spy on the ngOnChanges lifecycle method and assert initial state.<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">ngOnChanges<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBeUndefined<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">changeCouner<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">0<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Set the input variable and call on fixture to detect changes.<\/span>\n    <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">First Value<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n    <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">detectChanges<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert that lifecycle method was called and state has been updated.<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">ngOnChanges<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">changeCounter<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Output Variables\n<\/h2>\n\n<p>Components often expose event emitters as output variables. We can spy on these emitters directly to avoid having to test asynchronous subscriptions.<\/p>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">EmittingComponent<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"p\">@<\/span><span class=\"nd\">Output<\/span><span class=\"p\">()<\/span> <span class=\"nx\">valueUpdated<\/span><span class=\"p\">:<\/span> <span class=\"nx\">EventEmitter<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">string<\/span><span class=\"o\">&gt;<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">EventEmitter<\/span><span class=\"o\">&lt;&gt;<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"nx\">updateValue<\/span><span class=\"p\">(<\/span> <span class=\"nx\">value<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">valueUpdated<\/span><span class=\"p\">.<\/span><span class=\"nx\">emit<\/span><span class=\"p\">(<\/span> <span class=\"nx\">value<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When the updateValue() method is called with a string, Then the valueUpdated output will emit with the string<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Create a test argument and spy on the emitting output variable.<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">value<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Test Value<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">valueUpdated<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">emit<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Call a method that will trigger the output variable to emit.<\/span>\n    <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">updateValue<\/span><span class=\"p\">(<\/span> <span class=\"nx\">value<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert that the output variable has emitted correctly with the test argument.<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">valueUpdated<\/span><span class=\"p\">.<\/span><span class=\"nx\">emit<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"nx\">value<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Application Events\n<\/h2>\n\n<p>Testing event fired by a global object or parent component can be done by simulating the event dispatch in a fakeAsync environment. We can use the <code>flush()<\/code> function to resolve all pending, asynchronous operations in a synchronous manner.<\/p>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">ListeningComponent<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nl\">focus<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"p\">@<\/span><span class=\"nd\">HostListener<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">window:focus-on-dashboard<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"dl\">'<\/span><span class=\"s1\">$event<\/span><span class=\"dl\">'<\/span><span class=\"p\">]<\/span> <span class=\"p\">)<\/span>\n    <span class=\"nx\">onFocusOnDashboard<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">focus<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">dashboard<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When the window dispatches a focus-on-dashboard event, Then the focus is set to dashboard<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">fakeAsync<\/span><span class=\"p\">(<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Prepare spy for callback and validate initial state.<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">onFocusOnDashboard<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">focus<\/span> <span class=\"p\">).<\/span><span class=\"nx\">not<\/span><span class=\"p\">.<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">dashboard<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Dispatch the event, resolve all pending, asynchronous operations and call fixture to detect changes.<\/span>\n    <span class=\"nb\">window<\/span><span class=\"p\">.<\/span><span class=\"nx\">dispatchEvent<\/span><span class=\"p\">(<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Event<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">focus-on-dashboard<\/span><span class=\"dl\">'<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">flush<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">fixture<\/span><span class=\"p\">.<\/span><span class=\"nx\">detectChanges<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Assert that callback was called and state has changed correctly.<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">onFocusOnDashboard<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalled<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">component<\/span><span class=\"p\">.<\/span><span class=\"nx\">focus<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">dashboard<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  Life Cycle Methods\n<\/h2>\n\n<p>There is no real reason to test a life cycle method. This would be testing the framework, which is beyond our responsability. Any logic required by a life cycle method should be encapsulated in a helper method. Test that instead. See Async Behavior for tests that require calling the <code>ngOnInit()<\/code> life cycle method.<\/p>\n\n\n\n\n<h2>\n  \n  \n  Mock Method Chains\n<\/h2>\n\n<p>We may occassionally need to mock a series of method calls in the form of a method chain. This can be achieved using the <code>spyOn<\/code> function.<\/p>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">DatabseService<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nl\">db<\/span><span class=\"p\">:<\/span> <span class=\"nx\">DatabaseAdapter<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"nx\">getAdultUsers<\/span><span class=\"p\">():<\/span> <span class=\"nx\">User<\/span><span class=\"p\">[]<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">users<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">filter<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">age &gt; 17<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">sort<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">age<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">DESC<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Test Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When getAdultUsers is called, Then return users above 17 years of age<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">inject<\/span><span class=\"p\">([<\/span><span class=\"nx\">DatabaseService<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">databaseService<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"c1\">\/\/ GIVEN - Mock the database adapter object and the chained methods<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">testUsers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span>\n        <span class=\"p\">{<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Bob Odenkirk<\/span><span class=\"dl\">'<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span> <span class=\"na\">id<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"na\">name<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Ralph Morty<\/span><span class=\"dl\">'<\/span> <span class=\"p\">}<\/span>\n    <span class=\"p\">];<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">db<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span> <span class=\"na\">get<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{},<\/span> <span class=\"na\">filter<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{},<\/span> <span class=\"na\">sort<\/span><span class=\"p\">:<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{}<\/span> <span class=\"p\">};<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">get<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">filter<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">spyOn<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">sort<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">and<\/span><span class=\"p\">.<\/span><span class=\"nx\">returnValue<\/span><span class=\"p\">(<\/span> <span class=\"nx\">testUsers<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">databaseService<\/span><span class=\"p\">.<\/span><span class=\"nx\">db<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">db<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"c1\">\/\/ WHEN - Test the method call<\/span>\n    <span class=\"kd\">const<\/span> <span class=\"nx\">users<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">databaseService<\/span><span class=\"p\">.<\/span><span class=\"nx\">getAdultUsers<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"c1\">\/\/ THEN - Test interaction with method chain<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">users<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"nx\">filter<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">age &gt; 17<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">db<\/span><span class=\"p\">.<\/span><span class=\"nx\">sort<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toHaveBeenCalledWith<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">age<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">DESC<\/span><span class=\"dl\">'<\/span> <span class=\"p\">);<\/span>\n    <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">users<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">testUsers<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n\n\n\n<h2>\n  \n  \n  HTTP Calls\n<\/h2>\n\n<p>Angular provides several utilities for intercepting and mocking http calls in the test suite. We should never perform a real, http call during tests. A few important objects:<\/p>\n\n<ul>\n<li>\n<strong>XHRBackend<\/strong>: Intercepts requests performed by <em>HTTP<\/em> or <em>HTTPClient<\/em>.<\/li>\n<li>\n<strong>MockBackend<\/strong>: Test API for configuring how XHRBackend will interact with intercepted requests.<\/li>\n<li>\n<strong>MockConnection<\/strong>: Test API for configuring individual, intercepted requests and response.<\/li>\n<\/ul>\n\n<h4>\n  \n  \n  Code to Test\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">class<\/span> <span class=\"nx\">SearchService<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"k\">private<\/span> <span class=\"nx\">url<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span> <span class=\"o\">=<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">http:\/\/localhost:3000\/search?query=<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"kd\">constructor<\/span><span class=\"p\">(<\/span> <span class=\"k\">private<\/span> <span class=\"nx\">http<\/span><span class=\"p\">:<\/span> <span class=\"nx\">Http<\/span> <span class=\"p\">)<\/span> <span class=\"p\">{}<\/span>\n\n    <span class=\"nx\">search<\/span><span class=\"p\">(<\/span> <span class=\"nx\">query<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span> <span class=\"p\">):<\/span> <span class=\"nx\">Observable<\/span><span class=\"o\">&lt;<\/span><span class=\"kr\">string<\/span><span class=\"p\">[]<\/span><span class=\"o\">&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">http<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">url<\/span> <span class=\"o\">+<\/span> <span class=\"nx\">query<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span> <span class=\"na\">withCredentials<\/span><span class=\"p\">:<\/span> <span class=\"kc\">true<\/span> <span class=\"p\">}<\/span> <span class=\"p\">).<\/span><span class=\"nx\">pipe<\/span><span class=\"p\">(<\/span>\n            <span class=\"nx\">catchError<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"na\">error<\/span><span class=\"p\">:<\/span> <span class=\"kr\">any<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">UtilService<\/span><span class=\"p\">.<\/span><span class=\"nx\">logError<\/span><span class=\"p\">(<\/span> <span class=\"nx\">error<\/span> <span class=\"p\">);<\/span>\n                <span class=\"k\">return<\/span> <span class=\"k\">of<\/span><span class=\"p\">(<\/span> <span class=\"p\">[]<\/span> <span class=\"p\">);<\/span>\n            <span class=\"p\">}<\/span> <span class=\"p\">)<\/span>\n        <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h4>\n  \n  \n  Text Example\n<\/h4>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"kd\">let<\/span> <span class=\"nx\">backend<\/span><span class=\"p\">:<\/span> <span class=\"nx\">MockBackend<\/span><span class=\"p\">;<\/span>\n<span class=\"kd\">let<\/span> <span class=\"nx\">lastConnection<\/span><span class=\"p\">:<\/span> <span class=\"nx\">MockConnection<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nx\">beforeEach<\/span><span class=\"p\">(<\/span> <span class=\"p\">()<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n    <span class=\"nx\">TestBed<\/span><span class=\"p\">.<\/span><span class=\"nx\">configureTestingModule<\/span><span class=\"p\">(<\/span> <span class=\"p\">{<\/span>\n        <span class=\"na\">imports<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"nx\">HttpModule<\/span><span class=\"p\">],<\/span>\n        <span class=\"na\">providers<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n            <span class=\"p\">{<\/span> <span class=\"na\">provide<\/span><span class=\"p\">:<\/span> <span class=\"nx\">XHRBackend<\/span><span class=\"p\">,<\/span> <span class=\"na\">useClass<\/span><span class=\"p\">:<\/span> <span class=\"nx\">MockBackend<\/span> <span class=\"p\">},<\/span>\n            <span class=\"nx\">SearchService<\/span>\n        <span class=\"p\">]<\/span>\n    <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n\n    <span class=\"nx\">backend<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">TestBed<\/span><span class=\"p\">.<\/span><span class=\"kd\">get<\/span><span class=\"p\">(<\/span><span class=\"nx\">XHRBackend<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"nx\">MockBackend<\/span><span class=\"p\">;<\/span>\n    <span class=\"nx\">backend<\/span><span class=\"p\">.<\/span><span class=\"nx\">connections<\/span><span class=\"p\">.<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"na\">connection<\/span><span class=\"p\">:<\/span> <span class=\"nx\">MockConnection<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">lastConnection<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">connection<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n\n<span class=\"nx\">it<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">When a search request is sent, Then receive an array of string search results.<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> \n    <span class=\"nx\">fakeAsync<\/span><span class=\"p\">(<\/span> <span class=\"nx\">inject<\/span><span class=\"p\">(<\/span> <span class=\"p\">[<\/span><span class=\"nx\">SearchService<\/span><span class=\"p\">],<\/span> <span class=\"p\">(<\/span> <span class=\"nx\">searchService<\/span><span class=\"p\">:<\/span> <span class=\"nx\">SearchService<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n\n        <span class=\"c1\">\/\/ GIVEN - Prepare mock search results in the form of a HTTP Response<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">expectedSearchResults<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span> <span class=\"p\">...<\/span> <span class=\"p\">];<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">mockJSON<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">JSON<\/span><span class=\"p\">.<\/span><span class=\"nx\">stringify<\/span><span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"na\">data<\/span><span class=\"p\">:<\/span> <span class=\"nx\">expectedSearchResults<\/span> <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">mockBody<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">ResponseOptions<\/span><span class=\"p\">(<\/span> <span class=\"p\">{<\/span> <span class=\"na\">body<\/span><span class=\"p\">:<\/span> <span class=\"nx\">mockJSON<\/span> <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n        <span class=\"kd\">const<\/span> <span class=\"nx\">mockResponse<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Response<\/span><span class=\"p\">(<\/span> <span class=\"nx\">mockBody<\/span> <span class=\"p\">);<\/span>\n\n        <span class=\"c1\">\/\/ WHEN - Perform the call and intercept the connection with a mock response.<\/span>\n        <span class=\"kd\">let<\/span> <span class=\"na\">receivedSearchResults<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[];<\/span>   \n        <span class=\"nx\">searchService<\/span><span class=\"p\">.<\/span><span class=\"nx\">search<\/span><span class=\"p\">(<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">reso<\/span><span class=\"dl\">'<\/span> <span class=\"p\">).<\/span><span class=\"nx\">subscribe<\/span><span class=\"p\">(<\/span> <span class=\"p\">(<\/span> <span class=\"na\">searchResults<\/span><span class=\"p\">:<\/span> <span class=\"kr\">string<\/span><span class=\"p\">[]<\/span> <span class=\"p\">)<\/span> <span class=\"o\">=&gt;<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">receivedSearchResults<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">searchResults<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">}<\/span> <span class=\"p\">);<\/span>\n        <span class=\"nx\">lastConnection<\/span><span class=\"p\">.<\/span><span class=\"nx\">mockRespond<\/span><span class=\"p\">(<\/span> <span class=\"nx\">mockResponse<\/span> <span class=\"p\">);<\/span>\n\n        <span class=\"c1\">\/\/ THEN - Complete the pending transaction and assert that the mock response<\/span>\n        <span class=\"c1\">\/\/ was received and processed correctly.<\/span>\n        <span class=\"nx\">flushMicrotasks<\/span><span class=\"p\">();<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">receivedSearchResults<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toBeDefined<\/span><span class=\"p\">();<\/span>\n        <span class=\"nx\">expect<\/span><span class=\"p\">(<\/span> <span class=\"nx\">receivedSearchResults<\/span> <span class=\"p\">).<\/span><span class=\"nx\">toEqual<\/span><span class=\"p\">(<\/span> <span class=\"nx\">expectedSearchResults<\/span> <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span> <span class=\"p\">)<\/span> <span class=\"p\">)<\/span>\n<span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n","category":["angular","javascript","testing","tdd"]}]}}