1

I'm new with Angular test and I have a problem. The first problem is with the variable username into a component that I use to show logged username into HTML page: This is the test file:

describe('HeaderComponent', () => {
  let component: HeaderComponent;
  let fixture: ComponentFixture<HeaderComponent>;
  let app;
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
      providers: [ MessageService, JwtHelperService, AuthService ],  
      imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
        config: {
          tokenGetter: () => {
            return sessionStorage.getItem(environment.tokenName);
          },
          //Exclude this URL from JWT (doesn't add the authentication header)
          blacklistedRoutes: [
            '/api/login',
          ]
        }
      }), ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

The component is this:

export class HeaderComponent implements OnInit {
  @Output() sidebarEvent = new EventEmitter();
  @Output() clickOkButtonListConfigurationsEvent = new EventEmitter();
  username: String = this.authService.decodeToken.username;
  items = [] as MenuItem[];
  dialogListConfigurationVisible: boolean = false;
  faUserCircle = faUserCircle;
  defaultConfigurations: Configuration[];
  configurationCreated: boolean = false;
  dialogConfirmCreationVisible: boolean = false;
  constructor(private configurationService: ConfigurationService, private authService: AuthService) {   }

  ngOnInit() {
  ...
  }

The auth service method:

get decodeToken(): Jwt {
  return this.jwtHelper.decodeToken(this.getSessionToken);
}

The should create test fails with TypeError: Cannot read property 'username' of null

2 Answers 2

3

You need to Mock your AuthService since this is a component test.

you can do that by providing an object in the module initialization code

TestBed.configureTestingModule({
  declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
  providers: [
    MessageService,
    JwtHelperService,
    {provide: AuthService, useClass: AuthServiceMock} ],  
  imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
    config: {
      tokenGetter: () => {
        return sessionStorage.getItem(environment.tokenName);
      },
      //Exclude this URL from JWT (doesn't add the authentication header)
      blacklistedRoutes: [
        '/api/login',
      ]
    }
  }), ]
})
.compileComponents();

the AuthServiceMock class should implement the same interface as the original one. it can be something like this:

export class AuthServiceMock {
  // ...
  decodeToken: {
    username: 'testUser'
  };
}

than, before creating the component, setup the mock class if you don't want to set a default inside the mock.

NOTE: you can do this last step without creating a mock, but that will break the separation of concerns in your tests.

beforeEach(() => {
    let authServiceMock: AuthServiceMock = TestBed.get(AuthService);
    authServiceMock.decodeToken = { username: 'anotheruser' };

    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

This should allow for the HeaderComponent run the this.authService.decodedToken.username line.

As a guideline: need to mock dependencies that rely on outside data.

You might also be able to remove dependencies of the original AuthService if previously you included them in the test module initialization. for example, if JwtHelperService is only used internally for AuthService, the test module can exclude that provider.

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

2 Comments

It works, from your answer I fixed the bug without the mock
@luca it can work without the mock, but it means you test the AuthService in these tests as well. Usually, in unit tests you want to test each "part" by itself
0

From the @Thatkookooguy answer I got the problem and I add this two raw inside the beforeEach avoid so the use of mock object

const authService: AuthService = TestBed.get(AuthService);
authService.saveToken("token string");

Comments

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.