Environment
Provide version numbers for the following components (information can be retrieved by running tns info in your project folder or by inspecting the package.json of the project):
Describe the bug
ns test seem to be broken on a fresh nativescript angular project with "Error: zone-testing.js is needed for the async() test helper but could not be found."
To Reproduce
I've created a project using :
ns create --ng --id sample-ng sample-ng
Then, i've followed this documentation
https://docs.nativescript.org/angular/tooling/testing/testing
The documentation has not been updated, some path are incorrect in setup.ts.
My setup.ts
import '@nativescript/zone-js/testing.jasmine';
import {nsTestBedInit} from '@nativescript/angular/testing';
nsTestBedInit();
Then execute :
ns test ios
The result :
NativeScript / 14.2 (14.2; iPhone) Renderer E2E executes events inside NgZone when listen is called outside NgZone FAILED
Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
error properties: Object({ originalStack: 'Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
at new ZoneAwareError (file:///app/vendor.js:152354:33)
at resetFakeAsyncZone (file:///app/vendor.js:77146:11)
at UserContext.<anonymous> (file:///app/vendor.js:79298:9)
at ZoneQueueRunner.attempt (eval at runTest (file:///app/vendor.js:149440:17), <anonymous>:7063:44)
at ZoneQueueRunner.QueueRunner.run (eval at runTest (file:///app/vendor.js:149440:17), <anonymous>:7104:25)
at runNext (eval at runTest (file:///app/vendor.js:149440:17), <anonymous>:7023:18)
at next (eval at runTest (file:///app/vendor.js:149440:17), <anonymous>:7030:11)
at eval (eval at runTest (file:///app/vendor.js:149440:17), <anonymous>:6924:9)
at ZoneDelegate.push.../node_modules/@nativescript/zone-js/zone-nativescript.js.ZoneDelegate.invokeTask (file:///app/vendor.js:151477:31)
...
Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
at new ZoneAwareError (file:///app/vendor.js:152354:33)
at resetFakeAsyncZone (file:///app/vendor.js:77146:11)
at UserContext.<anonymous> (file:///app/vendor.js:79298:9)
at <Jasmine>
at ZoneDelegate.push.../node_modules/@nativescript/zone-js/zone-nativescript.js.ZoneDelegate.invokeTask (file:///app/vendor.js:151477:31)
at Zone.push.../node_modules/@nativescript/zone-js/zone-nativescript.js.Zone.runTask (file:///app/vendor.js:151244:47)
at drainMicroTaskQueue (file:///app/vendor.js:151651:35)
zone-testing.js is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/dist/zone-testing.js thrown
Yes I am having issues running tests as well. The issue is easy to replicate. Just create a new angular project, use karma 5.2.3 because 6 has issues, and add the following to example.ts
import '@nativescript/zone-js/testing.jasmine';
import {nsTestBedInit} from '@nativescript/angular/testing';
nsTestBedInit();
Without the import of testing.jasmine it also fails
The test will run fine if nsTestBedInit() is not called
Has anyone figured out how to get unit testing with NativeScript 7 and Angular working? I've never been able to test anything which really sucks. I've tried everything but nothing works. In my current project I always get Error: zone-testing.js is needed for the fakeAsync() test helper but could not be found.. And in a brand new project I get:
...
JS: NSUTR: fetching http://127.0.0.1:9876/context.json
JS: NSUTR: found karma at 192.168.42.225
JS: NSUTR: connecting to karma at http://192.168.42.225:9876
JS: ReferenceError: window is not defined
EDIT: I fixed the above error in the new project NS 7/Angular/Jasmine by setting global.window = global at the error point but now I am back to my original error in both projects:
Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
Please help! Thank you!
I have not been able to. I can only test basic utility files but anything that requires testbed I can't get it to run.
Thanks for responding. Damn that really sucks. I can't believe that the TestBed is broken, maybe it's a webpack issue. Does no one test their NS Angular Projects? I'm just really hoping it is fixed in NS 8.
Please see this: https://github.com/NativeScript/nativescript-angular/issues/2311#issuecomment-786125082
It might help you get past your errors, we would love to know if any of these fixes that are in that blog article fix your issues under Angular 11.
In addition, we would LOVE PR's to fix the issue.
No, it doesn't work on my project NS7 NG11:
NativeScript / 14.4 (14.4; iPhone) Test Component Function Tests - hello() should say "hello" FAILED
Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
error properties: Object({ originalStack: 'Error: zone-testing.js is needed for the async() test helper but could not be found.
Please make sure that your environment includes zone.js/dist/zone-testing.js
at new ZoneAwareError (file:///app/vendor.js:152224:33)
at resetFakeAsyncZone (file:///app/vendor.js:78027:11)
at UserContext.<anonymous> (file:///app/vendor.js:80179:9)
at QueueRunner.attempt (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:7063:44)
at QueueRunner.run (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:7104:25)
at runNext (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:7023:18)
at next (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:7030:11)
at QueueRunner.eval [as onComplete] (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:6924:9)
at eval (eval at runTest (file:///app/vendor.js:150781:17), <anonymous>:7120:12)
at TimerTargetImpl.invoke (file:///app/vendor.js: ...
Not sure if it will be useful in you case but I just fixed a similar error by changing the import order of zone-testing in my src/test.ts file :
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
Not sure if this helps, but I was able to get my NS7/NG11 app to run Jasmine/Karma unit tests. I had to do some serious package testing (dependency validation) to see what works, but all good.
package.json
{
"description": "NativeScript Mobile Template",
"license": "SEE LICENSE",
"repository": "<fill-your-repository-here>",
"dependencies": {
"@angular/animations": "11.2.6",
"@angular/common": "11.2.6",
"@angular/compiler": "11.2.6",
"@angular/core": "11.2.6",
"@angular/forms": "11.2.6",
"@angular/platform-browser": "11.2.6",
"@angular/platform-browser-dynamic": "11.2.6",
"@angular/router": "11.2.6",
"@nativescript/angular": "11.0.1",
"@nativescript/core": "7.3.0",
"@nativescript/theme": "3.0.1",
"@nativescript/unit-test-runner": "1.0.2",
"@nativescript/webpack": "3.0.9",
"base-64": "1.0.0",
"crypto-js": "4.0.0",
"reflect-metadata": "0.1.13",
"rxjs": "6.6.6",
"zone.js": "0.11.4"
},
"devDependencies": {
"@angular/compiler-cli": "11.2.6",
"@nativescript/android": "7.0.1",
"@nativescript/ios": "7.2.0",
"@nativescript/types": "7.3.0",
"@ngtools/webpack": "11.2.5",
"@types/jasmine": "3.6.7",
"istanbul-instrumenter-loader": "3.0.1",
"jasmine-core": "3.6.0",
"jasmine-spec-reporter": "6.0.0",
"karma": "6.1.2",
"karma-coverage": "2.0.3",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-jasmine": "4.0.1",
"karma-nativescript-launcher": "0.4.0",
"karma-sourcemap-loader": "0.3.8",
"karma-spec-reporter": "0.0.32",
"karma-typescript": "5.5.0",
"karma-webpack": "3.0.5",
"typescript": "4.0.2"
},
"main": "main.js"
}
karma.config.js
module.exports = function (config) {
const options = {
basePath: '',
frameworks: ['jasmine'],
plugins: [
'karma-jasmine',
'karma-coverage-istanbul-reporter',
'karma-coverage',
'karma-webpack',
'karma-nativescript-launcher',
'karma-sourcemap-loader',
'karma-spec-reporter'
],
files: [
'src/tests/setup.ts',
'src/tests/**/*.spec.ts',
'src/app/**/*.ts'
],
exclude: [
],
preprocessors: {
'src/tests/setup.ts': ['webpack'],
'src/tests/**/*.spec.ts': ['webpack'],
'src/app/**/*.ts': ['webpack', 'coverage']
},
reporters: ['progress', 'coverage', 'coverage-istanbul'],
coverageIstanbulReporter: {
dir: require('path').join(__dirname, 'coverage'),
reports: ['html', 'lcov', 'text-summary'],
fixWebpackSourcePaths: true
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: [],
singleRun: false,
customLaunchers: {
android: {
base: 'NS',
platform: 'android'
},
ios: {
base: 'NS',
platform: 'ios'
},
ios_simulator: {
base: 'NS',
platform: 'ios',
arguments: ['--emulator']
}
}
};
setWebpack(config, options);
config.set(options);
}
function setWebpack(config, options) {
if (config && config.bundle) {
const env = {};
env[config.platform] = true;
env.sourceMap = config.debugBrk;
env.appPath = config.appPath;
options.webpack = require('./webpack.config')(env);
options.webpack.module.rules.push(
{
test: /\.ts$/,
use: {
loader: "istanbul-instrumenter-loader",
options: {
esModules: true
}
},
enforce: 'post'
}
);
delete options.webpack.entry;
delete options.webpack.output.libraryTarget;
const invalidPluginsForUnitTesting = ["GenerateBundleStarterPlugin", "GenerateNativeScriptEntryPointsPlugin"];
options.webpack.plugins = options.webpack.plugins.filter(p => !invalidPluginsForUnitTesting.includes(p.constructor.name));
}
}
setup.ts (customized and placed in the root of the 'tests' folder):
import '@nativescript/zone-js';
import 'zone.js/dist/zone-testing';
import { TestBed } from '@angular/core/testing';
import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
import { BrowserTestingModule } from '@angular/platform-browser/testing';
export function customNsTestBedInit(): void {
TestBed.initTestEnvironment(
BrowserTestingModule,
platformBrowserDynamicTesting()
);
}
export function customNsTestBedBeforeEach(
components: any[],
providers: any[] = [],
imports: any[] = [],
entryComponents: any[] = []) {
return (done: () => void) => {
if (entryComponents.length === 0) {
TestBed.configureTestingModule({
declarations: [ ...components ],
providers: [ ...providers ],
imports: [ ...imports ]
});
}
TestBed.compileComponents()
.then(() => done())
.catch((e) => {
console.log(`Failed to instantiate test component with error: ${e}`);
console.log(e.stack);
done();
});
};
}
export function customNsTestBedAfterEach(resetEnv = true, resetFn = customNsTestBedInit): void {
TestBed.resetTestingModule();
if (resetEnv) {
TestBed.resetTestEnvironment();
resetFn();
}
}
// Note. This testing infrastructure can test components but it
// can only test the functions. No rendering of the dom is done
// Nativescript runs its own zone.js which intereferes with the
// zone.js code run by NG10. So my test suite completely disables
// the nativescript code and it should not execute anywhere.
// ** In testing if you inject something that calls any nativescript
// code it will reactivate the nativescript zone.js. make sure to stub
// this out so that it does not interfere with the unit test.
/// intialize Test bed.
customNsTestBedInit();
feedback.component.spec.ts (a spec file with a few tests)
import { TestBed } from '@angular/core/testing';
import { customNsTestBedAfterEach, customNsTestBedBeforeEach } from '../setup';
import { Page } from '@nativescript/core';
import { RouterTestingModule } from '@angular/router/testing';
import { FeedbackComponent } from "~/app/common/feedback/feedback.component";
describe('Initialize', () => {
beforeEach(
customNsTestBedBeforeEach(
[],
[
FeedbackComponent,
Page
],
[
RouterTestingModule
]
)
);
afterEach(() => customNsTestBedAfterEach());
describe('Component Tests -', () => {
let component: FeedbackComponent;
beforeEach(() => {
component = TestBed.inject(FeedbackComponent);
});
describe('FeedbackComponent', () => {
it('should resolve component', () => {
expect(component).toBeTruthy();
});
it('should initialize variables', () => {
expect(component.isTablet).toBeDefined();
expect(component.timer).toBeNull();
});
it('should call showFeedback()', () => {
spyOn(component, 'showFeedback');
component.showFeedback("test");
expect(component.showFeedback).toHaveBeenCalledWith('test');
});
it('should verify showFeedback() parameters', () => {
spyOn(Page.prototype, 'getViewById').and.callThrough();
component.showFeedback("test");
expect(Page.prototype.getViewById).toHaveBeenCalledWith('feedbackLayout');
expect(Page.prototype.getViewById).toHaveBeenCalledWith('feedbackFrame');
expect(Page.prototype.getViewById).toHaveBeenCalledWith('feedbackMessage');
expect(Page.prototype.getViewById).toHaveBeenCalledWith('feedbackClose');
});
it('should call hideFeedback()', () => {
spyOn(component, 'hideFeedback');
component.hideFeedback();
expect(component.hideFeedback).toHaveBeenCalled();
});
it('should verify hideFeedback() parameters', () => {
spyOn(Page.prototype, 'getViewById');
component.hideFeedback();
expect(Page.prototype.getViewById).toHaveBeenCalledWith('feedbackLayout');
});
});
});
});
Not sure if it will be useful in you case but I just fixed a similar error by changing the import order of
zone-testingin mysrc/test.tsfile :import 'zone.js/dist/zone-testing'; import { getTestBed } from '@angular/core/testing';
Actually thanks for that hint... never thought it could be the order of imports... Just as a small addition to this.
The import of zone-testing has to be the very first of all imports.
Line 1 - import 'zone.js/dist/zone-testing';
Not sure if it will be useful in you case but I just fixed a similar error by changing the import order of
zone-testingin mysrc/test.tsfile :import 'zone.js/dist/zone-testing'; import { getTestBed } from '@angular/core/testing';Actually thanks for that hint... never thought it could be the order of imports... Just as a small addition to this.
The import of zone-testing has to be the very first of all imports.
Line 1 -import 'zone.js/dist/zone-testing';
it worked, but is there any explanation for this?
Thanks @soodohkohd, your comment helped a lot to get Angular testing working again in NS7 and NG11
Most helpful comment
Not sure if it will be useful in you case but I just fixed a similar error by changing the import order of
zone-testingin mysrc/test.tsfile :