How to Fix 'Unknown provider: $rootscopeProvider <- $rootscope' in AngularJS Jasmine Tests
If you’ve worked with AngularJS and Jasmine for unit testing, you’ve likely encountered the frustrating error: Unknown provider: $rootscopeProvider <- $rootscope. This error typically pops up when AngularJS’s dependency injector cannot resolve the $rootScope service during test execution. While it may seem intimidating at first, it’s almost always caused by common setup issues in your test environment or code.
In this blog, we’ll demystify this error, explore its root causes, and walk through step-by-step solutions to fix it. Whether you’re new to AngularJS testing or a seasoned developer, this guide will help you resolve the issue quickly and prevent it from recurring.
Table of Contents#
- Understanding the Error: What Does It Mean?
- Common Causes of the Error
- Step-by-Step Solutions to Fix the Error
- Advanced Scenarios: When the Error Persists
- Prevention Tips to Avoid Future Errors
- Conclusion
- References
1. Understanding the Error: What Does It Mean?#
AngularJS relies on a dependency injector to manage services, controllers, and other components. When you see Unknown provider: $rootscopeProvider <- $rootscope, it means the injector tried to resolve a service named $rootscope but failed to find a corresponding provider ($rootscopeProvider).
Wait—AngularJS has a core service called $rootScope, not $rootscope! The key here is the lowercase s in $rootscope. AngularJS is case-sensitive, so even a tiny typo like this can break dependency resolution.
But typos aren’t the only culprit. The error can also occur if your test isn’t properly configured to load AngularJS modules, or if critical testing libraries like angular-mocks.js are missing. Let’s dive into the common causes.
2. Common Causes of the Error#
2.1 Typo in Service Name (Case Sensitivity)#
The most frequent cause is a case-sensitive typo in the service name. AngularJS core services like $rootScope, $http, and $controller use camelCase (e.g., $rootScope with an uppercase S). Writing $rootscope (lowercase s) confuses the injector, which looks for a non-existent $rootscopeProvider.
2.2 Missing AngularJS Module in Test Setup#
AngularJS services (including $rootScope) are registered with a module (e.g., your app’s main module, myApp). If your test doesn’t explicitly load this module, the injector won’t know where to find $rootScope. For example, if your app is defined as angular.module('myApp', []), but your test never calls module('myApp'), the injector can’t resolve $rootScope.
2.3 Absence of angular-mocks.js#
Jasmine alone can’t test AngularJS code. You need angular-mocks.js (part of the AngularJS testing utilities), which provides tools like module() (to load modules) and inject() (to inject services). Without angular-mocks.js, the module and inject functions won’t exist, and the injector will fail to resolve $rootScope.
2.4 Incorrect Use of angular.mock.inject#
Even if you load the module and include angular-mocks.js, you must use angular.mock.inject (or its alias inject) to inject $rootScope into your tests. Trying to access $rootScope directly (e.g., without wrapping it in inject()) will cause the injector to fail.
3. Step-by-Step Solutions to Fix the Error#
Let’s walk through actionable fixes for each common cause.
3.1 Check for Typos (Case Sensitivity)#
Fix: Ensure you’re using the correct camelCase service name: $rootScope (uppercase S), not $rootscope.
Example of the Error:
// ❌ Typo: $rootscope (lowercase 's')
beforeEach(inject(function($rootscope) {
$scope = $rootscope.$new(); // Fails with "Unknown provider: $rootscopeProvider"
}));Corrected Code:
// ✅ Correct: $rootScope (uppercase 'S')
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new(); // Works!
}));3.2 Load the AngularJS Module in Your Test#
Fix: Use Jasmine’s beforeEach (or beforeAll) to load your app’s module before injecting services.
Example of the Error:
// ❌ Missing module loading
describe('MyController', function() {
var $scope;
beforeEach(inject(function($rootScope) { // Fails: Module not loaded!
$scope = $rootScope.$new();
}));
});Corrected Code:
// ✅ Load the module first
describe('MyController', function() {
var $scope;
// Load your app's module (e.g., 'myApp') before injecting services
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new(); // Now $rootScope is resolved!
}));
});3.3 Verify angular-mocks.js is Included#
angular-mocks.js is required for Jasmine to test AngularJS code. Without it, the module and inject functions are undefined, leading to injector failures.
How to Fix:
- If using Karma (a test runner), ensure
angular-mocks.jsis listed in yourkarma.conf.jsunderfiles:// karma.conf.js module.exports = function(config) { config.set({ files: [ 'node_modules/angular/angular.js', // AngularJS core 'node_modules/angular-mocks/angular-mocks.js', // Required for testing! 'app/js/**/*.js', // Your app code 'test/**/*.spec.js' // Your test files ] }); }; - If testing in the browser directly, include it via a
<script>tag:<script src="path/to/angular.js"></script> <script src="path/to/angular-mocks.js"></script> <!-- Add this! --> <script src="path/to/jasmine.js"></script>
3.4 Use angular.mock.inject to Inject $rootScope#
$rootScope (and all AngularJS services) must be injected using angular.mock.inject (aliased as inject in tests). This function tells the injector to resolve the service and pass it to your test.
Example of the Error:
// ❌ Trying to inject $rootScope without `inject()`
describe('MyController', function() {
var $scope = $rootScope.$new(); // Fails: $rootScope is undefined!
});Corrected Code:
// ✅ Use inject() to resolve $rootScope
describe('MyController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope) { // Inject $rootScope here
$scope = $rootScope.$new(); // Now $rootScope is available
}));
});4. Advanced Scenarios: When the Error Persists#
If you’ve fixed typos, loaded the module, and included angular-mocks.js but still see the error, consider these edge cases.
4.1 Mocking Module Dependencies#
If your app module depends on other modules (e.g., myApp depends on ngRoute or a custom module myUtils), the injector may fail to resolve $rootScope if those dependencies are not loaded or mocked.
Fix: Load all dependencies in your test, or mock them if they’re not needed. For example:
// If your app module is 'myApp' with dependency 'myUtils'
beforeEach(module('myUtils')); // Load the dependency first
beforeEach(module('myApp')); // Then load your app moduleIf myUtils is complex, mock it using $provide to avoid side effects:
beforeEach(module(function($provide) {
$provide.value('myUtilsService', { mockMethod: jasmine.createSpy() });
}));
beforeEach(module('myApp')); // Now 'myApp' uses the mocked dependency4.2 Dealing with Minification Issues (Rare)#
Minification tools (like UglifyJS) often rename variables to shorten code (e.g., $rootScope → a). If your test code is minified, the injector may fail to resolve $rootScope because the variable name no longer matches the service name.
Fix: Use AngularJS’s inline array annotation to preserve dependency names:
// ❌ Vulnerable to minification: function($rootScope) { ... }
// ✅ Safe: ['$rootScope', function($rootScope) { ... }]
beforeEach(inject(['$rootScope', function($rootScope) {
$scope = $rootScope.$new();
}]));Most test setups don’t minify test code, so this is rare. But it’s good practice to use array annotation in production code, and it won’t hurt in tests.
4.3 Custom Providers Overriding Core Services#
In rare cases, a custom provider may accidentally override $rootScopeProvider, breaking the core $rootScope service. For example:
// ❌ Accidental override (never do this!)
angular.module('myApp').provider('$rootScope', function() {
this.$get = function() { return {}; }; // Replaces core $rootScope!
});Fix: Rename your custom provider to avoid conflicting with core services (e.g., myCustomRootScopeProvider instead of $rootScopeProvider).
5. Prevention Tips to Avoid Future Errors#
To keep this error at bay, follow these best practices:
- Use a Linter: Tools like ESLint with plugins (e.g.,
eslint-plugin-angular) flag typos and incorrect service names in AngularJS code. - Standardize Test Setup: Always load your app module in a
beforeEachblock at the start of your test suite. - Include
angular-mocks.js: Ensure it’s listed in your test runner config (e.g.,karma.conf.js) or<script>tags. - Review AngularJS Docs: Familiarize yourself with core service names (camelCase!) and testing patterns via the AngularJS Unit Testing Guide.
6. Conclusion#
The Unknown provider: $rootscopeProvider <- $rootscope error is almost always caused by preventable issues: typos in service names, missing module loading, or absent testing libraries like angular-mocks.js. By checking for case-sensitive typos, ensuring your app module is loaded, and using inject() correctly, you’ll resolve the error in minutes.
Remember: AngularJS’s dependency injector is strict but predictable. With careful setup and attention to detail, you’ll spend less time debugging and more time writing robust tests.