what's the correct way to import angular-mocks
Asked Answered
H

3

5

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'.
Hezekiah answered 12/1, 2017 at 15:56 Comment(0)
U
10

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

Undersize answered 5/2, 2017 at 12:56 Comment(11)
I feel like i must be missing something. Isn't this exactly the same as my code, apart from the fact that angular.mock.module is wrapped in a fat arrow?Hezekiah
@Hezekiah yes, it's the only difference. It means that the problem is not in import but in your Systemjs config. Put debugger statement before your beforeEach() and compare angular and window.angular, according to what you said (window.angular.mock is defined and you got Uncaught TypeError: Cannot read property 'module' of undefined) they are not the same.Undersize
I don't mean to be rude, but you're not telling me anything, that's not already clearly explained in my question. You're just repeating the description of the problem i'm trying to solve.Hezekiah
@Hezekiah 1) The question is worded like you think that the issue is in import, while its in config. 2) I told that you should look at angular variable in the debugger, it's shape will tell what is wrong with Systemjs config. You just specified that it doesn't have mock prop, but more important what it has. BTW if you want someone to investigate your case with debugger, you need publish minimal errror-reproducing project on github, so that it will be possible to just git clone && npm install && npm start (because rebuilding your structure from scratch is time-consuming and error prone)Undersize
1) As far as i'm aware (at this point in time), it's not possible to use the import keyword without using a transpiler/module loader. Which will also require a config. So when discussing the correct way to 'import' in javascript, the fact that this refers to the import statement and the config, is currently implicitly implied. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Hezekiah
@Hezekiah I cannot agree with your interpretation of import. Its standardised language keyword and specification defines what's the correct way to import. Even if in some community 'import' term implicitly implies config of 3rd party tools, in global public space ES keywords should be used in spec-defined meaning. Keep in mind that google search "import angular-mocks" leads to this page, so people searching it came here and upvoted on the answer. If you want the question to be systemjs-specific, consider changing question titleUndersize
@Hezekiah returning from offtopic, what about the shape of your angular variable value? is it an object? which properties it has?Undersize
The question is quite obviously systemjs related. Re-read the first 7 lines and then tell me otherwise. I would suggest reading questions more thoroughly in the future before answering. It's more helpful to the person who's asked the question and saves wasting both parties time.Hezekiah
At no point in my question do i state 'i think the issue is due to the import statement, do i? It's just how you've decided to interpret it, instead of actually reading the question. If i've already stated exactly the same way to import that you then repeat, supplied systemjs config and the exact error that occurs, it makes it pretty obvious that i've already tried to use that method. Which is then quite obviously failing due to an issue with the systemjs config, if the import statement is correct. As you've repeated.Hezekiah
@Hezekiah Actually in your question there are two things indicating that you suspected the issue to be in import statement: 1) your question title; 2) the solution you are currently using. Regarding (1) we figured out that it's misuse of 'import' keyword. Regarding (2) it's hard to guess why someone intentionally uses wrong code.Undersize
@Hezekiah I would suggest you one of two: A) change the question title and finally provide the required details; B) in case you are not interested in resolving this, please, do a favor for people who come here from google search "import angular-mocks", remove from the question all irrelevant stuff.Undersize
D
0

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.

Dean answered 1/7, 2020 at 16:57 Comment(0)
B
0

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')

Bryanbryana answered 6/8, 2021 at 20:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.