Creating custom views in Angular 8 based on user roles through directives

After reviewing an example on how to display components based on a user's role at this link:

I'm encountering compilation issues due to missing arguments in the constructor within has-role.directive.spec.ts. The constructor in has-role.directive.ts requires 3 arguments: ViewContainerRef and TemplateRef from Angular core, along with a service for retrieving user roles.

has-role.directive.ts

    constructor(
    private viewContainerRef: ViewContainerRef,
    private templateRef: TemplateRef<any>,
    private authenticationService: AuthenticationService)

However, in the provided tutorial example, it is utilized as follows: has-role.directive.spec.ts

 describe('HasRoleDirective', () => {
  it('should create an instance', () => {
    const directive = new HasRoleDirective();
    expect(directive).toBeTruthy();
  });
});

Why does the example work without any complaints about missing arguments while I encounter issues?


UPDATE:

Following Michał's suggestion, I have created classes to include in the constructor:

class TestViewContainerRef extends ViewContainerRef {
    element: ElementRef<any>;
    injector: Injector;
    parentInjector: Injector;
    clear(): void {
        throw new Error('Method not implemented.');
    }
    // more methods here...
}

let viewContainerRefMock = {
  viewContainerRef: TestViewContainerRef
};

describe('HasRoleDirective', () => {
  it('should create an instance', () => {
    const directive = new HasRoleDirective(viewContainerRefMock, templateRefMock, authenticationServiceMock);
    expect(directive).toBeTruthy();
  });
});

Now, the issue shifts to my class itself: https://i.sstatic.net/11P7x.jpg

Answer №1

It seems that you are encountering errors due to missing arguments, as indicated by the error message. When utilizing the directive in your application, Angular automatically generates and injects these 3 dependencies into your directive.

In the scenario you provided, where you are instantiating your directive within a test, Angular is unable to inject these dependencies since it is not running within an Angular environment but rather in a testing setup. Consequently, you will need to manually provide these dependencies yourself. This process is outlined here.

The reason why the blog post you mentioned does not encounter this issue is because it does not perform unit tests on the directive.

Answer №2

To simplify testing, you can generate mock classes for the constructor parameters that extend the necessary abstractions. For example, in the has-role.directive.spec.ts, you can create:

class MockViewContainerRef extends ViewContainerRef { }
class MockTemplateRef extends TemplateRef<any> { }
class MockAuthenticationService extends AuthenticationService { }

Next, implement all required methods from the interfaces. You can simply have them throw an error message like

throw new Error("Method not implemented.");
since they will not be used in this type of test. Then, instantiate objects for each mock class and pass them into the constructor of HasRoleDirective.

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

Provide a string argument when instantiating an abstract class

I am searching for a method to assign a name string within a class and utilize it in the abstract class at the constructor level, without the need for a function. Opening up the constructor is not an option due to using typedi. You can access the playgrou ...

typescript create a type from a schema

Recently, I received an auto-generated GraphQL schema mapping that looks like this: export const generatedSchema = { query: { __typename: { __type: 'String!' }, account_sample: { __type: '[account_sample!]!', __arg ...

The process of invoking a function within another function in TypeScript Angular

Just starting out with Angular 2, I've written the following code in my Angular project: export class TestClass { constructor() { this.initMap(); } initMap() { this.marker.addListener('dragend', this.onMarkerDr ...

Reduce the size of a container element without using jquery

In my Angular application, I have structured the header as follows: -- Header -- -- Sub header -- -- Search Box -- -- Create and Search Button -- -- Scroll Div -- HTML: <h1> Header </h1> <h3> Sub header </h3> <div class="s ...

Warning: NgOptimizedImage Optimization_NOTICE

Exploring the latest features of angular 15 to enhance image performance led me to encounter this cautionary message. `The NgOptimizedImage directive (used on an <img> element with `ngSrc="/assets/fascinating.png") has detected that the ori ...

Solving issues with malfunctioning Angular Materials

I'm facing an issue with using angular materials in my angular application. No matter what I try, they just don't seem to work. After researching the problem online, I came across many similar cases where the solution was to "import the ...

Is it feasible to create a set of standardized values for an array's properties?

My goal is to restrict the values for a property (or react props in this case) based on the values provided in another property. Firstly, I have my Option interface: interface Option { value: string; label: string; } Next, I define my SelectInputProp ...

Attempting to locate an element within the DOM using TypeScript

I am completely new to TypeScript. I have been attempting to locate an element using a selector, but no matter what I tried, the findElement() method always returns undefined. Can someone please point out where my mistake might be? Any assistance would b ...

An Unexpected ER_BAD_FIELD_ERROR in Loopback 4

I encountered an unusual error: Unhandled error in GET /managers: 500 Error: ER_BAD_FIELD_ERROR: Unknown column 'role_id' in 'field list' at Query.Sequence._packetToError (/Users/xxxx/node_modules/mysql/lib/protocol/se ...

How Can I Build a Dynamic Field Form Builder in Angular 4?

While working with dynamic JSON data, I needed to create fields dynamically. For instance, if my JSON array contains 3 values, I would generate 3 input checkboxes dynamically as shown below: <ng-template ngFor let-numberOfRow [ngForOf]="numberOfRows"&g ...

Struggling to create intricate validation with Yup for a Formik form

I am facing a challenge with my Formik form which contains complex validations. Below is the current schema I am working with: const applyPaymentFormValidation = yup.object().shape({ payments: yup.array().of( yup.object().shape({ applied: yup ...

Issue encountered post compilation of App: ag-grid using Angular 6

Currently, I am utilizing ag-grid with Angular 6 and so far everything is functioning smoothly. However, after building my application using ng build, the build process is successful. Yet, upon running my app, an error occurs: ERROR TypeError: Cannot re ...

When you use Array.push, it creates a copy that duplicates all nested elements,

Situation Currently, I am developing a web application using Typescript/Angular2 RC1. In my project, I have two classes - Class1 and Class2. Class1 is an Angular2 service with a variable myVar = [obj1, obj2, obj3]. On the other hand, Class2 is an Angular2 ...

Angular2/4 is throwing a 405 error, indicating that the method used is not

updateEmployeeData(ename,ejobtitle,edept,eunit,equal,eaqser,empid) { let url = GlobalVariable.BASE_API_URL + "api/updateEmployeeProfile"; let headers = new Headers({'Content-Type':'application/json'}); let options = new Reque ...

What is the correct way to define the interfaces/types in typescript?

I am currently working on setting up an Apollo GraphQL server in Typescript and struggling with understanding the correct approach in dealing with the type system. While GraphQL and Apollo are integral to the code, my main focus is on TypeScript. I am also ...

Encountering build errors in .xproj file when working with Type Script in ASP.Net Core

I recently started working on a new ASP.Net Core project and decided to integrate Angular 2 and Type Script by following a blog post tutorial. However, upon adding a Type Script file to my project, I encountered several build errors from the xproj file. h ...

Creating a seating arrangement for a movie theater screen

Need help creating a seating layout based on user input. When the user enters row number 1 and 12 seats, I want to generate 12 divs in one row. If the user enters row number 2 and 13 seats, then the next row should have 13 divs. import { Seats } from &ap ...

Leveraging symbols as object key type in TypeScript

I am attempting to create an object with a symbol as the key type, following MDN's guidance: A symbol value may be used as an identifier for object properties [...] However, when trying to use it as the key property type: type obj = { [key: s ...

esLint throws an error advising that a for-in loop should be enclosed within an if statement in order to exclude unnecessary properties from the prototype

While working on my Angular project, I encountered an error with esLint related to the code snippet below: private calculateFieldValue(value: any): any { let isEmptyObject = false; if (value && Array.isArray(value) & ...

Managing state in NGRX entities can be simplified by learning how to assign action.payload to a state property in Ups

In the entity state, I have a reducer that needs to assign action.payload.Message to saveMessage.msg when carrying out upsertOne on the UPSERT_Message_SUCCESS action. export interface MessageState extends EntityState<Message> { // additional enti ...