NodeJS 和客户端与 Yeoman 和 Mocha 的全面集成测试

2024-01-25

我与 Yeoman 一起运行了很棒的客户端测试。 Yeoman 编译我的 CoffeeScript,在服务器中打开测试页面,使用 PhantomJS 访问它,并将所有测试结果传递到命令行。这个过程非常hacky,测试结果通过alert()发送到 Phantom 进程的消息,该进程创建一个临时文件并用 JSON 格式的消息填充其中。 Yeoman(好吧,Grunt)循环临时文件,解析测试并将它们显示在命令行中。

我解释这个过程的原因是我想添加一些东西。我也进行了服务器端测试。他们使用 mocha 和 supertest 来检查 API 端点和 Redis 客户端,以确保数据库状态符合预期。但我想合并这两个测试套件!

我不想为服务器调用编写客户端模拟响应。我不想发送服务器模拟数据。在此过程中,我将更改服务器或客户端,并且测试不会失败。我想做一个真正的集成测试。因此,每当测试在客户端完成时,我都希望有一个钩子在服务器端运行相关测试(检查数据库状态、会话状态、移动到不同的测试页面)。

有什么解决办法吗?或者,我从哪里开始对 Yeoman / Grunt / grunt-mocha 进行黑客攻击才能实现这项工作?

我认为 grunt-mocha 中的 Phantom Handlers 是一个很好的起点:

// Handle methods passed from PhantomJS, including Mocha hooks.
  var phantomHandlers = {
    // Mocha hooks.
    suiteStart: function(name) {
      unfinished[name] = true;
      currentModule = name;
    },
    suiteDone: function(name, failed, passed, total) {
      delete unfinished[name];
    },
    testStart: function(name) {
      currentTest = (currentModule ? currentModule + ' - ' : '') + name;
      verbose.write(currentTest + '...');
    },
    testFail: function(name, result) {
        result.testName = currentTest;
        failedAssertions.push(result);
    },
    testDone: function(title, state) {
      // Log errors if necessary, otherwise success.
      if (state == 'failed') {
        // list assertions
        if (option('verbose')) {
          log.error();
          logFailedAssertions();
        } else {
          log.write('F'.red);
        }
      } else {
        verbose.ok().or.write('.');
      }
    },
    done: function(failed, passed, total, duration) {
      var nDuration = parseFloat(duration) || 0;
      status.failed += failed;
      status.passed += passed;
      status.total += total;
      status.duration += Math.round(nDuration*100)/100;
      // Print assertion errors here, if verbose mode is disabled.
      if (!option('verbose')) {
        if (failed > 0) {
          log.writeln();
          logFailedAssertions();
        } else {
          log.ok();
        }
      }
    },
    // Error handlers.
    done_fail: function(url) {
      verbose.write('Running PhantomJS...').or.write('...');
      log.error();
      grunt.warn('PhantomJS unable to load "' + url + '" URI.', 90);
    },
    done_timeout: function() {
      log.writeln();
      grunt.warn('PhantomJS timed out, possibly due to a missing Mocha run() call.', 90);
    },

    // console.log pass-through.
    // console: console.log.bind(console),
    // Debugging messages.
    debug: log.debug.bind(log, 'phantomjs')
  };

谢谢!对此将会有赏金。


我不知道Yeoman- 我还没有尝试过 - 但我已经完成了剩下的拼图。我相信你会弄清楚剩下的事情。

为什么要进行集成测试?

在您的问题中,您谈论的是当您同时使用模拟运行客户端测试和服务器端测试时的情况。我认为由于某种原因,您无法使用相同的模拟运行两个测试集。否则,如果您更改客户端上的模拟,您的服务器端测试将失败,因为它们会获取损坏的模拟数据。

您需要的是集成测试,因此当您在无头浏览器中运行一些客户端代码时,您的服务器端代码也会运行。此外,仅仅运行服务器端和客户端代码是不够的,您还希望能够在两侧都添加断言,不是吗?

Node 和 PhantomJS 的集成测试

我在网上找到的大多数集成测试示例都使用Selenium http://seleniumhq.org/ or 僵尸.js http://zombie.labnotes.org/。前者是一个基于 Java 的大型框架,用于驱动真正的浏览器,而后者是一个简单的包装器jsdom https://github.com/tmpvar/jsdom。我假设您对使用其中任何一个都犹豫不决,并且更喜欢PhantomJS http://phantomjs.org/。当然,棘手的部分是从 Node 应用程序中运行它。我明白了。

有两个节点模块来驱动 PhantomJS:

  1. phantom https://npmjs.org/package/phantom
  2. 节点幻象 https://npmjs.org/package/node-phantom

不幸的是,这两个项目似乎都被其作者放弃了,其他社区成员对它们进行了分叉并适应了他们的需求。这意味着这两个项目都被分叉了很多次,而且所有分叉都几乎没有运行。 API 几乎不存在。我的测试运行了幻叉之一 https://github.com/sebv/phantomjs-node(谢谢你,塞布·文森特 https://github.com/sebv)。这是一个简单的应用程序:

'use strict';
var express = require('express');

var app = express();

app.APP = {}; // we'll use it to check the state of the server in our tests

app.configure(function () {
    app.use(express.static(__dirname + '/public'));
});

app.get('/user/:name', function (req, res) {
    var data = app.APP.data = {
        name: req.params.name,
        secret: req.query.secret
    };
    res.send(data);
});

module.exports = app;

    app.listen(3000);
})();

它监听请求/user并返回路径参数name和查询参数secret。这是我调用服务器的页面:

window.APP = {};

(function () {
    'use strict';

    var name = 'Alex', secret ='Secret';
    var xhr = new XMLHttpRequest();
    xhr.open('get', '/user/' + name + '?secret=' + secret);
    xhr.onload = function (e) {
        APP.result = JSON.parse(xhr.responseText);
    };
    xhr.send();
})();

这是一个简单的测试:

describe('Simple user lookup', function () {
    'use strict';

    var browser, server;

    before(function (done) {
        // get our browser and server up and running
        phantom.create(function (ph) {
            ph.createPage(function (tab) {
                browser = tab;
                server = require('../app');
                server.listen(3000, function () {
                    done();
                });
            });
        });
    });

    it('should return data back', function (done) {
        browser.open('http://localhost:3000/app.html', function (status) {

            setTimeout(function () {
                browser.evaluate(function inBrowser() {
                    // this will be executed on a client-side
                    return window.APP.result;
                }, function fromBrowser(result) {
                    // server-side asserts
                    expect(server.APP.data.name).to.equal('Alex');
                    expect(server.APP.data.secret).to.equal('Secret');
                    // client-side asserts
                    expect(result.name).to.equal('Alex');
                    expect(result.secret).to.equal('Secret');
                    done();
                });
            }, 1000); // give time for xhr to run

        });
    });
});

正如你所看到的,我必须在超时时间内轮询服务器。那是因为所有的幻像绑定都是不完整的并且限制太多。正如您所看到的,我能够在一次测试中检查客户端状态和服务器状态。

运行你的测试Mocha http://visionmedia.github.com/mocha/: mocha -t 2s您可能需要增加默认超时设置才能运行更先进的测试。

所以,正如你所看到的,整个事情是可行的。 这是带有完整示例的存储库。 https://github.com/listochkin/node-phantom-test-example

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NodeJS 和客户端与 Yeoman 和 Mocha 的全面集成测试 的相关文章

  • 设置 JavaScript 对象的 length 属性

    假设我有一个 JavaScript 对象 function a var A this length function return A length this add function x A push x this remove func
  • Android 上的 setTimeOut() 相当于什么?

    我需要等效的代码setTimeOut call function milliseconds 对于安卓 setTimeOut call function milliseconds 您可能想查看定时任务 http developer andro
  • 如何获取数组中对象的属性名称?

    这是我的数组 var testeArray name Jovem1 esteira Macaco name Jovem esteira Doido horse Chimbinha 从上面 我想得到一个像这样的数组 var propertyN
  • 使用 Jasmine 监视 Backbone.js 路由调用

    在主干路由器上监视方法调用时遇到问题 以确保它在给定路由上调用正确的方法 测试摘录 describe Router gt beforeEach gt router new App Router Backbone history start
  • 仅返回 JavaScript 字符串中最后一个下划线之前的文本

    如果我有一个像这样的字符串 var str Arthropoda Arachnida Zodariidae Habronestes hunti 如何获取最后一个下划线之前的字符串的第一部分 在这种情况下我只想 Arthropoda Arac
  • 无法使用 Node.JS 将 null 值发送到 MySQL 数据库

    我正在尝试发送null使用 Node JS 到我的 MySQL 数据库 con query INSERT INTO Routes routeTrigger VALUES null title test function err result
  • 重置输入控件的边框颜色 (HTML/Javascript)

    有谁知道使用 javascript 修改输入控件后如何重置它的边框颜色 通过突出显示其中包含不正确或无效数据的字段等来进行验证非常有用 例如 改变边框 document getElementById myinput style border
  • 从mongoDB和Nodejs获取数据:toArray不是函数错误[重复]

    这个问题在这里已经有答案了 我有以下代码 var user User find limit 1 skip 10 toArray 但我收到错误消息toArray不是一个函数 但如果我执行以下操作 我将获得所有记录 User find func
  • 元素上的 jQuery touchSwipe 事件阻止滚动

    我有一些清单div元素垂直排序 使用jQuery TouchSwipe 插件 https github com mattbryson TouchSwipe Jquery Plugin添加了滑动事件来捕获左右滑动 想法是通过向左或向右滑动来从
  • 所有属性的 JavaScript getter

    长话短说 我现在的情况是想要一个 PHP 风格的 getter 但是是 JavaScript 的 我的 JavaScript 仅在 Firefox 中运行 因此 Mozilla 特定的 JS 对我来说没问题 我能找到的制作 JS gette
  • 与玻璃钢战斗

    我读过有关 FRP 的内容 非常兴奋 它看起来很棒 因此您可以编写更多高级代码 并且一切都更加可组合 等等 然后我尝试用数百个 sloc 从纯 js 到 Bacon 重写我自己的小游戏 我发现 我实际上不是编写高级纯逻辑代码 而是击败了 B
  • 更改导航栏悬停时 div 的背景图像

    我正在开发一个项目 我对 Javascript 很陌生 所以我想知道是否有 Jquery 代码或只是一个关于如何使背景图像在导航菜单悬停时更改的过程 例如将鼠标悬停在链接一上会将 div 的背景图像更改为图像 1 将鼠标悬停在链接二上会将
  • 如何使 Loopback 模型事件起作用?

    我尝试过一个例子http apidocs strongloop com loopback model http apidocs strongloop com loopback model MyModel on changed functio
  • 按位非运算符

    为什么要按位运算 0 打印 1 在二进制中 不是0应该是1 为什么 你实际上很接近 在二进制中 不是0应该是1 是的 当我们谈论一位时 这是绝对正确的 然而 一个int其值为0的实际上是32位全零 将所有 32 个 0 反转为 32 个 1
  • 如何从 dataurl 在服务器上创建图像文件

    我有一个 dataurl 格式的图像 例如 data image jpeg base64 9j 4AAQSkZJRgABAQAAAQABAAD 2wBDAAMCAgMCAgMDAwMEAwME iiigAooooAKKKKACiiigAoo
  • 错误:UNABLE_TO_VERIFY_LEAF_SIGNATURE Phonegap 安装

    我正在尝试在 Ubuntu 中安装 Phonegap NodeJS 安装成功 但是我无法安装 Phonegap 本身 这是终端的错误输出 test test VirtualBox sudo npm install g phonegap np
  • 使用 Java 进行 AES 加密并使用 Javascript 进行解密

    我正在制作一个需要基于 Java 的 AES 加密和基于 JavaScript 的解密的应用程序 我使用以下代码作为基本形式进行加密 public class AESencrp private static final String ALG
  • 是否可以阻止在每个 HTTP 请求中发送 cookie?

    我最近发现 这里 每个网络请求都会发送浏览器cookie吗 https stackoverflow com questions 1336126 does every web request send the browser cookies
  • JavaScript 不是 DOM 的一部分吗?

    为什么即使从 DOM 中删除用于创建脚本的代码 脚本仍然可以运行 我遇到了一种情况 我想阻止损坏的脚本运行 查看我的帖子 https stackoverflow com questions 2685581 is there a way to
  • 如何在 Mongo 聚合管道的 $unwind 阶段保留零长度值?

    我正在使用聚合管道编写 Mongo 查询 在聚合过程中 我需要 unwind领域之一 但是 我不想要 unwind排除该字段具有零长度数组的条目 因为我仍然需要它们进一步深入管道 我的领域叫做items它是一个对象数组 每个对象包含两个值

随机推荐

  • 如何扩展 LoginUrlAuthenticationEntryPoint 或如何实现 AuthenticationEntryPoint

    我正在尝试这样做 让 spring security 在登录页面的查询字符串中添加 return to url https stackoverflow com q 4696905 即 让spring告诉登录页面我来自哪里 我有一些 SSO
  • 在 Yii 的控制器中创建构造方法

    我刚刚开始学习Yii 我在那里创建了一个PostController控制器 在这个控制器中 我有一个使用要求Sessions 所以我创建了一个构造函数方法 其代码如下 public session public function const
  • open() 不适用于隐藏文件 python

    我想使用 python 在隐藏文件夹中创建并写入 txt 文件 我正在使用这段代码 file name hi txt temp path myfolder docs file name file open temp path w file
  • 在实践中,std::sort 和 std::stable_sort 之间的性能差距有多大?

    两者都应该以 O n log n 的速度运行 但一般来说排序比 stable sort 更快 实践中的性能差距有多大 你对此有一些经验吗 我想要对大量大小约为 20 字节的结构进行排序 对于我来说 结果的稳定性很好 但这不是必须的 目前底层
  • C++ 联合中“受保护”的意义是什么

    受保护的成员或函数有什么用途吗 您不能从联合继承 因此没有子项可以访问它 它是否提供了功能用途 或者只是因为移除它很麻烦而存在 protected in a union变得完全等价于private 但是这个津贴没有坏处 并且避免了额外的特殊
  • 循环播放特定 Gmail 标签的邮件(而非线程)

    我添加了具体的messages 而且不是全部thread 到标签to process通过以下步骤 Turn Conversation ModeGmail 设置中关闭 贴上标签to process到特定消息 当显示消息时 我可以确认只有特定的
  • 如何在Python中使用循环创建元组[重复]

    这个问题在这里已经有答案了 我想创建这个元组 a 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 我尝试过这个 a 1 1 1 for i in range 2 10 a a i
  • 访问 coo_matrix 中的元素

    这是一个非常简单的问题 对于像 coo matrix 这样的 SciPy 稀疏矩阵 如何访问单个元素 类比 Eigen 线性代数库 可以使用 coeffRef 访问元素 i j 如下所示 myMatrix coeffRef i j 来自 c
  • Web 应用程序中的 Spring 线程

    我正在为MMO浏览器游戏编写服务器 我需要创建几个线程 他们将一直运行 并有一些睡眠时间 使用这样的弹簧线是个好主意吗 Component Scope prototype public class PrintTask2 implements
  • Instagram 基本显示 API 分页

    无论如何 是否可以对使用 Instagram Basic Display API 获得的媒体结果使用分页 我已阅读以下文档 但他们没有任何使用分页的示例 https developers facebook com docs instagra
  • 将带有描述性注释的框添加到 ggplot2 中的 y 轴

    我正在尝试向我的 Y 轴添加另一个标签或描述 我附上了一张图片作为我想要完成的任务的参考 我找不到任何描述如何向轴添加其他元素的内容 它是 Y 轴旁边的 好 和 坏 框 我试图将其合并到我的 ggplot 中 谢谢 在此输入图像描述 htt
  • 使用 React Native 和 Hooks 时,Jest 测试期间状态不会更新

    我正在尝试测试组件中的功能 基本思想是设置某种状态 当按下按钮时 将使用设置的状态调用函数 该代码可以工作 但是当我尝试测试它时 我没有得到预期的结果 就好像在测试期间状态从未被设置 我正在使用 Jest 和 Enzyme 测试的 Reac
  • SQL Server 中 INNER 连接和笛卡尔连接的区别[重复]

    这个问题在这里已经有答案了 可能的重复 内连接和全连接的区别 https stackoverflow com questions 3022713 difference between inner join full join 这两者之间有什
  • Node js Express 应用程序中使用 setTimeout 获取请求的并发性

    控制台日志图片 https i stack imgur com TKhfa png const express require express const app express const port 4444 app get async
  • 提高 Python 模块导入速度

    之前已经问过如何加速Python模块导入的问题 加速 python 导入 加载器 https stackoverflow com questions 2010255 speeding up the python import loader
  • 内存不足异常selenium服务器2.0b3

    我们刚刚部署了selenium服务器2 0b3 从1 0 3升级 它 看起来有一些相当严重的内存泄漏 OutOfMemory 运行时间超过 30 分钟时抛出异常 是否有任何直接的解决方法来处理内存泄漏 2 0b3 硒服务器 我希望获得 2
  • gun db 中公共空间、用户空间和冻结空间的简单示例

    枪看起来很棒 既有用又好用 然而 我很难理解之间的区别public空间放置 auser空间放置和frozen空间放置 https gun eco docs Introduction data 我尝试的最简单的例子是 公共场所 let gun
  • 如何将X11事件传递给QDialog

    目前 我正在尝试将系统 X11 事件 在 Linux 上 传递给我创建的对象 为此 我从 QApplication 中将 eventFilter 安装到了我的对象上 这是有效的 因为它获取应用程序的所有事件 但是我还需要传递对象 X11 事
  • bash 中的数组运算符

    有没有办法测试数组是否包含指定元素 例如 array one two three if one in array then fi 一个 for 循环就可以解决这个问题 array one two three for i in array d
  • NodeJS 和客户端与 Yeoman 和 Mocha 的全面集成测试

    我与 Yeoman 一起运行了很棒的客户端测试 Yeoman 编译我的 CoffeeScript 在服务器中打开测试页面 使用 PhantomJS 访问它 并将所有测试结果传递到命令行 这个过程非常hacky 测试结果通过alert 发送到