使用 RequireJs + Karma + Jasmine 测试事件

时间:2021-02-15 14:34:22

标签: javascript jasmine requirejs karma-jasmine karma-runner

我正在寻找一种测试事件的方法。就像主题标题一样,我的堆栈是 RequireJs + Karma + Jasmine。我不想使用 jQuery 或任何非必要的外部库。

我在导航栏中使用了 icon-utils 代码: icon -utils.js

define('icon-utils', [], function () {
  return {
    toggleIcon: function (icon, baseIcon, toggledIcon) {
      if (baseIcon === icon.getAttribute("data-icon")) {
        icon.setAttribute("data-icon", toggledIcon);
      } else {
        icon.setAttribute("data-icon", baseIcon);
      }
    }
  };
});

并对其进行测试:

define(['icon-utils'], function(iconUtils) {
  describe('test iconUtils', function () {
    let toggledIcon = 'toggledIcon';
    let baseIcon = 'unToggledIcon';

    it('should change icon to toggled', function() {
      let icon = document.createElement("i");
      icon.setAttribute("data-icon", baseIcon)

      iconUtils.toggleIcon(icon, baseIcon, toggledIcon);
      expect(icon.getAttribute("data-icon")).toEqual(toggledIcon)
    });

    it('should change icon to unToggled', function() {
      let icon = document.createElement("i");
      icon.setAttribute("data-icon", toggledIcon)

      iconUtils.toggleIcon(icon, baseIcon, toggledIcon);
      expect(icon.getAttribute("data-icon")).toEqual(baseIcon)
    });
  })
})

现在有我要测试的nabar.js

define('navbar', ['icon-utils'], function (iconUtils) {
  Array.from(document.getElementsByClassName("jb-navbar-menu-toggle")).forEach(
    (el) => {
      el.addEventListener("click", (e) => {
        console.log("clicked");
        const dropdownIcon = e.currentTarget
          .getElementsByClassName("icon")[0]
          .getElementsByClassName("material-icons")[0];

        document
          .getElementById(e.currentTarget.getAttribute("data-target"))
          .classList.toggle("is-active");

        iconUtils.toggleIcon(dropdownIcon, "more_vert", "close");
      });
    }
  );
});

是的,我需要测试所选 dom 元素的类是否在单击时发生变化:

define(['navbar'], function(navBar) {
  describe('test navBar', function () {
    
      it('should toggle is-active class on click ', function() {
      });
    })
})

我花了很多时间寻找好的解决方案,但我找不到任何有用的东西。我需要找到一种方法将事件侦听器从 navbar.js 附加到 dom 元素,并检查是否触发了事件以及是否切换了 is-active 类。

此外,由于测试纯 Js 的良好来源并不多,我将不胜感激每一条有助于我保持良好实践和编写质量测试的提示。

如果有帮助的话,还有我的 karma.conf.js

// Karma configuration
// Generated on Tue Feb 09 2021 08:09:01 GMT+0100 (Central European Standard Time)

module.exports = function (config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '../..',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine', 'requirejs'],


    // list of files / patterns to load in the browser
    files: [
      'tests/Ecommerce.Admin.Tests/test-main.js',
      {pattern: 'src/Ecommerce.Admin/wwwroot/js/**/*.js', included: false},
      {pattern: 'tests/Ecommerce.Admin.Tests/js/**/*.spec.js', included: false},
    ],


    // list of files / patterns to exclude
    exclude: [],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {},


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    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_DEBUG,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity,

    captureTimeout: 210000,
    browserDisconnectTolerance: 3,
    browserDisconnectTimeout : 210000,
    browserNoActivityTimeout : 210000,
  })
}

1 个答案:

答案 0 :(得分:0)

问题在于 navbar 模块在定义自身时附加了事件侦听器。

我在之前的工作中遇到过类似的问题。

有两种可能的解决方案。

第一次

第一个非常简单,它不需要更改 navbar 模块的代码,但需要在测试模块中进行一些修改。

  1. 定义一个测试模块,它没有被测试模块作为依赖项 - 这很关键
  2. 在测试用例中,将有效的 html 添加到文档中
  3. 需要经过测试的模块
  4. 触发事件
  5. 检查结果
  6. 拆除 - undef 测试模块并清除文档 html

这是伪代码:

define(function() {
  beforeEach(function(done) {
    document.body.innerHtml = 'put your html here'
    require(['navbar'], function() {
      done() // RequireJS is async so we need to give Jasmine information that the beforeEach section is finished
    })
  })

  beforeEach((done) => {
    document.body.innerHtml = ''
    require.undef('navbar')
  })

  describe('test navBar', function () {
      it('should toggle is-active class on click ', function() {
        // trigger click
        // do assertions
      });
    })
})

第二个

第二种方法需要更改模块的代码。您可以返回一个允许按需附加侦听器的函数,而不是在定义模块时附加事件侦听器。

模块代码:

define('navbar', ['icon-utils'], function (iconUtils) {
  return () => {
  Array.from(document.getElementsByClassName("jb-navbar-menu-toggle")).forEach(
    (el) => {
      el.addEventListener("click", (e) => {
        console.log("clicked");
        const dropdownIcon = e.currentTarget
          .getElementsByClassName("icon")[0]
          .getElementsByClassName("material-icons")[0];

        document
          .getElementById(e.currentTarget.getAttribute("data-target"))
          .classList.toggle("is-active");

        iconUtils.toggleIcon(dropdownIcon, "more_vert", "close");
      });
    }
  );
  });
});

测试会容易得多:

define(['navbar'], function(navbar) {
  beforeEach((done) => {
    document.body.innerHtml = ''
  })

  describe('test navBar', function () {
      it('should toggle is-active class on click ', function() {
        document.body.innerHtml = 'put your html here'
        navbar()
        // trigger click
        // do assertions
      });
    })
})