Template parse error in Jasmine test but not actual app

15,291

Solution 1

Well, the module of your test only has MiddleRowComponent declared. So it doesn't know about CircleComponent:

TestBed.configureTestingModule({
    declarations: [MiddleRowComponent], // declare the test component
})

Add all the necessary components in the declarations of the testing module, or add LandingPageModule to the imports of the testing module.

Solution 2

I had a similar problem and found this page, and while JB Nizet's answer led to a solution for me, it didn't work for me as-is. I'm not trying to take away from his solid answer to the original question, just trying to help the next person who comes along.

My problem was exactly like the OP's, except that my custom component (MiddleRowComponent in this example) used a third-party component. The unit test error was given about the third-party tag used in my template, even though it worked just fine in the actual app. The solution for me was to also include an imports for the third-party in my testing module:

TestBed.configureTestingModule({
    declarations: [MiddleRowComponent],
    imports: [TheThirdPartyModule]
})

Then my unit tests ran without the error. Hope that helps!

Solution 3

Another option is to add the NO_ERRORS_SCHEMA schema to the test setup. Any unrecognised components will now not cause an error. I use this a lot when working with third party modules like Angular Material Design.

import { NO_ERRORS_SCHEMA } from '@angular/core';
...
  beforeEach(
    async(() => {
      TestBed.configureTestingModule({
        declarations: [MiddleRowComponent],
        schemas: [NO_ERRORS_SCHEMA]
      }).compileComponents();
    })
  );
Share:
15,291

Related videos on Youtube

BeniaminoBaggins
Author by

BeniaminoBaggins

I dabble in developing web and mobile apps.

Updated on June 11, 2022

Comments

  • BeniaminoBaggins
    BeniaminoBaggins about 2 years

    I've developed a Jasmine spec to test an angular 2 component MiddleRowComponent. When I run the jasmine test, it gives this error:

    zone.js:388 Unhandled Promise rejection: Template parse errors:
    'circles' is not a known element:
    1. If 'circles' is an Angular component, then verify that it is part of this module.
    2. If 'circles' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("</div>
          <div class="col-md-10 col-sm-12 offset-md-1 flex-xs-middle" id="circles-div">
             [ERROR ->]<circles (onWordChanged)="onWordChanged($event)"></circles>
          </div>
          <div class="col-md-10 "): MiddleRowComponent@9:9
    'custom-button' is not a known element:
    

    However if i just run my web app in the browser like normal, the error does not occur. circles is indeed a part of the module. And custom-button is part of a shared module that is imported. Here is the module.ts:

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { SharedModule } from '../shared/shared.module';
    import * as LandingPage from './index';
    
    @NgModule({
       imports: [ CommonModule, SharedModule ],
       declarations: [
          LandingPage.MiddleRowComponent,
          LandingPage.LandingPageComponent,
          LandingPage.CirclesComponent
       ],
       exports: [ LandingPage.LandingPageComponent ],
    })
    export class LandingPageModule { }
    

    Everything is imported and declared as it should be and works when running the app without testing it. I use a done to make the beforeEach work given its async nature of getting the component template from a separate template file. I run the test with a jasmine spec runner HTML file. How come my components that MiddleRowComponent uses are not known elements in the jasmine test but are when running the app normally?

    Here is the jasmine spec:

    import 'zone.js/dist/long-stack-trace-zone.js';
    import 'zone.js/dist/async-test.js';
    import 'zone.js/dist/fake-async-test.js';
    import 'zone.js/dist/sync-test.js';
    import 'zone.js/dist/proxy.js';
    import 'zone.js/dist/jasmine-patch.js';
    
    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import {
        BrowserDynamicTestingModule,
        platformBrowserDynamicTesting
    } from '@angular/platform-browser-dynamic/testing';
    import { By } from '@angular/platform-browser';
    import { DebugElement } from '@angular/core';
    
    import { MiddleRowComponent } from './middle-row.component';
    
    let comp: MiddleRowComponent;
    let fixture: ComponentFixture<MiddleRowComponent>;
    let de: DebugElement;
    let el: HTMLElement;
    
    describe('MiddleRowComponent', () => {
       var fixture: any;
       var comp: any;
        beforeAll(() => {
            TestBed.resetTestEnvironment();
            TestBed.initTestEnvironment(BrowserDynamicTestingModule,
                platformBrowserDynamicTesting());
        });
    
        beforeEach((done) => {
            TestBed.configureTestingModule({
                declarations: [MiddleRowComponent], // declare the test component
            }).compileComponents().then(() => {
                fixture = TestBed.createComponent(MiddleRowComponent);
                comp = fixture.componentInstance; // MiddleRowComponent test instance
                // query for the title <h1> by CSS element selector
                de = fixture.debugElement.query(By.css('h1'));
                el = de.nativeElement;
                done();
            });
        });
    
        it('should display original title', () => {
            fixture.detectChanges();
            expect(el.textContent).toContain(comp.word);
        });
    
        it('should display a different test title', () => {
            comp.word = 'Test Title';
            fixture.detectChanges();
            expect(el.textContent).toContain('Test Title');
        });
    });
    

    full error:

    zone.js:388 Unhandled Promise rejection: Template parse errors:
    'circles' is not a known element:
    1. If 'circles' is an Angular component, then verify that it is part of this module.
    2. If 'circles' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("</div>
          <div class="col-md-10 col-sm-12 offset-md-1 flex-xs-middle" id="circles-div">
             [ERROR ->]<circles (onWordChanged)="onWordChanged($event)"></circles>
          </div>
          <div class="col-md-10 "): MiddleRowComponent@9:9
    'custom-button' is not a known element:
    1. If 'custom-button' is an Angular component, then verify that it is part of this module.
    2. If 'custom-button' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
          </div>
          <div class="col-md-10 offset-md-1 flex-xs-middle" id="try-now-div">
             [ERROR ->]<custom-button buttonName="try now" (click)="tryNowClick()"></custom-button>
          </div>
       </div>
    "): MiddleRowComponent@12:9 ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
    'circles' is not a known element:
    1. If 'circles' is an Angular component, then verify that it is part of this module.
    2. If 'circles' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("</div>
          <div class="col-md-10 col-sm-12 offset-md-1 flex-xs-middle" id="circles-div">
             [ERROR ->]<circles (onWordChanged)="onWordChanged($event)"></circles>
          </div>
          <div class="col-md-10 "): MiddleRowComponent@9:9
    'custom-button' is not a known element:
    1. If 'custom-button' is an Angular component, then verify that it is part of this module.
    2. If 'custom-button' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
          </div>
          <div class="col-md-10 offset-md-1 flex-xs-middle" id="try-now-div">
             [ERROR ->]<custom-button buttonName="try now" (click)="tryNowClick()"></custom-button>
          </div>
       </div>
    "): MiddleRowComponent@12:9
        at TemplateParser.parse (http://localhost:3002/node_modules/@angular/compiler/bundles/compiler.umd.js:7730:21)
        at RuntimeCompiler._compileTemplate (http://localhost:3002/node_modules/@angular/compiler/bundles/compiler.umd.js:17573:53)
        at eval (http://localhost:3002/node_modules/@angular/compiler/bundles/compiler.umd.js:17493:64)
        at Set.forEach (native)
        at RuntimeCompiler._compileComponents (http://localhost:3002/node_modules/@angular/compiler/bundles/compiler.umd.js:17493:21)
        at createResult (http://localhost:3002/node_modules/@angular/compiler/bundles/compiler.umd.js:17404:21)
        at ZoneDelegate.invoke (http://localhost:3002/node_modules/zone.js/dist/zone.js:232:26)
        at ProxyZoneSpec.onInvoke (http://localhost:3002/node_modules/zone.js/dist/proxy.js:79:39)
        at ZoneDelegate.invoke (http://localhost:3002/node_modules/zone.js/dist/zone.js:231:32)
        at Zone.run (http://localhost:3002/node_modules/zone.js/dist/zone.js:114:43)consoleError @ zone.js:388_loop_1 @ zone.js:417drainMicroTaskQueue @ zone.js:421ZoneTask.invoke @ zone.js:339
    zone.js:390 Error: Uncaught (in promise): Error: Template parse errors:(…)
    
  • Paul G
    Paul G about 2 years
    In my case my new component's test passed but an injected shared component that used Testbed was the culprit. That Testbed component used a Pipe that the new component didn't need or import. By just doing the tests straight up without Testbed it fixed the problem with that import and this similar error to OP