Wrapped mat-radio component tests input checked property not working

86 views Asked by At

Hi I am trying to wrap the mat radio button and write unit test but im now blocked on this: "should uniquely select radios by a name".

I am trying to test the wrapped component with some basic test to check that all functionality is working correctly.

but when I set the checked input of my component it does not seem to propagate to the mat-radio-button wrapped when i test


  it('should uniquely select radios by a name', () => {
    seasonRadioInstances[0].checked = true;
    weatherRadioInstances[1].checked = true; 


    fixture.detectChanges();
// now the mat-radio-button should be updated but is not
    expect(seasonRadioInstances[0].checked).toBe(true);
    expect(seasonRadioInstances[1].checked).toBe(false);
    expect(seasonRadioInstances[2].checked).toBe(false);
    expect(weatherRadioInstances[0].checked).toBe(false);
    expect(weatherRadioInstances[1].checked).toBe(true);
    expect(weatherRadioInstances[2].checked).toBe(false);
}))

@Component({
  template: `
        <my-wrap-radio-button name="season" value="spring">Spring</my-wrap-radio-button>
        <my-wrap-radio-button name="season" value="summer">Summer</my-wrap-radio-button>
        <my-wrap-radio-button name="season" value="autum">Autumn</my-wrap-radio-button>

        <my-wrap-radio-button name="weather" value="warm">Spring</my-wrap-radio-button>
        <my-wrap-radio-button name="weather" value="hot">Summer</my-wrap-radio-button>
        <my-wrap-radio-button name="weather" value="cool">Autumn</my-wrap-radio-button>

        <span id="xyz">Baby Banana</span>
        <span id="abc">A smaller banana</span>
        <my-wrap-radio-button
          name="fruit"
          value="banana"
        >
        </my-wrap-radio-button>
        <my-wrap-radio-button name="fruit" value="raspberry">Raspberry</my-wrap-radio-button>
        <my-wrap-radio-button id="nameless" value="no-name">No name</my-wrap-radio-button>
      `,
})
class StandaloneRadioButtons {
  ariaLabel: string = 'Banana';
  ariaLabelledby: string = 'xyz';
  ariaDescribedby: string = 'abc';
}

where im going wrong with this wrap? i suppose this is a "ChangeDetection" issue, but i cannot i only update the inputs, find how to fix it... i am trying to tick and fixture when stable but no one is working.

here I have reproduced the issue with tests:

https://stackblitz.com/edit/bjdbyf?file=src%2Fapp%2Fradio-example.spec.ts

2

There are 2 answers

0
luigi denora On BEST ANSWER

I fixed the test. Just add detectChanges in the test after fixture.detectChanges for each radio instance."

Here's the code:

    it('should uniquely select radios by a name', () => {
      seasonRadioInstances[0].checked = true;
      weatherRadioInstances[1].checked = true;

      detectChanges();

      expect(seasonRadioInstances[0].checked).toBe(true);
      expect(seasonRadioInstances[1].checked).toBe(false);
      expect(seasonRadioInstances[2].checked).toBe(false);
      expect(weatherRadioInstances[0].checked).toBe(false);
      expect(weatherRadioInstances[1].checked).toBe(true);
      expect(weatherRadioInstances[2].checked).toBe(false);

      seasonRadioInstances[1].checked = true;

      detectChanges();

      expect(seasonRadioInstances[0].checked).toBe(false);
      expect(seasonRadioInstances[1].checked).toBe(true);
      expect(seasonRadioInstances[2].checked).toBe(false);
      expect(weatherRadioInstances[0].checked).toBe(false);
      expect(weatherRadioInstances[1].checked).toBe(true);
      expect(weatherRadioInstances[2].checked).toBe(false);

      weatherRadioInstances[2].checked = true;

      detectChanges();

      expect(seasonRadioInstances[0].checked).toBe(false);
      expect(seasonRadioInstances[1].checked).toBe(true);
      expect(seasonRadioInstances[2].checked).toBe(false);
      expect(weatherRadioInstances[0].checked).toBe(false);
      expect(weatherRadioInstances[1].checked).toBe(false);
      expect(weatherRadioInstances[2].checked).toBe(true);

      function detectChanges() {
        // need to force detectChanges in components
        seasonRadioInstances.forEach(r => r['_changeDetector'].detectChanges());
        weatherRadioInstances.forEach(r => r['_changeDetector'].detectChanges());
        fixture.detectChanges();
      }
    });
0
Naren Murali On

Please refer the below stackblitz on how to test for material.

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ReactiveFormsModule } from '@angular/forms';
import { Component, DebugElement } from '@angular/core';
import { MyWrapRadioButtonComponent } from './wrap/wrap-example.component';
import { MyModule } from './wrap/wrap.module';
import { By } from '@angular/platform-browser';
import { HarnessLoader } from '@angular/cdk/testing';
import {
  MatRadioButtonHarness,
  MatRadioGroupHarness,
} from '@angular/material/radio/testing';
import {
  BrowserDynamicTestingModule,
  platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
import { MatRadioModule } from '@angular/material/radio';

describe('test', () => {
  let fixture: ComponentFixture<StandaloneRadioButtons>;
  let loader: HarnessLoader;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MatRadioModule, ReactiveFormsModule],
      declarations: [MyWrapRadioButtonComponent, StandaloneRadioButtons],
    }).compileComponents();
    fixture = TestBed.createComponent(StandaloneRadioButtons);
    fixture.detectChanges();
    loader = TestbedHarnessEnvironment.loader(fixture);
  });

  it('should load all radio-group harnesses', async () => {
    const groups = await loader.getAllChildLoaders(
      'my-wrap-radio-button[name="season"]'
    );
    expect(groups.length).toBe(3);
  });

  // it('should get name of radio-group', async () => {
  //   const group = await loader.getHarness(MatRadioGroupHarness);
  //   const name = await group.getName();
  //   expect(name).toBe('flavors');
  // });

  it('should check radio button', async () => {
    const groups = await loader.getAllChildLoaders(
      'my-wrap-radio-button[name="season"]'
    );
    const buttons: any = [];
    groups.forEach(async (x) => {
      const buttonsIn = x.getHarness(MatRadioButtonHarness);
      buttons.push(buttonsIn);
    });
    const data = await Promise.all(buttons);
    await data[1].check();
    expect(await data[1].isChecked()).toBeTrue();
    expect(await data[0].isChecked()).toBeFalse();
    expect(await data[2].isChecked()).toBeFalse();
    await data[0].check();
    expect(await data[1].isChecked()).toBeFalse();
    expect(await data[0].isChecked()).toBeTrue();
    expect(await data[2].isChecked()).toBeFalse();
    await data[2].check();
    expect(await data[1].isChecked()).toBeFalse();
    expect(await data[0].isChecked()).toBeFalse();
    expect(await data[2].isChecked()).toBeTrue();
  });

  // it('should get label text of buttons', async () => {
  //   const [firstRadio, secondRadio, thirdRadio] = await loader.getAllHarnesses(
  //     MatRadioButtonHarness
  //   );
  //   expect(await firstRadio.getLabelText()).toBe('Chocolate');
  //   expect(await secondRadio.getLabelText()).toBe('Vanilla');
  //   expect(await thirdRadio.getLabelText()).toBe('Strawberry');
  // });
});

@Component({
  template: `
        <my-wrap-radio-button name="season" value="spring">Spring</my-wrap-radio-button>
        <my-wrap-radio-button name="season" value="summer">Summer</my-wrap-radio-button>
        <my-wrap-radio-button name="season" value="autum">Autumn</my-wrap-radio-button>

        <my-wrap-radio-button name="weather" value="warm">Spring</my-wrap-radio-button>
        <my-wrap-radio-button name="weather" value="hot">Summer</my-wrap-radio-button>
        <my-wrap-radio-button name="weather" value="cool">Autumn</my-wrap-radio-button>

        <span id="xyz">Baby Banana</span>
        <span id="abc">A smaller banana</span>
        <my-wrap-radio-button
          name="fruit"
          value="banana"
        >
        </my-wrap-radio-button>
        <my-wrap-radio-button name="fruit" value="raspberry">Raspberry</my-wrap-radio-button>
        <my-wrap-radio-button id="nameless" value="no-name">No name</my-wrap-radio-button>
      `,
})
class StandaloneRadioButtons {
  ariaLabel: string = 'Banana';
  ariaLabelledby: string = 'xyz';
  ariaDescribedby: string = 'abc';
}

stackblitz

Reference: radio material testing example