Joshua Webb
Joshua Webb

Reputation: 646

Import angular component in PhantomJS with jasmine/karma

The following unit test works in Chrome (due to its native support for HTML-imports), but I'm struggling to get it to work with PhantomJS (and other browsers for that matter).

I'm trying to polyfill the import ('webcomponents.js/HTMLImports.min.js') but it doesn't have any effect.

karma.conf.js

module.exports = function(config) {
  config.set({
    frameworks: ['jasmine'],
    plugins: [
      'karma-phantomjs-launcher',
      'karma-chrome-launcher',
      'karma-jasmine'
    ],
    files: [
      'node_modules/angular/angular.js',
      'node_modules/angular-mocks/angular-mocks.js',
      'node_modules/webcomponents.js/HTMLImports.min.js',

      'component/so-example.html',

      'test/test.spec.js'
    ],
    port: 9876,
    browsers: ['Chrome', 'PhantomJS']
  });
};

component/so-example.html

<script>
(function () {
  var soExampleComponent = {
    transclude: true,
    bindings: {
      number: '@'
    },
    template: '<span class="compiled">{{$ctrl.number}}</span>'
  };

  angular.module('so.components.example', []).component('soExample', soExampleComponent);
})();
</script>

test/test.spec.js

describe('<so-example>', function () {
  var $scope, el;

  beforeEach(module('so.components.example'));

  beforeEach(inject(function ($compile, $rootScope) {
    $scope = $rootScope.$new();
    el = $compile('<so-example number="{{ 3 }}"></so-example>')($scope)[0];
    $scope.$digest();
  }));

  it('should import and compile', function () {
    expect(el.querySelector('.compiled').textContent).toBe('3');
  });
});

the error from PhantomJS

forEach@C:/Temp/so-example/node_modules/angular/angular.js:322:24
loadModules@C:/Temp/so-example/node_modules/angular/angular.js:4591:12
createInjector@C:/Temp/so-example/node_modules/angular/angular.js:4513:30
workFn@C:/Temp/so-example/node_modules/angular-mocks/angular-mocks.js:3060:60
C:/Temp/so-example/node_modules/angular/angular.js:4631:53
TypeError: undefined is not an object (evaluating 'el.querySelector') in C:/Temp/so-example/test/test.spec.js (line 14)
C:/Temp/so-example/test/test.spec.js:14:14

Upvotes: 1

Views: 590

Answers (1)

Joshua Webb
Joshua Webb

Reputation: 646

After banging my head against this for about a day, it turns out the solution was quite simple.

We can force jasmine to wait until the import has finished by having the following block execute before any tests which rely on an HTML import.

// Wait for the HTML Imports polyfill to finish before running anything else
beforeAll(function(done) {
  window.addEventListener('HTMLImportsLoaded', done);
});

I've put this into a separate file that is referenced in karma.conf.js before all of my other spec.js files.

However, it can be placed within a single describe block or a single spec.js if it isn't required anywhere else.

Upvotes: 1

Related Questions