james
james

Reputation: 4583

what's the correct way to import angular-mocks

Versions

typescript: 2.1.4
systemjs: 0.19.41
angular: 1.5.10
angular-mocks: 1.5.10

Problem

I'm trying to load angular-mocks with systemjs in a typescript 2.0 project.

If i use the following it works, but i get a TS error and {module} is also marked as an error in webstorm.

import {module} from 'angular-mocks';

describe('someClass', function () {
    'use strict';

    beforeEach(module('someModule'));

    ...
});

error TS2305: Module '"/node_modules/@types/angular-mocks/index"' has no exported member 'module'.

I originally tried to simply import angular-mocks, but the imported angular object does not have a mock property (even though window.angular.mock is defined), so it throws an error.

import * as angular from 'angular';
import 'angular-mocks';

describe('someClass', function () {
    'use strict';

    beforeEach(angular.mock.module('someModule'));

    ...
});

Uncaught TypeError: Cannot read property 'module' of undefined

Systemjs config

System.config({
    transpiler: 'typescript',
    paths: {
        'src:*': '/src/*',
        'npm:*': '/node_modules/*'
    },
    map: {
        'angular': 'npm:angular/angular.js',
        'angular-mocks': 'npm:angular-mocks/angular-mocks.js',
        'lib': 'src:lib',
        'typescript': 'npm:typescript/lib/typescript.js',
        'systemjs': 'npm:systemjs/dist/system.src.js'
    },
    packages: {
        lib: {
            defaultExtension: 'js'
        }
    },
    meta: {
        angular: {
            format: 'global',
            exports: 'angular'
        },
        'angular-mocks': {
            format: 'global',
            deps: ['angular']
        }
    }
});

Question

Any idea what the correct way to import this is?

Update

This is the solution i'm currently using, that imports the full angular object with mock correctly assigned to it.

import * as angular 'angular-mocks';

describe('someClass', function () {
    'use strict';

    beforeEach(module('someModule'));

    ...
});

Note the addition of exports: 'angular' to the angular-mocks meta, in order for it to correctly import the whole angular object:

System.config({
    ...
    meta: {
        angular: {
            format: 'global',
            exports: 'angular'
        },
        'angular-mocks': {
            format: 'global',
            exports: 'angular',
            deps: ['angular']
        }
    }
}

This still produces a TS error, but at this point it's the shortest one, so is easier to differentiate from other errors...

error TS2304: Cannot find name 'module'.

Upvotes: 5

Views: 9407

Answers (3)

jasonli468
jasonli468

Reputation: 1

I also ran into this issue and it ended up being because esModuleInterop was enabled in my TS config. In order to resolve the issue, you can either change your angular import in your unit tests to import angular from 'angular' or disable the flag (but that will break importing Lodash as import _ from 'lodash')

Upvotes: 0

Patrick Cakes
Patrick Cakes

Reputation: 129

I'm not sure I had the same problem, but in trying to find the answer to my problem google brought me here a few times. So hope this helps someone.

If you are making a hybrid angular app and you are writing your first test which is something like

import * as angular from 'angular';
import 'angular-mocks';

describe('some component', () => {

    beforeEach(() => {
        angular.mock.module('someModule');
    });

});

and you get the error message

ERROR in something.spec.ts
Module not found: Error: Can't resolve 'angular' in ...

or

ERROR in something.spec.ts
Module not found: Error: Can't resolve 'angular-mocks' in ...

Then you may want to check that angular and angular-mocks is installed.

I was referencing them via karma.conf but I found if I instead declare them in package.json under dependencies and devDependencies (respectively), then the test started passing.

Upvotes: 0

Maxim Kulikov
Maxim Kulikov

Reputation: 731

The correct way to import angular-mocks and use it (pay attention to beforeEach()):

import * as angular from 'angular';
import 'angular-mocks';

describe('some component', () => {

    beforeEach(() => {
        angular.mock.module('someModule');
    });

});

It's so because angular-mocks doesn't export anything. It augments angular object.

Here is how it's declaration looks like. Pay attention to mock property, which is added to IAngularStatic interface.

import * as angular from 'angular';

///////////////////////////////////////////////////////////////////////////////
// ngMock module (angular-mocks.js)
///////////////////////////////////////////////////////////////////////////////

declare module 'angular' {

  ///////////////////////////////////////////////////////////////////////////
  // AngularStatic
  // We reopen it to add the MockStatic definition
  ///////////////////////////////////////////////////////////////////////////
  interface IAngularStatic {
    mock: IMockStatic;
  }

  ...

  interface IMockStatic {
    ...

    inject: IInjectStatic

    // see https://docs.angularjs.org/api/ngMock/function/angular.mock.module
    module: {
      (...modules: any[]): any;
      sharedInjector(): void;
    }

    ...
  }
  ...
}

Full declaration: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/angular-mocks/index.d.ts

Upvotes: 10

Related Questions