1

I have a component I want to test. The test fails with message

AdminPanelComponent > should create

TypeError: Cannot read property 'role' of undefined

error properties: Object({ ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 50577443, rootNodeFlags: 1, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 1, childFlags: 50577443, directChildFlags: 1, childMatchedQueries: 0, matchedQueries: Object({ }), matchedQueryIds: 0, references: Object({ }), ngContentIndex: null, childCount: 11, bindings: [ ], bindingFlags: 0, outputs: [ ], element: Object({ ns: '', name: 'div', attrs: [ Array ], template: null, componentProvider: null, componentView: null, componentRendererType: null, publicProviders: null({ }), allProviders: null({ }), handleEvent: Function }), provider: null, text: null, query: null, ngContent: null }), Object({ nodeIndex: 1, parent: Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 1, childFlags: 50577443, directChildFlags: 1, chi ... at at HasRoleDirective.ngOnInit (http://localhost:9876/_karma_webpack_/src/app/_directives/hasRole.directive.ts:16:53) at checkAndUpdateDirectiveInline (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:26276:1) at checkAndUpdateNodeInline (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:37133:1) at checkAndUpdateNode (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:37072:1) at debugCheckAndUpdateNode (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:38094:36) at debugCheckDirectivesFn (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:38037:1) at Object.eval [as updateDirectives] (ng:///DynamicTestModule/AdminPanelComponent.ngfactory.js:62:5) at Object.debugUpdateDirectives [as updateDirectives] (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:38025:1) at checkAndUpdateView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:37037:1) at callViewAction (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:37403:1)

admin-panel.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-admin-panel',
  templateUrl: './admin-panel.component.html',
  styleUrls: ['./admin-panel.component.css']
})
export class AdminPanelComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

admin-panel.component.html

<div class="container mt-5">
  <h2>Admin panel</h2>
  <div class="tab-panel">
    <tabset class="member-tabset">
      <tab heading="User Management" *appHasRole="['Admin']">
        <div class="container">
            <app-user-management></app-user-management>  
        </div>        
      </tab>
      <tab heading="Photo management" *appHasRole="['Admin', 'Moderator']">
        <app-photo-management></app-photo-management>
      </tab>
    </tabset>
  </div>
</div>

hasRole.directive.ts

import { Directive, Input, ViewContainerRef, TemplateRef, OnInit } from '@angular/core';
import { AuthService } from '../_services/auth.service';

@Directive({
  selector: '[appHasRole]'
})
export class HasRoleDirective implements OnInit {
  @Input() appHasRole: string[];
  isVisible = false;

  constructor(private viewContainerRef: ViewContainerRef,
              private templateRef: TemplateRef<any>,
              private authService: AuthService) { }

  ngOnInit() {
    const userRoles = this.authService.decodedToken.role as Array<string>;
    // if no roles clear the viewContainerRef
    if (!userRoles) {
      this.viewContainerRef.clear();
    }

    // if user has role need to render the element
    if (this.authService.roleMatch(this.appHasRole)) {
      if (!this.isVisible) {
        this.isVisible = true;
        this.viewContainerRef.createEmbeddedView(this.templateRef);
      } else {
        this.isVisible = false;
        this.viewContainerRef.clear();
      }
    }
  }
}

The code part that is failing to work is

const userRoles = this.authService.decodedToken.role as Array<string>;

How do I test this component?

1 Answer 1

1

The best way to test an angular app is to mock everything except the component you want to test.

The easiest way to do it is to use a lib like ng-mocks.

Nevertheless you need to stub the AuthService like that

TestBed.configureTestingModule({
  declarations: [HasRoleDirective, AdminPanelComponent],
  provides: [
    {
      provide: AuthService,
      useValue: {
        decodedToken: {
          role: [], // <- you can put here values for the test
        },
        roleMatch: () => false, // <- or to use a spy here.
      },
    },
  ],
})

in this case AuthService will be a stub with fake methods that don't do anything.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, looks easier than I thought initialy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.