title: How to test Durandal.js viewmodel containing i18next implementation?
body: <p>I'm new to both Durandal.js and Javascript testing with Jasmine, and need some help. I have managed to get a testing environment up and running with Karma and Jasmine, but I struggle to figure out how to test my viewmodels that contains i18next dependencies.</p>
  
  <p>Here's a stripped down example of my setup:</p>
  
  <p><strong>main.js</strong></p>
  
  <pre><code>requirejs.config({
      paths: {
          'models': 'models',
          'text': '../lib/require/text',
          'durandal': '../lib/durandal/js',
          'plugins': '../lib/durandal/js/plugins',
          'transitions': '../lib/durandal/js/transitions',
          'knockout': '../lib/knockout/knockout-2.3.0',
          'bootstrap': '../lib/bootstrap/js/bootstrap.min',
          'jquery': '../lib/jquery/jquery-1.9.1',
          'i18next': '../lib/i18next/i18next.amd.withJQuery-1.7.1.min'
      }
  });
  
  define(['plugins/router', 'durandal/system', 'durandal/app', 'durandal/binder', 'durandal/viewLocator', 'knockout', 'jquery', 'i18next'], function (router, system, app, binder, viewLocator, ko, $, i18n) {    
      app.configurePlugins({
          router: true
      });
  
      app.start().then(function () {
          // Setup of i18n
          i18n.init({
              detectFromHeaders: false,
              fallbackLng: 'en',
              preload: ['nb', 'en'],
              supportedLngs: ['nb', 'en'],
              resGetPath: 'locales/__lng__.json',
              useCookie: true,
          }, function () {
              binder.binding = function (obj, view) {
                  $(view).i18n();
              };
  
              viewLocator.useConvention();
              app.setRoot('viewmodels/shell');
          });
      });
  });
  </code></pre>
  
  <p><strong>shell.js</strong></p>
  
  <pre><code>define(['plugins/router', 'durandal/app', 'i18next'], function (router, app, i18n) {
      return {
          router: router,
          activate: function () {
              return router.map([
                  { route: '', title: i18n.t('pageTitle'), moduleId: 'viewmodels/ViewModel', nav: true }
              ]).buildNavigationModel().mapUnknownRoutes('viewmodels/ViewModel', 'unknown').activate({
                  pushState: false,
                  hashChange: true
              });
          }
      };
  });
  </code></pre>
  
  <p><strong>test.js</strong> (own require.js config)</p>
  
  <pre><code>var tests = [];
  
  for (var file in window.__karma__.files) {
      if (window.__karma__.files.hasOwnProperty(file)) {
          if (/.*\.spec\.js$/.test(file)) {
              tests.push(file);
          }
      }
  }
  
  //Workaround for the timestamp issue
  for (var file in window.__karma__.files) {
      window.__karma__.files[file.replace(/^\//, '')] = window.__karma__.files[file];
  }
  
  require.config({
      baseUrl: 'base',
      paths: {
          'models': 'app/models',
          'viewModels': 'app/viewmodels',
          'specs': 'tests/specs/',
          'text': 'lib/require/text',
          'durandal': 'lib/durandal/js',
          'plugins': 'lib/durandal/js/plugins',
          'transitions': 'lib/durandal/js/transitions',
          'knockout': 'lib/knockout/knockout-2.3.0',
          'jquery': 'lib/jquery/jquery-1.9.1',
          'i18next': 'lib/i18next/i18next.amd.withJQuery-1.7.1.min',
      },
  
      // ask Require.js to load these files (all our tests)
      deps: tests,
  
      // start test run, once Require.js is done
      callback: window.__karma__.start
  });
  </code></pre>
  
  <p><strong>karma.conf.js</strong></p>
  
  <pre><code>// Karma configuration
  
  module.exports = function (config) {
      config.set({
          // base path, that will be used to resolve files and exclude
          basePath: '',
  
  
          // frameworks to use
          frameworks: ['jasmine', 'requirejs'],
  
  
          // list of files / patterns to load in the browser
          files: [
              { pattern: 'lib/jquery/jquery-1.9.1.js', watched: false, included: true, served: true },
              { pattern: 'tests/jasmine/jasmine-jquery.js', watched: false, served: true, included: true },
  
              { pattern: 'tests/specs/**/*.js', included: false },
              { pattern: 'tests/sinon.js', included: false },
              { pattern: 'lib/**/*.js', included: false, served: true },
              { pattern: 'app/**/*.js', included: false, served: true },
  
              'tests/test.js',
  
              //Serve the fixtures
              { pattern: 'app/**/*.html', watched: true, served: true, included: false },
              { pattern: 'app/**/*.json', watched: true, served: true, included: false },
              { pattern: 'tests/**/*.json', watched: true, served: true, included: false }
          ],
  
          preprocessors: [
              { '**/*.html': '' }
          ],
          // list of files to exclude
          exclude: [
              'foundation/*.js',
              'require.js',
              'init.js',
              'jasmine/jasmine.js',
              'jasmine/jasmine-html.js',
              'node_modules/**/*.html'
          ],
  
  
          // test results reporter to use
          // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
          reporters: ['progress'],
  
  
          // web server port
          port: 9876,
  
  
          // enable / disable colors in the output (reporters and logs)
          colors: true,
  
  
          // level of logging
          // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
          logLevel: config.LOG_INFO,
  
  
          // enable / disable watching file and executing tests whenever any file changes
          autoWatch: true,
  
  
          // Start these browsers, currently available:
          // - Chrome
          // - ChromeCanary
          // - Firefox
          // - Opera
          // - Safari (only Mac)
          // - PhantomJS
          // - IE (only Windows)
          browsers: ['PhantomJS'],
          //browsers: ['Chrome', 'Firefox', 'IE'],
  
          // If browser does not capture in given timeout [ms], kill it
          captureTimeout: 60000,
  
  
          // Continuous Integration mode
          // if true, it capture browsers, run tests and exit
          singleRun: false
      });
  };
  </code></pre>
  
  <p><strong>ViewModel (i18next):</strong></p>
  
  <pre><code>define(["i18next"], function (i18n) {
      var pageTitle = i18n.t("pageTitle");
  
      return {
          pageTitle: pageTitle
      };
  });
  </code></pre>
  
  <p><strong>Spec (i18next)</strong></p>
  
  <pre><code>define(['viewModels/ViewModel'], function (ViewModel) {
      describe("Viewmodel test", function () {
          it("should be testable", function () {
              expect(true).toEqual(true);
          });
          it("should have title", function () {
              expect(ViewModel.pageTitle).not.toBeEmpty();
          });
      });
  });
  </code></pre>
  
  <p><strong>Test runner output</strong></p>
  
  <blockquote>
    <p>PhantomJS 1.9.2 (Mac OS X) ERROR
      ReferenceError: Can't find variable: initialized
      at /Users/xxx/dev/projectXYZ/lib/i18next/i18next.amd.withJQuery-1.7.1.min.js:5
    PhantomJS 1.9.2 (Mac OS X): Executed 0 of 0 ERROR (0.312 secs / 0 secs)</p>
  </blockquote>
  
  <p><strong>ViewModel (wo/i18next):</strong></p>
  
  <pre><code>define([], function () {
      var pageTitle = "This is the page title";
  
      return {
          pageTitle: pageTitle
      };
  });
  </code></pre>
  
  <p><strong>Spec (wo/i18next)</strong></p>
  
  <pre><code>define(['viewModels/ViewModel'], function (ViewModel) {
      describe("Viewmodel test", function () {
          it("should be testable", function () {
              expect(true).toEqual(true);
          });
          it("should have title", function () {
              expect(ViewModel.pageTitle).toEqual("This is the page title");
          });
      });
  });
  </code></pre>
  
  <p><strong>Test runner output (wo/i18next)</strong></p>
  
  <blockquote>
    <p>PhantomJS 1.9.2 (Mac OS X): Executed 2 of 2 SUCCESS (0.312 secs / 0.164 secs)</p>
  </blockquote>
  
  <p>I guess I have to somehow initialize i18next, but I dont know how.</p>
  
  <p>Any help would be much appreciated.</p>
  
  <p>Regards,</p>
  
  <p>Remi</p>
  
  <hr>
  
  <p><strong>UPDATE</strong></p>
  
  <p>This is what I ended up doing:</p>
  
  <p><strong>test.js:</strong></p>
  
  <pre><code>'i18next-original': 'lib/i18next/i18next.amd.withJQuery-1.7.1.min',
  'i18next': 'tests/i18n-test'
  </code></pre>
  
  <p><strong>i18n-test.js:</strong></p>
  
  <pre><code>define(['i18next-original'], function (i18noriginal) {
  'use strict';
  
  i18noriginal.init({
      lng: 'nb',
      detectFromHeaders: false,
      fallbackLng: 'en',
      preload: ['nb', 'en'],
      supportedLngs: ['nb', 'en'],
      resGetPath: 'base/locales/__lng__.json',
      useCookie: false,
      debug: false,
      getAsync: false
  });
  
  return i18noriginal;
  });
  </code></pre>
  
  <p><strong>karma.conf.js:</strong></p>
  
  <pre><code>{ pattern: 'tests/i18n-test.js', included: false, served: true },
  </code></pre>