<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lars Gyrup Brink Nielsen</title>
    <description>The latest articles on Forem by Lars Gyrup Brink Nielsen (@layzee).</description>
    <link>https://forem.com/layzee</link>
    <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%2F89994%2F41ad1b6f-3d5a-4c73-894e-f7b0da8862c1.jpeg</url>
      <title>Forem: Lars Gyrup Brink Nielsen</title>
      <link>https://forem.com/layzee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/layzee"/>
    <language>en</language>
    <item>
      <title>You don't need importProvidersFrom with Angular Material</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Tue, 18 Feb 2025 22:38:00 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/you-dont-need-importprovidersfrom-with-angular-material-3nih</link>
      <guid>https://forem.com/playfulprogramming-angular/you-dont-need-importprovidersfrom-with-angular-material-3nih</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo generated with Microsoft Designer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Traditionally, we had to import mixed Angular modules from Angular Material at the root level to provide services required for the following components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/datepicker" rel="noopener noreferrer"&gt;Datepicker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/dialog" rel="noopener noreferrer"&gt;Dialog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/snack-bar" rel="noopener noreferrer"&gt;Snackbar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/timepicker" rel="noopener noreferrer"&gt;Timepicker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/tooltip" rel="noopener noreferrer"&gt;Tooltip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Standalone Angular application
&lt;/h2&gt;

&lt;p&gt;In Angular 14.0, the &lt;a href="https://angular.dev/api/core/importProvidersFrom" rel="noopener noreferrer"&gt;&lt;code&gt;importProvidersFrom&lt;/code&gt;&lt;/a&gt; function was introduced with standalone application support in Angular. This allowed us to be more explicit about the reason for adding the Angular module import to the &lt;a href="https://angular.dev/api/core/ApplicationConfig" rel="noopener noreferrer"&gt;&lt;code&gt;ApplicationConfig&lt;/code&gt;&lt;/a&gt; used with &lt;a href="https://angular.dev/api/platform-browser/bootstrapApplication" rel="noopener noreferrer"&gt;&lt;code&gt;bootstrapApplication&lt;/code&gt;&lt;/a&gt; as seen in the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;importProvidersFrom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatNativeDateModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MAT_DATE_FORMATS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatDatepickerModule&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/datepicker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatDialogModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatSnackbarModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/snack-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatTooltipModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/tooltip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appDateFormats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app-date-formats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Datepicker (and Timepicker)&lt;/span&gt;
    &lt;span class="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MatDatepickerModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MatNativeDateModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MAT_DATE_FORMATS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appDateFormats&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MatDialogModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MatSnackbarModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MatTooltipModule&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;code&gt;app.config.ts&lt;/code&gt; example with Angular Material 14.0.





&lt;h2&gt;
  
  
  Classic Angular application
&lt;/h2&gt;

&lt;p&gt;In an &lt;code&gt;AppModule&lt;/code&gt; in a classic Angular application, it is less clear why we need to maintain these Angular module imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;importProvidersFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatNativeDateModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MAT_DATE_FORMATS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatDatepickerModule&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/datepicker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatDialogModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatSnackbarModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/snack-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatTooltipModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/tooltip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserAnimationsModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser/animations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appDateFormats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app-date-formats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Angular Material&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserAnimationsModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Datepicker (and Timepicker)&lt;/span&gt;
    &lt;span class="nx"&gt;MatDatepickerModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MatNativeDateModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MAT_DATE_FORMATS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appDateFormats&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;MatDialogModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MatSnackbarModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MatTooltipModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;code&gt;app.module.ts&lt;/code&gt; example with Angular Material 13.3.





&lt;h2&gt;
  
  
  Standalone Angular Material providers
&lt;/h2&gt;

&lt;p&gt;In recent Angular Material versions, we can leave out the following imports from our &lt;code&gt;ApplicationConfig&lt;/code&gt; as the dependencies they provide are all tree-shakable (&lt;a href="https://angular.dev/api/core/Injectable" rel="noopener noreferrer"&gt;&lt;code&gt;@Injectable&lt;/code&gt;&lt;/a&gt;&lt;code&gt;({ providedIn: 'root' })&lt;/code&gt; or &lt;a href="https://angular.dev/api/core/InjectionToken" rel="noopener noreferrer"&gt;&lt;code&gt;InjectionToken&lt;/code&gt;&lt;/a&gt; with an inline provider).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/dialog/api" rel="noopener noreferrer"&gt;&lt;code&gt;MatDialogModule&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/snack-bar/api" rel="noopener noreferrer"&gt;&lt;code&gt;MatSnackbarModule&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://material.angular.io/components/tooltip/api" rel="noopener noreferrer"&gt;&lt;code&gt;MatTooltipModule&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As for the &lt;a href="https://material.angular.io/components/datepicker" rel="noopener noreferrer"&gt;Datepicker&lt;/a&gt; and &lt;a href="https://material.angular.io/components/timepicker" rel="noopener noreferrer"&gt;Timepicker&lt;/a&gt; dependencies, we can use the &lt;a href="https://material.angular.io/components/datepicker/overview#choosing-a-date-implementation-and-date-format-settings" rel="noopener noreferrer"&gt;&lt;code&gt;provideNativeDateAdapter&lt;/code&gt;&lt;/a&gt; function or a date-time library-specific date adapter like &lt;a href="https://material.angular.io/components/datepicker/overview#choosing-a-date-implementation-and-date-format-settings" rel="noopener noreferrer"&gt;&lt;code&gt;provideDateFnsAdapter&lt;/code&gt;&lt;/a&gt; as seen in the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideNativeDateAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideAnimationsAsync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser/animations/async&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appDateFormats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app-date-formats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideAnimations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;// Datepicker (and Timepicker)&lt;/span&gt;
    &lt;span class="nf"&gt;provideNativeDateAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appDateFormats&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;code&gt;app.config.ts&lt;/code&gt; example with Angular Material 17.1.





&lt;p&gt;Much cleaner, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;Other than simpler application configuration code that is easier to reason about, we get the following benefits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller bundle size as the Angular Material service dependencies are loaded when a lazy-loaded chunk need them for the first time&lt;/li&gt;
&lt;li&gt;Simpler component story configuration in Storybook as they can be simplified simlar to our &lt;code&gt;ApplicationConfig&lt;/code&gt; as seen in the next section&lt;/li&gt;
&lt;li&gt;Simpler component test configuration as it is simplified in a similar way as seen in a later section&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Storybook component stories
&lt;/h2&gt;

&lt;p&gt;In component stories, we use the &lt;a href="https://storybook.js.org/tutorials/intro-to-storybook/angular/en/screen/" rel="noopener noreferrer"&gt;&lt;code&gt;applicationConfig&lt;/code&gt;&lt;/a&gt; Storybook decorator to add root-level providers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideNativeDateAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideAnimationsAsync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser/animations/async&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StoryObj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;applicationConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;myDateFormats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./my-date-formats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./my-material.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;decorators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;applicationConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// Angular Material&lt;/span&gt;
        &lt;span class="nf"&gt;provideAnimationsAsync&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="c1"&gt;// Datepicker (and Timepicker)&lt;/span&gt;
        &lt;span class="nf"&gt;provideNativeDateAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myDateFormats&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Story&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StoryObj&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Story&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;code&gt;my-material.component.stories.ts&lt;/code&gt; example with Angular Material 17.1.





&lt;p&gt;In earlier versions of Angular Material, we had to use &lt;a href="https://angular.dev/api/core/importProvidersFrom" rel="noopener noreferrer"&gt;&lt;code&gt;importProvidersFrom&lt;/code&gt;&lt;/a&gt; or pass the Angular modules to the &lt;code&gt;imports&lt;/code&gt; option of thte &lt;a href="https://storybook.js.org/recipes/@angular/material" rel="noopener noreferrer"&gt;&lt;code&gt;moduleMetadata&lt;/code&gt;&lt;/a&gt; Storybook decorator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component tests
&lt;/h2&gt;

&lt;p&gt;Angular Material depdendencies are also simpler to configure in component tests. When unit testing an Angular component, we configure root-level providers with &lt;a href="https://angular.dev/api/core/testing/TestModuleMetadata#providers" rel="noopener noreferrer"&gt;the &lt;code&gt;providers&lt;/code&gt; option&lt;/a&gt; for the &lt;a href="https://angular.dev/api/core/testing/TestBedStatic#configureTestingModule" rel="noopener noreferrer"&gt;&lt;code&gt;TestBed.configureTestingModule&lt;/code&gt;&lt;/a&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideNoopAnimations&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser/animations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;myDateFormats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./my-date-formats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./my-material.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// Angular Material&lt;/span&gt;
      &lt;span class="nf"&gt;provideNoopAnimations&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="c1"&gt;// Datepicker (and Timepicker)&lt;/span&gt;
      &lt;span class="nf"&gt;provideNativeDateAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myDateFormats&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyMaterialComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;componentInstance&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;code&gt;my-material.component.spec.ts&lt;/code&gt; example with Angular Material 17.1.





&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Modern Angular Material versions are easier to use, in part because of the standalone providers used for component dependencies since version 17.1. The following table shows the exact versions when each Angular Material component was converted to standalone providers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;First version with standalone providers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Datepicker&lt;/td&gt;
&lt;td&gt;&lt;code&gt;17.1.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dialog&lt;/td&gt;
&lt;td&gt;&lt;code&gt;17.0.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snackbar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;17.0.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timepicker&lt;/td&gt;
&lt;td&gt;&lt;code&gt;19.0.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tooltip&lt;/td&gt;
&lt;td&gt;&lt;code&gt;15.0.4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Root-level provider configuration for Angular Material components is easier to set up and reason about both in Angular applications, Storybook component stories, and Angular component tests.&lt;/p&gt;

&lt;p&gt;Bundle sizes are optimized because of the tree-shakable providers.&lt;/p&gt;

&lt;p&gt;Except for Date picker and Timepicker components, we don't have to remember to add any providers. Similarly, we don't have to remember to remove them if and when we remove all Angular Material component uses in an application, a component story, or a component test.&lt;/p&gt;

&lt;p&gt;Historically, Angular and Angular Material progressed in the following way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add Angular modules to &lt;code&gt;NgModule.imports&lt;/code&gt; for &lt;code&gt;AppModule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pass Angular modules to &lt;code&gt;importProvidersFrom&lt;/code&gt; in &lt;code&gt;ApplicationConfig.providers&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No Angular modules but a provider function for the &lt;a href="https://material.angular.io/components/datepicker" rel="noopener noreferrer"&gt;Datepicker&lt;/a&gt; and &lt;a href="https://material.angular.io/components/timepicker" rel="noopener noreferrer"&gt;Timerpicker&lt;/a&gt; dependencies&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>angular</category>
      <category>material</category>
      <category>providers</category>
      <category>standalone</category>
    </item>
    <item>
      <title>Testing routed components with RouterTestingHarness</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Thu, 07 Dec 2023 00:00:00 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/testing-routed-components-with-routertestingharness-22dl</link>
      <guid>https://forem.com/playfulprogramming-angular/testing-routed-components-with-routertestingharness-22dl</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover art by Microsoft Designer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/angular/angular/issues/15779" rel="noopener noreferrer"&gt;Since 2017&lt;/a&gt;, Angular documentation has offered little advice on testing routing components, routed components, routes, and route guards other than to create partial and brittle &lt;a href="https://angular.dev/api/router/ActivatedRoute" rel="noopener noreferrer"&gt;&lt;code&gt;ActivatedRoute&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.dev/api/router/Router" rel="noopener noreferrer"&gt;&lt;code&gt;Router&lt;/code&gt;&lt;/a&gt; test doubles.&lt;/p&gt;

&lt;p&gt;While &lt;a href="https://angular.dev/api/router/testing/RouterTestingModule" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingModule&lt;/code&gt;&lt;/a&gt;—recently replacable using the equivalent standalone APIs, &lt;a href="https://angular.dev/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.dev/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt;—has been available since Angular version 2, documentation has been lacking at best.&lt;/p&gt;

&lt;p&gt;In February 2023, Angular version 15.2 introduced &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt;, the out-of-the-box experience for solving this 6 year old testing pain. The &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; sets up a testing root component with a &lt;a href="https://angular.dev/api/router/RouterOutlet" rel="noopener noreferrer"&gt;&lt;code&gt;RouterOutlet&lt;/code&gt;&lt;/a&gt; and uses the actual Angular Router API in our component tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcz5frqfs1ei7y9x5f1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcz5frqfs1ei7y9x5f1t.png" alt="Tour of Heroes router tutorial: DashboardComponent" width="468" height="975"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we test and use parts of Angular.io's &lt;a href="https://angular.io/guide/router-tutorial-toh" rel="noopener noreferrer"&gt;Tour of Heroes router tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt;, we first set up a test for a routing component or routed component using &lt;a href="https://angular.dev/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt; as we would set up any standalone Angular application or feature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;superhero/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="nf"&gt;provideLocationMocks&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could provide just enough test routes for our component test as seen in the previous code listing or even use—and thereby test—our real feature routes. Exercising the actual routes as part of our component tests is one part of what I call &lt;a href="https://ngworker.github.io/ngworker/docs/feature-testing" rel="noopener noreferrer"&gt;Angular feature tests&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Tip&lt;/strong&gt;&lt;br&gt;
We use &lt;a href="https://angular.dev/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt; to replace the &lt;a href="https://angular.dev/api/common/Location" rel="noopener noreferrer"&gt;&lt;code&gt;Location&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.dev/api/common/LocationStrategy" rel="noopener noreferrer"&gt;&lt;code&gt;LocationStrategy&lt;/code&gt;&lt;/a&gt; services used internally by the Angular Router with test doubles to isolate the tests from browser History and Location APIs that would trigger navigation in test runners with a real browser environment like Karma, Web Test Runner, or Cypress Component Test Runner and might not be available in test runners without a browser environment like Jest or Mocha.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With dependendencies set up for our test, we call and resolve the static method &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness.create&lt;/code&gt;&lt;/a&gt; to create an instance of a &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; as demonstrated in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RouterTestingHarness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could have pass an initial URL to the method to activate the component-under-test, &lt;code&gt;HeroDetailComponent&lt;/code&gt; but we will do that using the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; method instead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Warning&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness.create&lt;/code&gt;&lt;/a&gt; must only be called once per test case and requires &lt;a href="https://angular.dev/api/core/testing/ModuleTeardownOptions" rel="noopener noreferrer"&gt;&lt;code&gt;ModuleTeardownOptions#destroyAfterEach&lt;/code&gt;&lt;/a&gt; to be set to &lt;code&gt;true&lt;/code&gt; (the default value).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; method optionally accepts the component we want to activate and asserts that this is the result of navigating to the specified application URL as seen in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigateByUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;superhero/12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As suggested by the previous code snippet, the activated component instance is resolved by the &lt;code&gt;Promise&lt;/code&gt; returned by the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;I recommend that we make test assertions via the DOM to also exercise the component template. Additionally, this avoid relying on implementation details like whether the loaded hero is represented as a raw data structure, an RxJS &lt;a href="https://rxjs.dev/api/index/class/Observable" rel="noopener noreferrer"&gt;&lt;code&gt;Observable&lt;/code&gt;&lt;/a&gt;, or an Angular &lt;a href="https://angular.dev/api/core/Signal" rel="noopener noreferrer"&gt;&lt;code&gt;Signal&lt;/code&gt;&lt;/a&gt;. This decreases the brittleness of the test to support refactoring the component and its collaborators without breaking our component test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81q8n2t9c5o19ro12apa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81q8n2t9c5o19ro12apa.png" alt="Tour of Heroes router tutorial: HeroDetailComponent" width="468" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make assertions via the DOM, we use either of the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#routeDebugElement&lt;/code&gt;&lt;/a&gt; or the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#routeNativeElement&lt;/code&gt;&lt;/a&gt; properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routeNativeElement&lt;/span&gt;
  &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;
  &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dr. Nice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous code snippet, we use the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#routeNativeElement&lt;/code&gt;&lt;/a&gt; property to access the DOM managed by Angular and &lt;code&gt;HeroDetailComponent&lt;/code&gt;. We query for the hero heading and assert its content to be &lt;em&gt;Dr. Nice&lt;/em&gt;, the name of the hero who has the ID of &lt;code&gt;12&lt;/code&gt; as specified in the application URL we navigated to using the &lt;a href="https://angular.dev/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;The final test suite looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideLocationMocks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;withComponentInputBinding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouterTestingHarness&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hero-detail.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;displays the name of the hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;superhero/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="nf"&gt;provideLocationMocks&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RouterTestingHarness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigateByUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;superhero/12&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;HeroDetailComponent&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routeNativeElement&lt;/span&gt;
      &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;
      &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Dr. Nice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, we successfully exercised a routed Angular component in a component test! Better yet, because the test uses &lt;code&gt;RouterTestingHarness&lt;/code&gt; and makes assertions via the DOM, it is resilient to component and service refactorings.&lt;/p&gt;

&lt;p&gt;As an exercise, write a routed component test similar to the one in the previous code listing. Then refactor the component to accept an input property instead of depending on &lt;code&gt;ActivatedRoute&lt;/code&gt; and provide the &lt;a href="https://angular.dev/api/router/withComponentInputBinding" rel="noopener noreferrer"&gt;&lt;code&gt;withComponentInputBinding&lt;/code&gt;&lt;/a&gt; Angular Router feature. The only thing you should have to change in your test is to provide the same Angular Router feature to the Angular tesitng module.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>router</category>
      <category>testing</category>
    </item>
    <item>
      <title>Manage Nx library dependencies with the @nx/dependency-checks ESLint rule</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Thu, 06 Jul 2023 21:56:24 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/manage-nx-library-dependencies-with-the-nxdependency-checks-eslint-rule-2lem</link>
      <guid>https://forem.com/playfulprogramming/manage-nx-library-dependencies-with-the-nxdependency-checks-eslint-rule-2lem</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover art by DALL-E.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nx 16.4 introduces the &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule to the &lt;code&gt;@nx/linter&lt;/code&gt; package for verifying, adding, removing, and updating &lt;code&gt;peerDependencies&lt;/code&gt; in the &lt;code&gt;package.json&lt;/code&gt; source configuration file of buildable or publishable Nx library projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;&lt;br&gt;
Prefer at least Nx version 16.5 when using the &lt;code&gt;@nx/dependency-checks&lt;/code&gt; lint rule. Significant bugs were patched in this version.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a replacement for the &lt;code&gt;updateBuildableProjectDepsInPackageJson&lt;/code&gt; and &lt;code&gt;buildableProjectDepsInPackageJsonType&lt;/code&gt; Nx build executor options so expect them to be deprecated. In fact, they are turned off by default in Nx 16.6 (but migrated to &lt;code&gt;true&lt;/code&gt; for existing projects) and these options shouldn't be used for a project using the &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule.&lt;/p&gt;

&lt;p&gt;Let's start with instructions on adding the lint rule to a library project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling @nx/dependency-checks in .eslintrc.json
&lt;/h2&gt;

&lt;p&gt;To enable the &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule in a buildable or publishable library project, open its &lt;code&gt;.eslintrc.json&lt;/code&gt; ESLint configuration file and add the following settings to the &lt;code&gt;overrrides&lt;/code&gt; array in the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{package,project}.json"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsonc-eslint-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@nx/dependency-checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;overrides&lt;/code&gt; section of the project-specific &lt;code&gt;.eslintrc.json&lt;/code&gt; file.





&lt;p&gt;This enables the &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule with default options.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Info&lt;/strong&gt;&lt;br&gt;
We do not have to install &lt;code&gt;json-eslint-parser&lt;/code&gt; as a dependency in our workspace as it is a direct dependency of the &lt;code&gt;@nx/eslint-plugin&lt;/code&gt; package, not a peer dependency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The lint rule scans the project's &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;project.json&lt;/code&gt; files. Because of this, we must also add these files to the lint file patterns in the &lt;code&gt;project.json&lt;/code&gt; configuration file as described in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Including configuration files in the lint target
&lt;/h2&gt;

&lt;p&gt;To pass the &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;project.json&lt;/code&gt; files to ESLint, we must add them to the &lt;code&gt;lintFilePatterns&lt;/code&gt; option for the &lt;code&gt;@nx/linter:eslint&lt;/code&gt; Nx executor as seen in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"executor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@nx/linter:eslint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{options.outputFile}"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lintFilePatterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"libs/ui-design-system/**/*.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"libs/ui-design-system/**/*.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"libs/ui-design-system/package.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"libs/ui-design-system/project.json"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;targets&lt;/code&gt; section of the &lt;code&gt;project.json&lt;/code&gt; file.





&lt;p&gt;In addition to the existing lint file patterns, we add one listing the path of the project's &lt;code&gt;package.json&lt;/code&gt; file and one listing the path of the &lt;code&gt;project.json&lt;/code&gt; file, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;"libs/ui-design-system/package.json"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"libs/ui-design-system/project.json"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring @nx/dependency-checks options
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule supports a range of options. Let's have a look at the default settings and then explore them all.&lt;/p&gt;

&lt;p&gt;To match the default ESLint rule options, we add the following to the library project's &lt;code&gt;.eslintrc.json&lt;/code&gt; ESLint configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{package,project}.json"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsonc-eslint-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@nx/dependency-checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"buildTargets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkMissingDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkObsoleteDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkVersionMismatches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ignoredDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;overrides&lt;/code&gt; section of the project-specific &lt;code&gt;.eslintrc.json&lt;/code&gt; file.





&lt;h3&gt;
  
  
  The buildTargets option
&lt;/h3&gt;

&lt;p&gt;We use &lt;code&gt;buildTargets&lt;/code&gt; to instruct the lint rule about the Nx target(s) that we use to build the library. This is used to determine the library's dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  The checkMissingDependencies option
&lt;/h3&gt;

&lt;p&gt;This lint check determines the library's dependencies from its source code and compares it to the dependencies and peer dependencies listed in its &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;As an example, we add the following Button Angular component to a library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MatButtonModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myorg-button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;MatButtonModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;button mat-button&amp;gt;&amp;lt;ng-content /&amp;gt;&amp;lt;/button&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyOrgButtonComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we don't add &lt;code&gt;@angular/material&lt;/code&gt; and its peer dependency &lt;code&gt;@angular/cdk&lt;/code&gt; to the library's &lt;code&gt;package.json&lt;/code&gt; file, we get lint errors like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;libs\ui-design-system\package.json
  4:3  error  The "ui-design-system" uses the package "@angular/material", but it is missing from the project's "package.json"  @nx/dependency-checks
  4:3  error  The "ui-design-system" uses the package "@angular/cdk", but it is missing from the project's "package.json"  @nx/dependency-checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Example lint error output when the &lt;code&gt;checkMissingDependencies&lt;/code&gt; option is enabled.





&lt;p&gt;As long as our library doesnot directly depend on &lt;code&gt;@angular/cdk&lt;/code&gt;, we can choose to ignore the detected &lt;code&gt;@angular/cdk&lt;/code&gt; peer dependency as installing the &lt;code&gt;@angular/material&lt;/code&gt; package should prompt consumers to install &lt;code&gt;@angular/cdk&lt;/code&gt; as well. See how to ignore a detected dependency in the the section &lt;em&gt;The ignoredDependencies list&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The checkObsoleteDependencies option
&lt;/h3&gt;

&lt;p&gt;Enable the &lt;code&gt;checkObsoleteDependencies&lt;/code&gt; option to detect dependencies that are listed in the library's &lt;code&gt;package.json&lt;/code&gt; file but are unused by its source code.&lt;/p&gt;

&lt;p&gt;As an example, our &lt;code&gt;MyOrgButtonComponent&lt;/code&gt; doesn't depend on &lt;code&gt;@angular/common&lt;/code&gt; but it was added to the &lt;code&gt;peerDependencies&lt;/code&gt; array of the library's &lt;code&gt;package.json&lt;/code&gt; file by the &lt;code&gt;@nx/angular:library&lt;/code&gt; generator. Since it is no longer a dependency, we get a lint error like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;libs\ui-design-system\package.json
  7:5  error  The "@angular/common" package is not used by "ui-design-system"  @nx/dependency-checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Example lint error output when the &lt;code&gt;checkObsoleteDependencies&lt;/code&gt; option is enabled.





&lt;p&gt;On the other hand, we want to keep &lt;code&gt;tslib&lt;/code&gt; in the &lt;code&gt;dependencies&lt;/code&gt; section of the Angular library's &lt;code&gt;package.json&lt;/code&gt; file so we must add it to the ´ignoredDependencies´ list as described in the &lt;em&gt;The ignoredDependencies list&lt;/em&gt; section.&lt;/p&gt;

&lt;h3&gt;
  
  
  The checkVersionMismatches option
&lt;/h3&gt;

&lt;p&gt;The lint check enabled when the value of the &lt;code&gt;checkVersionMismatches&lt;/code&gt; option is set to &lt;code&gt;true&lt;/code&gt; verifies that the version range listed in the library's &lt;code&gt;package.json&lt;/code&gt; file includes the version installed in the Nx workspace.&lt;/p&gt;

&lt;p&gt;As an example, our Nx workspace uses Angular with the following version range listed in the &lt;code&gt;dependencies&lt;/code&gt; array of the &lt;code&gt;package.json&lt;/code&gt; file in the root of the workspace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~16.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;dependencies&lt;/code&gt; section of the workspace-level &lt;code&gt;package.json&lt;/code&gt; file.





&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; file of our example Angular library has the following version range for &lt;code&gt;@angular/core&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"peerDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@angular/core"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^15.1.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;peerDependencies&lt;/code&gt; section of the project's &lt;code&gt;package.json&lt;/code&gt; file.





&lt;p&gt;When we lint the library, we get a lint error like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;libs\ui-design-system\package.json
  6:5  error  The version specifier does not contain the installed version of "@angular/core" package: 16.1.3  @nx/dependency-checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Example lint error output when the &lt;code&gt;checkVersionMismatches&lt;/code&gt; option is enabled.





&lt;h3&gt;
  
  
  The ignoredDependencies list
&lt;/h3&gt;

&lt;p&gt;To exclude certain packages from the dependency checks, we add them to the &lt;code&gt;ignoredDependencies&lt;/code&gt; array. This option does not support glob patterns.&lt;/p&gt;

&lt;p&gt;For example, when we generate an Angular library, the Angular-specific classes use the &lt;code&gt;@angular/core&lt;/code&gt; package which has a peer dependency on &lt;code&gt;zone.js&lt;/code&gt; and &lt;code&gt;rxjs&lt;/code&gt;. As long as our library don't have direct dependencies on these packages, we can choose to add them to the &lt;code&gt;ignoredDependencies&lt;/code&gt; list as seen in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{package,project}.json"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsonc-eslint-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@nx/dependency-checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"buildTargets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkMissingDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkObsoleteDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkVersionMismatches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ignoredDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"rxjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"zone.js"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;overrides&lt;/code&gt; section of the project-specific &lt;code&gt;.eslintrc.json&lt;/code&gt; file.





&lt;p&gt;In the section &lt;em&gt;The checkObsoleteDependencies option&lt;/em&gt;, we said that we want to keep &lt;code&gt;tslib&lt;/code&gt; in the &lt;code&gt;dependencies&lt;/code&gt; section of the Angular library's &lt;code&gt;package.json&lt;/code&gt; file. To do so, we must add it to the &lt;code&gt;ignoredDependencies&lt;/code&gt; list as seen in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{package,project}.json"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsonc-eslint-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@nx/dependency-checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"buildTargets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkMissingDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkObsoleteDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkVersionMismatches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ignoredDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"rxjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"tslib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"zone.js"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;overrides&lt;/code&gt; section of the project-specific &lt;code&gt;.eslintrc.json&lt;/code&gt; file.





&lt;p&gt;As described in the section &lt;em&gt;The checkMissingDependencies option&lt;/em&gt;, we can choose to ignore the &lt;code&gt;@angular/cdk&lt;/code&gt; peer dependency as well as long as our library has no direct dependency on &lt;code&gt;@angular/cdk&lt;/code&gt;. Let's add it to the &lt;code&gt;ignoredDependencies&lt;/code&gt;, keeping in mind that if we add an import statement targeting &lt;code&gt;@angular/cdk&lt;/code&gt;, we must remove this package from the &lt;code&gt;ignoredDependencies&lt;/code&gt; list again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"{package,project}.json"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"parser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsonc-eslint-parser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@nx/dependency-checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"buildTargets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkMissingDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkObsoleteDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"checkVersionMismatches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ignoredDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"@angular/cdk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"rxjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"tslib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="s2"&gt;"zone.js"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;overrides&lt;/code&gt; section of the project-specific &lt;code&gt;.eslintrc.json&lt;/code&gt; file.





&lt;h2&gt;
  
  
  @nx/dependency-checks lint fixers
&lt;/h2&gt;

&lt;p&gt;Lint fixers are available for the following &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;checkMissingDependencies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checkObsoleteDependencies&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checkVersionMismatches&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Info&lt;/strong&gt;&lt;br&gt;
The lint fixers for the &lt;code&gt;checkMissingDependencies&lt;/code&gt; and &lt;code&gt;checkVersionMismatches&lt;/code&gt; lint checks insert or replace version ranges in the Nx library's &lt;code&gt;package.json&lt;/code&gt; file with the ones listed in the Nx workspace's root-level &lt;code&gt;package.json&lt;/code&gt; file. This usually works well with buildable libraries but make sure to verify version ranges for publishable libraries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The lint fixer for the &lt;code&gt;checkMissingDependencies&lt;/code&gt; ESLint rule option adds dependencies to the &lt;code&gt;peerDependencies&lt;/code&gt; or &lt;code&gt;dependencies&lt;/code&gt; section of the library's &lt;code&gt;package.json&lt;/code&gt; file, depending on which section is declared first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ignoring test-setup.ts and similar files
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule detects dependencies in files like &lt;code&gt;test-setup.ts&lt;/code&gt; that are in the &lt;code&gt;sourceRoot&lt;/code&gt; of a project. When using &lt;code&gt;create-nx-workspace&lt;/code&gt; version 16.5 or newer, the solution for this is already set up for us. In existing Nx workspaces, we either run the &lt;code&gt;add-test-setup-to-inputs-ignore&lt;/code&gt; Nx migration from the &lt;code&gt;@nx/jest&lt;/code&gt; package or manually add the pattern &lt;code&gt;"!{projectRoot}/src/test-setup.[jt]s"&lt;/code&gt; to &lt;code&gt;nx.json#namedInputs.production&lt;/code&gt; as seen in the following code snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"namedInputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"!{projectRoot}/tsconfig.spec.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"!{projectRoot}/jest.config.[jt]s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"!{projectRoot}/src/test-setup.[jt]s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"!{projectRoot}/.eslintrc.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
Excerpt of the &lt;code&gt;namedInputs&lt;/code&gt; section of the &lt;code&gt;nx.json&lt;/code&gt; file.





&lt;p&gt;As you can see in the previous code snippet, &lt;code&gt;jest.config.js&lt;/code&gt; and &lt;code&gt;jest.config.ts&lt;/code&gt; are also ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@nx/dependency-checks&lt;/code&gt; ESLint rule introduced to the &lt;code&gt;@nx/linter&lt;/code&gt; package in version 16.4 is an invaluable tool in managing peer dependencies of a buildable or publishable Nx library.&lt;/p&gt;

&lt;p&gt;Its built-in lint fixers is a semi-automated way of resolving peer dependency issues in the &lt;code&gt;package.json&lt;/code&gt; source configuration file of a library. Library dependencies are detected based on the library's source code.&lt;/p&gt;

&lt;p&gt;This ESLint rule is a replacement for the &lt;code&gt;updateBuildableProjectDepsInPackageJson&lt;/code&gt; and &lt;code&gt;buildableProjectDepsInPackageJsonType&lt;/code&gt; Nx build executor options.&lt;/p&gt;

</description>
      <category>nx</category>
      <category>eslint</category>
      <category>npm</category>
      <category>angular</category>
    </item>
    <item>
      <title>Stop using the defaultProject Nx CLI setting and start using NX_DEFAULT_PROJECT</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Tue, 30 May 2023 06:26:51 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/stop-using-the-defaultproject-nx-cli-setting-and-start-using-nxdefaultproject-2ka5</link>
      <guid>https://forem.com/playfulprogramming/stop-using-the-defaultproject-nx-cli-setting-and-start-using-nxdefaultproject-2ka5</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover image by DALL-E.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;defaultProject&lt;/code&gt; setting for the Nx CLI was originally inherited from the Angular CLI. In integrated and standalone Nx workspaces, the &lt;code&gt;defaultProject&lt;/code&gt; setting is located in &lt;code&gt;nx.json&lt;/code&gt;. In package-based Nx workspaces, &lt;code&gt;defaultProject&lt;/code&gt; is located in &lt;code&gt;package.json#nx&lt;/code&gt;. While it was removed from Angular CLI version 16, it is still present but unofficially deprecated in Nx version 16.x as evident by &lt;a href="https://nx.dev/reference/nx-json" rel="noopener noreferrer"&gt;the &lt;code&gt;nx.json&lt;/code&gt; reference&lt;/a&gt; which doesn't list it.&lt;/p&gt;

&lt;p&gt;As of Nx 16.2, a &lt;code&gt;defaultProject&lt;/code&gt; setting is still configured when using &lt;a href="//npmjs.com/package/create-nx-workspace"&gt;&lt;code&gt;create-nx-workspace&lt;/code&gt;&lt;/a&gt; to generate a standalone Nx workspace. However, it is safe to remove this setting as Nx detects the &lt;code&gt;project.json&lt;/code&gt; file in the root directory of a standalone workspace.&lt;/p&gt;

&lt;p&gt;In this article, we discuss why the &lt;code&gt;defaultProject&lt;/code&gt; is being deprecated, which use cases it affects with example commands not depending on it, and finally the viable replacement for &lt;code&gt;defaultProject&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why will &lt;code&gt;defaultProject&lt;/code&gt; be removed?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;defaultProject&lt;/code&gt; setting is being depreacted and eventually removed because it doesn't make sense in integrated and package-based Nx workspaces where the preferred project usually varies between teams and developers and so shouldn't be committed to a configuration shared between most or all teams and developers.&lt;/p&gt;

&lt;p&gt;Standalone Nx workspaces can have more than one project but the original project is defined in a &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;project.json&lt;/code&gt; file in the root workspace directory which Nx detects to infer the project for Nx CLI commands run from this directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does &lt;code&gt;defaultProject&lt;/code&gt; affect?
&lt;/h2&gt;

&lt;p&gt;Let's explore most of the use cases affected by the &lt;code&gt;defaultProject&lt;/code&gt; setting and how we can complete them without this setting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running tasks
&lt;/h3&gt;

&lt;p&gt;An Nx workspace defines projects, targets, and, optionally, configurations.&lt;/p&gt;

&lt;p&gt;To run a task for a specific configuration of a project target, we use the following command format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;--configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to start a task running the &lt;code&gt;build&lt;/code&gt; target on the &lt;code&gt;my-app&lt;/code&gt; project, we use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;my-app:build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Common target names have alias commands, for example the following command is an alias of the previous &lt;code&gt;nx run&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure we use the &lt;code&gt;production&lt;/code&gt; build configuration, we prepend &lt;code&gt;:production&lt;/code&gt; to our &lt;code&gt;nx run&lt;/code&gt; command as seen in the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;my-app:build:configuration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The aliased version is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running generators
&lt;/h3&gt;

&lt;p&gt;Some Nx generators and Angular schematics require a &lt;code&gt;--project&lt;/code&gt; option but use the &lt;code&gt;defaultProject&lt;/code&gt; setting when omitted, for example &lt;code&gt;@nx/component&lt;/code&gt; and &lt;code&gt;@schematics/angular:component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Without a &lt;code&gt;deafultProject&lt;/code&gt; setting, we must pass a &lt;code&gt;--project&lt;/code&gt; option as seen in the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;nx/angular:component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--standalone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What should I use instead of &lt;code&gt;defaultProject&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;Although the preferred project isn't the same for all teams or developers, it is still convenient to leave out the same project name for most task runs and generators.&lt;/p&gt;

&lt;p&gt;As a viable replacement for the &lt;code&gt;defaultProject&lt;/code&gt; setting, we can use &lt;a href="https://nx.dev/reference/environment-variables" rel="noopener noreferrer"&gt;the &lt;code&gt;NX_DEFAULT_PROJECT&lt;/code&gt; environment variable&lt;/a&gt; which is planned to outlive the &lt;code&gt;defaultProject&lt;/code&gt; setting as we have many options for setting this in individual environments, both for CI and local development use cases.&lt;/p&gt;

&lt;p&gt;When we set the value of the &lt;code&gt;NX_DEFAULT_PROJECT&lt;/code&gt; environment variable to a project name, both task running and code generation works as if we had specified the &lt;code&gt;defaultProject&lt;/code&gt; setting but without committing it to a shared configuration.&lt;/p&gt;

&lt;p&gt;For example, with the &lt;code&gt;NX_DEFAULT_PROJECT&lt;/code&gt; environment variable set to &lt;code&gt;my-app&lt;/code&gt;, we can use the following build commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build the app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# or&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# build the app in production mode&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build:production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# or&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, we can use generators and schematics that require a &lt;code&gt;--project&lt;/code&gt; option witout specifying a project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;nx/angular:component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--standalone&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# or&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;schematics/angular:component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--standalone&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we learned that &lt;code&gt;defaultProject&lt;/code&gt; is being deprecated and removed because it is no longer necessary for standalone Nx workspaces and in the case of integrated or package-based Nx workspaces, different teams and developers often want a different default project. Because of this, we shouldn't commit a shared setting.&lt;/p&gt;

&lt;p&gt;We learned how the &lt;code&gt;defaultProject&lt;/code&gt; setting affects the &lt;code&gt;nx run&lt;/code&gt; command as well as Nx generators and Angular schematics that require a &lt;code&gt;--project&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;Finally, we learned how we can use the &lt;code&gt;NX_DEFAULT_PROJECT&lt;/code&gt; environment variable to configure an individual environment for CI tasks or local development in the same way as we would have used the &lt;code&gt;defaultProject&lt;/code&gt; setting in the past but without committing a setting to a shared configuration.&lt;/p&gt;

</description>
      <category>nx</category>
      <category>angular</category>
      <category>deprecation</category>
    </item>
    <item>
      <title>Testing Angular routing components with RouterTestingHarness, provideLocationMocks, and provideRouter</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Wed, 08 Feb 2023 23:54:59 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/testing-angular-routing-components-with-routertestingharness-providelocationmocks-and-providerouter-oi8</link>
      <guid>https://forem.com/playfulprogramming-angular/testing-angular-routing-components-with-routertestingharness-providelocationmocks-and-providerouter-oi8</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover art by DALL·E 2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's been three years since &lt;a href="https://dev.to/this-is-angular/testing-angular-routing-components-with-the-routertestingmodule-4cj0"&gt;Testing Angular routing components with the RouterTestingModule&lt;/a&gt;. This article revisits integrated routing component tests with modern Angular APIs, including standalone components, &lt;a href="https://angular.io/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt;. Additionally, we use a &lt;a href="https://medium.com/@kolodny/testing-with-sifers-c9d6bb5b362" rel="noopener noreferrer"&gt;SIFERS&lt;/a&gt; for managing our test setup and test utilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nmyzdvl6jlded36ix89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2nmyzdvl6jlded36ix89.png" alt="The show hero detail use case" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;
The &lt;em&gt;show hero detail&lt;/em&gt; use case.



&lt;h2&gt;
  
  
  providerRouter and provideLocationMocks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://angular.io/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 14.2) is the standalone version of &lt;a href="https://angular.io/api/router/RouterModule#forroot" rel="noopener noreferrer"&gt;&lt;code&gt;RouterModule.forRoot&lt;/code&gt;&lt;/a&gt;. Combine it with &lt;a href="https://angular.io/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 15.0) and we have the standalone version of &lt;a href="https://angular.io/api/router/testing/RouterTestingModule#withroutes" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingModule.withRoutes&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ Note&lt;br&gt;
Read &lt;a href="https://dev.to/this-is-angular/testing-angular-routing-components-with-the-routertestingmodule-4cj0#what-does-the-routertestingmodule-do"&gt;What does the RouterTestingModule do?&lt;/a&gt; for a detailed explanation of how &lt;a href="https://angular.io/api/router/testing/RouterTestingModule" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingModule&lt;/code&gt;&lt;/a&gt; replaces Angular Router dependencies. &lt;a href="https://angular.io/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt; does the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  RouterTestingHarness
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 15.2) is similar to &lt;a href="https://www.npmjs.com/package/@ngworker/spectacular" rel="noopener noreferrer"&gt;Spectacular&lt;/a&gt;'s &lt;a href="https://ngworker.github.io/ngworker/docs/feature-testing" rel="noopener noreferrer"&gt;Feature testing API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we call &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#create" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness.create&lt;/code&gt;&lt;/a&gt; (only call it once per test), a test root component with a router outlet is created behind the scenes but we don't get access to this component or its component fixture.&lt;/p&gt;

&lt;p&gt;The resolved &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; instance has the properties &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#properties" rel="noopener noreferrer"&gt;&lt;code&gt;routeDebugElement&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#properties" rel="noopener noreferrer"&gt;&lt;code&gt;routeNativeElement&lt;/code&gt;&lt;/a&gt; which access the &lt;a href="https://angular.io/api/core/DebugElement" rel="noopener noreferrer"&gt;&lt;code&gt;DebugElement&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" rel="noopener noreferrer"&gt;&lt;code&gt;HTMLElement&lt;/code&gt;&lt;/a&gt; corresponding to the component currently activated by the test root component's &lt;a href="https://angular.io/api/router/RouterOutlet" rel="noopener noreferrer"&gt;&lt;code&gt;RouterOutlet&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; has a &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#detectchanges" rel="noopener noreferrer"&gt;&lt;code&gt;detectChanges&lt;/code&gt;&lt;/a&gt; method which calls &lt;a href="https://angular.io/api/core/testing/ComponentFixture#detectChanges" rel="noopener noreferrer"&gt;&lt;code&gt;ComponentFixture#detectChanges&lt;/code&gt;&lt;/a&gt; for the test root component.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#navigatebyurl" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; method wraps &lt;a href="https://angular.io/api/router/Router#navigatebyurl" rel="noopener noreferrer"&gt;&lt;code&gt;Router#navigateByUrl&lt;/code&gt;&lt;/a&gt; and resolves the component activated by that navigation.&lt;/p&gt;

&lt;p&gt;That's all the background we need. Let's explore a &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; version of the integrated routed component test for the &lt;code&gt;DashboardComponent&lt;/code&gt; from &lt;a href="https://angular.io/guide/router-tutorial-toh" rel="noopener noreferrer"&gt;the Tour of Heroes Router tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrated routing component test suite
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Location&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideLocationMocks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fakeAsync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;By&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouterTestingHarness&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;asapScheduler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;observeOn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HeroService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../hero.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HEROES&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../mock-heroes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DashboardComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dashboard.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fakeService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getHeroes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;HEROES&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;observeOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asapScheduler&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HeroService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;pathMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;full&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DashboardComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestHeroDetailComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;]),&lt;/span&gt;
      &lt;span class="nf"&gt;provideLocationMocks&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HeroService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fakeService&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RouterTestingHarness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// [1]&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TestBed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;advance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detectChanges&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;clickTopHero&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstHeroLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routeDebugElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;firstHeroLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triggerEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;leftMouseButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHeroDetailComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;leftMouseButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DashboardComponent (integrated)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigates to the detail view when a hero link is clicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;fakeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;advance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clickTopHero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="cm"&gt;/* [2] */&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigateByUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;DashboardComponent&lt;/span&gt; &lt;span class="c1"&gt;// [3]&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;topHero&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;heroes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;clickTopHero&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;advance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/detail/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;topHero&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;must navigate to the detail view for the top hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(1) Notice how we only call &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#create" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness.create&lt;/code&gt;&lt;/a&gt; once per test case in our &lt;code&gt;setup&lt;/code&gt; SIFERS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Warning&lt;br&gt;
&lt;a href="https://angular.io/api/core/testing/ModuleTeardownOptions#properties" rel="noopener noreferrer"&gt;&lt;code&gt;ModuleTeardownOptions#destroyAfterEach&lt;/code&gt;&lt;/a&gt; must be set to &lt;code&gt;true&lt;/code&gt; for &lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; to work correctly. See &lt;a href="https://dev.to/this-is-angular/improving-angular-tests-by-enabling-angular-testing-module-teardown-38kh"&gt;Improving Angular tests by enabling Angular testing module teardown&lt;/a&gt; for details on this option.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(1) We could have passed an initial URL, for example &lt;code&gt;await RouterTestingHarness.create("/")&lt;/code&gt; or &lt;code&gt;await RouterTestingHarness.create("/heroes")&lt;/code&gt; but it doesn't return an activated component.&lt;/p&gt;

&lt;p&gt;(2) &lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt; resolves an activated component and optionally accepts the type (class) of the activated component we expect (3). If the component activated by that navigation is not of the expected type, an error is thrown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/LayZeeDK/e2350b4f839effac80d84fabd4840c39" rel="noopener noreferrer"&gt;The full test suite is available in this Gist&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Let's sum up what we learned in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 15.2) is a testing harness specifically for interacting with Angular Router-related APIs in tests&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 14.2) is the standalone version of &lt;a href="https://angular.io/api/router/RouterModule#forroot" rel="noopener noreferrer"&gt;&lt;code&gt;RouterModule.forRoot&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt; (introduced by Angular version 15.0) is the standalone version of &lt;a href="https://angular.io/api/router/testing/RouterTestingModule" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingModule&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The standalone version of &lt;a href="https://angular.io/api/router/testing/RouterTestingModule#withroutes" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingModule.withRoutes&lt;/code&gt;&lt;/a&gt; is &lt;a href="https://angular.io/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/common/testing/provideLocationMocks" rel="noopener noreferrer"&gt;&lt;code&gt;provideLocationMocks&lt;/code&gt;&lt;/a&gt; combined.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#create" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness.create&lt;/code&gt;&lt;/a&gt; creates an initializes a test root component with a router outlet. It must only be called once per test case and requires &lt;a href="https://angular.io/api/core/testing/ModuleTeardownOptions#properties" rel="noopener noreferrer"&gt;&lt;code&gt;ModuleTeardownOptions#destroyAfterEach&lt;/code&gt;&lt;/a&gt; to be set to &lt;code&gt;true&lt;/code&gt;. It optionally accepts an initial URL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#navigatebyurl" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#navigateByUrl&lt;/code&gt;&lt;/a&gt; accepts a URL for navigation and optionally the expected type of the component activated by that navigation. The activated component is resolved by the method call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://next.angular.io/api/router/testing/RouterTestingHarness#detectchanges" rel="noopener noreferrer"&gt;&lt;code&gt;RouterTestingHarness#detectChanges&lt;/code&gt;&lt;/a&gt; triggers a change detection cycle starting at the test root component.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>testing</category>
      <category>router</category>
    </item>
    <item>
      <title>YAML collections: Sequences and mappings</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Mon, 21 Nov 2022 17:14:55 +0000</pubDate>
      <link>https://forem.com/playfulprogramming/yaml-collections-sequences-and-mappings-4meb</link>
      <guid>https://forem.com/playfulprogramming/yaml-collections-sequences-and-mappings-4meb</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@bright" rel="noopener noreferrer"&gt;Karen Vardazaryan&lt;/a&gt; on Unsplash.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequences
&lt;/h2&gt;

&lt;p&gt;A sequence is a YAML node that contains an ordered list of zero to &lt;em&gt;n&lt;/em&gt; YAML &lt;em&gt;nodes&lt;/em&gt; (mappings, sequences, or scalars). Sequences are commonly known as arrays or lists in other languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Block collection style
&lt;/h3&gt;

&lt;p&gt;A block sequence is a series of YAML nodes lead by a dash (&lt;code&gt;-&lt;/code&gt;) indicator and white space.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;integers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;red&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;green&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;blue&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;yellow&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cyan&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;magenta&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;black&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;white&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JSON, this is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"colors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"green"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"blue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"yellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"cyan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"magenta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"white"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Flow collection style
&lt;/h3&gt;

&lt;p&gt;A flow sequence is a series of YAML nodes contained in square brackets (&lt;code&gt;[&lt;/code&gt; and &lt;code&gt;]&lt;/code&gt;). Flow sequence entries are separated by a comma (&lt;code&gt;,&lt;/code&gt;) with a trailing comma allowed but empty node entries disallowed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;integers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;6&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;7&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;8&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;9&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;10&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;red&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;green&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;yellow&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cyan&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;magenta&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;black&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;white&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but also&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;integers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
  &lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;6&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;7&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;8&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;9&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;10&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;red&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;green&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;yellow&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;cyan&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;magenta&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;black&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;white&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or any other white space variation.&lt;/p&gt;

&lt;p&gt;In JSON, this is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"colors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"red"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"green"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"blue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"yellow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"cyan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"magenta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"black"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"white"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mappings
&lt;/h2&gt;

&lt;p&gt;A mapping is a YAML node that contains an unordered set of zero to &lt;em&gt;n&lt;/em&gt; key-value pairs. A key and its value are separated by a colon (&lt;code&gt;:&lt;/code&gt;). Keys must be unique. Both keys and values may be any kind of YAML node. Mappings are commonly known as hash maps or associative arrays in other languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Block collection style
&lt;/h3&gt;

&lt;p&gt;A block mapping is a series of key-value pairs on separate lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;integer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;blue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JSON, this is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Flow collection style
&lt;/h3&gt;

&lt;p&gt;A flow mapping is a series of key-value pairs contained in curly braces (&lt;code&gt;{&lt;/code&gt; and &lt;code&gt;}&lt;/code&gt;). Flow mapping entries are separated by a comma (&lt;code&gt;,&lt;/code&gt;) with a trailing comma allowed but empty node entries disallowed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;integer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but also&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;integer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
&lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="pi"&gt;,}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or any other white space variation.&lt;/p&gt;

&lt;p&gt;In JSON, this is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit mapping entries
&lt;/h3&gt;

&lt;p&gt;A mapping key and value pair is optionally put on separate lines where the key is lead by a question mark (&lt;code&gt;?&lt;/code&gt;) and the value is lead by a colon (&lt;code&gt;:&lt;/code&gt;). This allows for special keys such as the empty node or complex non-scalar nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;?&lt;/span&gt; 
&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My key is empty&lt;/span&gt;
&lt;span class="pi"&gt;?&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;autocorrect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;On&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My key is a nested collection&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous example is a mapping containing two key-value pairs where the values are strings. It has no equivalent JSON expression.&lt;/p&gt;

</description>
      <category>yaml</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The local component scope of standalone Angular components</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Wed, 31 Aug 2022 07:03:12 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/the-local-component-scope-of-standalone-angular-components-3g60</link>
      <guid>https://forem.com/playfulprogramming-angular/the-local-component-scope-of-standalone-angular-components-3g60</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/photos/E4bn9ScilAA" rel="noopener noreferrer"&gt;Clay Banks&lt;/a&gt; on Unsplash.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A standalone component is independent from an Angular module. It directly references the declarables (components, directives, and pipes) used in its template.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declarable dependencies
&lt;/h2&gt;

&lt;p&gt;A standalone Angular component specifies declarable dependencies in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option to manage its &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#local-component-scope"&gt;local component scope&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's consider a standalone implementation of the hero detail component from &lt;a href="https://angular.io/tutorial" rel="noopener noreferrer"&gt;the Tour of Heroes tutorial&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgIf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UpperCasePipe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormsModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;FormsModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NgIf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UpperCasePipe&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toh-hero-detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./hero-detail.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div *ngIf="hero"&amp;gt;
      &amp;lt;h2&amp;gt;{{ hero.name | uppercase }} Details&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;&amp;lt;span&amp;gt;id: &amp;lt;/span&amp;gt;{{ hero.id }}&amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;label for="hero-name"&amp;gt;Hero name: &amp;lt;/label&amp;gt;
        &amp;lt;input
          id="hero-name"
          [(ngModel)]="hero.name"
          placeholder="Hero name"
        /&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;button type="button" (click)="goBack()"&amp;gt;go back&amp;lt;/button&amp;gt;
      &amp;lt;button type="button" (click)="save()"&amp;gt;save&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HeroDetailComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Class body omitted&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importantly, the &lt;a href="https://angular.io/api/core/Component#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Component.standalone&lt;/code&gt;&lt;/a&gt; metadata option is set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we list declarable dependencies and/or Angular modules exporting declarbales in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option. See how the structural directive &lt;code&gt;NgIf&lt;/code&gt; is listed alongside the Angular pipe &lt;code&gt;UppercasePipe&lt;/code&gt;, both from the &lt;code&gt;@angular/common&lt;/code&gt; package. This is possible since they are both standalone declarables in modern versions of Angular.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
It is still possible to import &lt;code&gt;CommonModule&lt;/code&gt; to introduce all the common Angular declarables to a standalone component's local component scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Additionally, the &lt;code&gt;FormsModule&lt;/code&gt; is added to the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option, introducing the attribute directive &lt;code&gt;NgModel&lt;/code&gt; to the hero detail component's local component scope.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
Importantly, components, directives, and pipes listed in &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; must be marked with the &lt;code&gt;standalone: true&lt;/code&gt; metadata option available as &lt;a href="https://angular.io/api/core/Component#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Component.standalone&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/core/Directive#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Directive.standalone&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/core/Pipe#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Pipe.standalone&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The default setting for this metadata option is &lt;code&gt;standalone: false&lt;/code&gt; as of Angular version 15, subject to future change depending on how well standalone declarables are received by the Angular ecosystem and community.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inspecting the component template, we see the &lt;code&gt;NgIf&lt;/code&gt; directive in use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;*ngIf=&lt;/span&gt;&lt;span class="s"&gt;"hero"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Conditional content omitted --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we see the &lt;code&gt;UppercasePipe&lt;/code&gt; pipe being used in the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{ hero.name | uppercase }} Details&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the &lt;code&gt;Hero#name&lt;/code&gt; property is bound to a form control using two-way data binding with the &lt;code&gt;NgModel&lt;/code&gt; directive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hero-name"&lt;/span&gt;
  &lt;span class="na"&gt;[(ngModel)]=&lt;/span&gt;&lt;span class="s"&gt;"hero.name"&lt;/span&gt;
  &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Hero name"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Local component scope
&lt;/h2&gt;

&lt;p&gt;In the dependency graph of the standalone hero detail component's local component scope, we see the relationship between our component and its declarable dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0vyfq24xnr6vzvqxx3j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0vyfq24xnr6vzvqxx3j.png" alt="The local component scope of the standalone hero detail component" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the exception of the &lt;code&gt;FormsModule&lt;/code&gt;, this closely matches the component template's indirect dependencies on declarables it uses:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoe4ib9f7qkzxzl05xas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoe4ib9f7qkzxzl05xas.png" alt="The declarables used in the hero detail component's template" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Indirect dependencies&lt;/em&gt; meaning that the component template uses the element selectors, attribute selectors, and pipe names specified in the &lt;a href="https://angular.io/api/core/Component#inherited-from-directive-decorator" rel="noopener noreferrer"&gt;&lt;code&gt;Component.selector&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/core/Directive#selector" rel="noopener noreferrer"&gt;&lt;code&gt;Directive.selector&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/core/Pipe#name" rel="noopener noreferrer"&gt;&lt;code&gt;Pipe.name&lt;/code&gt;&lt;/a&gt; metadata options of the component's declarable dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transitive compilation scope
&lt;/h2&gt;

&lt;p&gt;When we compare this to the &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#transitive-compilation-scope"&gt;transitive compilation scope&lt;/a&gt; of the declaring module of a classic Angular component, we notice an increased mental overhead in the classic Angular component style:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbou443zhcmnpat7k55h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbou443zhcmnpat7k55h7.png" alt="The transitive compilation scope of the classic hero detail module (simplified)" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HeroDetailModule&lt;/code&gt; and &lt;code&gt;CommonModule&lt;/code&gt; introduce layers of indirection to the dependency graph. Instead of a direct dependency from the &lt;code&gt;HeroDetailComponent&lt;/code&gt; to &lt;code&gt;NgIf&lt;/code&gt; and &lt;code&gt;UppercasePipe&lt;/code&gt;, there is no direct flow of dependencies between the &lt;code&gt;HeroDetailComponent&lt;/code&gt; class and any of its declarable dependencies. This is caused by the &lt;code&gt;HeroDetailModule&lt;/code&gt; referencing the &lt;code&gt;HeroDetailComponent&lt;/code&gt;, not the other way around. Another indirection is the unnecessary &lt;code&gt;CommonModule&lt;/code&gt; encapsulating the Angular declarables of which we only use 2 in the component template.&lt;/p&gt;

&lt;p&gt;The classic Angular dependency graph does not match the component template's indirect dependencies on declarables it needs.&lt;/p&gt;

&lt;p&gt;Imagine the logic needed by the Angular compiler to determine dependencies between classes and the maintenance it requires when significant changes are made to Angular, the TypeScript compiler, and other dependencies.&lt;/p&gt;

&lt;p&gt;What's worse, the previous classic dependency graph is simplified. The full transitive compilation scope of the hero detail module is seen in this expanded classic dependency graph:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frus5k8e6dyrvnf8pt664.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frus5k8e6dyrvnf8pt664.png" alt="The transitive compilation scope of the classic hero detail module (expanded)" width="800" height="1575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's 52 declarables imported to the transitive compilation scope of which the component template uses only 3. Fifty-two.&lt;/p&gt;

&lt;p&gt;Luckily for us, the Angular Development Kit's Build Optimizer tree shakes unused declarables from transitive compilation scopes and local component scopes. If that was not the case, our bundle would increase every time we imported an Angular module that exported more declarables than we were using in our component template.&lt;/p&gt;

&lt;p&gt;This brings us to the next topic: Maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maintaining declarable dependencies
&lt;/h2&gt;

&lt;p&gt;Take another look at the previous expanded transitive compilation scope. As the codebase evolves, how do we keep the declarable dependencies in sync with the transitive compilation scope? How do we determine when our component template no longer uses any declarable from an Angular module exporting more than a dozen declarables.&lt;/p&gt;

&lt;p&gt;This gets harder for every declared component in an Angular module and every non-&lt;a href="https://dev.to/this-is-angular/emulating-tree-shakable-components-using-single-component-angular-modules-13do"&gt;SCAM&lt;/a&gt; module imported.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
It's time to convert &lt;a href="https://dev.to/this-is-angular/emulating-tree-shakable-components-using-single-component-angular-modules-13do"&gt;SCAMs&lt;/a&gt; to standalone declarables. That was always their purpose, after all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's easier to scan a standalone component template and compare it to the imported standalone declarables listed in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A standalone component has a local component scope consisting of its declarables dependencies which are listed in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option.&lt;/p&gt;

&lt;p&gt;We must maintain the local component scope so that it matches the declarables used in the component template. We do this by comparing the standalone component template to the standalone declarables and Angular modules listed in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option, keeping them in sync.&lt;/p&gt;

&lt;p&gt;Common declarables such as &lt;code&gt;NgIf&lt;/code&gt; and &lt;code&gt;UppercasePipe&lt;/code&gt; that are exported by &lt;code&gt;CommonModule&lt;/code&gt; are now standalone declarables that can be referenced directly in the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option.&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Revisited: Standalone Angular applications, the replacement for NgModules</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Tue, 30 Aug 2022 14:00:17 +0000</pubDate>
      <link>https://forem.com/playfulprogramming-angular/angular-revisited-standalone-angular-applications-the-replacement-for-ngmodules-238m</link>
      <guid>https://forem.com/playfulprogramming-angular/angular-revisited-standalone-angular-applications-the-replacement-for-ngmodules-238m</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/photos/rL6q_Y5uBLs" rel="noopener noreferrer"&gt;Laura Cleffman&lt;/a&gt; on Unsplash.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's been 4 years since I started looking into &lt;em&gt;standalone&lt;/em&gt; Angular applications, that is Angular applications that unlike &lt;em&gt;classic&lt;/em&gt; Angular applications have no Angular modules.&lt;/p&gt;

&lt;p&gt;Angular version 15 delivers an amazing full-on standalone Angular application experience and it is about much more than standalone components. It is a shift in perspective on Angular concepts as we know them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional NgModules
&lt;/h2&gt;

&lt;p&gt;Standalone Angular applications mark the final milestone of the &lt;em&gt;optional NgModules&lt;/em&gt; epic. No longer do we have to use or write Angular modules. We now have an alternative for every use case.&lt;/p&gt;

&lt;p&gt;Angular modules are one of the most confusing concepts of the Angular framework. The vision for Angular was to get rid of Angular modules following AngularJS versions 1.x but shortly before Angular version 2.0, Angular modules were reintroduced for the sake of the compiler to pave the path for application-scoped Ahead-of-Time compilation, a major improvement compared to Just-in-Time compilation, the only compilation mode for AngularJS.&lt;/p&gt;

&lt;p&gt;Angular modules are difficult to teach and learn. Introduced as necessary compiler annotations rather than to improve the developer experience, Angular modules address many concerns with declarable linking to component templates and environment injector configuration being the two major concerns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;entryComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;BrowserAnimationsModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;HttpClientModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MatButtonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;RouterModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;jit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CUSTOM_ELEMENTS_SCHEMA&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's have a look at every metadata option for the &lt;code&gt;NgModule&lt;/code&gt; decorator, discuss their purpose and their standalone application replacements.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.bootstrap
&lt;/h3&gt;

&lt;p&gt;Marks one or more components to be bootstrapped as root components.&lt;/p&gt;

&lt;p&gt;Replace with &lt;a href="https://angular.io/api/platform-browser/bootstrapApplication" rel="noopener noreferrer"&gt;&lt;code&gt;bootstrapApplication&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.declarations
&lt;/h3&gt;

&lt;p&gt;Declares components, directives, and pipes, including them in Angular module's &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#transitive-compilation-scope"&gt;transitive compilation scope&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
A classic component, directive, or pipe can only be declared in one Angular module. Declaring them in multiple Angular modules results in compilation errors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Replace with the &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/core/Component#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Component.standalone&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/core/Directive#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Directive.standalone&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/core/Pipe#standalone" rel="noopener noreferrer"&gt;&lt;code&gt;Pipe.standalone&lt;/code&gt;&lt;/a&gt; metadata options.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.entryComponents
&lt;/h3&gt;

&lt;p&gt;Deprecated since Angular version 9, the first stable release of Angular Ivy, the &lt;code&gt;NgModule.entryComponents&lt;/code&gt; option marks a component for dynamic rendering support. This was implicitly done for components marked with &lt;a href="https://angular.io/api/core/NgModule#bootstrap" rel="noopener noreferrer"&gt;&lt;code&gt;NgModule.bootstrap&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/router/Route#properties" rel="noopener noreferrer"&gt;&lt;code&gt;Route#component&lt;/code&gt;&lt;/a&gt; in the Angular Template Compiler and Angular View Engine framework generations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
Stop using this metadata option in classic Angular applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Angular Ivy, components do not have to be marked explicitly as entry components. Dynamic rendering of any component is possible so no replacement is necessary. &lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.exports
&lt;/h3&gt;

&lt;p&gt;Marks classic and/or standalone declarables as part of this Angular module's &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#transitive-exported-scope"&gt;transitive exported scope&lt;/a&gt;. Listing other Angular modules includes their transitive exported scope in this Angular module's transitive exported scope.&lt;/p&gt;

&lt;p&gt;Replace with the native &lt;code&gt;export&lt;/code&gt; declaration to make a standalone declarable accessible to the template of a component including it in its &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option or the transitive scope of an Angular module including it in its &lt;a href="https://angular.io/api/core/NgModule#imports" rel="noopener noreferrer"&gt;&lt;code&gt;NgModule.imports&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://angular.io/api/core/NgModule#exports" rel="noopener noreferrer"&gt;&lt;code&gt;NgModule.exports&lt;/code&gt;&lt;/a&gt; metadata options.&lt;/p&gt;

&lt;p&gt;To indicate public or internal access to a standalone declarable, we can structure our Angular workspaces using barrel files, workspace libraries, and or lint rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.id
&lt;/h3&gt;

&lt;p&gt;Marks this Angular module as non-tree-shakable and allows access through the &lt;a href="https://angular.io/api/core/getNgModuleById" rel="noopener noreferrer"&gt;&lt;code&gt;getNgModuleById&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://angular.io/errors/NG6100" rel="noopener noreferrer"&gt;You probably don't need this option&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not needed in standalone applications. For classic application, replace with a dynamic import statement, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TheModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./the.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;esModule&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;esModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TheModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  NgModule.jit
&lt;/h3&gt;

&lt;p&gt;Excludes this Angular module and its declarations from Ahead-of-Time compilation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
The JIT compiler must be bundled with the application for this option to work for example by adding the following statement in the &lt;code&gt;main.ts&lt;/code&gt; file:&lt;/p&gt;


&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/compiler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Introduced in Angular version 6 to support the ongoing work of what was going to be the next framework generation, Angular Ivy.&lt;/p&gt;

&lt;p&gt;Replace with the &lt;a href="https://angular.io/api/core/Component#inherited-from-directive-decorator" rel="noopener noreferrer"&gt;&lt;code&gt;Component.jit&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/core/Directive#jit" rel="noopener noreferrer"&gt;&lt;code&gt;Directive.jit&lt;/code&gt;&lt;/a&gt; metadata options.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.imports
&lt;/h3&gt;

&lt;p&gt;Includes the &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#transitive-exported-scope"&gt;transitive exported scope&lt;/a&gt; of listed Angular modules in this Angular module's &lt;a href="https://dev.to/this-is-angular/angular-revisited-tree-shakable-components-and-optional-ngmodules-36d2#transitive-module-scope"&gt;transitive module scope&lt;/a&gt;. Standalone declarables can also be listed to include them in this Angular module's transitive module scope.&lt;/p&gt;

&lt;p&gt;This links imported declarables to templates of components declared by this Angular module.&lt;/p&gt;

&lt;p&gt;Providers listed in Angular modules added to the &lt;a href="https://angular.io/api/core/NgModule#imports" rel="noopener noreferrer"&gt;&lt;code&gt;NgModule.imports&lt;/code&gt;&lt;/a&gt; metadata option are added to the environment injector(s) (formerly known as module injectors) that this Angular module is part of.&lt;/p&gt;

&lt;p&gt;To mark components, directives, and pipes as declarable dependencies of a standalone component, use its &lt;a href="https://angular.io/api/core/Component#imports" rel="noopener noreferrer"&gt;&lt;code&gt;Component.imports&lt;/code&gt;&lt;/a&gt; metadata option which also supports Angular modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  NgModule.providers
&lt;/h3&gt;

&lt;p&gt;Lists providers that are added to the environment injector(s) (formerly known as module injectors) that this Angular module is part of.&lt;/p&gt;

&lt;p&gt;Angular version 6 introduced &lt;a href="https://dev.to/this-is-angular/tree-shakable-dependencies-in-angular-projects-1ifg"&gt;tree-shakable providers&lt;/a&gt;, removing the need for Angular modules to configure environment injectors, at the time known as module injectors.&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;NgModule.providers&lt;/code&gt; with the &lt;a href="https://angular.io/api/core/InjectionToken" rel="noopener noreferrer"&gt;&lt;code&gt;InjectionToken.factory&lt;/code&gt;&lt;/a&gt; metadata option, &lt;a href="https://angular.io/api/core/Injectable#providedIn" rel="noopener noreferrer"&gt;&lt;code&gt;Injectable.providedIn&lt;/code&gt;&lt;/a&gt; metadata option, &lt;a href="https://angular.io/api/router/Route#properties" rel="noopener noreferrer"&gt;&lt;code&gt;Route#providers&lt;/code&gt;&lt;/a&gt; setting, and &lt;a href="https://angular.io/api/platform-browser/ApplicationConfig" rel="noopener noreferrer"&gt;&lt;code&gt;ApplicationConfig#providers&lt;/code&gt;&lt;/a&gt; setting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Tip&lt;/strong&gt;&lt;br&gt;
Consider using a component-level provider to follow the lifecycle of a directive or component by specifying the &lt;a href="https://angular.io/api/core/Component#inherited-from-directive-decorator" rel="noopener noreferrer"&gt;&lt;code&gt;Component.providers&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/core/Component#viewproviders" rel="noopener noreferrer"&gt;&lt;code&gt;Component.viewProviders&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/core/Directive#providers" rel="noopener noreferrer"&gt;&lt;code&gt;Directive.providers&lt;/code&gt;&lt;/a&gt; metadata options. Consider this both for classic and standalone Angular applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  NgModule.schemas
&lt;/h3&gt;

&lt;p&gt;Adds template compilation schemas to support web component usage by listing the &lt;a href="https://angular.io/api/core/CUSTOM_ELEMENTS_SCHEMA" rel="noopener noreferrer"&gt;&lt;code&gt;CUSTOM_ELEMENTS_SCHEMA&lt;/code&gt;&lt;/a&gt; or to ignore the use of any unknown element, attribute, or property by listing the &lt;a href="https://angular.io/api/core/NO_ERRORS_SCHEMA" rel="noopener noreferrer"&gt;&lt;code&gt;NO_ERRORS_SCHEMA&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This controls the template compilation schemas for components that are declared by this Angular module.&lt;/p&gt;

&lt;p&gt;Replace with the &lt;a href="https://angular.io/api/core/Component#schemas" rel="noopener noreferrer"&gt;&lt;code&gt;Component.schemas&lt;/code&gt;&lt;/a&gt; metadata option.&lt;/p&gt;

&lt;p&gt;As we have learned in this introductory article, every possible Angular module metadata option now has a standalone Angular application replacement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standalone alternatives for official Angular modules
&lt;/h2&gt;

&lt;p&gt;Several Angular modules are exposed in the public APIs of official Angular packages. As of Angular version 15.1, there are standalone alternatives for the following official Angular modules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Angular module&lt;/th&gt;
&lt;th&gt;Standalone replacement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/platform-browser/animations/BrowserAnimationsModule" rel="noopener noreferrer"&gt;&lt;code&gt;BrowserAnimationsModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/platform-browser/animations/provideAnimations" rel="noopener noreferrer"&gt;&lt;code&gt;provideAnimations&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/CommonModule" rel="noopener noreferrer"&gt;&lt;code&gt;CommonModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://angular.io/api/common/AsyncPipe" rel="noopener noreferrer"&gt;&lt;code&gt;AsyncPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/CurrencyPipe" rel="noopener noreferrer"&gt;&lt;code&gt;CurrencyPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/DatePipe" rel="noopener noreferrer"&gt;&lt;code&gt;DatePipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/DecimalPipe" rel="noopener noreferrer"&gt;&lt;code&gt;DecimalPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/I18nPluralPipe" rel="noopener noreferrer"&gt;&lt;code&gt;I18nPluralPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/I18nSelectPipe" rel="noopener noreferrer"&gt;&lt;code&gt;I18nSelectPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/JsonPipe" rel="noopener noreferrer"&gt;&lt;code&gt;JsonPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/KeyValuePipe" rel="noopener noreferrer"&gt;&lt;code&gt;KeyValuePipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/LowerCasePipe" rel="noopener noreferrer"&gt;&lt;code&gt;LowerCasePipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgClass" rel="noopener noreferrer"&gt;&lt;code&gt;NgClass&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgComponentOutlet" rel="noopener noreferrer"&gt;&lt;code&gt;NgComponentOutlet&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgIf" rel="noopener noreferrer"&gt;&lt;code&gt;NgIf&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgForOf" rel="noopener noreferrer"&gt;&lt;code&gt;NgForOf&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgPlural" rel="noopener noreferrer"&gt;&lt;code&gt;NgPlural&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgPluralCase" rel="noopener noreferrer"&gt;&lt;code&gt;NgPluralCase&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgStyle" rel="noopener noreferrer"&gt;&lt;code&gt;NgStyle&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgSwitch" rel="noopener noreferrer"&gt;&lt;code&gt;NgSwitch&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgSwitchCase" rel="noopener noreferrer"&gt;&lt;code&gt;NgSwitchCase&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgSwitchDefault" rel="noopener noreferrer"&gt;&lt;code&gt;NgSwitchDefault&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/NgTemplateOutlet" rel="noopener noreferrer"&gt;&lt;code&gt;NgTemplateOutlet&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/PercentPipe" rel="noopener noreferrer"&gt;&lt;code&gt;PercentPipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/SlicePipe" rel="noopener noreferrer"&gt;&lt;code&gt;SlicePipe&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/TitleCasePipe" rel="noopener noreferrer"&gt;&lt;code&gt;TitleCasePipe&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/common/UppercasePipe" rel="noopener noreferrer"&gt;&lt;code&gt;UppercasePipe&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CdkScrollableModule&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://material.angular.io/cdk/scrolling/api#CdkScrollable" rel="noopener noreferrer"&gt;&lt;code&gt;CdkScrollable&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://material.angular.io/cdk/drag-drop/api" rel="noopener noreferrer"&gt;&lt;code&gt;DragDropModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDrag" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDrag&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDragHandle" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDragHandle&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDragPlaceholder" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDragPlaceholder&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDragPreview" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDragPreview&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDropList" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDropList&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/drag-drop/api#CdkDropListGroup" rel="noopener noreferrer"&gt;&lt;code&gt;CdkDropListGroup&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkScrollable" rel="noopener noreferrer"&gt;&lt;code&gt;CdkScrollable&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/HttpClientModule" rel="noopener noreferrer"&gt;&lt;code&gt;HttpClientModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/provideHttpClient" rel="noopener noreferrer"&gt;&lt;code&gt;provideHttpClient&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/HttpClientJsonpModule" rel="noopener noreferrer"&gt;&lt;code&gt;HttpClientJsonpModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://angular.io/api/common/http/provideHttpClient" rel="noopener noreferrer"&gt;&lt;code&gt;provideHttpClient&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/common/http/withJsonpSupport" rel="noopener noreferrer"&gt;&lt;code&gt;withJsonpSupport&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/testing/HttpClientTestingModule" rel="noopener noreferrer"&gt;&lt;code&gt;HttpClientTestingModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/testing/provideHttpClientTesting" rel="noopener noreferrer"&gt;&lt;code&gt;provideHttpClientTesting&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/common/http/HttpClientXsrfModule" rel="noopener noreferrer"&gt;&lt;code&gt;HttpClientXsrfModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://angular.io/api/common/http/provideHttpClient" rel="noopener noreferrer"&gt;&lt;code&gt;provideHttpClient&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/common/http/withNoXsrfProtection" rel="noopener noreferrer"&gt;&lt;code&gt;withNoXsrfProtection&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/common/http/withXsrfConfiguration" rel="noopener noreferrer"&gt;&lt;code&gt;withXsrfConfiguration&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/platform-browser/animations/NoopAnimationsModule" rel="noopener noreferrer"&gt;&lt;code&gt;NoopAnimationsModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/platform-browser/animations/provideNoopAnimations" rel="noopener noreferrer"&gt;&lt;code&gt;provideNoopAnimations&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://angular.io/api/router/RouterModule" rel="noopener noreferrer"&gt;&lt;code&gt;RouterModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://angular.io/api/router/provideRouter" rel="noopener noreferrer"&gt;&lt;code&gt;provideRouter&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/RouterLink" rel="noopener noreferrer"&gt;&lt;code&gt;RouterLink&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/RouterLinkActive" rel="noopener noreferrer"&gt;&lt;code&gt;RouterLinkActive&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/RouterOutlet" rel="noopener noreferrer"&gt;&lt;code&gt;RouterOutlet&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withDebugTracing" rel="noopener noreferrer"&gt;&lt;code&gt;withDebugTracing&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withDisabledInitialNavigation" rel="noopener noreferrer"&gt;&lt;code&gt;withDisabledInitialNavigation&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withEnabledBlockingInitialNavigation" rel="noopener noreferrer"&gt;&lt;code&gt;withEnabledBlockingInitialNavigation&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withHashLocation" rel="noopener noreferrer"&gt;&lt;code&gt;withHashLocation&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withInMemoryScrolling" rel="noopener noreferrer"&gt;&lt;code&gt;withInMemoryScrolling&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://angular.io/api/router/withPreloading" rel="noopener noreferrer"&gt;&lt;code&gt;withPreloading&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://angular.io/api/router/withRouterConfig" rel="noopener noreferrer"&gt;&lt;code&gt;withRouterConfig&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://material.angular.io/cdk/scrolling/api" rel="noopener noreferrer"&gt;&lt;code&gt;ScrollingModule&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://material.angular.io/cdk/scrolling/api#CdkFixedSizeVirtualScroll" rel="noopener noreferrer"&gt;&lt;code&gt;CdkFixedSizeVirtualScroll&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkScrollable" rel="noopener noreferrer"&gt;&lt;code&gt;CdkScrollable&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkVirtualForOf" rel="noopener noreferrer"&gt;&lt;code&gt;CdkVirtualForOf&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollableElement" rel="noopener noreferrer"&gt;&lt;code&gt;CdkVirtualScrollableElement&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollableWindow" rel="noopener noreferrer"&gt;&lt;code&gt;CdkVirtualScrollableWindow&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://material.angular.io/cdk/scrolling/api#CdkVirtualScrollViewport" rel="noopener noreferrer"&gt;&lt;code&gt;CdkVirtualScrollViewport&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
The classic Angular modules can still be used and are not deprecated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Standalone vs. classic Angular applications
&lt;/h2&gt;

&lt;p&gt;Due to interoperability between standalone APIs and Angular modules, standalone Angular applications do not require a big bang migration. We can gradually migrate to standalone APIs or use standalone APIs for new features but leave the classic Angular APIs in-place for now.&lt;/p&gt;

&lt;p&gt;In Angular version 15.x, picking between standalone and classic Angular applications was mostly a stylistic choice. However, there are already noteworthy differences to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://angular.io/api/platform-browser/bootstrapApplication" rel="noopener noreferrer"&gt;&lt;code&gt;bootstrapApplication&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://angular.io/api/platform-browser/createApplication" rel="noopener noreferrer"&gt;&lt;code&gt;createApplication&lt;/code&gt;&lt;/a&gt; do not support NgZone options unlike &lt;a href="https://angular.io/api/core/PlatformRef#bootstrapmodule" rel="noopener noreferrer"&gt;&lt;code&gt;PlatformRef#bootstrapModule&lt;/code&gt;&lt;/a&gt;, making it impossible to exclude Zone.js from our standalone application bundle using these APIs&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://angular.io/guide/directive-composition-api" rel="noopener noreferrer"&gt;Directive composition API&lt;/a&gt; only supports standalone directives and components as host directives&lt;/li&gt;
&lt;li&gt;Standalone APIs are easier to teach and learn because of less mental overhead and simpler APIs using native data structures without framework-specific metadata&lt;/li&gt;
&lt;li&gt;The Angular Language Service only supports automatic imports for standalone components&lt;/li&gt;
&lt;li&gt;Component testing is easier with standalone declarables&lt;/li&gt;
&lt;li&gt;Storybook stories are easier with standalone declarables&lt;/li&gt;
&lt;li&gt;Standalone components can be lazy-loaded and dynamically  rendered using &lt;a href="https://angular.io/api/core/ViewContainerRef#createcomponent" rel="noopener noreferrer"&gt;ViewContainerRef#createComponent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Standalone components can be wrapped in React components as demonstrated by the &lt;a href="https://gist.github.com/lacolaco/8e81f61d82327b42f664cdc7080761ac" rel="noopener noreferrer"&gt;ngx-reactify&lt;/a&gt; proof-of-concept Gist&lt;/li&gt;
&lt;li&gt;Standalone components can be rendered and hydrated by &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; by &lt;a href="https://dev.to/brandontroberts/bringing-angular-components-to-astro-islands-52jp"&gt;using a plugin by Analog.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://angular.io/guide/defer" rel="noopener noreferrer"&gt;&lt;code&gt;@defer&lt;/code&gt; blocks&lt;/a&gt; only support standalone components in their derrable views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59ix6dlbbsrkcda57rx9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59ix6dlbbsrkcda57rx9.jpg" alt="Red pill: Standalone. Blue pill: NgModules." width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill, you stay in wonderland, and I show you how deep the rabbit hole goes.&lt;br&gt;
—Morpheus&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Angular CLI example for Jest Preview - the visual debugger for Jest</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Mon, 22 Aug 2022 11:22:31 +0000</pubDate>
      <link>https://forem.com/transient-thoughts/angular-cli-example-for-jest-preview-the-visual-debugger-for-jest-3hao</link>
      <guid>https://forem.com/transient-thoughts/angular-cli-example-for-jest-preview-the-visual-debugger-for-jest-3hao</guid>
      <description>&lt;p&gt;Recently, I contributed an Angular CLI example for &lt;a href="https://www.jest-preview.com/" rel="noopener noreferrer"&gt;Jest Preview&lt;/a&gt; in collaboration with its creator, &lt;a href="https://twitter.com/hung_dev" rel="noopener noreferrer"&gt;Hung Viet Nguyen&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jest Preview
&lt;/h2&gt;

&lt;p&gt;Jest Preview is a visual debugger for Jest component tests. It runs a preview server and either displays the rendered DOM of a failed test when the &lt;a href="https://www.jest-preview.com/docs/api/jestpreviewconfigure/#autopreview-boolean" rel="noopener noreferrer"&gt;&lt;code&gt;autoPreview&lt;/code&gt;&lt;/a&gt; option is set or the test we explicitly mark for debugging using the &lt;a href="https://www.jest-preview.com/docs/api/debug/" rel="noopener noreferrer"&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/a&gt; function, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// counter.component.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/user-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-preview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CounterComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CounterComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;initially has a zero count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CounterComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Open http://localhost:3336 to see preview&lt;/span&gt;
    &lt;span class="c1"&gt;// Require to run `jest-preview` server before&lt;/span&gt;
    &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 👈&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByTestId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toContainHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7awvwp2j6yjnir2g9sp6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7awvwp2j6yjnir2g9sp6.png" alt="Jest Preview displaying the counter component with a count of 0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular CLI integration
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nvh95/jest-preview/tree/main/examples/angular" rel="noopener noreferrer"&gt;The Angular CLI guide for Jest Preview&lt;/a&gt; refers to the common &lt;a href="https://www.jest-preview.com/docs/getting-started/installation" rel="noopener noreferrer"&gt;installation&lt;/a&gt; and &lt;a href="https://www.jest-preview.com/docs/getting-started/usage" rel="noopener noreferrer"&gt;usage&lt;/a&gt; instructions while describing Angular-specific configuration and usage instructions.&lt;/p&gt;

&lt;p&gt;While there is room for improvement, we documented workarounds in the guide. Jest Preview is not currently able to automatically transform &lt;code&gt;styleUrls&lt;/code&gt; in component tests, support inline component styles, or automatically import application-wide stylesheets. Because of this, we have to add stylesheet import statements in our tests to match the external stylesheet used by the component-under-test.&lt;/p&gt;

&lt;p&gt;For example, say we have this counter component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// counter.component.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// 👈&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;button type="button" (click)="onCount()"&amp;gt;
      The count is:
      &amp;lt;div data-testid="count"&amp;gt;{{ count }}&amp;lt;/div&amp;gt;
    &amp;lt;/button&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;onCount&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would have to add an import statement for &lt;code&gt;./counter.component.css&lt;/code&gt; in our component test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// counter.component.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/user-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-preview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CounterComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 👈&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CounterComponent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;displays multiple counts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CounterComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Open http://localhost:3336 to see preview&lt;/span&gt;
    &lt;span class="c1"&gt;// Require to run `jest-preview` server before&lt;/span&gt;
    &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByTestId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toContainHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx4027ibh4p1ycnv3q47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx4027ibh4p1ycnv3q47.png" alt="Jest Preview displaying the counter component with a count of 2"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>jest</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>Docusaurus website for Analog.js - the full-stack meta-framework for Angular using Vite</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Sun, 21 Aug 2022 19:28:06 +0000</pubDate>
      <link>https://forem.com/transient-thoughts/docusaurus-website-for-analogjs-the-full-stack-meta-framework-for-angular-using-vite-239j</link>
      <guid>https://forem.com/transient-thoughts/docusaurus-website-for-analogjs-the-full-stack-meta-framework-for-angular-using-vite-239j</guid>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/brandontroberts"&gt;Brandon Roberts&lt;/a&gt; is creating the first full-stack meta-framework for Angular and it is open sourced under the MIT license.&lt;/p&gt;

&lt;p&gt;Recently, I contributed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A website with documentation using Docusaurus, GitHub Pages, and GitHub Actions&lt;/li&gt;
&lt;li&gt;Cypress end-to-end test suites demonstrating and verifying how to use Cypress with Vite as the development server for an Angular application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The analogjs.org website
&lt;/h2&gt;

&lt;p&gt;The official website for Analog.js is &lt;a href="https://analogjs.org"&gt;analogjs.org&lt;/a&gt;. I set it up using &lt;a href="https://docusaurus.io/"&gt;Docusaurus&lt;/a&gt; on a free &lt;a href="https://docs.github.com/en/pages"&gt;GitHub Pages&lt;/a&gt; host with the brand-new GitHub Pages experience using GitHub Actions[&lt;a href="https://github.blog/2022-08-10-github-pages-now-uses-actions-by-default/"&gt;blog post&lt;/a&gt;][&lt;a href="https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow"&gt;documentation&lt;/a&gt;], GitHub Environments, and GitHub Deployments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ImSK0nv7KfY"&gt;
&lt;/iframe&gt;
&lt;br&gt;
I created this video demonstrating how to set up a Docusaurus website from scratch using GitHub Pages and GitHub Actions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The home page
&lt;/h3&gt;

&lt;p&gt;The hero banner on the home page links to the documentation and an Analog.js sandbox on StackBlitz.&lt;/p&gt;

&lt;p&gt;Next, the home page lists the current and upcoming features of Analog.js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vite-powered&lt;/li&gt;
&lt;li&gt;Hybrid SSR/SSG-support&lt;/li&gt;
&lt;li&gt;File-based routing&lt;/li&gt;
&lt;li&gt;API (server) routes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the Angular CLI has been using Webpack for a number of years, more modern and especially faster alternatives have emerged in the web ecosystem. One of them is &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt;. Analog.js publishes an Angular plugin for Vite demonstrating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Vite development server&lt;/li&gt;
&lt;li&gt;Bundling an application using Vite&lt;/li&gt;
&lt;li&gt;Unit testing using Vitest&lt;/li&gt;
&lt;li&gt;End-to-end-testing using a Vite development server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;Navigating to the documentation, the initial version of the website has these pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Contributors&lt;/li&gt;
&lt;li&gt;Contributing&lt;/li&gt;
&lt;li&gt;Sponsoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Packages
&lt;/h3&gt;

&lt;p&gt;Currently, two npm packages are released and documented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@analogjs/vite-plugin-angular"&gt;&lt;code&gt;@analogjs/vite-plugin-angular&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/create-analog"&gt;&lt;code&gt;create-analog&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first package is a Vite plugin to support Angular applications and the initializer scaffolds an Analog project.&lt;/p&gt;

&lt;h2&gt;
  
  
  End-to-end testing using Cypress and Vite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.cypress.io/"&gt;Cypress&lt;/a&gt; is a popular end-to-end testing framework. When using the Angular CLI, Webpack is used as the development server for Angular applications. &lt;a href="https://github.com/analogjs/analog"&gt;The Analog.js repository&lt;/a&gt; covers &lt;a href="https://angular.io/start"&gt;the Angular Getting Started tutorial application&lt;/a&gt; with end-to-end tests using Cypress with the Vite development server.&lt;/p&gt;

&lt;h2&gt;
  
  
  More to come
&lt;/h2&gt;

&lt;p&gt;Analog.js is just getting started. There are plenty of areas to contribute in. Contribute to &lt;a href="https://github.com/analogjs/analog/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc"&gt;Analog.js' GitHub issues&lt;/a&gt; or &lt;a href="https://analogjs.org/docs/sponsoring"&gt;support the core team on GitHub Sponsors&lt;/a&gt; to help make it happen.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>vite</category>
      <category>docusaurus</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Spectacular prerelease v0.5 supports standalone feature tests and uses partial Ivy compilation</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Wed, 10 Aug 2022 18:53:38 +0000</pubDate>
      <link>https://forem.com/transient-thoughts/spectacular-prerelease-v05-supports-standalone-feature-tests-and-uses-partial-ivy-compilation-6i8</link>
      <guid>https://forem.com/transient-thoughts/spectacular-prerelease-v05-supports-standalone-feature-tests-and-uses-partial-ivy-compilation-6i8</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover art by DALL-E.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In July 2022, we &lt;a href="https://github.com/ngworker/ngworker/releases/tag/spectacular-v0.5.0"&gt;published the version 0.5.0 of Spectacular&lt;/a&gt;, the integration testing library for Angular.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that for prerelase versions, that is versions &amp;lt;1.0.0, minor version increases indicate breaking changes, for example releasing version 0.4.0 introduces at least one breaking change compared to version 0.3.0. Patch version increases for prerelease versions indicate bugfixes, refactors, performance improvements, and/or feature additions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's discuss the features and breaking changes of these versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partial Ivy compilation
&lt;/h2&gt;

&lt;p&gt;Spectacular version 0.1.0-0.4.0 are compiled as View Engine-compatible bundles requiring the Angular Compatibility Compiler (NGCC) to be consumed.&lt;/p&gt;

&lt;p&gt;As of version 0.5.0, Spectacular is partially Ivy compiled as is the recommended practice for Angular libraries targeting Angular &amp;lt;=12.2.0. Starting with the future Angular version that removes NGCC, View Engine-compatible libraries stop working.&lt;/p&gt;

&lt;p&gt;The partial compilation is a performance improvement as most of the library is compiled before being published to a package registry. However, component templates are still required to be compiled in the context of an application.&lt;/p&gt;

&lt;p&gt;To use partial Ivy compilation, Spectacular version 0.5.0 requires at least Angular 12.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standalone feature test provider
&lt;/h2&gt;

&lt;p&gt;With the introduction of standalone Angular components and other standalone Angular APIs starting in Angular version 14 where standalone APIs are considered in &lt;em&gt;developer preview&lt;/em&gt;, we start exposing standalone APIs in Spectacular.&lt;/p&gt;

&lt;p&gt;Spectacular's first standalone API is a standalone provider factory for Spectacular's Feature testing API.&lt;/p&gt;

&lt;p&gt;Spectacular version 0.5.0 introduces &lt;a href="https://ngworker.github.io/ngworker/docs/api/modules#providespectacularfeaturetest"&gt;&lt;code&gt;provideSpectacularFeatureTest&lt;/code&gt;&lt;/a&gt; that configures the feature-aware navigation services &lt;a href="https://ngworker.github.io/ngworker/docs/api/classes/SpectacularFeatureLocation"&gt;&lt;code&gt;SpectacularFeatureLocation&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://ngworker.github.io/ngworker/docs/api/classes/SpectacularFeatureRouter"&gt;&lt;code&gt;SpectacularFeatureRouter&lt;/code&gt;&lt;/a&gt; for standalone Angular features.&lt;/p&gt;

&lt;p&gt;Feature testing a standalone Angular feature using Angular Testing Library and Spectacular:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provideSpectacularFeatureTest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularAppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularFeatureLocation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularFeatureRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ngworker/spectacular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Matcher&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/user-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;crisisCenterPath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tour-of-heroes/crisis-center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findCrisisCenterHomeGreeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/welcome to the crisis center/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findCrisisLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Exclude&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Matcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findNameControl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByPlaceholderText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/name/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findSaveButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/save/i&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findSelectedCrisis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Matcher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.selected a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularAppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;provideSpectacularFeatureTest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;featurePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crisisCenterPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularFeatureLocation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularFeatureRouter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Edit crisis from crisis detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crisisId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;crisisId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findNameControl&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findNameControl&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The global temperature is rising&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findSaveButton&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findSelectedCrisis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/the global temperature is rising/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`~/;id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;crisisId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;foo=foo`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Edit crisis from crisis center home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;navigateByUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findCrisisLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/procrastinators meeting delayed again/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findNameControl&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findNameControl&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Coral reefs are dying&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findSaveButton&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findCrisisCenterHomeGreeting&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;findSelectedCrisis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/coral reefs are dying/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Comparing the previous example to the following code snippet, the difference is in the &lt;code&gt;setup&lt;/code&gt; &lt;a href="https://medium.com/@kolodny/testing-with-sifers-c9d6bb5b362"&gt;SIFERS&lt;/a&gt; where we use &lt;a href="https://ngworker.github.io/ngworker/docs/api/modules#providespectacularfeaturetest"&gt;&lt;code&gt;provideSpectacularFeatureTest&lt;/code&gt;&lt;/a&gt; instead of &lt;a href="https://ngworker.github.io/ngworker/docs/api/classes/SpectacularFeatureTestingModule"&gt;&lt;code&gt;SpectacularFeatureTestingModule&lt;/code&gt;&lt;/a&gt; to adjust the options configuring Angular Testing Library's &lt;a href="https://testing-library.com/docs/angular-testing-library/api#render"&gt;&lt;code&gt;render&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;Feature test setup &lt;a href="https://medium.com/@kolodny/testing-with-sifers-c9d6bb5b362"&gt;SIFERS&lt;/a&gt; for an Angular feature module using Angular Testing Library and Spectacular:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularAppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularFeatureLocation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularFeatureRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;SpectacularFeatureTestingModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ngworker/spectacular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/user-event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CrisisCenterModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;crisisCenterPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tour-of-heroes/crisis-center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;debugElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularAppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;SpectacularFeatureTestingModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withFeature&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;featureModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CrisisCenterModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;featurePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;crisisCenterPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularFeatureLocation&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SpectacularFeatureRouter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://github.com/ngworker/ngworker/tree/main/packages/spectacular"&gt;the source code for Spectacular&lt;/a&gt; for more examples using the feature testing API or visit  &lt;a href="https://ngworker.github.io/ngworker/docs/feature-testing"&gt;our documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>angular</category>
      <category>testing</category>
      <category>spectacular</category>
    </item>
    <item>
      <title>Spectacular prerelease v0.4 reintroduces the required pipeName option for pipe harnesses</title>
      <dc:creator>Lars Gyrup Brink Nielsen</dc:creator>
      <pubDate>Wed, 10 Aug 2022 18:50:29 +0000</pubDate>
      <link>https://forem.com/transient-thoughts/spectacular-prerelease-v04-reintroduces-the-required-pipename-option-for-pipe-harnesses-23b7</link>
      <guid>https://forem.com/transient-thoughts/spectacular-prerelease-v04-reintroduces-the-required-pipename-option-for-pipe-harnesses-23b7</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover art by DALL-E.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In July 2022, we &lt;a href="https://github.com/ngworker/ngworker/releases/tag/spectacular-v0.4.0"&gt;published the version 0.4.0 prerelease of Spectacular&lt;/a&gt;, the integration testing library for Angular.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that for prerelase versions, that is versions &amp;lt;1.0.0, minor version increases indicate breaking changes, for example releasing version 0.4.0 introduces at least one breaking change compared to version 0.3.0. Patch version increases for prerelease versions indicate bugfixes, refactors, performance improvements, and/or feature additions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's discuss the breaking changes between prerelease versions 0.2.0-0.4.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pipeName option for pipe harnesses is reintroduced
&lt;/h2&gt;

&lt;p&gt;Back in Spectacular prerelease version 0.3.0, released in May 2022, we removed the &lt;code&gt;pipeName&lt;/code&gt; option from the &lt;code&gt;createPipeHarness&lt;/code&gt; factory to make Angular pipe testing easier. This was a breaking change as the &lt;code&gt;pipeName&lt;/code&gt; option was removed entirely in version 0.3.0.&lt;/p&gt;

&lt;p&gt;Unfortunately, a function we used internally for determining the pipe name was removed from Angular as it was a leftover from Angular View Engine.&lt;/p&gt;

&lt;p&gt;Because of this, Spectacular version 0.4.0 introduces the breaking change of adding back the required &lt;code&gt;pipeName&lt;/code&gt; option for &lt;code&gt;createPipeHarness&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Spectacular version 0.3.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createPipeHarness&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PowPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spectacular versions &amp;lt;0.3.0 &amp;gt;=0.4.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;harness&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createPipeHarness&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PowPipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;pipeName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read &lt;a href="https://ngworker.github.io/ngworker/docs/pipe-testing"&gt;the documentation for Spectacular's Pipe testing API&lt;/a&gt; for full examples of Angular pipe integration tests.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>angular</category>
      <category>testing</category>
      <category>spectacular</category>
    </item>
  </channel>
</rss>
