Tips for effectively unit testing the Angular @viewChild directive with ElementRef

In my component file, I have the following code snippet

@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;

      /* Check if the card is available, position point of the card and the cluster are the same, and the 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);
      });
  }

The HTML file for this code snippet looks like:

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

I am trying to unit test the highLightTheClusterCard method, but I encounter errors such as "TypeError: Cannot read property 'pipe' of undefined" and "TypeError: Cannot set property 'borderLeft' of undefined."

For the unit test in the test file, I've included:

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();
     });
  });

Despite trying different approaches like mocking 'nativeElement.focus()', the test is still failing.

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

Solution: To resolve the issue, I added positioningPoint$: of(undefined) in the mock service within the Provider section.

describe('highLightTheClusterCard', () => {
        it('should expect the cluster card to be highlighted when hovering over the 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 the cluster card not to be highlighted when moving away 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');
      });
     });

Answer №1

It appears that you are facing multiple issues.

The first issue is related to:

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

This problem arises from the fact that you have not initialized your pickupClusterPointsService service correctly.

The second issue pertains to:

Error: Cannot set property 'borderLeft' of undefined at

I am currently investigating this further.

Answer №2

Your spy has been customized for a more stylish look using the native element function

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

Instead of just creating a property, you can enhance it like this:

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

The error

TypeError: Cannot set property 'borderLeft' of undefined
occurs because in card['style'].borderLeft, card['style'] is not defined. To fix this, try the following approach:

component.clusterCard = { nativeElement: jasmine.createSpyObj('nativeElement', ['scrollIntoView'], {style: jasmine.createSpyObj('style', [], {borderLeft: 'some string value'})})};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The absence of type-safety in the MUI System sx is a glaring issue

I want to ensure that the TypeScript compiler can identify typos in my MUI System sx props: import { Box, SxProps, Theme, Typography } from '@mui/material' const sxRoot: SxProps<Theme> = { width: '100vw', height: '10 ...

HTML5 Drag and Drop: How to Stop Drag and Drop Actions from Occurring Between a Browser and Browser Windows

Is it possible to restrict HTML5 Drag & Drop functionality between different browsers or windows? I am currently working on an Angular2 app that utilizes native HTML5 Drag and Drop feature. Is there a way to prevent users from dragging items out of th ...

A TypeScript class designed to serve as a function type as well

When trying to utilize angular's IHttpService, I am unsure of how to manage the following function. interface IHttpService { <T>(config: IRequestConfig): IHttpPromise<T>; } class MyHttpService implements IHttpService { // The cod ...

exclude a few countries from ngx-intl-tel-input

I'm facing an issue where I need to remove certain countries, like Mexico, from the list displayed in ngx-intl-tel-input. Even after trying the 'excludeCountries' option, it doesn't seem to be working for me. Below is a snippet of my ...

Is it possible for Angular 2 JWT to have an unauthenticatedRedirector feature?

Having transitioned from Angular 1 where JWT tokens were used for user authentication, I had the following code: .config(function Config($httpProvider, jwtOptionsProvider) { // Interceptor to add token to every $http request jwtOptionsProv ...

Encountered a 404 error while using a MEAN stack application

Encountering a 404 error while attempting to post data using Postman in Chrome. Any assistance will be greatly valued. I am following the application from this link: https://www.youtube.com/watch?v=wtIvu085uU0 Here is the code snippet: //importing modul ...

Tips for reverting from Angular 7 to Angular 6

I attempted to switch from angular 7 back to angular 6 by executing the following npm commands: npm uninstall -g angular-cli npm cache clean npm install -g <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="32535c55475e53401f515e5 ...

Angular 2 router generates incorrect URLpaths

When navigating through my routes, I encountered an issue with the following routing setup: const routes: Routes = [ { path: '', component : HomeComponent, children: [] }, { path: 'login', ...

Angular Application cannot locate the interface file

Attempting to create a basic test environment for the OMBD Api. Utilizing an interface file named ombdresponse.ts: interface IOMBDResponse { Title: string; Year: string; Director: string; Poster: string; } The issue arises within the ombd- ...

Angular is throwing error TS2322 stating that the type 'string' cannot be assigned to the type '"canvas" while working with ng-particles

My goal is to incorporate particles.js into the home screen component of my project. I have successfully installed "npm install ng-particles" and "npm install tsparticles." However, even after serving and restarting the application, I am unable to resolve ...

Difficulty displaying API information on a web browser with react.js

I am currently working on developing a trivia game using React.js Typescript and The Trivia API. I have been successfully passing data between components with useContext and navigating through components using react-router-dom. However, I encountered an is ...

Exciting Update: Next.js V13 revalidate not triggering post router.push

Currently using Next.js version 13 for app routing, I've encountered an issue with the revalidate feature not triggering after a router.push call. Within my project, users have the ability to create blog posts on the /blog/create page. Once a post is ...

What is the best way to implement "computeIfAbsent" or "getOrElseUpdate" functionality for a Map in JavaScript?

If we assume that m represents a Map<number, V> for a certain type V k is a number, how can we create an expression that can either retrieve an existing V for the key k, or generate a new v: V, insert it into the map for the key k, and result in v ...

What is the process of defining a TypeScript AWS Lambda handler for Lambda Function URLs?

The npm package @types/aws-lambda provides TypeScript declarations for different ways Lambda functions can be triggered. For instance, when triggering the Lambda function through API Gateway, you can use the following code snippet: import { APIGatewayProxy ...

Having trouble typing computed values in Vue Composition API with TypeScript?

I'm attempting to obtain a computed value using the composition API in vue, and here is the code I am working with: setup() { const store = useStore(); const spaUrls = inject<SpaUrls>('spaUrls'); const azureAd = inject<AzureAd ...

Angular: Navigating through two levels of fetched data from Firebase

I'm currently working on parsing retrieved data from Firebase within an Angular (Typescript) project. The structure of my JSON data in Firebase resembles the following: "customer" : { "customerId1" : { "documents" : { "documentId1" : { ...

How should one sort the Object and Array derived from Observables within a foreach loop in an Asynchronous Angular 4/5 environment?

Having an issue with the order of execution in my code. I'm running a method (myTableService.getAllTables()) that returns a JSON to create an object (this.myTables). Then, for each element in this.myTables, I execute another request (this.myTableS ...

I'm having trouble with my Typescript file in Vscode - every time I try to edit the css code, all the text turns red. Can someone

Check out this visual representation: [1]: https://i.stack.imgur.com/9yXUJ.png Followed by the corresponding code snippet. export const GlobalStyle = createGlobalStyle` html { height: 100%; } body { background-image: url(${BGImage}); ba ...

Tips for utilizing express in your typescript projects

I'm curious about the transition of definition files from tsd to typings, and now to @types. How can I incorporate @types in a node/express project? What is currently preferred and what's the reason for moving from tsd to typing and finally to @t ...

Issue with displaying decimal places in Nivo HeatMap

While utilizing Nivo HeatMap, I have observed that the y value always requires a number. Even if I attempt to include decimal places (.00), it will still trim the trailing zeros and display the value without them. The expected format of the data is as foll ...