1

I am receiving this error:

Error: [$injector:unpr] Unknown provider: checkListDirectiveProvider <- checkListDirective
why would $componentController issue an unknown directive provider error?

enter image description here

Looking in the source code for angular mocks, the problem is here:

return function $componentController(componentName, locals, bindings, ident) {
  // get all directives associated to the component name
  var directives = $injector.get(componentName + 'Directive');

Why would $injector try and find directives, when I am registering a component?

module("app").component("checkList", new CheckListComponent());

TL;DR

(for more background information)
My test (using webpack) is structured as follows:

var mocks = require("angular");
require("angular-mocks");
require("../app.js");
require("./CheckListComponent.js");

describe("component: check list component",
    function () {
        var q;
        var r;

        beforeEach(() => mocks.module("app"));
        beforeEach(inject(function (_$componentController_, $q, $rootScope) {
            $componentController = _$componentController_;
            q = $q;
            r = $rootScope;
        }));

        it("show question should calculate correct answers",
            function () {
                var bindings = {};
                var ctrl = $componentController("checkList", null, bindings);
                expect(ctrl.showQuestion).toBeDefined();
            });
    });

I am trying to understand why this is not working. Digging into the debugger I can see that mocks.module("app")._invokeQueue seems to contain the registered component, so why is $componentController unable to create it?

enter image description here

The complete source for the component (in typescript) is:

/**
 * the component wrapper.
 */
export class CheckListComponent implements ng.IComponentOptions {

    controllerAs: string = "cl";
    bindings: any;
    controller: any;
    templateUrl: string;

    /**
     * @constructor create a new instance of the component.
     */
    constructor() {
        this.bindings = { checkList: "<" };
        this.controller = CheckListController;
        this.templateUrl = "compliance/checklist/component";
    }
}

module("app").component("checkList", new CheckListComponent());
Jim
  • 14,952
  • 15
  • 80
  • 167

1 Answers1

2

The problem is here,

var mocks = require("angular");

This will cause mocks.module("app") to be angular.module("app"), which does nothing in tests. No module is loaded in tests, app units are not available for injection, including checkList component.

It should be

var angular = require("angular");
require("angular-mocks");
...
beforeEach(() => angular.mock.module("app"));

The error is caused by the fact that Angular components are directives (see this answer for explanation), and directives are providers. All that $componentController does is getting an instance of a provider that contains directive definition object and instantiating its controller property.

This is what the error refers to:

Error: [$injector:unpr] Unknown provider: checkListDirectiveProvider <- checkListDirective

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • do you know what the equivalent set of ES6 import statements would look like? For instance `import { * } as angular from "angular";`, assuming I am using webpack (as above) – Jim May 25 '17 at 10:51
  • Yes, it is. Usually lib files are included in Karma config, so there's no need to import them in every spec file. – Estus Flask May 25 '17 at 11:07
  • @Jim the correct sintax of import that works for me was without braces: `import * as angular from "angular";` – Victor Oliveira Oct 08 '18 at 11:42