How to Unit test the @viewChild ElementRef angular
Asked Answered
B

2

10

My component file has the following code

@ViewChild('clusterCard', { static: false }) clusterCard: ElementRef;



highLightTheClusterCard(point: PickupClusterPoint) {
    if (point) {
      const card: HTMLElement = _get(this.clusterCard, 'nativeElement');
      const selectedPoint: PositioningPoint = this.lane.data.selectedPostioningPoint;

      /* if card is available, position point of the card and the cluster is same and infowindow over the cluster is open then
         highlight the card */
      if (card && _isEqual(point.pointData, selectedPoint) && point.openInfoWindow) {
        card.scrollIntoView();
        card['style'].borderLeft = `5px solid ${this.lane.data.color || 'transparent'}`;
      } else {
        card['style'].borderLeft = `5px solid transparent`;
      }
    }
  }

  ngAfterViewChecked(): void {
    ...some code

    this.pickupClusterPointsService.positioningPoint$
      .pipe(skip(1), takeUntil(this.unsubscriber.done))
      .subscribe((point: PickupClusterPoint) => {
        this.highLightTheClusterCard(point);
      });
  }

HTML file

    <div #clusterCard>
      <pickup-cluster-stop-card
       ..some code
      >
      </pickup-cluster-stop-card>
    </div>

I want to unit test the highLightTheClusterCard method. I am getting

TypeError: Cannot read property 'pipe' of undefined error properties

and TypeError: Cannot set property 'borderLeft' of undefined at

Unit test file

  beforeEach(() => {
   
     ...some code

    fixture = TestBed.createComponent(RouteLaneComponent);
    component = fixture.componentInstance;

    ....some code

    fixture.detectChanges();
  });

  fdescribe('highLightTheClusterCard', () => {
     it('should expect cluster card to be defined ', () => {
        // component.clusterCard.nativeElement = new HTMLElement();
        component.clusterCard = new ElementRef({ nativeElement: jasmine.createSpyObj('nativeElement', ['scrollIntoView', 'style'])});
        component.highLightTheClusterCard({ pointData: new PositioningPoint(), openInfoWindow: true} as PickupClusterPoint);
        // expect(component.clusterCard).toBeDefined();
         // expect(component.clusterCard.nativeElement.scrollIntoView).toHaveBeenCalled();
     });
  });

I read this How to mock a nativeElement.focus() in Angular 4 spec file

but still, I am unable to make it green.

  MockService(PickupClusterPointsService, {
          ...more code
          positioningPoint$: of(undefined),
        }),  

Solution: I have added positioningPoint$: of(undefined) in mock service. MockService is inside the Provider. you can see above lines.

describe('highLightTheClusterCard', () => {
        it('should expect cluster card to be highlighted when hover over infowindow ', () => {
            component.lane.data.selectedPostioningPoint = new PositioningPoint();
            component.lane.data.color = '#2196F3';
            component.clusterCard = {
              nativeElement: jasmine.createSpyObj('nativeElement', ['scrollIntoView', 'style'])
            };
    
           component.highLightTheClusterCard({ pointData: new PositioningPoint(), openInfoWindow: true} as PickupClusterPoint);
    
           expect(component.clusterCard).toBeDefined();
           expect(component.clusterCard.nativeElement.scrollIntoView).toHaveBeenCalled();
           expect(component.clusterCard.nativeElement.style.borderLeft).toBe('5px solid #2196F3');
        });
        it('should expect cluster card not to be highlighted when hover out from the infowindow', () => {
          component.lane.data.selectedPostioningPoint = new PositioningPoint();
          component.clusterCard = {
            nativeElement: jasmine.createSpyObj('nativeElement', ['scrollIntoView', 'style'])
          };
         component.highLightTheClusterCard({ pointData: new PositioningPoint(), openInfoWindow: false} as PickupClusterPoint);
    
         expect(component.clusterCard).toBeDefined();
         expect(component.clusterCard.nativeElement.style.borderLeft).toBe('5px solid transparent');
      });
     });
Barracks answered 28/11, 2020 at 19:7 Comment(0)
K
2

You have several issues it seems.

Your first error

TypeError: Cannot read property 'pipe' of undefined error properties

come from that you haven't instantiated your pickupClusterPointsService service properly.

The second error

TypeError: Cannot set property 'borderLeft' of undefined at

I'm not sure just yet

Kitchener answered 28/11, 2020 at 21:30 Comment(6)
Yes, you are right. I got it. will update my code.Barracks
I need some help to unit test this pastebin.pl/view/08e0f7caBarracks
Hi, if you create a new post with this code in a stackblitz and pm me i can take a look at it.Kitchener
Hi Lucho I can not create it at stackblitz. It is a part of application and application is huge. But if you look at the code it is almost the same as the above code in the current question. card is HTMLElement element. In the new code, I do not want to apply a border to the card (card is div). I want to apply the border to the angular component which is within the div.Barracks
I am using this line pickupClusterCard = card.querySelector('.pnd-BaseStopCard'); to get the angular component (<pickup-cluster-stop-card ..) you can see it in the current question. once I have pickupClusterCard, I am finding it's first chid and applying a border to it. I need help to mock all this. Please let me know.Barracks
Again you have to write a new separate post with your new questions. You don't have to include your whole app, just include the isolated issue in the stackblitzKitchener
A
0

You have created your spy with "style" as a function of native element

jasmine.createSpyObj('nativeElement', ['scrollIntoView', 'style'])

instead of property

jasmine.createSpyObj('nativeElement', ['scrollIntoView'], {style: {}})

Therefore TypeError: Cannot set property 'borderLeft' of undefined is because in card['style'].borderLeft, card['style'] doesn't exist. instead, try it like this:

component.clusterCard = { nativeElement: jasmine.createSpyObj('nativeElement', ['scrollIntoView'], {style: jasmine.createSpyObj('style', [], {borderLeft: 'some string value'})})};
Alewife answered 7/9, 2022 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.