【问题标题】:Conditionally ignore individual tests with Karma / Jasmine有条件地忽略 Karma / Jasmine 的个别测试
【发布时间】:2015-11-19 19:29:57
【问题描述】:

我有一些测试在 PhantomJS 中失败,但在其他浏览器中没有。

我希望在我的监视任务中使用 PhantomJS 运行时忽略这些测试(因此新的浏览器窗口不会集中注意力并且性能会更快一些),但是在我的标准测试任务和我的 CI 管道中,我希望所有测试在 Chrome、Firefox 等中运行...

我考虑过像 foo.spec.dont-use-phantom.js 这样的文件命名约定,并排除了我的 Karma 配置中的那些,但这意味着我必须将失败的单个测试分离到它们自己的文件中,将它们与它们的逻辑分开describe 块和拥有更多具有奇怪命名约定的文件通常会很糟糕。

简而言之:

有没有一种方法可以扩展 Jasmine 和/或 Karma 并以某种方式注释单个测试以仅在某些配置下运行?

【问题讨论】:

    标签: jasmine karma-runner karma-jasmine


    【解决方案1】:

    Jasmine 支持pending() 函数。

    如果您在规范正文的任何​​位置调用pending(),无论期望如何,规范都会被标记为待处理。

    您可以直接在测试中调用pending(),或者在从测试中调用的其他函数中。

    function skipIfCondition() {
      pending();
    }
    
    function someSkipCheck() {
      return true;
    }
    
    describe("test", function() {
      it("call pending directly by condition", function() {
        if (someSkipCheck()) {
          pending();
        }
    
        expect(1).toBe(2);
      });
    
      it("call conditionally skip function", function() {
        skipIfCondition();
    
        expect(1).toBe(3);
      });
    
      it("is executed", function() {
        expect(1).toBe(1);
      });
    
    });
    

    这里的工作示例:http://plnkr.co/edit/JZtAKALK9wi5PdIkbw8r?p=preview

    我认为这是最纯粹的解决方案。在测试结果中,您可以看到已完成和已跳过的测试的计数。

    【讨论】:

    【解决方案2】:

    我看到的最简单的解决方案是覆盖全局函数 describeit 以使它们接受第三个可选参数,该参数必须是布尔值或返回布尔值的函数 - 以判断当前套件是否/spec 应该被执行。覆盖时,我们应该检查这第三个可选参数是否解析为true,如果是,则调用xdescribe/xit(或ddescribe/iit,取决于 Jasmine 版本),这是 Jasmine 的方法跳过套件/规范,而不是原始的describe/it。这个块必须在测试之前执行,但在 Jasmine 被包含到页面之后。在 Karma 中,只需将此代码移动到一个文件中,并将其包含在 karma.conf.js 中的测试文件之前。代码如下:

    (function (global) {
    
      // save references to original methods
      var _super = {
        describe: global.describe,
        it: global.it
      };
    
      // override, take third optional "disable"
      global.describe = function (name, fn, disable) {
        var disabled = disable;
        if (typeof disable === 'function') {
          disabled = disable();
        }
    
        // if should be disabled - call "xdescribe" (or "ddescribe")
        if (disable) {
          return global.xdescribe.apply(this, arguments);
        }
    
        // otherwise call original "describe"
        return _super.describe.apply(this, arguments);
      };
    
      // override, take third optional "disable"
      global.it = function (name, fn, disable) {
        var disabled = disable;
        if (typeof disable === 'function') {
          disabled = disable();
        }
    
        // if should be disabled - call "xit" (or "iit")
        if (disable) {
          return global.xit.apply(this, arguments);
        }
    
        // otherwise call original "it"
        return _super.it.apply(this, arguments);
      };
    
    }(window));
    

    及用法示例:

    describe('foo', function () {
    
      it('should foo 1 ', function () {
        expect(true).toBe(true);
      });
    
      it('should foo 2', function () {
        expect(true).toBe(true);
      }); 
    
    }, true); // disable suite
    
    describe('bar', function () {
    
      it('should bar 1 ', function () {
        expect(true).toBe(true);
      });
    
      it('should bar 2', function () {
        expect(true).toBe(true);
      }, function () {
        return true; // disable spec
      });
    
    }); 
    

    See a working example here

    我还偶然发现了this issue,它的想法是为describeit 添加一个链方法.when(),它的作用与我上面描述的几乎相同。它可能看起来更好,但实现起来有点困难。

    describe('foo', function () {
    
      it('bar', function () {
        // ...
      }).when(anything);      
    
    }).when(something);
    

    如果您真的对第二种方法感兴趣,我很乐意多尝试一下并尝试实现链.when()

    更新:

    Jasmine 使用第三个参数作为超时选项 (see docs),所以我的代码示例正在替换此功能,这是不行的。我更喜欢 @milanlempera 和 @MarcoCI 的答案,我的似乎有点老套而且不直观。我会尽快更新我的解决方案,以免破坏与 Jasmine 默认功能的兼容性。

    【讨论】:

    • 太棒了。我用它来禁止 fdescribe 并适合构建环境。只需覆盖 fdescribe 和 fit 并抛出异常。
    【解决方案3】:

    我可以分享我的经验。

    在我们的环境中,我们有几个测试在不同的浏览器和不同的技术上运行。 为了在所有平台和浏览器上始终运行相同的套件,我们在 karma (helper.js) 中加载了一个帮助文件,其中全局加载了一些特征检测功能。

    function isFullScreenSupported(){
      // run some feature detection code here
    }
    

    您也可以为此使用Modernizr

    在我们的测试中,我们将东西包装在 if/else 块中,如下所示:

    it('should work with fullscreen', function(){
      if(isFullScreenSupported()){
        // run the test
      }
      // don't do anything otherwise
    });
    

    或用于异步测试

    it('should work with fullscreen', function(done){
      if(isFullScreenSupported()){
        // run the test
        ...
        done();
      } else {
        done();
      }
    });
    

    虽然它有点冗长,但它会为你所面临的场景节省时间。

    在某些情况下,您可以使用用户代理嗅探来检测特定的浏览器类型或版本 - 我知道这是不好的做法,但有时实际上没有其他方法。

    【讨论】:

      【解决方案4】:

      试试这个。我在我的项目中使用这个解决方案。

      it('should do something', function () {
          if (!/PhantomJS/.test(window.navigator.userAgent)) {
              expect(true).to.be.true;
          }
      });
      

      这不会在 PhantomJS 中运行此特定测试,但会在其他浏览器中运行。

      【讨论】:

        【解决方案5】:

        只需将要禁用的测试从 it(...) 重命名为 xit(...)

        function xit: A 暂时禁用它。该规范将报告为 待处理,不会被执行。

        【讨论】:

        • 感谢您的回复,但这实际上并不能解决问题中的问题。当我问这个问题时,我正在寻找一种有条件地跳过测试的方法。 xit 无条件跳过测试。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-13
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        • 1970-01-01
        • 2016-10-06
        • 1970-01-01
        相关资源
        最近更新 更多