How to Test Storybook Components in Angular Applications
How to build an Angular app, add some Storybook stories, and perform visual regression testing using the Applitools SDK to create snapshots to view and analyze.
Join the DZone community and get the full member experience.
Join For FreeTo better understand the Applitools Storybook SDK for Angular, here is a tutorial on how to build 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
Create the ContentEditable Component
The ContentEditable component we are going to build in this section wraps an HTML <div> 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.
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:
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 Applitools 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
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 this article: Applitools - The automated visual regression testing framework.
The results for running the Storybook tests show the following:
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:
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~~
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:
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:
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.
So how are you going to test the Storybook components in your Angular apps?
Published at DZone with permission of Al Sargent. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments