Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular error running Karma tests: HTML5 mode requires a <base> tag

I have a single-page Angular app with a Rails backend. I am using a tag in my index.html file, but when I run my front-end unit tests using Karma, I get this:

$location in HTML5 mode requires a <base> tag to be present

I am doing this in my main .js file:

angular.module('my.module').config( function($locationProvider, $routeProvider) {
  $locationProvider.html5Mode( true );
}

So, is there any way I can inject a <base> element in the page that karma actually renders? Or else, tell Angular/Karma to ignore this error when running unit tests?

Update

This Google Groups thread and this GitHub issue both describe this problem but in both cases the solution is to simply bump up the version of Angular. I've done that and I can even see the line in angular-mocks.js where the default baseHref gets set...

Here is the spec in question:

describe 'amnResource', ->
  $compile = null
  $rootScope = null

  beforeEach ->
    module 'ngMock'
    module 'amn'
    module 'directive.template.cache'

    inject([ '$compile', '$rootScope', ($c, $r) ->
      $compile = $c
      $rootScope = $r
    ])

  it 'compiles to an article', ->
    console.log $rootScope
    console.log $rootScope.foo
    $rootScope.foo =
      title: 'Foo'
      excerpt: 'foo bar qux'

    element = $compile('<amn-resource resource="foo"></amn-resource>')($rootScope)
    console.log element.html()
    console.log $rootScope.foo
    expect( element.html() ).toMatch /Foo/

Karma output:

Running "karma:unit" (karma) task
INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 39.0.2171 (Mac OS X 10.9.5)]: Connected on socket hOvsC6ji15heHZmiHxJt with id 45528987
ERROR: 'Error: [$location:nobase] $location in HTML5 mode requires a <base> tag to be present!
http://errors.angularjs.org/1.3.5/$location/nobase
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:63:12
    at $LocationProvider.$get (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:11187:15)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4138:17)
    at $LocationProvider.origProvider.$get (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4024:43)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4138:17)
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:3956:37
    at getService (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4097:39)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4129:13)
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:3956:37
    at getService (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4097:39)'
ERROR: 'Error: [$location:nobase] $location in HTML5 mode requires a <base> tag to be present!
http://errors.angularjs.org/1.3.5/$location/nobase
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:63:12
    at $LocationProvider.$get (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:11187:15)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4138:17)
    at $LocationProvider.origProvider.$get (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4024:43)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4138:17)
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:3956:37
    at getService (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4097:39)
    at Object.invoke (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4129:13)
    at http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:3956:37
    at getService (http://localhost:9876/base/vendor/assets/javascripts/angular/angular.js?3a16995fbea0062d6334adb9277e9776ca069fa1:4097:39)'
Chrome 39.0.2171 (Mac OS X 10.9.5) Midway: Resource performs a GET request FAILED
    Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
LOG: Scope{$id: 2, $$childTail: null, $$childHead: null, $$prevSibling: null, $$nextSibling: null, $$watchers: null, $parent: null, $$phase: null, $root: Scope{$id: 2, $$childTail: null, $$childHead: null, $$prevSibling: null, $$nextSibling: null, $$watchers: null, $parent: null, $$phase: null, $root: Scope{$id: ..., $$childTail: ..., $$childHead: ..., $$prevSibling: ..., $$nextSibling: ..., $$watchers: ..., $parent: ..., $$phase: ..., $root: ..., $$destroyed: ..., $$listeners: ..., $$listenerCount: ..., $$isolateBindings: ..., $$asyncQueue: ..., $$postDigestQueue: ..., $$applyAsyncQueue: ...}, $$destroyed: false, $$listeners: Object{}, $$listenerCount: Object{}, $$isolateBindings: null, $$asyncQueue: [], $$postDigestQueue: [], $$applyAsyncQueue: []}, $$destroyed: false, $$listeners: Object{}, $$listenerCount: Object{}, $$isolateBindings: null, $$asyncQueue: [], $$postDigestQueue: [], $$applyAsyncQueue: []}
LOG: undefined
LOG: ''
LOG: Object{title: 'Foo', excerpt: 'foo bar qux'}
Chrome 39.0.2171 (Mac OS X 10.9.5) amnResource compiles to an article FAILED
    Expected '' to match /Foo/.
    Error: Expected '' to match /Foo/.
        at Object.<anonymous> (/Users/acobster/Dropbox/amn/amn-0.5/spec/javascripts/unit/directives/resource_spec.js:27:35)
Chrome 39.0.2171 (Mac OS X 10.9.5): Executed 3 of 3 (2 FAILED) (5.078 secs / 5.074 secs)
like image 701
acobster Avatar asked Dec 05 '14 02:12

acobster


3 Answers

You can disable the base tag check by doing the following:

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});
like image 144
connorbode Avatar answered Nov 13 '22 06:11

connorbode


You can specify your base tag in your index.html <head> like that:

<head>
  <base href="/">
  ...
</head>

Source: from angularjs documentation

like image 27
zurfyx Avatar answered Nov 13 '22 06:11

zurfyx


If you can't or do not want to set requireBase to false, the solution - as others pointed out - is to add <base href="/"> in the header of your primary HTML file. To do this, you will need to specify custom HTML files for Karma, which you can then edit.

First find and copy node_modules/karma/static/context.html and node_modules/karma/static/debug.html to your unit test folder, and amend the headers of both.

Then in your karma.conf.js add the following two lines:

customContextFile: 'test/unit/context.html',
customDebugFile:   'test/unit/debug.html',

Of course your path may vary.

like image 6
The Victor Avatar answered Nov 13 '22 07:11

The Victor