Как изменить window.location в тестах кармы / мокко простого клиентского приложения javascript - PullRequest
0 голосов
/ 25 сентября 2019

У меня довольно простое клиентское приложение javascript, оно не использует никаких фреймворков, просто шаблон jquery и модуля.Он поддерживается простым экспресс-сервером, который просто включает клиентское приложение js в теги скрипта на каждой странице.

Вот соответствующие части приложения:

// public/js/lib/namespace.js
const App = {
  pages: {},
  state: {},
  routes: {}
};
// public/js/lib/routes.js
App.routes = (function(app) {
  const mod = {
    init: function(options) {
      options = options || {};
      this.bindRoutes();
    },
    bindRoutes: function() {
      app.state.router.add('login', () => app.pages.login.init());
    }
  };

  return mod;
})(App);
// public/js/lib/pages/login.js
App.pages.login = (function($, app) {
  const mod = {
    init: function(opts) {
      const options = opts || {};
      // tests should run the code that is here, but code it's never reached
      // ...
    }
  };

  return mod;
})(jQuery, App);   
// public/js/lib/app.js
App.main = (function($, window, app) {
  const l = window.location;
  app.state.location = `${l.pathname}${l.search}${l.hash}`;
  app.state.router = new Router({
    mode: 'history',
    page404: function (path) {}
  });

  const mod = {
    init: function(options) { // When this runs window.location is set to debug.html
      options = options || {};
      app.routes.init();
      app.state.router.addUriListener();
      app.state.router.navigateTo(app.state.location);
    }
  }

  return mod;   
})(jQuery, window, App);

Шаблон ejs-сервера Express:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' type="text/css" href='css/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>

    <script src="js/vendor/jquery/dist/jquery.min.js"></script>
    <script src="js/vendor/vanilla-router/dist/vanilla-router.js"></script>

    <script src="js/namespace.js"></script>
    <script src="js/lib/routes.js"></script>
    <script src="js/lib/pages/login.js"></script>
    <script src="js/lib/app.js"></script>
    <script type="text/javascript">
      $(function() { App.main.init(); });
    </script>
  </body>
</html>
// karma.conf.js
const vendorFileGlob = 'public/js/vendor/**/dist/*.min.js';
const testFileGlob = 'test/client/**/*.test.js';
const appFiles = [
  'public/js/lib/namespace.js',
  'public/js/lib/routes.js',
  'public/js/lib/pages/login.js',
  'public/js/lib/app.js',
]

module.exports = function setKarmaConfig(config) {
  config.set({
    basePath: '',
    frameworks: [ 'mocha', 'chai', 'sinon' ],
    files: [
      // 'test/client/util/globals.js', // doesn't make any difference to window.location
      vendorFileGlob,
      ...appFiles,
      testFileGlob
    ],
    exclude: [],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: [ 'Chrome', 'Firefox', 'Safari', 'Opera' ],
    singleRun: true,
    concurrency: Infinity
  });
};

Полная структура файла приложения:

.
├── index.js
├── karma.conf.js
├── lib
│   └── views
│       └── layout.ejs
├── package-lock.json
├── package.json
├── public
│   ├── css
│   │   └── style.css
│   ├── favicon.ico
│   └── js
│       ├── lib
│       │   ├── app.js
│       │   ├── namespace.js
│       │   ├── pages
│       │   │   └── login.js
│       │   └── routes.js
│       └── vendor
│           ├── jquery
│           └── vanilla-router
└── test
    └── client
        ├── app.test.js
        ├── lib
        │   └── pages
        │       └── login.test.js
        └── util
            └── globals.js

Тесты:

// test/client/util/globals.js
window = {
  location: {
    hash: "",
    pathname: "/login",
    search: ""
  }
}
// test/client/lib/app.test.js
describe('the environment', function() {
  it('works,hopefully', function() {
    expect(true).to.be.true;
  });

  it('should have a window object', function() {
    expect(typeof window === 'object').to.be.true;
  });
});

describe('the app', function() {
  it('exists', function() {
    expect(App).to.be.an('object');
  });
});

it('should have the correct app basic structure', function() {
  expect(Object.keys(App).length).to.be.equal(4);
  expect(App.pages).to.be.an('object');
  expect(App.main).to.be.an('object');
  expect(App.routes).to.be.an('object');
  expect(App.state).to.be.an('object');
});
// test/client/lib/pages/login.test.js
describe('#login', function() {
  it('should run login page module', function() {
    const loginSpy = sinon.spy(App.pages.login, 'init');
    App.main.init();
    expect(window.location.pathname).to.be.equal('/login');
    expect(loginSpy.calledOnce).to.be.true;
  });
});

Этот последний тестовый файл завершается с ошибкой:

expected '/context.html' to equal '/login'

Я запускаю тесты с помощью сценариев npm:

// scripts part of package.json
  "scripts": {
    "postinstall": "mkdir -p public/js/vendor; cp -r node_modules/{jquery,vanilla-router} public/js/vendor/",
    "start": "node index.js",
    "test": "karma start 2> /dev/null"
  },

Проблема в том, что код в public / js / lib / pages/login.js никогда не достигается во время теста, потому что он выполняется только тогда, когда маршрутизатор получает значение window.location, равное «/ login», но при выполнении тестов всегда устанавливается значение debug.html или context.html.

Я попытался добавить файл global.js в массив файлов опций кармы, который устанавливает окно в ложную версию, но это не имеет никакого эффекта.

Как настроить window.location в тестах, чтобыкод клиентских страниц javascript выполняется?Возможно, есть какой-то другой способ проверить этот код?

[Обновление 1: добавлен шаблон ejs для экспресс-сервера]

[Обновление 2: добавлен karma.conf.js]

[Обновление 3: добавлена ​​часть сценариев package.json]

[Обновление 4: добавлена ​​проверка существования объекта окна]

...