DEV Community

This Dot Media for This Dot

Posted on • Edited on • Originally published at thisdot.co

Mixing Storybook with Angular with a Sprinkle of Applitools

To better understand the Applitools Storybook SDK for Angular, we will be building a small Angular application from scratch, adding some Storybook stories, and then finally performing visual regression testing using the Applitools SDK to generate snapshots for us to view and analyze.

You can find the source code for this article on GitHub by following this link storybook-angular-applitools repo.

Create Angular 7 App using the latest CLI

Make sure you have the latest Angular CLI installed. In my case, I will be using the Angular CLI v7.0.2. Create a new Angular App using the following npm command:

ng new storybook-angular-applitools
Enter fullscreen mode Exit fullscreen mode




Create the ContentEditable Component

The ContentEditable component we are going to build in this section wraps an HTML

element and adds an HTML attribute of contenteditable=”true”. The component implements the ControlValueAccessor so that the component can be used like any other Angular form control inside HTML forms.
<div contenteditable=”true”>This is an editable paragraph.</div>

The HTML fragment above renders in the browser as an editable area that users can click and enter any text or HTML.

Create a new component file and add the following markup to contenteditable.component.html file:

<div 
 #container 
 [ngStyle]=”styles” 
 [innerHTML]=”contentValue” 
 (input)=”setContent($event)” 
 contenteditable=”true”>
 </div>

Next, add the code below to the contenteditable.component.ts file:

import { Component, ChangeDetectionStrategy, Input, forwardRef, OnChanges, SimpleChanges, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'editable',
  templateUrl: `./contenteditable.component.html`,
  styles: [],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ContentEditableComponent),
      multi: true
    }
  ],

})
export class ContentEditableComponent
  implements ControlValueAccessor, OnChanges {
  @ViewChild('container') container;
  private _styles: any;
  private _contentValue: any;

  propagateChange: (value: any) => void = () => {};

  @Input()
  set styles(style: any) {
    this._styles = style;
  }

  get styles(): any {
    return this._styles;
  }

  get contentValue(): any {
    return this._contentValue;
  }

  set contentValue(val: any) {
    if (this._contentValue !== val) {
      this._contentValue = val;
      this.propagateChange(val);
    }
  }

  writeValue(value: any) {
    if (value !== this._contentValue) {
      this.contentValue = value;
    }
  }

  registerOnChange(fn: (value: any) => void) {
    this.propagateChange = fn;
  }

  registerOnTouched(fn: () => void) {}

  setContent($event: any): void {
    // this._contentValue = $event.target.innerHTML;
    this.propagateChange($event.target.innerHTML);
  }

  ngOnChanges(changes: SimpleChanges): void {}
}

The component is straightforward and follows the best practices in building a ControlValueAccessor. It defines a single @Input() property to allow the consumer of this component to control its styling.

If you want to fully understand how ControlValueAccessor works in Angular check out Max’s article titled Never again be confused when implementing ControlValueAccessor in Angular.

Next, add the following HTML snippet to the app.component.html file:

<section class="section">
 <h2>Two-way Data-binding</h2>
 <editable name="editable2" [styles]="styles()" [(ngModel)]="content1"></editable>
 <pre>{ content1 | json }</pre>
</section>

Define the styles() method inside the AppComponent class:

styles() {
 return {
  "background-color": "yellow",
   margin: "10px auto",
  "max-width": "60%",
  "line-height": "25px",
  padding: "10px"
 };
}

And now run the application. You should see something similar to this below.

ContentEditableComponent in action

You can start typing in the yellow editable rectangle and you will see whatever you type underneath.

Let’s switch gears and add Storybook to the application.

Add Storybook packages

We need to add Storybook for Angular to your application. The Storybook website offers a detailed installation guide on Storybook for Angular. Once installed, apply the following changes, so that Storybook runs correctly with your Angular 7 application.

Open the src/app/tsconfig.app.json file and make sure the exclude property has the following values:

"exclude": [
  "test.ts",
  "**/*.spec.ts",
  "stories"
 ]

Open the .storybook/tsconfig.json file and paste the following:

{
 "extends": "../src/tsconfig.app.json",
 "compilerOptions": {
    "types": [
    "node"
  ]
 },
 "exclude": [
    "../src/test.ts",
    "../src/**/*.spec.ts",
    "../projects/**/*.spec.ts"
 ],
 "include": [
    "../src/**/*",
    "../projects/**/*"
 ]
}

Create and run a few Storybook stories

Add the following Storybook stories into the file located at src/app/stories/index.stories.ts:

storiesOf('ContentEditable Component', module)
 .add(
   'with yellow background',
   withNotes('Testing the background color for the editable area and setting it to yellow')(() => ({
     component: ContentEditableComponent,
     props: {
       styles: { 'background-color': 'yellow', 'padding': '20px' },
       ngModel: 'The content goes here',
       ngModelChange: action('ngModelChange')
     }
   }))
 )
 .add(
   'with red background',
   withNotes('Testing the background color for the editable area by setting it to red')(() => ({
     component: ContentEditableComponent,
     props: {
       styles: { 'background-color': 'red', 'color': '#fff', 'padding': '20px' },
       ngModel: 'The content goes here',
       ngModelChange: action('ngModelChange')
     }
   }))
 );

The first story renders the ContentEditable component with a yellow background. While the second renders the component with a red background.

Run the Storybook tool to view and test your stories by issuing the following CLI command:

npm run storybook

You should be able to see something similar to this:

ContentEditableComponent under Storybook IDE

Now that we are sure the Storybook stories are up and running, let’s set up Applitools to use these stories and run our visual automated tests.

Add and run Applitools Storybook SDK for Angular

To add Applitools Storybook SDK for Angular to this application issue the following CLI command:

npm install @applitools/eyes.storybook --save-dev

Make sure to grab an Applitool API Key and store it on your machine. For a complete tutorial on how to install and run Applitools Storybook SDK for Angular, you may check this link: Storybook Angular Tutorial.

To run the Storybook stories and send the snapshots to the Applitools Server, issue the following command:

npx [eyes-storybook](https://github.com/applitools/eyes.storybook)

The command simply opens the Storybook stories, runs them one by one, and then sends all the DOM snapshots to the Applitools Server. Let’s have a look at the test results inside Applitools Test Manager.

Review test results on Applitools Test Manager

We can see the results of the tests we just ran from the Applitools Test Manager. To access the Applitools Test Manager, navigate to https://www.applitools.com. Sign in to get onto the Dashboard. For a detailed look at the Applitools Test Manager, you can check my article on Applitools — The automated visual regression testing framework

The results for running the Storybook tests show the following:

Applitools Test Manager Results

The test manager lists the test runs or batches (as referred to by Applitools) on the left- hand side. Clicking on any of the batches displays all of the snapshots for all of the Storybook stories in your application.

Click on the first snapshot (the red color) to expand and review it in detail:

Inspecting results with Test Manager

A rich toolbox is available to zoom in/out on the snapshot and compare this snapshot to any previously taken, known as the baseline. In this case, since this is the first time we are running the stories, there won’t be any baseline set. Therefore, Applitools Test Manager sets these snapshots as a baseline for upcoming regression test cycles.

Next, we’re going to simulate what happens when we have a visual regression in one of our components. To do this most easily, we’ll change one of our Storybook stories to render our component in a way that will be different from the baseline images we took earlier. Then, when we re-run the visual testing, we should see a discrepancy appear that we’ll have to resolve.

To do this, let’s assume that the story named in the red background above, has the ngModel value changed and now reads as follows:

.add(
  'with red background',
  withNotes('Testing the background color for the editable area by setting it to red')(() => ({
    component: ContentEditableComponent,
    props: {
      styles: { 'background-color': 'red', 'color': '#fff', 'padding': '20px' },
      ngModel: 'The red content goes here',
      ngModelChange: action('ngModelChange')
    }
  }))
 )

Now run this command:

npx eyes-storybook

The command gives you a detailed test result every time you run it. Check the following results:

Using @applitools/eyes.storybook version 2.1.9.

√ Storybook was started
√ Reading stories
√ Done 2 stories out of 2

[EYES: TEST RESULTS]:

ContentEditable Component: with yellow background [1024x768] — Passed

ContentEditable Component: with red background [1024x768] — Failed 1 of 1

A total of 1 difference was found.

See details at [https://eyes.applitools.com/app/test-results/00000251861893628194?accountId=D9XKRBVuYUmBxXpWWWsB3g~~](https://eyes.applitools.com/app/test-results/00000251861893628194?accountId=D9XKRBVuYUmBxXpWWWsB3g~~)

Total time: 36 seconds

Running the second story fails, as expected because we changed the content that was initially displayed inside the ContentEditable component. The test result output provides you with a link to check the discrepancies online. Click on the link to open the issues directly in the Applitools Test Manager:

Showing differences on the Test Manager

A new batch is displayed on the left-hand side with a status of Unresolved. The Unresolved status indicates that the Applitools Test Manager discovered a discrepancy between the two test runs. This will require your input in order to resolve the discrepancy. Either approve the difference, and create a new baseline, or reject it to keep the original baseline.

Notice the blue square above indicating the Not Equal sign. This means the second snapshot test run has some differences to the first test run snapshot (the baseline). Clicking on the first snapshot reveals the differences between both snapshots. The current one and the baseline. The differences in content are highlighted in blue. You can also compare the new snapshot with the baseline by selecting both:

Compare two snapshots side by side

This should display both side by side and all differences are highlighted for you. You may spend more time at the Applitools Test Manager to explore all the rich features provided for you to do a thorough analysis on running the story tests.

Conclusion

This article touched the surface on how you can mix together Storybook and Angular together in one application. By means of Applitools Storybook SDK for Angular, you can provide automated visual UI testing by running the Storybook stories and generate snapshots that are then sent to the Applitools AI Server to compare and analyze and prepare the test results for you.

You can grab the code for this article by cloning the repository on GitHub.

This post was written by Bilal Haidar, a mentor with This Dot.

Need JavaScript consulting, mentoring, or training help? Check out our list of services at This Dot Labs.

Top comments (0)