ng-metadata icon indicating copy to clipboard operation
ng-metadata copied to clipboard

[$compile:tpload] Failed to load template

Open ptomaszi opened this issue 7 years ago • 2 comments

The component I am testing is using the "templateUrl" to provide a template:

import { Component, Inject, Input, Output, EventEmitter, OnChanges } from 'ng-metadata/core';

@Component({
    selector: 'diContactList',
    templateUrl: 'src/app/portal/parties/contacts/list/contact-list.component.html'
})
export class ContactListComponent implements OnChanges {

Then I have a corresponding unit test:

import { bundle, getInjectableName, NgModule, Component } from 'ng-metadata/core';

describe('ContactListComponent', () => {
    @Component({
        selector: 'test-component',
        template: `
            <di-contact-list>
            </di-contact-list>`
    })
    class TestComponent {
        constructor() {}
    }
    @NgModule({
        declarations: [TestComponent, ContactListComponent]     
    })
    class TestNgModule { } 
    
    let $compile: ng.ICompileService;
    let $rootScope: ng.IRootScopeService;
    let $scope: ng.IScope;
    let render: IRender<TestComponent>;
    let sut: ContactListComponent;
    
    beforeEach(() => {
        const TestModule: string = bundle(TestNgModule).name;
        ng.mock.module(TestModule);
    });

    beforeEach(ng.mock.inject(function($injector: ng.auto.IInjectorService) {
        $compile = $injector.get<ng.ICompileService>('$compile');
        $rootScope = $injector.get<ng.IRootScopeService>('$rootScope');
        $scope = $rootScope.$new();
        
        render = renderFactory($compile, $scope);
        sut = render(ContactListComponent).ctrl;
    }));

When run I am getting the following error:

Error: [$compile:tpload] Failed to load template: src/app/portal/parties/contacts/list/contact-list.component.html (HTTP status: undefined undefined) http://errors.angularjs.org/1.6.5/$compile/tpload?p0=src%2Fapp%2Fportal%2Fparties%2Fcontacts%2Flist%2Fcontact-list.component.html&p1=undefined&p2=undefined

When I remove templateUrl or replace with template in the component, unit tests run correctly.

ptomaszi avatar Sep 18 '17 10:09 ptomaszi

Hello, this shouldn't be any different than testing normal AngularJS components. If you want to test the component template you will need to populate the template cache with the template for that path. Depending on your build system there are several ways you can do that.

https://blog.logentries.com/2015/03/template-caching-in-angular-how-to-avoid-the-storm/

aciccarello avatar Sep 18 '17 13:09 aciccarello

I have found where the issue was. If my component is using the "templateUrl" instead of "template", the render function returns "undefined" for the "ctrl". I have fixed it by modifying "src/testing/utils.js" file and adding "$scope.$digest();" after the $compile:

function renderFactory($compile, $scope) {
    return _compileAndDigest;
    function _compileAndDigest(Directive, _a) {
        var _b = _a === void 0 ? {} : _a, jqHost = _b.jqHost, attrs = _b.attrs, jqChildren = _b.jqChildren;
        var ctrlName = provider_1.getInjectableName(Directive);
        var selector = primitives_1.StringWrapper.kebabCase(ctrlName);
        // is Directive
        if (jqHost) {
            jqHost.attr(selector, '');
        }
        else {
            // is Component
            var hostElement = "<" + selector + "></" + selector + ">";
            jqHost = lang_1.global.angular.element(hostElement);
        }
        // since attributes can be undefined we check them
        if (attrs) {
            jqHost.attr(attrs);
        }
        if (jqChildren) {
            jqHost.append(jqChildren);
        }
        // angular api
        var compiledElement = $compile(jqHost)($scope);
        $scope.$digest();
        var ctrl = compiledElement.controller(ctrlName);
        $scope.$apply();
        return { compiledElement: compiledElement, ctrl: ctrl };
    }
}

ptomaszi avatar Sep 25 '17 13:09 ptomaszi