mseemann/angular2-mdl

View on GitHub
projects/core/src/lib/radio/mdl-radio.component.spec.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { TestBed, waitForAsync } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { Component, OnInit } from "@angular/core";
import { MdlRadioComponent, MdlRadioGroupRegisty } from "./mdl-radio.component";
import {
  UntypedFormBuilder,
  UntypedFormControl,
  UntypedFormGroup,
  FormsModule,
  ReactiveFormsModule,
} from "@angular/forms";
import { MdlRadioModule } from "./mdl-radio.module";

@Component({
  // eslint-disable-next-line
  selector: "test-radio",
  template: `
    <mdl-radio
      name="r"
      [(ngModel)]="radioValue"
      value="1"
      mdl-ripple
      (change)="onChange($event)"
      >radio label 1
    </mdl-radio>
    <mdl-radio
      name="r"
      [(ngModel)]="radioValue"
      value="2"
      mdl-ripple
      (change)="onChange($event)"
      >radio label 2
    </mdl-radio>
  `,
})
class MdlTestRadioComponent {
  radioValue = "2";
  radioVisible = true;
  form: UntypedFormGroup;
  test = new UntypedFormControl("");

  constructor(private fb: UntypedFormBuilder) {
    this.form = this.fb.group({
      test: this.test,
    });
  }

  // eslint-disable-next-line @typescript-eslint/no-empty-function,@typescript-eslint/no-unused-vars
  public onChange(v: string | unknown) {}
}

@Component({
  // eslint-disable-next-line
  selector: "test-radio",
  template: `
    <form [formGroup]="testForm">
      <div formGroupName="group1" mdl-radio-group>
        <mdl-radio formControlName="type" value="type1" id="g1t1"></mdl-radio>
        <mdl-radio formControlName="type" value="type2" id="g1t2"></mdl-radio>
      </div>
      <div formGroupName="group2">
        <mdl-radio formControlName="type" value="type1" id="g2t1"></mdl-radio>
        <mdl-radio formControlName="type" value="type2" id="g2t2"></mdl-radio>
      </div>
    </form>
  `,
})
class MdlTestUseSameRadioInGroupsComponent {
  public testForm = new UntypedFormGroup({
    group1: new UntypedFormGroup({
      type: new UntypedFormControl(""),
    }),
    group2: new UntypedFormGroup({
      type: new UntypedFormControl(""),
    }),
  });
}

describe("Component: MdlRadio", () => {
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        imports: [MdlRadioModule.forRoot(), FormsModule, ReactiveFormsModule],
        declarations: [
          MdlTestRadioComponent,
          MdlTestUseSameRadioInGroupsComponent,
        ],
      });
    })
  );

  it("should add the css class mdl-radio to the host element", () => {
    const fixture = TestBed.createComponent(MdlTestRadioComponent);
    fixture.detectChanges();

    const checkboxEl: HTMLElement = fixture.nativeElement.children.item(0);
    expect(checkboxEl.classList.contains("mdl-radio")).toBe(true);
  });

  it(
    "should support ngModel",
    waitForAsync(() => {
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const instance = fixture.componentInstance;
      const component = fixture.debugElement.queryAll(
        By.directive(MdlRadioComponent)
      )[0];

      instance.radioValue = "1";
      fixture.detectChanges();
      fixture.whenStable().then(() => {
        expect(component.componentInstance.optionValue).toEqual("1");

        const component2 = fixture.debugElement.queryAll(
          By.directive(MdlRadioComponent)
        )[1];
        component2.nativeElement.click();
        fixture.detectChanges();
        fixture.whenStable().then(() => {
          expect(component.componentInstance.optionValue).toEqual("2");
        });
      });
    })
  );

  it("should mark the component as focused and blured", () => {
    const fixture = TestBed.createComponent(MdlTestRadioComponent);
    fixture.detectChanges();

    const inputEl: HTMLInputElement = fixture.debugElement.queryAll(
      By.css("input")
    )[0].nativeElement;

    inputEl.dispatchEvent(new Event("focus"));

    fixture.detectChanges();

    const radioEl: HTMLElement = fixture.debugElement.queryAll(
      By.directive(MdlRadioComponent)
    )[0].nativeElement;
    expect(radioEl.classList.contains("is-focused")).toBe(true);

    inputEl.dispatchEvent(new Event("blur"));

    fixture.detectChanges();
    expect(radioEl.classList.contains("is-focused")).toBe(false);
  });

  it(
    "should throw if name and formcontrolname are different",
    waitForAsync(() => {
      TestBed.overrideComponent(MdlTestRadioComponent, {
        set: {
          template: `
        <mdl-radio name="r" formControlName="test" value="1" mdl-ripple>radio label 1</mdl-radio>
        <mdl-radio name="r" formControlName="test" value="2" mdl-ripple>radio label 2</mdl-radio>
      `,
        },
      });
      const fixture = TestBed.createComponent(MdlTestRadioComponent);

      expect(() => {
        fixture.detectChanges();
      }).toThrow();
    })
  );

  it(
    "should take the name from formcontrolname if no name os provided",
    waitForAsync(() => {
      TestBed.overrideComponent(MdlTestRadioComponent, {
        set: {
          template: `
        <form [formGroup]="form">
          <mdl-radio formControlName="test" value="1" mdl-ripple>radio label 1</mdl-radio>
        </form>
      `,
        },
      });
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const radioComponent = fixture.debugElement.query(
        By.directive(MdlRadioComponent)
      ).componentInstance;
      expect(radioComponent.name).toEqual("test");
    })
  );

  it(
    "should remove mdl-radio if the component is destroyed",
    waitForAsync(() => {
      TestBed.overrideComponent(MdlTestRadioComponent, {
        set: {
          template: `
      <form [formGroup]="form">
        <mdl-radio formControlName="test" value="1" mdl-ripple>radio label 1</mdl-radio>
        <mdl-radio *ngIf="radioVisible" formControlName="test" value="2" mdl-ripple>radio label 3</mdl-radio>
      </form>
    `,
        },
      });
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const registry = TestBed.inject(MdlRadioGroupRegisty);

      spyOn(registry, "remove").and.callThrough();

      fixture.componentInstance.radioVisible = false;

      fixture.detectChanges();

      expect(registry.remove).toHaveBeenCalled();
    })
  );

  it(
    "should fire a change event if the state changed",
    waitForAsync(() => {
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const instance = fixture.componentInstance;

      spyOn(instance, "onChange");

      const component2 = fixture.debugElement.queryAll(
        By.directive(MdlRadioComponent)
      )[1];
      component2.nativeElement.click();

      expect(instance.onChange).toHaveBeenCalledWith("2");
    })
  );

  it(
    "should be possible to disable the radio input",
    waitForAsync(() => {
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const instance = fixture.componentInstance;
      const cbDebugElem = fixture.debugElement.queryAll(
        By.directive(MdlRadioComponent)
      )[0];

      cbDebugElem.componentInstance.setDisabledState(true);
      fixture.detectChanges();

      const checkboxEl: HTMLElement = cbDebugElem.nativeElement;
      expect(checkboxEl.classList.contains("is-disabled")).toBe(
        true,
        "should have css is-disabled"
      );

      const value = instance.radioValue;
      // should not change on click
      cbDebugElem.nativeElement.click();
      expect(instance.radioValue).toEqual(value);
    })
  );

  it(
    "should not change its current state if it is already checked",
    waitForAsync(() => {
      const fixture = TestBed.createComponent(MdlTestRadioComponent);
      fixture.detectChanges();

      const cbDebugElem1 = fixture.debugElement.queryAll(
        By.directive(MdlRadioComponent)
      )[0];
      const cbInputEl = cbDebugElem1.query(By.css("input"));

      expect(cbDebugElem1.componentInstance.checked).toBe(false);

      cbInputEl.triggerEventHandler("keyup.space", {});
      fixture.detectChanges();
      expect(cbDebugElem1.componentInstance.checked).toBe(false);
    })
  );

  it("should be possible to use the same radio buttons in different groups", () => {
    const fixture = TestBed.createComponent(
      MdlTestUseSameRadioInGroupsComponent
    );
    fixture.detectChanges();

    const g1t1Elem = fixture.debugElement.query(By.css("#g1t1")).nativeElement;
    const g1t2Elem = fixture.debugElement.query(By.css("#g1t2")).nativeElement;
    const g2t1Elem = fixture.debugElement.query(By.css("#g2t1")).nativeElement;

    g1t1Elem.click();
    fixture.detectChanges();

    expect(g1t1Elem.classList.contains("is-checked")).toBe(
      true,
      "the clicked one should be selected"
    );
    expect(g2t1Elem.classList.contains("is-checked")).toBe(
      false,
      "the not clicked one should not be selected"
    );

    g1t2Elem.click();
    fixture.detectChanges();

    expect(g1t1Elem.classList.contains("is-checked")).toBe(
      false,
      "the not clicked one should not be selected"
    );
    expect(g2t1Elem.classList.contains("is-checked")).toBe(
      false,
      "the not clicked one should not be selected"
    );
  });

  it("should be possible to set a tabindex", () => {
    TestBed.overrideComponent(MdlTestRadioComponent, {
      set: {
        template: '<mdl-radio tabindex="2"></mdl-radio>',
      },
    });

    const fixture = TestBed.createComponent(MdlTestRadioComponent);
    fixture.detectChanges();

    const btnEl: HTMLInputElement = fixture.debugElement.query(
      By.css("input")
    ).nativeElement;
    expect(btnEl.tabIndex).toBe(2);
  });

  it("should not set a default tabindex", () => {
    TestBed.overrideComponent(MdlTestRadioComponent, {
      set: {
        template: "<mdl-radio></mdl-radio>",
      },
    });

    const fixture = TestBed.createComponent(MdlTestRadioComponent);
    fixture.detectChanges();

    const el: HTMLInputElement = fixture.debugElement.query(
      By.css("input")
    ).nativeElement;

    expect(el.getAttribute("tabindex")).toEqual(null);
  });
});