Cannot access modules with ng-mock in angular unit tests - unit-testing

I am using Karma and Jasmine for my unit tests. However, I am unable to mock or acquire the modules in my unit tests. I keep getting the same error
Error: [$injector:modulerr] Failed to instantiate module ha.module.core due to:
Error: [$injector:nomod] Module 'duScroll' is not available! You either
misspelled the module name or forgot to load it. If registering a module
ensure that you specify the dependencies as the second argument.
However, I am injecting the modules in the beforeEach function on top
angular.mock.module('duScroll');
angular.mock.module('ui.router');
angular.mock.module('ha.module.utility');
angular.mock.module('ha.module.core');
In my karma.config file I am requiring the js files
files: [
'../node_modules/jquery/dist/jquery.js',
'../node_modules/angular/angular.js',
'../node_modules/angular-mocks/angular-mocks.js',
'src/modules/utility/module.utility.built.js',
'src/modules/utility/services/*.js',
'src/modules/core/module.core.built.js',
'src/modules/**/**/*.js',
'src/modules/core/**/*.js',
'../Templates/**/*.html',
'tests2/**/*.js',
],
I have attached a screen shot to show what is showing up when I run karma. I am getting the files to show up in my developer tools.
All I can wonder is if there is something else additional that I must do to get the modules initiated to run the tests? The files are loaded after angular and angular mocks and they are loaded before my testing folder. Not sure why I cannot get the modules though.

You do not need to call angular.mock.module, it is enough to call beforeAll(module('<module-name>')) for each module you want to mock.
Then, to inject your controllers afterwards, you have to use
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
Inforation from https://docs.angularjs.org/guide/unit-testing#testing-a-controller. Please visit it for more info.

Related

jest manual ES6 class mock is not active and I want to understand why

I am having problems using Jest manual mocks (the one in a parallel __mocks__ directory) in my project.
I think I understand how to use it and it actually works fine if I remove a single line in a file specified in the Jest setupFiles array.
In that file a global helper is installed (into global.createComp) that uses the vuex store.
This is a vue + vuex project but even running the stripped down spec using only jest gives unexpected results.
Can somebody look at my minimal reproducible example repo at https://github.com/thenoseman/jest-manual-mock-not-working, do a npm i and npm run test:unit and help me understand why the mock is not active?
You can find the line that need to be commented out in test/unit/support/helpers.js.
Also the README shows a screenshot and further explains what the problem looks like.
setupFiles are evaluated before test files. As the reference states,
A list of paths to modules that run some code to configure or set up the testing environment. Each setupFile will be run once per test file. Since every test runs in its own environment, these scripts will be executed in the testing environment immediately before executing the test code itself.
JavaScript modules are evaluated once on first import. Importing #/store/modules/internetAtHome in helpers.js results in importing original #/api/DslService.
The mock in test file doesn't affect #/api/DslService because it has already been evaluated earlier:
jest.mock("#/api/DslService");
import DslService from "#/api/DslService";
In case helpers.js needs mocked #/api/DslService, jest.mock needs to be moved there.
In case helpers.js needs original #/api/DslService but tests need mocked one, the module (and any module that depends on it) needs to be re-imported with jest.resetModules or jest.isolatedModules:
jest.mock('#/api/DslService');
let DslService;
jest.isolateModules(() => {
DslService = require("#/api/DslService").default;
});
...
For a module that was imported with original implementation and needs to be re-imported as a mock, jest.requireMock can be used, it doesn't need jest.mock('#/api/DslService'):
let DslService = jest.requireMock("#/api/DslService").default;
...

Unit testing Nativescript application logic on a browser

I am trying to set up unit testing for a Nativescript application, run by ng test on a browser. The problem is that whenever there is a tns-core-modules or another plugin import, the module cannot be resolved because of the platform specific files (e.g. "tns-core-modules/application/application.android.js") that never get compiled into the bundle, thus throwing an error like "Module not found: Error: Can't resolve 'tns-core-modules/application'".
I know there is a built-in unit test support in Nativescript. The problem I have with it is that it can't run on CI. I would like to be a ble to have lightweight tests for my business logic, mocking out all platform dependencies.
I have looked for a way to mock the module imports at runtime with no luck. I looked into rewire package but it only runs on node.
I finally managed to get it working. Not a very elegant solution and I have yet to see how much maintenance it requires. Key points here:
Use paths section of the tsconfig.json to add mock import
locations
In the mocks directory create files for any unresolved module
Some nativescript modules are referencing helper functions on global
scope but they're undefined. My solution was to define them in
test.ts like this
window['__decorate'] = () => {};
window['__extends'] = () => {};
window['__metadata'] = () => {};
window['__param'] = () => {};
window['layout_base_1'] = { CSSType: () => {} };
window['Crashlytics'] = {};
window['Fabric'] = {};
You simply can not run NativeScript application on Browser.
In case if you are looking for something like headless mode, Appium has one too, isHeadless in capabilities.
Between, may I know why you think you can not run the {N} unit tests on CI? It should work on CI too, after all it's a machine that runs the same commands based on some trigger.

ReferenceError: ga is not defined [Ionic 2.2 Unit Testing With Karma]

I'm adding unit tests to an Ionic 2.2.0 app I manage, but my Components crash at test-time when they encounter Google Analytics code. I'm using Ionic's official unit testing example as a basis, and my current progress can be seen on our public repo.
My project uses Google Analytics, which is added to the HTML and downloaded at runtime (because we have different keys for development vs production).
The code that initializes Analytics is in my main.ts, and it sets a global variable ga, which is subsequently available throughout the application.
I'm beginning the tests for the app's first page, which uses Analytics. When I run the tests, I'm met with the following error
Component should be created FAILED
ReferenceError: ga is not defined
at new MyBusesComponent (webpack:///src/pages/my-buses/my-buses.component.ts:33:6 <- karma-test-shim.js:138419:9)
at new Wrapper_MyBusesComponent (/DynamicTestModule/MyBusesComponent/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_MyBusesComponent_Host0.createInternal (/DynamicTestModule/MyBusesComponent/host.ngfactory.js:15:32)
........
This is because main.ts doesn't seem to be loaded or executed, and I assume TestBed is doing that purposefully. It's certainly better that I don't have the actual Google Analytics object, but the Component does need a function called ga.
My question, therefore, is as follows: how can I create Google Analytics' ga variable in my test configuration such that it's passed through to my components at test-time?
I've tried exporting a function from my mocks file and adding it to either the imports or providers arrays in my spec file, but to no avail.
I appreciate any advice! Feel free to check my code at our repo I linked to above and ask any followups you need. Thanks!
You declare the var ga but that is just to make TypeScript happy. At runtime, the ga is made global from some external script. But this script is not included in the test.
What you could do is just add the (mock) function to the window for the tests. You could probably do this in your karma-test-shim.js.
window.ga = function() {}
Or if you wanted to test that the component is calling the function with the correct arguments, you could just add the function separately in each test that uses the function. For example
beforeEach(() => {
(<any>window).ga = jasmine.createSpy('ga');
});
afterEach(() => {
(<any>window).ga = undefined;
})
Then in your test
it('..', () => {
const fixture = TestBed.creatComponent(MyBusesComponent);
expect(window.ga.calls.allArgs()).toEqual([
['set', 'page', '/my-buses.html'],
['send', 'pageview']
]);
})
Since you're making multiple calls to ga in the constructor, the Spy.calls will get the argument of all each call and put them in separate arrays.

How to use "rewire" module in my Angular 2 - cli, Karma, Jasmine unit test

I have a file which has few classes. One of them is exported and rest are internally used by it. All those 'used' classes are not exported.
I am trying to write a unit test for those non-exported classes and wanted to try 'rewire'module. However, when I try
var rewire = require("rewire")
my Karma, returns me an error
404: base/dist/rewire
How to handle that error?

AngularJS mocking $logProvider in config block

Is there a way to inject providers when writing unit tests using Karma(Testacular) and Jasmine in angular?
Our team decided recently to use angularjs $log to write debugging details to the console. This way we can leverage the ability to disable the logging via the $logProvider.debugEnabled() method.
angular.module("App", ["prismLogin", "ui.bootstrap"])
.config(["$routeProvider", "$logProvider",
function ($routeProvider, $logProvider) {
$routeProvider
//routes here edited for brevity
//This is the offending line, it breaks several pre-existing tests
$logProvider.debugEnabled(true);
}]);
However after adding the $logProvider.debugEnabled(true); line several of our tests no longer execute successfully, failing with the following message:
TypeError: Object doesn't support property or method 'debugEnabled' from App
So my question again, is it possible to mock the $logProvider? Or should I provide my own configuration block for the test harness?
I attempted searching for a way to mock the app module with no luck. It seems to me that using the concrete app module instead of a mock is very brittle. I would like to avoid reworking tests associated with the app module every time a change is made in the app or run configuration blocks.
The tests that are failing are units of code with no relation to the $logProvider? I feel as if I a missing something here and making things much harder than they should be. How should one go about writing tests that are flexible and are not affected by other side effects introduced in your application?
It appears that this is a know issue with angular-mocks.
Until the issue is addressed , I was able to resolve the issue by adding the following method to the angular.mock.$LogProvider definition in angular-mocks.js at line 295.
this.debugEnabled = function(flag) {
return this;
};