Angular-Testing-Library
Tags: angular, testing, typescript, javascript
Published: 2020-02-20 20:34:44

The Angular-Testing-Library implementation fits into the Karma/Jasmine framework like this:

```typescript
async function renderCheckbox(checked) {
   let temp = await render(CheckboxComponent, {
      imports: [ReactiveFormsModule]
   });
   let control = {
      GroupName: "This group name test",
      PropertyName: "The Checkbox component PropertyName Test",
      Type: "checkbox",
      CurrentValue: "checked",
      Checked: checked
   };
   temp.fixture.componentInstance.control = control;
   temp.fixture.detectChanges();
   return { temp, control };
}
```
The key function is "render" from which is an import from this framework.

Assume an Angular Component like this:

**Typescript**
```typescript
export class CheckboxComponent implements OnInit {
   @Input("control") control = {
      GroupName: "",
      PropertyName: "",
      Type: "",
      CurrentValue: "",
      Checked: ""
   };
   @Output() emitChange: EventEmitter<any> = new EventEmitter();

   public myFormGroup: FormGroup = new FormGroup({
      checkbox: new FormControl(this.control, [])
   });
   constructor() {}

   ngOnInit() {}
   onCheckBoxChanged() {
      let context = this.myFormGroup.controls.checkbox.value;
      let change = {
         GroupName: this.control.GroupName,
         PropertyName: this.control.PropertyName,
         Type: this.control.Type,
         CurrentValue: context
      };
      this.emitChange.emit(change);
   }
}

```
**HTML**

```html
<form [formGroup]="myFormGroup">
   <label>{{ control.PropertyName }}</label>
   <input
      data-testid="checkbox"
      *ngIf="control.Type === 'checkbox'"
      formControlName="checkbox"
      type="checkbox"
      [(ngModel)]="control.Checked"
      (change)="onCheckBoxChanged()"
   />
</form>
```
**Write your [Angular-Testing-Library](https://testing-library.com/docs/angular-testing-library/intro) Test**

This construct bypasses the default Angular test schematic. It majorly improves the dependency chain manual configuration problem.

```typescript
import { render} from "@testing-library/angular";
import { ReactiveFormsModule } from "@angular/forms";
import { CheckboxComponent } from "../checkbox/checkbox.component";

//our wrapper for the render function
async function renderCheckbox(checked) {
   let temp = 
await render(CheckboxComponent, {
      imports: [ReactiveFormsModule]
   });
   let control = {
      GroupName: "This group name test",
      PropertyName: "The Checkbox component PropertyName Test",
      Type: "checkbox",
      CurrentValue: "checked",
      Checked: checked
   };
   temp.fixture.componentInstance.control = control;
   temp.fixture.detectChanges();
   return { temp, control };
}

//jasmine tests start here
describe("CheckboxComponent", () => {
   it("should have a PropertyName", async () => {
      let { temp, control } = 

await renderCheckbox(true);
      let label = await temp.findByText(control.PropertyName);
      expect(label.innerText).toContain(control.PropertyName);
   });
   it("should not be checked", async () => {
      let { temp, control } = 

await renderCheckbox(false);
      let cb: any = temp.getByTestId("checkbox");
      expect(cb.checked).toBe(false);
   });
   it("should be checked", async () => {
      let { temp, control } = 

await renderCheckbox(true);
      let cb: any = temp.getByTestId("checkbox");
      expect(cb.checked).toBe(true);
   });
   it("should emit change", async () => {
      let { temp, control } = 

await renderCheckbox(true);
      temp.fixture.componentInstance.emitChange.subscribe(change => {
         expect(change.CurrentValue).toBe(false);
      });
      let checkbox: any = temp.getAllByTestId("checkbox")[0];
      checkbox.click();
      let actual = checkbox.checked;
      let currentContext =
         temp.fixture.componentInstance.myFormGroup.controls.checkbox.value;
      expect(actual).toBe(false);
   });
});

```

**Notes**

This function is the key:
```javascript
async function renderCheckbox(checked) {
   let temp = await render(CheckboxComponent, {
      imports: [ReactiveFormsModule]
   });
   let control = {
      GroupName: "This group name test",
      PropertyName: "The Checkbox component PropertyName Test",
      Type: "checkbox",
      CurrentValue: "checked",
      Checked: checked
   };
   temp.fixture.componentInstance.control = control;
   temp.fixture.detectChanges();
   return { temp, control };
}
```

Notice that temp is the RenderResult, See this article for what a RenderResult looks liks: 

{% link https://dev.to/jwp/converting-your-karma-jasmine-test-to-use-angular-testing-library-1id5 %}

The *renderResult.fixture.componentInstance* is the Angular Component. Getting addressibility to any HTMLElement in the component is easily done using the attribute as shown in the HTML above; (named data-testid) as shown here:

```html
data-testid="checkbox"

```
Allowing this statement to get the checkbox.  We ensure it's type of any because it allows us to easily test the "checked" property.

```Typescript
let cb: any = temp.getByTestId("checkbox");
  expect(cb.checked).toBe(false);
```

Note that we can subscribe to the component output as follows:

```Typescript
temp.fixture.componentInstance.emitChange.subscribe(change => {
 (change.CurrentValue).toBe(false);
});
```
However this subscription only works when we emulate a click event on the checkbox, like this:

```Typescript
 let checkbox: any = temp.getAllByTestId("checkbox")[0];
 checkbox.click();
```

All in all a nice way to allow something else to do the rendering *without* worrying about the dependencies.  Angular-Testing-Library is a good tool.

JWP2020