I am trying to write some tests for a component that uses Angular Material Components. I read about the CDK Test Harness https://material.angular.io/guide/using-component-harnesses and I want to fetch the count of options in the Mat Select component based on that.
<mat-card>
<mat-card-content>
<form [formGroup]="filterLikelihoodForm" (ngSubmit)="onSearchClick()">
<div class="container">
<div class="row align-items-center">
<div class="col-sm">
<mat-form-field class="full-width" id="periodField">
<mat-label>Select Period</mat-label>
<mat-select formControlName="period" id="period">
<mat-option *ngFor="let period of periodList" [value]="period.id">
{{ period.monthName }}
</mat-option>
</mat-select>
<mat-error *ngIf="f.period.errors">
Please select a valid period
</mat-error>
</mat-form-field>
</div>
<div class="col-sm">
<mat-form-field class="full-width">
<input
matInput
type="number"
formControlName="finishedDeals"
placeholder="Enter no of finished deals"
/>
<mat-error *ngIf="f.finishedDeals.errors">
Please enter a valid number
</mat-error>
</mat-form-field>
</div>
<div class="col-sm">
<button
mat-flat-button
color="primary"
[disabled]="filterLikelihoodForm.invalid"
class="full-width"
>
Search
</button>
</div>
</div>
</div>
</form>
</mat-card-content>
</mat-card>
Here is my spec file code:
import { HarnessLoader } from "@angular/cdk/testing";
import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed";
import { TestBed, async, ComponentFixture } from "@angular/core/testing";
import { FilterLikelihoodComponent } from "./filter-likelihood.component";
import { MatFormFieldHarness } from "@angular/material/form-field/testing";
import { MatFormFieldModule } from "@angular/material/form-field";
import { ReactiveFormsModule } from "@angular/forms";
import { MatSelectModule } from "@angular/material/select";
import { MatCardModule } from "@angular/material/card";
import { MatButtonModule } from "@angular/material/button";
import { MatInputModule } from "@angular/material/input";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { periodListMock } from "./mock/filter-likelihood.mock";
import { MatSelectHarness } from "@angular/material/select/testing";
import { MatButtonHarness } from "@angular/material/button/testing";
import { Component } from "@angular/core";
import { MatInputHarness } from "@angular/material/input/testing";
describe("Filter Likelihood Component", () => {
let testHostComponent: TestHostComponent;
let testHostFixture: ComponentFixture<TestHostComponent>;
let component: FilterLikelihoodComponent;
let fixture: ComponentFixture<FilterLikelihoodComponent>;
let loader: HarnessLoader;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [FilterLikelihoodComponent, TestHostComponent],
imports: [
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatCardModule,
MatButtonModule,
MatInputModule,
NoopAnimationsModule,
],
}).compileComponents();
}));
beforeEach(() => {
testHostFixture = TestBed.createComponent(TestHostComponent);
testHostComponent = testHostFixture.componentInstance;
testHostFixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(testHostFixture);
});
it("should have correct period label", async () => {
const expectedLabel = "Select Period";
const periodFieldHarness = await loader.getHarness<MatFormFieldHarness>(
MatFormFieldHarness.with({ selector: "#periodField" })
);
const actual = await periodFieldHarness.getLabel();
expect(actual).toBe(expectedLabel);
});
it("should have 3 recent periods in the dropdown", async () => {
const expectedCount = 3;
const selectHarness = await loader.getHarness<MatSelectHarness>(
MatSelectHarness
);
const actual = ((await selectHarness.getOptions()).length);
expect(actual).toBe(expectedCount);
});
it("should have a search button", async () => {
const expectedLabel = "Search";
const buttonHarness = await loader.getHarness<MatButtonHarness>(
MatButtonHarness
);
const actual = await buttonHarness.getText();
expect(actual).toBe(expectedLabel);
});
it("should have 10 finished deals by default", async () => {
const expectedFinishedDeals = 10;
const inputHarness = await loader.getHarness<MatInputHarness>(
MatInputHarness
);
const actual = await inputHarness.getValue();
expect(parseInt(actual)).toBe(expectedFinishedDeals);
});
it("should have a enabled button by default", async () => {
const expectedDisabledState = false;
const buttonHarness = await loader.getHarness<MatButtonHarness>(
MatButtonHarness
);
const actual = await buttonHarness.isDisabled();
expect(actual).toBe(expectedDisabledState);
});
@Component({
selector: `host-component`,
template: `<app-filter-likelihood
[periodList]="periodList"
[initialFinishedDeals]="defaultFinishedDeals"
></app-filter-likelihood>`,
})
class TestHostComponent {
periodList = new Helper().mockPeriodList;
defaultFinishedDeals = 10;
}
});
class Helper {
mockPeriodList = periodListMock;
}
The second spec with title "should have 3 recent periods in the dropdown" is failing as I am getting the options count as 0 always.
Can someone help me figure out my bug and let me know the correct way to write this spec using Mat test harness?
Thanks in advance!
A component harness is a testing API around an Angular directive or component. Component harnesses can be shared between unit tests, integration tests, and end-to-end tests. They result in less brittle tests as implementation details are hidden from test suites.
It represents an abstraction of the core functionalities found in the Angular Material library, without any styling specific to Material Design. Think of the CDK as a blank state of well-tested functionality upon which you can develop your own bespoke components. Common Behaviors Tools for implementing common application features.
Complete Example 7. Run Test Cases To run the test cases, find the steps. 1. Install Angular CLI using link . 2. Download source code using download link given below on this page. 3. Use downloaded src in your Angular CLI application. 4. Run ng test using command prompt. Test result can be seen on command prompt as well as on browser.
In our component we have two select elements and their property binding are performed by FormControl. Our test cases will be as following. 1. When we change the value of component property, the selected value should be changed of the associated select element. 2. We will test the changing of selected value from dropdown. 3.
After some tinkering with the Select Harness API, I was able to solve this. I have updated the spec to get the host element and then triggered a click event.
it("should have 3 recent periods in the dropdown", async () => {
const expectedCount = 3;
const selectHarness = await loader.getHarness<MatSelectHarness>(
MatSelectHarness
);
//Click the select element host
await (await selectHarness.host()).click();
const actual = (await selectHarness.getOptions()).length;
expect(actual).toBe(expectedCount);
});
You are trying to get number of options before you open select element.
const selectHarness = await loader.getHarness<MatSelectHarness>(MatSelectHarness);
const count = (await selectHarness.getOptions()).length; // count will be 0
await selectHarness.open(); // you can open matselect element via open method
const count = (await selectHarness.getOptions()).length; // count will be as expected
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With