<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Angular Archives - Ronnie Schaniel</title>
	<atom:link href="https://ronnieschaniel.com/category/angular/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Blog</description>
	<lastBuildDate>Mon, 17 Oct 2022 05:44:36 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Why you should stop using boolean @Input in Angular</title>
		<link>https://ronnieschaniel.com/angular/why-you-should-stop-using-boolean-input-in-angular/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 08 Oct 2022 15:30:23 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=1645</guid>

					<description><![CDATA[<p>Four problematic cases with alternative.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/why-you-should-stop-using-boolean-input-in-angular/">Why you should stop using boolean @Input in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Or at least you should be using boolean @Inputs in Angular less often. Because when they are introduced in Angular components it often leads to problems. It is in most cases not extendable and causes unnecessary dependencies. In this article, I am presenting four examples where boolean Inputs are a problem, and I am showing a better alternative.</p>



<h2 class="wp-block-heading">#1 Boolean inputs are often unnecessary</h2>



<p>In this first problem case, an Angular boolean input is introduced into a component unnecessarily. The logic that depends on the boolean input could also be dependent on other data. Let&#8217;s see a simple example. In a <code>ProductComponent</code> there is a boolean @Input <code>showProductDescription</code>. As the name suggests, the variable is used to decide whether a description should be shown for a product.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export class ProductComponent {
  @Input()
  product: Product;

  @Input()
  showProductDescription: boolean;
}</code></pre>



<p>The value for this boolean input is calculated on the consumer side of the <code>ProductComponent</code>. Probably it looks like the following and is solely dependent on the product itself: <code>!!product.description</code>. So, it just checks on the presence of the description value on the product.</p>



<p>The component&#8217;s template consumes then the flag in a ngIf:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;article&gt;
  &lt;img [src]="'/assets/images/shop/' + product.image" /&gt;
  {{ product.name }} - {{ product.price | price }}

  &lt;p *ngIf="showProductDescription"&gt;
    {{ product.description }}
  &lt;/p&gt;
&lt;/article&gt;</code></pre>



<p>The above implementation comes with the following problems:</p>



<ul class="wp-block-list"><li>The <code>showProductDescription</code> is an additional input to the <code>ProductComponent</code> and makes its interface more complex.</li><li>If this <code>showProductDescription</code> is also needed further down the component hierarchy it needs to be passed multiple times alongside the product. This makes code hard to change.</li></ul>



<h3 class="wp-block-heading">The alternative</h3>



<p>We can just make the displaying of the paragraph dependent on the <code>description</code> field of the product.  Then we can get rid of <code>showProductDescription</code>. The ngIf is therefore updated and receives the argument <code>product.description</code>.</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;article&gt;
  &lt;img [src]="'/assets/images/shop/' + product.image" /&gt;
  {{ product.name }} - {{ product.price | price }}

  &lt;p *ngIf="product.description"&gt;
    {{ product.description }}
  &lt;/p&gt;
&lt;/article&gt;</code></pre>



<p>This first example was an easy one. I guess most Angular developers do not make such mistakes. However, I have seen such cases already and wanted to point them out too. The next case will be more interesting.</p>



<h2 class="wp-block-heading">#2 Boolean inputs are hard to extend</h2>



<p>As we know a boolean can only have two values (or four if you count null/undefined). When we want to extend by a third variant, we are restricted because of the type. Let&#8217;s see an example. For that, we stay with the theme of products. But this time we deal with product availability:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export class ProductAvailabilityComponent {
  @Input() availability: boolean;
}</code></pre>



<p>We have a <code>ProductAvailabilityComponent</code> that shows if the product is available or not. The corresponding template might look like that:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;span *ngIf="availability; else notAvailable"&gt;Product is available&lt;/span&gt;

&lt;ng-template #notAvailable&gt;
  &lt;span&gt;Unfortunately not available&lt;/span&gt;
&lt;/ng-template&gt;</code></pre>



<p>And availability is always a boolean, isn&#8217;t it? Well, it turns out that our products can be unavailable in the online shop, but could be available for preorder. And we want to inform the customers about that fact. So, now we have three mutually exclusive options: available, available for preorder, and unavailable. But availability is not easily extendable because it&#8217;s a boolean. Therefore we add another flag:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export class ProductAvailabilityComponent {
  @Input() availability: boolean;
  @Input() preorderPossible: boolean;
}</code></pre>



<p>Consequently, our template becomes something like this:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;span *ngIf="availability; else notAvailable">Product is available&lt;/span>

&lt;ng-template #notAvailable>
  &lt;span *ngIf="preorderPossible; else reallyNotAvailable">
    Not available yet. Preorder possible.
  &lt;/span>

  &lt;ng-template #reallyNotAvailable>
    &lt;span>Unfortunately not available&lt;/span>
  &lt;/ng-template>
&lt;/ng-template></code></pre>



<p>This doesn&#8217;t look too good. The template is already a bit bloated and the ngIf-else logic is not ideal. Especially if we would like to add a fourth possible value in the future it&#8217;s not clear at first sight how to do it. But there is for sure a cleaner way.</p>



<h3 class="wp-block-heading">The alternative</h3>



<p>We need to define the availability as an extendable data type. In this case, we choose a union type. Availability changes from boolean to:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export type Availability = 'AVAILABLE' | 'NOT_AVAILABLE' | 'PREORDER_POSSIBLE';</code></pre>



<p>And our component and template can be simplified to the following:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export class ProductAvailabilityComponent {
  @Input() availability: Availability;
}</code></pre>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;div [ngSwitch]="availability">
  &lt;span *ngSwitchCase="'AVAILABLE'">Product available&lt;/span>
  &lt;span *ngSwitchCase="'PREORDER_POSSIBLE'">Not available yet. Preorder possible.&lt;/span>
  &lt;span *ngSwitchCase="'NOT_AVAILABLE'">Unfortunately not available&lt;/span>
&lt;/div></code></pre>



<p>This is more extendable and we can even add a fourth value without a problem.</p>



<h2 class="wp-block-heading">#3 Boolean inputs cause breaking changes</h2>



<p>This is related to point #2 above. The consumer of the <code>ProductAvailabilityComponent</code> relied on a boolean and now would have to pass the two booleans <code>availability</code> and <code>preorderPossible</code>. This is a breaking change in most situations. Would the data type have been the Availability union type from the beginning then the consumer can adapt more easily.</p>



<p>This becomes even clearer when the <code>ProductAvailabilityComponent</code> is deep down a component tree. The type potentially has to be adapted in the whole chain from <code>Store, StoreFacade,  ProductPageComponent, ProductComponent, ProductDetailComponent to ProductAvailabilityComponent</code>. Depending on the setup and where the product availability is determined this could result in changes in a lot of files.</p>



<p>The alternative is, as mentioned, to use a type that allows adding further values. Also moving from the boolean to the union type is quite some change. You should go with the more extendable type from the beginning if you can&#8217;t rule out an extension to the values.</p>



<h2 class="wp-block-heading">#4 Boolean inputs bloat your templates</h2>



<p>Here we are considering again the example from point #2 where we had the two boolean flags and ended up with the following template:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;span *ngIf="availability; else notAvailable">Product is available&lt;/span>

&lt;ng-template #notAvailable>
  &lt;span *ngIf="preorderPossible; else reallyNotAvailable">
    Not available yet. Preorder possible.
  &lt;/span>

  &lt;ng-template #reallyNotAvailable>
    &lt;span>Unfortunately not available&lt;/span>
  &lt;/ng-template>
&lt;/ng-template></code></pre>



<p>This looks terrible. It is hard to read and hard to extend. Especially if all options are mutually exclusive there is a cleaner way where everything is on one level.</p>



<h3 class="wp-block-heading">The alternative</h3>



<p>We have already seen a better way and it looked like that using a ngSwitch:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;div [ngSwitch]="availability">
  &lt;span *ngSwitchCase="'AVAILABLE'">Product available&lt;/span>
  &lt;span *ngSwitchCase="'PREORDER_POSSIBLE'">Not available yet. Preorder possible.&lt;/span>
  &lt;span *ngSwitchCase="'NOT_AVAILABLE'">Unfortunately not available&lt;/span>
&lt;/div></code></pre>



<p>All the cases are handled the same way which brings clarity and consistency. But we can even simplify more in certain situations when it is just about showing the text:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;span&gt;{{ ('PRODUCT_AVAILABILITY.' + availability ) | translate }}&lt;/span&gt;</code></pre>



<p>The translation keys can be directly constructed based on the availability union type value. This leaves us with a one-liner in the template compared to about 9 lines before. </p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Importantly, <strong>you should not stop entirely using boolean inputs in Angular</strong>. But you should think carefully about the above scenarios when introducing one. In a lot of cases, your code becomes simpler and better maintainable when you choose alternative types.<br>If the boolean input really maps to something that is not extendable and completely boolean it might be okay.</p>



<p>Another interesting article on boolean parameters in general, is <em><a href="https://understandlegacycode.com/blog/what-is-wrong-with-boolean-parameters/" target="_blank" rel="noreferrer noopener">What is wrong with boolean parameters?</a></em> They suggest splitting methods that have a boolean parameter. Related to that, you could also think of splitting into two different components for certain cases where you started with a boolean input for a single component.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/why-you-should-stop-using-boolean-input-in-angular/">Why you should stop using boolean @Input in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Angular Schematics &#8211; Add Method to an HTTP Service</title>
		<link>https://ronnieschaniel.com/angular/angular-schematics-add-method-to-an-http-service/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 27 Nov 2021 12:58:47 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=957</guid>

					<description><![CDATA[<p>How to add a POST call method via CLI.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/angular-schematics-add-method-to-an-http-service/">Angular Schematics &#8211; Add Method to an HTTP Service</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="592" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-1024x592.png" alt="Angular Schematic to add http call" class="wp-image-959" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-1024x592.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-300x174.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-768x444.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-1536x889.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_add_http_call-2048x1185.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We saw how to generate a basic Angular http service with a schematic in the previous <a href="https://ronnieschaniel.com/angular/angular-schematics-generate-http-services/">post</a>. What if we want to easily add a new call to an existing service the same way? Just using the basic Angular schematic for http services would replace the file. Then we probably loose some other methods or imports. </p>



<p>This is why we will explore in this article how to update existing files. Specifically we will add a new method to an existing service class. </p>



<p>But first we need to understand what an Abstract Syntax Tree is.</p>



<h2 class="wp-block-heading">AST Basics</h2>



<p>An Abstract Syntax Tree (AST) describes a programming language&#8217;s source file. As the name suggests, constructs like classes or methods are represented as a tree. Let&#8217;s check the AST of the following simple TypeScript class to understand it:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export class Service {
    public call(): Observable&lt;Response&gt; {
        return of(null);
    }
}</code></pre>



<p>The tree behind this source &#8220;file&#8221; looks as follows:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="549" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example-1024x549.png" alt="" class="wp-image-961" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example-1024x549.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example-300x161.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example-768x412.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example-1536x824.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2021/11/ast_typescript_example.png 1916w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Source: <a href="https://ts-ast-viewer.com" target="_blank" rel="noreferrer noopener">https://ts-ast-viewer.com</a></figcaption></figure>



<p>On the left hand side, we see the high-level view. There is a <em>ClassDeclaration</em> with an <em>Identifier</em> as child. Another child of the <em>ClassDeclaration</em> is of course the <em>MethodDeclaration</em>. Since the class <em>Service</em> has a method <em>call</em> there is a direct parent-child relation between those two language constructs. All those children (and also the SourceFile itself) are <em>Nodes</em>.</p>



<p>Furthermore, as we can see on the right hand side of above picture, the <em>Identifier</em> is another interesting child of the <em>ClassDeclaration</em>. The <em>Identifier</em> contains the name of the class in the <em>escapedText</em>, here &#8220;Service&#8221;. So, basically the AST gives you the access to everything in the code in a structured way.</p>



<p>How do we read a tree programmatically? We have to traverse it and check the attributes of the nodes to find a node we&#8217;re interested in.</p>



<h2 class="wp-block-heading">Reading an Existing File</h2>



<p>Our goal is to add a method for an HTTP call into an existing Angular http service. As an example we take the following service that already contains two methods to load customers by GET. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class CustomerHttpService {
  private readonly baseUrl = '';

  constructor(private http: HttpClient) {
  }

  public getAll(): Observable&lt;Customer[]&gt; {
    return this.http.get&lt;Customer[]&gt;(this.baseUrl);
  }

  public getById(id: number): Observable&lt;Customer&gt; {
    return this.http.get&lt;Customer&gt;(`${this.baseUrl}/${id}`);
  }
}</code></pre>



<p>If we now want to add a method to the <em>CustomerHttpService</em> class we need to know a few things:</p>



<ul class="wp-block-list"><li>What is the source text of the <em>customer.http-service.ts</em> file in an Angular project?</li><li>Where is our existing Service class in the tree, i.e. <em>CustomerHttpService</em>?</li><li>What is the last position in the file for a certain method within <em>CustomerHttpService</em>, e.g. what is the position of the closing } for the <em>getById</em> method?</li></ul>



<h3 class="wp-block-heading">Basic Angular add http call schematic function</h3>



<p>The high-level view of our schematic function is shown in the code below.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export function addHttpCall(_options: any): Rule {
    return (tree: Tree, _context: SchematicContext) =&gt; {
        const workspaceConfigBuffer = tree.read('angular.json');
        if (!workspaceConfigBuffer) {
            throw new SchematicsException('Not an Angular CLI workspace! The angular.json file is missing');
        }
        const methodName = 'getById';

        // steps 1 to 5:
        const filePath = determineTargetFilePath(workspaceConfigBuffer, _options);
        const nodes: ts.Node[] = getASTFromSourceFilePath(tree, filePath);
        const lastPositionOfMethod = getLastPositionOfMethod(nodes, methodName);
        const methodAddChange = createInsertChange(filePath, lastPositionOfMethod!);
        updateTree(tree, filePath, methodAddChange);

        return tree;
    };
}</code></pre>



<p>To get some helper methods we install a schematics package:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm i @schematics/angular</code></pre>



<p>Please also install @angular-devkit/schematics and @angular-devkit/core if not yet done.</p>



<p>We want to keep things simple at the moment. So, we skip a few inputs for the schematic, like the HTTP method or the <em>placeMethodAfterExistingMethodNamed</em>. So, the schematic can be called as follows:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng generate add-http-call shared/services/Customer</code></pre>



<p>We have divided the overall functionality into 5 steps:</p>



<ol class="wp-block-list"><li>Determining the file path in the Angular project dependent on the input (shared/services/Customer is mapped to the correct path in the project)</li><li>Having the file path we can read the existing file, create a temporary source file and create the AST for that file</li><li>In the AST we search for a method after which we want to position our new method. In this example I simplified it by hardcoding &#8216;getById&#8217;. So, we will return the last position of the <em>getByI</em>d method.</li><li>Based on the position and file path we can create an <em>InsertChange </em>object to modify the actual file. In the <em>InsertChange</em> we hardcode the method to a <em>create()</em> method using POST.</li><li>Finally the tree is updated with the <em>InsertChange</em> for the new method</li></ol>



<p>These 5 steps are described in the rest of this section.</p>



<h3 class="wp-block-heading">1. Determine target file path</h3>



<p>We use the workspace config together with the options to find the file path:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function  determineTargetFilePath(workspaceConfigBuffer: Buffer, _options: any): string {
    const workspaceConfig = JSON.parse(workspaceConfigBuffer.toString());
    const projectName = _options.project || workspaceConfig.defaultProject;
    const project = workspaceConfig.projects[projectName];

    const defaultProjectPath = buildDefaultPath(project);
    const parsedPath = parseName(defaultProjectPath, _options.name);
    const {name, path} = parsedPath;

    const filePath = `${path}/${name.toLowerCase()}.http-service.ts`;
    return filePath;
}</code></pre>



<p>This is somewhat basic code for a lot of schematics. After reading the angular.json config we create the file name. In our case we assume that http service files end with <em>http-service.ts</em>. Like that we find the <em>customer.http-service.ts</em>.</p>



<h3 class="wp-block-heading">2. Retrieve source code and create the AST</h3>



<p>Now it becomes interesting. We create the AST based on the file path:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function getASTFromSourceFilePath(tree: Tree, filePath: string): ts.Node[] {
    const content = tree.read(filePath);
    if (!content) {
        throw new SchematicsException(`File ${filePath} does not exist.`);
    }

    const sourceText = content.toString('utf-8');
    const sourceFile = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
    const nodes = getSourceNodes(sourceFile);
    return nodes;
}</code></pre>



<p>The schematic&#8217;s <em>Tree </em>helps us to read the file content. Based on the <em>sourceText</em> we can then create a TypeScript file. Now we are using the <em>getSourceNodes</em> method from @schematics/angular/utility/ast-utils to get the AST of this source file.</p>



<h3 class="wp-block-heading">3. Find the last position of an existing method</h3>



<p>We read a file and got the AST of that file. Now we need to work with this AST. That means we need to traverse the tree and find relevant nodes. </p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function getLastPositionOfMethod(nodes: ts.Node[], methodName: string) {
    const serviceClassNode = findServiceClassNode(nodes[0]);
    if (!serviceClassNode) {
        throw new SchematicsException(`Did not find a service class node`);
    }

    const methodNode = findMethodNode(serviceClassNode, methodName);
    if (!methodNode) {
        throw new SchematicsException(`Did not find the ${methodName}`);
    }

    const lastPositionOfMethod = getLastPosition(methodNode);
    return lastPositionOfMethod;
}</code></pre>



<p>In simple words we are finding the last position of the &#8216;getById&#8217; method by:</p>



<ul class="wp-block-list"><li>traversing through the nodes to find the service class node (helper method <em>findServiceClassNode</em>)</li><li>starting from this service class node to find the method&#8217;s node (helper method <em>findMethodNode</em>)</li><li>examining the <em>methodNode</em> and returning the last position of it in the file (helper method <em>getLastPosition)</em></li></ul>



<p>The helper methods are available here <a href="https://github.com/rschaniel/ng-blocks-factory/blob/main/src/add-http-call/ast-utils/ast-utils.ts" target="_blank" rel="noreferrer noopener">https://github.com/rschaniel/ng-blocks-factory/blob/main/src/add-http-call/ast-utils/ast-utils.ts</a> if you are interested in the details. Probably there are more efficient and safer ways to traverse the tree. Anyway the created utils were good enough to get a basic example running and should be optimised later.</p>



<h3 class="wp-block-heading">4. Generate the new method</h3>



<p>We have found the last position of an existing method. This allows us to create a change for the file because now we know where to insert the new code.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function createInsertChange(filePath: string, lastPositionOfMethod: number) {
    const methodToAdd = 'public create(customer: Customer): Observable&lt;Customer&gt; {\n' +
        '    return this.http.post&lt;Customer&gt;(this.baseUrl, customer);\n' +
        '  }';
    const methodAddChange = new InsertChange(filePath, lastPositionOfMethod! + 1, methodToAdd);
    return methodAddChange;
}
</code></pre>



<p>First we create the text for the new method as simple string. The <em>methodToAdd</em> is currently hardcoded to keep things simple. Based on this String we can then create an <em>InsertChange</em> by specifying also the filePath and the position where to insert. In our case we are just inserting one position after the } of our <em>getById.</em></p>



<h3 class="wp-block-heading">5. Insert change into an Existing File</h3>



<p>Lastly, we can insert the change into our tree. This is what happens in the <em>updateTree</em> method.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function updateTree(tree: Tree, filePath: string, methodAddChange: InsertChange) {
    const declarationRecorder = tree.beginUpdate(filePath);
    declarationRecorder.insertLeft(methodAddChange.pos, methodAddChange.toAdd);
    tree.commitUpdate(declarationRecorder);
}</code></pre>



<p>We start kind of a transaction and add our change to that transaction before committing the update. This transaction is especially helpful of course in case of multiple changes that could go wrong. In the last step the tree is returned from the schematics method and our service file is updated.</p>



<h2 class="wp-block-heading">Using the add-http-call Angular Schematic to Update a Service</h2>



<p>After building the schematic project we can use it in an Angular project:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng generate ../ng-blocks-factory/src/collection.json:add-http-call shared/services/Customer</code></pre>



<p>If all went well we should see a success message in our terminal:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="43" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/add_http_call_schematic_success-1024x43.png" alt="" class="wp-image-978" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/add_http_call_schematic_success-1024x43.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/11/add_http_call_schematic_success-300x12.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/add_http_call_schematic_success-768x32.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/11/add_http_call_schematic_success.png 1108w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Our <em>customer.http-service.ts</em> file&#8217;s size increased by 696 bytes and if we open it we can find a new method:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="974" height="612" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_service_with_new_method_from_schematics.png" alt="" class="wp-image-979" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_service_with_new_method_from_schematics.png 974w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_service_with_new_method_from_schematics-300x189.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_service_with_new_method_from_schematics-768x483.png 768w" sizes="(max-width: 974px) 100vw, 974px" /></figure>



<p>Correcting the formatting should be easy then.</p>



<h2 class="wp-block-heading">Summary and Limitations</h2>



<p>You could see above how to do basic file updates with Angular schematics. In our case it was just adding a method. However, the same principles can be reused to change code in other ways. Nevertheless the described approach has some limitations. Hence, the next steps should be:</p>



<ul class="wp-block-list"><li>Format the code after inserting the change into a file. Probably it&#8217;s a good idea to reuse existing format tools, e.g. prettier</li><li>Having a more robust and user friendly AST util or find an npm package that already offers such functionality</li><li>The added method is based on some assumptions, e.g. the <em>HttpClient</em> field is named <em>http</em>. This could also be retrieved dynamically from the existing file by checking the constructor AST.</li><li>It is not checked if the method already exists in the file or a method with the same name.</li></ul>



<p>Please find the code for this Angular add-http-call schematic on <a href="https://github.com/rschaniel/ng-blocks-factory/tree/main/src/add-http-call" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>



<p>Finally the question: is it worth it? All this complicated tree traversal just to add three lines of code? In this basic example, I&#8217;d say no. But what if there is more code involved for such updates? Generating mocks, generating io-ts types, updating related NgRx files, etc.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/angular-schematics-add-method-to-an-http-service/">Angular Schematics &#8211; Add Method to an HTTP Service</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Angular Schematics &#8211; Generate an Http Service</title>
		<link>https://ronnieschaniel.com/angular/angular-schematics-generate-http-services/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Thu, 11 Nov 2021 20:45:00 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=903</guid>

					<description><![CDATA[<p>Create a custom schematic to generate http services.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/angular-schematics-generate-http-services/">Angular Schematics &#8211; Generate an Http Service</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="596" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-1024x596.png" alt="" class="wp-image-947" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-1024x596.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-300x175.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-768x447.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-1536x895.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_http_service_dark-2048x1193.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>We all know about the value of <em>ng g c HeaderComponent</em>. The powerful angular schematics are part of basically every Angular developer&#8217;s repertoire. But still we often tend to create those components, services, pipes, etc. and then always add the same code to the generated files:</p>



<ul class="wp-block-list"><li>We generate a dumb component and add the <em>ChangeDetectionStrategy.OnPush</em> manually</li><li>A container component is generated but the store field is added manually to the constructor and the ngOnDestroy to unsubscribe from Observables too</li><li>The angular CLI generates a service for us but when we want to add an HTTP request to that service manual work is involved</li></ul>



<p>In this article we want to tackle the last point of the list above: using angular schematics to generate HTTP services. Generally, there are two main approaches:</p>



<ul class="wp-block-list"><li>Extending the schematic for services used in the Angular CLI</li><li>Creating a new schematic on our own</li></ul>



<p>Because we don&#8217;t really need much of what is generated in case of a normal service we go for the second option. If we&#8217;re interested in spec file generation or want to keep much of what is generated, the first option would be more fitting.</p>



<h2 class="wp-block-heading">Basic Setup for Angular Schematics</h2>



<p>Angular schematics should be hermetic and standalone. Therefore we will create a separate project where our schematics are developed. Later this project can be consumed as a dependency in those projects that want to generate http services.</p>



<p>To get started we install the angular-devkit <a href="https://www.npmjs.com/package/@angular-devkit/schematics-cli" target="_blank" rel="noreferrer noopener">schematics-cli</a> globally.</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm i -g @angular-devkit/schematics-cli</code></pre>



<p>We want to generate a general angular building blocks schematic project with the following command:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">schematics blank --name=ng-blocks-factory</code></pre>



<p>Now we&#8217;ve got a blank project where we can develop our schematics:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_blank_project-1.png" alt="" class="wp-image-915" width="395" height="338" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_blank_project-1.png 698w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_blank_project-1-300x256.png 300w" sizes="(max-width: 395px) 100vw, 395px" /></figure>



<p>Most interesting for us are the following two files:</p>



<ul class="wp-block-list"><li><em>collection.json</em> defines all the schematics available </li><li><em>ng-blocks-factory/index.ts</em> is the main file for our first schematic</li></ul>



<p>We will rename a bit. The <em>ng-blocks-factory</em> folder inside <em>src </em>is changed to<em> http-service</em> to better indicate what the first schematic is about (don&#8217;t forget to rename inside the <em>collection.json</em> file too).</p>



<p>In the project we install another dependency that will give us some useful methods when working with schematics:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm i --save-dev @schematics/angular</code></pre>



<p>So far so good. We have a project and a more or less empty schematic.</p>



<h2 class="wp-block-heading">Define the Angular schematics input parameters for the http service</h2>



<p>In our use case a developer wants to create an HTTP service. Let&#8217;s think a moment about the basic inputs. I guess we can start with a name and base url. If we follow REST principles these two arguments should already suffice to generate the needed methods in the http service.</p>



<p>Hence, we create the following <em>schema.json</em> for our http-service schematic. This <em>schema.json</em> defines the inputs.</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "$schema": "http://json-schema.org/schema",
  "$id": "HttpServiceSchema",
  "type": "object",
  "properties": {
    "path": {
      "type": "string",
      "format": "path",
      "visible": false
    },
    "name": {
      "type": "string",
      "$default": {
        "$source": "argv",
        "index": 0
      }
    },
    "url": {
      "type": "string",
      "$default": {
        "$source": "argv",
        "index": 1
      }
    }
  },
  "required": [
    "name",
    "url"
  ]
}</code></pre>



<p>The file should be located in the <em>http-service</em> folder. Alongside <em>url</em> and <em>name</em>, we&#8217;ve also got a<em> path</em> input parameter. This path points to the location where the service should actually be created inside a project.</p>



<p>Afterwards we also need to update our <em>collection.json</em> to include the <em>schema.json</em> of the <em>http-service</em> schematic. We&#8217;re also updating the function name in the <em>index.ts</em> file. This function name is used to reference the <em>factory</em> in the <em>schema.json</em> (<em>httpService</em> in our case after #):</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
  "schematics": {
    "http-service": {
      "description": "Generate http services",
      "factory": "./http-service/index#httpService",
      "schema": "./http-service/schema.json"
    }
  }
}</code></pre>



<h2 class="wp-block-heading">Implementing the factory function</h2>



<p>The <em>index.ts</em> contains the factory function used to create the files in our schematic. As a parameter it receives the options passed by the user (and defined in the <em>schema.json</em>). The basic version should look similar to that below.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';

export function httpService(_options: any): Rule {
    return (tree: Tree, _context: SchematicContext) =&gt; {
        return tree;
    };
}</code></pre>



<p>We extend that file by the following parts:</p>



<ul class="wp-block-list"><li>We first check if we&#8217;re in an Angular CLI workspace. If so, we read the workspace config, i.e. <em>angular.json</em></li><li>The options name and path are cleaned up and the path constructed based on the passed project (or default project).</li><li>The template sources are defined. They point to a files folder where our templates will be added later. In the template function we provide the <em>options</em> alongside the functions <em>classify</em> and <em>dasherize</em>. This ensures that those values and functions are available in our template.</li></ul>



<p>This should be the result:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">export function httpService(_options: any): Rule {
    return (tree: Tree, _context: SchematicContext) =&gt; {
        const workspaceConfigBuffer = tree.read('angular.json');
        if (!workspaceConfigBuffer) {
            throw new SchematicsException('Not an Angular CLI workspace! The angular.json file is missing');
        }

        const workspaceConfig = JSON.parse(workspaceConfigBuffer.toString());
        const projectName = _options.project || workspaceConfig.defaultProject;
        const project = workspaceConfig.projects[projectName];

        const defaultProjectPath = buildDefaultPath(project);
        const parsedPath = parseName(defaultProjectPath, _options.name);
        const {name, path} = parsedPath;

        const templateSource = apply(
            url('./files'),
            [
                template({
                    ..._options,
                    classify: strings.classify,
                    dasherize: strings.dasherize,
                    name,
                }),
                move(path),
            ],
        );

        return mergeWith(templateSource)(tree, _context)
    };
}
</code></pre>



<p>The @schematics/angular utility method <em>buildDefaultPath </em>didn&#8217;t really work in my case and threw an error (reg. <em>projectType</em> property). That&#8217;s why I implemented the method myself as follows:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">function buildDefaultPath(project: any) {
    const root = project.sourceRoot ? `/${project.sourceRoot}/` : `/${project.root}/src/`;
    const projectDirName = project['projectType'] === 'application' ? 'app' : 'lib';
    return `${root}${projectDirName}`;
}</code></pre>



<p>This is our index.ts file. Next we can create the template file for our service.</p>



<h2 class="wp-block-heading">Creating the Template for our Http Service</h2>



<p>Templates in schematics are used as a base for the generated files. For our service we create a file named __<em>name@dasherize__.http-service.ts</em> in our <em>http-service/files</em> folder. The <em>__name__</em> part refers to the name option passed to the templates in the <em>index.ts</em> file. To have a nice name we use<em> @dasherize</em> to format, e.g. <em>ShoppingCart</em> to <em>shopping-cart</em>. Because in the end we want to have dashes in our file names.</p>



<p>The content of the file will look similar to normal Angular service files, but the option values are included by using the &lt;%= %&gt; syntax.</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root',
})
export class &lt;%= classify(name) %&gt;HttpService {
    private readonly baseUrl = '&lt;%= path %&gt;';

    constructor(private http: HttpClient) {}

    public getAll(): Observable&lt;&lt;%= name %&gt;[]&gt; {
        return this.http.get&lt;&lt;%= name %&gt;[]&gt;(this.baseUrl);
    }

    public getById(id: number): Observable&lt;&lt;%= name %&gt;&gt; {
        return this.http.get&lt;&lt;%= name %&gt;&gt;(`${this.baseUrl}/${id}`);
    }
}

export interface &lt;%= classify(name) %&gt; {
    id: number;
    // other properties
}</code></pre>



<p>As a start we are adding two GET calls to load either all resources or a specific resource identified through its ID. So, this template is created based on the following assumptions taking <em>Customer</em> as an example.</p>



<ul class="wp-block-list"><li>All customers are available under the base url defined by the path, e.g. /api/v1/customers</li><li>A specific customer is exposed under /api/v1/customers/&lt;ID&gt;</li><li>The returned object&#8217;s type is Customer</li></ul>



<p>To have valid code we define the interface for the response type inside the http service file. In the end that should probably be moved to a separate file. </p>



<p>After the factory function we now also have our template ready and can start to test our schematic.</p>



<h2 class="wp-block-heading">Test the Schematic in an Angular Project</h2>



<p>To test the schematic we first have to build it:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm run build</code></pre>



<p>Afterwards we can link it locally from an Angular Project. This assumes that your Angular project is on the same folder level as your <em>ng-blocks-factory</em> schematic project.</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm i --save-dev ../ng-blocks-factory</code></pre>



<p>The schematic project is installed and we can now execute the schematic:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng generate ng-blocks-factory:http-service Customer /api/v1/customer</code></pre>



<p>We could also skip the installing and just execute the schematic by specifying the path to the collection as well as adding the schematic name after the colon:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng generate ../ng-blocks-factory/src/collection.json:http-service shared/services/Customer /api/v1/customer </code></pre>



<p>This generates an http service for us:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="73" src="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_generation-1-1024x73.png" alt="" class="wp-image-931" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_generation-1-1024x73.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_generation-1-300x22.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_generation-1-768x55.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/11/angular_schematics_generation-1.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root',
})
export class CustomerHttpService {
    private readonly baseUrl = '';

    constructor(private http: HttpClient) {}

    public getAll(): Observable&lt;Customer[]&gt; {
        return this.http.get&lt;Customer[]&gt;(this.baseUrl);
    }

    public getById(id: number): Observable&lt;Customer&gt; {
        return this.http.get&lt;Customer&gt;(`${this.baseUrl}/${id}`);
    }
}

export interface Customer {
    id: number;
    // other properties
}</code></pre>



<p>We&#8217;ve got our service generated. So, in the future we can just use a simple command instead of copying an existing services or generating a normal service and adding all the http part.</p>



<p>Of course you should probably build and publish your schematic to have an easy integration into any project. Finally, you could also add POST, PUT, PATCH and DELETE methods to your template.</p>



<p>The source are available on <a href="https://github.com/rschaniel/ng-blocks-factory" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/angular-schematics-generate-http-services/">Angular Schematics &#8211; Generate an Http Service</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Webpack Module Federation in Angular</title>
		<link>https://ronnieschaniel.com/angular/webpack-module-federation-in-angular/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Thu, 29 Apr 2021 16:08:40 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=414</guid>

					<description><![CDATA[<p>A short tutorial and comparison with traditional approaches for Angular microfrontends.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/webpack-module-federation-in-angular/">Webpack Module Federation in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The implementation and especially integration of microfrontends in Angular is not that satisfying. This changes with Webpack v5 where <a href="https://webpack.js.org/concepts/module-federation/" target="_blank" rel="noreferrer noopener">module federation</a> is introduced.</p>



<p>Previously Webpack wanted to know all dependencies at compile time. With module federation dependencies can be resolved at run time. This allows us to deploy microfrontends independently while having a smooth integration. Despite all that hype and the technical possibilities, we should be careful. It is vital to think about the scenarios where module federation usage makes sense. </p>



<p>Let&#8217;s go through an example based on our <a href="https://github.com/rschaniel/angular_ecommerce_playground" target="_blank" rel="noreferrer noopener">eCommerce Playground</a> Angular app. In this context we compare module federation to approaches using default Angular modules and additional Angular applications running separately.</p>



<h2 class="wp-block-heading">Our Goal: Adding an Overview of Orders</h2>



<p>Our application currently looks like this:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="753" src="https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview-1024x753.png" alt="Screenshot of an eCommerce Demo application showing products and a My Orders link in the header." class="wp-image-415" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview-1024x753.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview-300x220.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview-768x564.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview-1536x1129.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2021/04/webpack_module_federation_application_overview.png 1728w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>It&#8217;s an online shop with e.g. product list, search box and navigation bar at the bottom. Our customers want to have an overview of their orders. That&#8217;s why we plan to integrate an orders overview page and link it in the header behind &#8220;My Orders&#8221;.</p>



<h2 class="wp-block-heading">Different Variants for the Solution</h2>



<p>There are different variants how to integrate such an orders overview. We will explore 3 different ones. In this context the &#8220;main&#8221; app is the eCommerce application and &#8220;orders&#8221; the orders overview.</p>



<h3 class="wp-block-heading">1) Integrate as Standard Angular Module</h3>



<p>The most obvious solution is just to create a separate Angular Module and lazy load it through the router. This gives you the following advantages:</p>



<ul class="list-none wp-block-list"><li>🧩 Smooth integration and lazy loading</li><li>🖇 Easy code sharing between main and orders</li></ul>



<p>But this approach also comes with some drawbacks:</p>



<ul class="list-none wp-block-list"><li>⏳ Main app build takes longer</li><li>📦 No separate deployments</li><li>🖇 More tightly coupled</li></ul>



<h3 class="wp-block-heading">2) Use a Second Angular App on a Specific URL</h3>



<p>We can build a separate Angular app for the orders overview and just deploy it under the link behind &#8220;My Orders&#8221;. This gives us the following:</p>



<ul class="list-none wp-block-list"><li>⏳ Lower build time because separated</li><li>📦 Standalone deployment possible</li></ul>



<p>But it comes with disadvantages:</p>



<ul class="list-none wp-block-list"><li>🧩 The integration is not smooth</li><li>⏱ Shared dependencies downloaded twice</li></ul>



<h3 class="wp-block-heading">3) Integrate by Using Module Federation</h3>



<p>Finally, we are having a look at the new possibility. Webpack module federation allows us to integrate the orders overview like a module but still having it as a separate application. We walk through a short how-to for adding module federation and then come to the evaluation.</p>



<h4 class="wp-block-heading">Setup webpack version 5</h4>



<p>We need webpack version 5 to make use of module federation. First, we want to switch to yarn as package manager:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng config cli.packageManager yarn</code></pre>



<p>When we use yarn instead of npm, the resolutions section in the package.json forces our dependencies, e.g. the Angular CLI, to use a certain webpack version we specify. So, we can enable webpack 5 in our package.json:</p>



<pre class="wp-block-code"><code lang="json" class="language-json">"resolutions": {
    "webpack": "^5.0.0"
},</code></pre>



<p>Finally run yarn install to get all the dependencies considering webpack 5:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">yarn install</code></pre>



<h4 class="wp-block-heading">Create a project in the workspace</h4>



<p>We assume you are having a <a href="https://nx.dev/" target="_blank" rel="noreferrer noopener">nx</a> workspace. With the following command we create a second project in that workspace named &#8220;orders&#8221;:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">nx generate @nrwl/angular:app orders</code></pre>



<p>There we add <em>OrderModule</em> with a component that shows the orders. Nothing fancy and nothing worth showing. </p>



<h4 class="wp-block-heading">Adding module federation</h4>



<p>We need some customisation for the Angular CLI to change the webpack behaviour. That&#8217;s why we install and use <a href="https://www.npmjs.com/package/@angular-architects/module-federation" target="_blank" rel="noreferrer noopener">@angular-architects/module-federation</a> (thanks to Manfred Steyer). Let&#8217;s configure module federation for our two projects with the following commands:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng add @angular-architects/module-federation --project main --port 4200 
ng add @angular-architects/module-federation --project orders --port 5000</code></pre>



<p>Main should run under port 4200, while orders is running on 5000. </p>



<h4 class="wp-block-heading">Configure the orders app as federated module</h4>



<p>Now we would be able to run the two apps, main and orders, but they are not really integrated yet. Let&#8217;s first add the relevant configuration to the &#8220;microfrontend&#8221;, i.e. orders app. Let&#8217;s first edit the webpack.config.js. Thanks to the module-federation package added above, the relevant config is already added to the ModuleFederationPlugin, but commented out. So, let&#8217;s enable the part for the orders app that is a &#8220;remote&#8221;:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">// For remotes (please adjust)
name: "orders",
filename: "remoteEntry.js",
exposes: {
    './OrderModule': './apps/orders/src/app/order/order.module.ts',
},   
shared: {
  "@angular/core": { singleton: <strong>true</strong>, strictVersion: <strong>true </strong>}, 
  ...</code></pre>



<p>We are setting a name and exposing a module. This is it for the orders app that functions as a remote in our federated module landscape. Note that libraries under &#8220;shared&#8221;, e.g. @angular/core, will only be downloaded once.<br>Further adjustments were done previously when installing the module-federation package. Please check for example the main.ts of the orders app.</p>



<h4 class="wp-block-heading">Integrate the orders app into the main app</h4>



<p>We have the orders app ready to be integrated as federated module. Let&#8217;s first add a route to the routing config of the main app:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">{
  path: 'orders',
  loadChildren: () =&gt; <strong>import</strong>('orders/OrderModule').then(m =&gt; m.OrderModule)
},</code></pre>



<p>We specify a path and a loadChildren function similar to traditional Angular modules. In the import path we specify the microfrontend &#8220;orders&#8221; and its Module. The TypeScript compiler is not happy about that because the &#8216;orders/Module&#8217; is not known in the main app. To make the compiler happy again we can add a type definition by creating a decl.d.ts in the main app&#8217;s src directoy</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript"><strong>declare module </strong>'orders/OrderModule';</code></pre>



<p>We also add an actual link to the new route in our template:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;a [routerLink]="['/orders']"&gt;My Orders&lt;/a&gt;</code></pre>



<p>As a last step we update the webpack.config also on the main app&#8217;s side. This time the &#8220;host&#8221; section is the relevant one:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">// For hosts (please adjust)
remotes: {
     "orders": "orders@http://localhost:5000/remoteEntry.js",
},</code></pre>



<p>We are telling webpack that the &#8220;orders&#8221; remote is found on port 5000.</p>



<h4 class="wp-block-heading">Running everything</h4>



<p>Let&#8217;s start both applications in separate terminals:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ng serve main
ng serve orders</code></pre>



<p>If we now click on the &#8220;My Orders&#8221; link in the header the order list is shown:</p>



<figure class="wp-block-image size-large mt-6"><img decoding="async" width="1024" height="504" src="https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-1024x504.png" alt="" class="wp-image-440" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-1024x504.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-300x148.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-768x378.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-1536x756.png 1536w, https://ronnieschaniel.com/wp-content/uploads/2021/04/orders_module_federated-2048x1008.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In the network tab we see a common.js loaded that contains the OrderListComponent (but not the entire Angular package). The integration is very smooth and one doesn&#8217;t really notice that the functionality is coming from a different app. </p>



<h4 class="wp-block-heading">Conclusion</h4>



<p>Of course this was a quick walkthrough and possibly the simplest setup for webpack federated modules. But it demonstrated the idea and we can summarise the benefits as following:</p>



<ul class="list-none wp-block-list"><li>🧩 The integration is smooth</li><li>⏳ Lower build time because separated</li><li>📦 Standalone deployment possible</li><li>⏱ Shared dependencies downloaded only once</li></ul>



<p>My verdict on webpack module federation: something to try out!</p>



<p>Again, sources for above example can be found on <a href="https://github.com/rschaniel/angular_ecommerce_playground" target="_blank" rel="noreferrer noopener">GitHub</a>.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/webpack-module-federation-in-angular/">Webpack Module Federation in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Cypress e2e Testing in the Jenkins Pipeline</title>
		<link>https://ronnieschaniel.com/angular/cypress-e2e-testing-in-the-jenkins-pipeline/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sun, 07 Feb 2021 15:25:00 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">http://ronnieschaniel.com/?p=18</guid>

					<description><![CDATA[<p>Learn how to setup a Jenkins build pipeline stage for the execution of the cypress tests.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/cypress-e2e-testing-in-the-jenkins-pipeline/">Cypress e2e Testing in the Jenkins Pipeline</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The article&nbsp;<a href="https://ronnieschaniel.com/posts/getting-started-with-cypress-e2e-testing-in-angular/">Getting Started with Cypress e2e Testing in Angular</a>&nbsp;describes how to setup&nbsp;<a href="https://www.cypress.io/" target="_blank" rel="noreferrer noopener">Cypress</a>&nbsp;for an Angular project. In this post we go a step further and cover how to use Cypress for automated e2e testing in your CI/CD workflow.<br>Jenkins is used as automation server and I assume that you already have an instance up and running. Furthermore your application should be pushed to a VCS repository, e.g. GitHub.</p>



<h2 class="wp-block-heading">Setting up Jenkins</h2>



<p>First, we create the needed configuration in Jenkins, by creating a new pipeline:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="970" height="325" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/cypress_jenkins_pipeline_creation.png" alt="" class="wp-image-91" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/cypress_jenkins_pipeline_creation.png 970w, https://ronnieschaniel.com/wp-content/uploads/2021/02/cypress_jenkins_pipeline_creation-300x101.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/02/cypress_jenkins_pipeline_creation-768x257.png 768w" sizes="(max-width: 970px) 100vw, 970px" /></figure>



<p>The source code&nbsp;of our application should be coming from GitHub. So, we need to setup a connection. On the machine, where we are running Jenkins, we create a public/private key pair:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">ssh-keygen -t rsa -b 4096</code></pre>



<p>We add the public key to GitHub under deploy keys. And set the following for our pipeline in Jenkins:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="1023" height="548" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/github_public_key.png" alt="" class="wp-image-92" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/github_public_key.png 1023w, https://ronnieschaniel.com/wp-content/uploads/2021/02/github_public_key-300x161.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/02/github_public_key-768x411.png 768w" sizes="(max-width: 1023px) 100vw, 1023px" /></figure>



<p>If there is no red error message below the “Repository URL” field, you have successfully connected the GitHub repository to Jenkins. </p>



<p>As we have an Angular project we need to execute npm scripts for building and testing our application. So, we need NodeJs. Let’s install it under “Manage Jenkins” → ”Manage Plugins” → “Available”:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="515" height="143" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_plugin.png" alt="" class="wp-image-94" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_plugin.png 515w, https://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_plugin-300x83.png 300w" sizes="(max-width: 515px) 100vw, 515px" /></figure>



<p>Next, we navigate to “Manage Jenkins” → “Global Tool Configuration” and make sure that a node version is installed and configured:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="831" height="635" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_configuration.png" alt="" class="wp-image-95" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_configuration.png 831w, https://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_configuration-300x229.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/02/node_js_jenkins_configuration-768x587.png 768w" sizes="(max-width: 831px) 100vw, 831px" /></figure>



<p>The name “node” here is important. It will be used later on. At this point Jenkins is set up for our needs and we can continue with the Angular project.</p>



<h2 class="wp-block-heading">Configuring the Angular Project</h2>



<p>The prerequisite for this part is that you have an Angular project ready that already uses Cypress (check for example&nbsp;<a href="https://medium.com/@ronnieschaniel/getting-started-with-cypress-e2e-testing-in-angular-bc42186d913d">this post</a>) or other tutorials.</p>



<p>We don’t want to have our pipeline configuration stored in the Jenkins itself. What we want is the pipeline defined as code. Hence, we create a “Jenkinsfile” in our project’s root directory:</p>



<pre class="wp-block-code"><code lang="ruby" class="language-ruby">pipeline {
    agent any
    tools {nodejs "node"}

    environment {
        CHROME_BIN = '/bin/google-chrome'
    }

    stages {
        stage('Dependencies') {
            steps {
                sh 'npm i'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }

        stage('Unit Tests') {
            steps {
                sh 'npm run test'
            }
        }

        stage('e2e Tests') {
            steps {
                sh 'npm run cypress:ci'
            }
        }

        stage('Deploy') {
            steps {
                echo 'Deploying....'
            }
        }
    }
}</code></pre>



<p>We tell the pipeline to use Node.js with the version “node” previously defined. Additionally, you have to make sure that you have Google Chrome installed and referenced in the Jenkinsfile. The exact definition of the ‘Deploy’ stage is left out here for simplicity. This is a task for you.</p>



<p>We use a Chrome Browser for unit testing. Hence, we adjust our karma.conf.js to use the headless Chrome:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">customLaunchers: {
  ChromeHeadless: {
    base: 'Chrome',
    flags: [
      '--headless',
      '--disable-gpu',
      '--no-sandbox',
      '--remote-debugging-port=9222',
    ]
  }
},
browsers: ['ChromeHeadless'],

</code></pre>



<p>That means we have our unit tests running. Let’s continue with the Cypress tests. If you have problems running Cypress in Jenkins, this excellent article will help:&nbsp;<a href="https://medium.com/aubergine-solutions/install-cypress-io-front-end-testing-tool-dependencies-on-amazon-linux-ami-ec2-instance-f676da4abbdd">https://medium.com/aubergine-solutions/install-cypress-io-front-end-testing-tool-dependencies-on-amazon-linux-ami-ec2-instance-f676da4abbdd</a>.</p>



<p>For the Cypress part we install the following node package that allows us to execute commands in parallel:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm install concurrently --save-dev</code></pre>



<p>And extend our package.json scripts section by:</p>



<pre class="wp-block-code"><code lang="json" class="language-json">"cypress:ci": "concurrently \"cypress run\" --kill-others \"ng serve\" --success first",</code></pre>



<h2 class="wp-block-heading">Running the build</h2>



<p>The “cypress:ci” task will be executed by the “e2e Tests” step in the Jenkins pipeline. Now we can press the “Build Now” button in the Jenkins and get the following result:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="1024" height="204" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_run-1024x204.png" alt="" class="wp-image-96" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_run-1024x204.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_run-300x60.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_run-768x153.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_run.png 1320w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>When inspecting the console output of the build, we can verify that the Cypress tests really ran:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="885" height="230" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_console.png" alt="" class="wp-image-97" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_console.png 885w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_console-300x78.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_pipeline_console-768x200.png 768w" sizes="(max-width: 885px) 100vw, 885px" /></figure>



<p>But what if a test fails? Currently we would need to check the console output in Jenkins to figure out what went wrong. What we need is a test reporter for Mocha. To have the relevant settings we put the following into the cypress.json file in our project’s root directory:</p>



<pre class="wp-block-code"><code lang="json" class="language-json">{
  "reporter": "junit",
  "reporterOptions": {
    "mochaFile": "results/cypress-report.xml",
    "toConsole": true
  }
}</code></pre>



<p>For this to work we need to have the JUnit Plugin installed in the Jenkins. That should already be the case by default. We then insert a “post” block after the “stages” in our Jenkinsfile:</p>



<pre class="wp-block-code"><code lang="ruby" class="language-ruby">stages {
    ...
} post {
    always {
        junit 'results/cypress-report.xml'
    }
}</code></pre>



<p>Thus, an action is added to the end of the pipeline, which is generating the test report and allows us to see the failing tests:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="717" height="389" src="http://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_result_failed_build.png" alt="" class="wp-image-98" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_result_failed_build.png 717w, https://ronnieschaniel.com/wp-content/uploads/2021/02/jenkins_cypress_result_failed_build-300x163.png 300w" sizes="(max-width: 717px) 100vw, 717px" /></figure>



<p>That’s it for now. Our Cypress tests run in Jenkins. The complete sources are available on&nbsp;<a href="https://github.com/rschaniel/angular_cypress_example">GitHub</a>. As a next step, you could look into&nbsp;<a href="https://docs.cypress.io/guides/guides/parallelization.html">Parallelisation</a>&nbsp;of cypress tests to decrease your overall build time. And of course it would be cool to also see the screenshots and videos of the failed tests directly in Jenkins.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/cypress-e2e-testing-in-the-jenkins-pipeline/">Cypress e2e Testing in the Jenkins Pipeline</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Getting Started with Cypress e2e Testing in Angular</title>
		<link>https://ronnieschaniel.com/angular/getting-started-with-cypress-e2e-testing-in-angular/</link>
		
		<dc:creator><![CDATA[ronnieschaniel@hey.com]]></dc:creator>
		<pubDate>Sat, 13 Mar 2021 14:34:59 +0000</pubDate>
				<category><![CDATA[Angular]]></category>
		<guid isPermaLink="false">https://ronnieschaniel.com/?p=288</guid>

					<description><![CDATA[<p>How to add and run cypress tests in Angular.</p>
<p>The post <a href="https://ronnieschaniel.com/angular/getting-started-with-cypress-e2e-testing-in-angular/">Getting Started with Cypress e2e Testing in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p id="2deb">Automating e2e tests is an important aspect of software engineering. It helps shipping updates often while quickly being able to see that the software is most likely still working properly. Unfortunately such tests are usually time consuming in creation and execution.<br>We have a look at how&nbsp;<a href="https://www.cypress.io/">cypress.io</a>&nbsp;can be used for front-end testing in an Angular app to see how it compares to Selenium, Protractor and co. The Cypress website tells us it’s “A Test runner built for humans”. Let’s see if this claim is true.</p>



<p id="b553">We go through&nbsp;the process of integrating Cypress into an Angular project followed by writing and running a test. The example project we are using comes from the&nbsp;<a href="https://angular.io/tutorial">heroes tutorial</a>&nbsp;that you probably know. After downloading the tutorial’s sources and installing it’s dependencies via npm, we add the Cypress package:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm i cypress --save-dev</code></pre>



<p><a href="https://ronnieschaniel.medium.com/?source=post_page-----bc42186d913d--------------------------------"></a>This command not only installs the Cypress node package but also creates a “cypress” directory in our Angular project. Within that directory we find examples for fixtures and tests amongst other stuff. The “integration” directory is the one wherein we write our tests later.</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="1024" height="414" src="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_directory_overview-1024x414.png" alt="" class="wp-image-289" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_directory_overview-1024x414.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_directory_overview-300x121.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_directory_overview-768x311.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_directory_overview.png 1092w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Next we create a cypress open command in the scripts section of our package.json alongside the `ng` command and others (that are omitted below):</p>



<pre class="wp-block-code"><code lang="json" class="language-json">"scripts": {
  "ng": "ng",
  "cypress:open": "$(npm bin)/cypress open"
},</code></pre>



<p><a href="https://ronnieschaniel.medium.com/?source=post_page-----bc42186d913d--------------------------------"></a>It allows us to fire up the Cypress Electron app by executing `npm run cypress:open`. Once started, the Cypress app shows us the example tests that we can explore.<br>Before we use this app further&nbsp;though, we should write our own test. For that we create a new test file from our project directory:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">touch cypress/integration/sample_spec.js</code></pre>



<p id="d1b6">The Cypress app has auto reloading. So, if we switch back to it we can see the sample_spec.js file listed.</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="800" height="549" src="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_electron_app.png" alt="" class="wp-image-290" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_electron_app.png 800w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_electron_app-300x206.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_electron_app-768x527.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p>A click on the sample_spec.js opens the Chrome browser, where we have the following view:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="1024" height="713" src="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_tests_not_found-1024x713.png" alt="" class="wp-image-291" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_tests_not_found-1024x713.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_tests_not_found-300x209.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_tests_not_found-768x535.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_tests_not_found.png 1400w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>So, Cypress notifies us that our test file does not contain a test yet. Let’s change that by putting content into sample_spec.js:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript">describe('Testing the hero list page', function() {
  it('should contain the word heroes', function() {
    cy.visit('http://localhost:4200');
    cy.contains("Heroes");
  });
});</code></pre>



<p>Probably this looks quite familiar to you. What you see is the BDD syntax of&nbsp;<a href="https://mochajs.org/">mochajs</a>&nbsp;with its expressions “describe”, “it”, and so on. Cypress itself offers a lot of test methods that we can access through the cy object.<br>No servers, drivers or other dependencies are needed. Only one thing is left to run the test. Of course we need to start the Angular app now to give Cypress a website to test:</p>



<pre class="wp-block-code"><code lang="bash" class="language-bash">npm start</code></pre>



<p id="9633">Back on the Cypress app’s test browser the test has already run. We have the following result:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="1024" height="581" src="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_test_green-1024x581.png" alt="" class="wp-image-292" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_test_green-1024x581.png 1024w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_test_green-300x170.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_test_green-768x436.png 768w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_in_angular_test_green.png 1400w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p id="e26b">On the left hand side the test results are displayed. While on the right hand side the page under test is shown. The test is green since the page contains the word “Heroes”. You could even inspect the right hand side and debug. In the end it’s a browser.</p>



<p id="3aa8">Let’s compare our Cypress test browser view to the protractor output of a similar test:</p>



<figure class="wp-block-image size-large is-style-default mt-6"><img decoding="async" width="830" height="534" src="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_vs_protractor.png" alt="" class="wp-image-293" srcset="https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_vs_protractor.png 830w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_vs_protractor-300x193.png 300w, https://ronnieschaniel.com/wp-content/uploads/2021/03/cypress_vs_protractor-768x494.png 768w" sizes="(max-width: 830px) 100vw, 830px" /></figure>



<p id="2ac6">I don’t know about you, but I prefer the Cypress view.</p>



<p id="7e7f">To conclude, the Cypress installation is straight-forward. There is zero configuration needed. Most importantly the test runs quickly and a nice interface shows exactly what went well or wrong. Cypress appears way more user friendly than for example Protractor. So, after this first steps, Cypress seems to be really the “Test runner built for humans”.</p>



<p id="b48c">This is all it needs to get started with Cypress in Angular. For further steps and information to all the great features the excellent Cypress website&nbsp;<a href="https://www.cypress.io/">https://www.cypress.io/</a>&nbsp;should be consulted.</p>



<p><a href="https://ronnieschaniel.medium.com/?source=post_page-----bc42186d913d--------------------------------"></a></p>
<p>The post <a href="https://ronnieschaniel.com/angular/getting-started-with-cypress-e2e-testing-in-angular/">Getting Started with Cypress e2e Testing in Angular</a> appeared first on <a href="https://ronnieschaniel.com">Ronnie Schaniel</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
