如何测试需要jquery的ES6类?

2024-02-23

我有一个需要 jquery 的 ES6 模块。

import $ from 'jquery';

export class Weather {
    /**
     * Constructor for Weather class
     *
     * @param latitude
     * @param longitude
     */
    constructor(latitude, longitude) {
        this.latitude  = latitude;
        this.longitude = longitude;
    }

    /**
     * Fetches the weather using API
     */
    getWeather() {
        return $.ajax({
            url: 'http://localhost:8080/weather?lat=' + this.latitude + '&lon=' + this.longitude,
            method: "GET",
        }).promise();
    }
}

模块在我的中使用时工作正常main模块,但问题在于我正在为其编写的测试。

这是测试:

import {Weather} from '../js/weather';
import chai from 'chai';
import sinon from 'sinon';

chai.should();

describe('weatherbot', function() {
    beforeEach(function() {
        this.xhr = sinon.useFakeXMLHttpRequest();

        this.requests = [];
        this.xhr.onCreate = function(xhr) {
            this.requests.push(xhr);
        }.bind(this);
    });

    afterEach(function() {
        this.xhr.restore();
    });

    it('should return a resolved promise if call is successful', (done) => {
        let weather = new Weather(43.65967339999999, -79.72506369999999);

        let data = '{"coord":{"lon":-79.73,"lat":43.66},"weather":[{"id":521,"main":"Rain","description":"shower rain","icon":"09d"}],"base":"stations","main":{"temp":15.28,"pressure":1009,"humidity":82,"temp_min":13,"temp_max":17},"visibility":24140,"wind":{"speed":7.2,"deg":30},"clouds":{"all":90},"dt":1496770020,"sys":{"type":1,"id":3722,"message":0.0047,"country":"CA","sunrise":1496741873,"sunset":1496797083},"id":5907364,"name":"Brampton","cod":200}';

        weather.getWeather().then((data) => {
            expect(data.main.temp).to.equal(15.28);
            done();
        });

        this.requests[0].respond("GET", "/weather?lat=43.659673399999996&lon=-79.72506369999999", [
            200, {"Content-Type":"application/json"}, JSON.stringify(data)
        ]);
    });
});

这是我的package.json:

{
  "devDependencies": {
    "babel-core": "^6.24.1",
    "babel-loader": "^6.1.0",
    "babel-polyfill": "^6.3.14",
    "babel-preset-es2015": "^6.1.18",
    "chai": "^3.5.0",
    "copy-webpack-plugin": "^0.2.0",
    "css-loader": "^0.28.0",
    "extract-text-webpack-plugin": "^2.1.0",
    "file-loader": "^0.11.1",
    "mocha": "^3.4.1",
    "mocha-webpack": "^1.0.0-beta.1",
    "qunitjs": "^2.3.2",
    "sinon": "^2.2.0",
    "style-loader": "^0.16.1",
    "svg-inline-loader": "^0.7.1",
    "webpack": "*",
    "webpack-dev-server": "^1.12.1",
    "webpack-node-externals": "^1.6.0"
  },
  "scripts": {
    "build": "webpack",
    "watch": "webpack --watch --display-error-details",
    "start": "webpack-dev-server --hot --inline --port 8383",
    "test": "mocha --compilers js:babel-core/register ./test/*.js",
    "test:watch": "npm run test -- --watch"
  },
  "babel": {
    "presets": [
      "es2015"
    ]
  },
  "dependencies": {
    "bootstrap": "^3.3.7",
    "jquery": "^3.2.1",
    "webpack": "*"
  }
}

正如你所看到的,我只需要做npm test运行测试。

When do npm test,我收到此错误:

TypeError: _jquery2.default.ajax is not a function
      at Weather.getWeather (js/weather.js:19:18)
      at Context.<anonymous> (test/index.js:26:17)

但我正在导入jquery在模块中,为什么会发生这种情况?


two主要问题在这里。第一个当然是您需要解决导入问题,但这与测试无关。在进行测试之前,您需要解决这个问题,这可能与构建工具的配置与在 Node.js 中运行有关。您应该为此提出一个单独的问题,虽然这可能有帮助 https://stackoverflow.com/questions/34338411/how-to-import-jquery-using-es6-syntax。也许您需要做的就是用这个替换导入import * as jQuery from 'jquery';

另一个大问题是你正在运行它Node (using npm test触发摩卡)同时您的代码需要浏览器。 Sinon 的假服务器实现旨在在浏览器环境中使用,而您正在服务器环境中运行测试。这意味着 jQuery 和假服务器设置都不起作用,因为 Node 没有XHR对象 https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest.

因此,尽管 Sinon XHR 设置看起来不错,但除非您愿意更改测试运行器以在浏览器环境中运行测试(Karma https://karma-runner.github.io/1.0/index.html非常适合从 CLI 执行此操作!),您需要以其他方式处理此问题。我很少去伪造 XHR,而是在更高级别上消除依赖关系。 @CarlMarkham 的答案谈到了这一点,但他没有详细说明这将如何与您的代码一起使用。

在 Node 中运行代码时,基本上有两个选择:

  1. 拦截导入 JQuery 模块的调用,并将其替换为您自己的具有存根版本的对象ajax。这需要一个模块加载拦截器,例如rewire or proxyquire.
  2. 直接在模块中使用依赖注入。

诗农主页有摩根罗德里克的一篇好文章 http://sinonjs.org/how-to/link-seams-commonjs/关于第一个选项,以及几个链接到网络上其他地方的其他文章 http://sinonjs.org/how-to/,但没有解释如何执行第一个选项。当我有时间的时候我应该写一篇......但是这里是:

在实例级别使用依赖注入

侵入性最小的方法就是直接暴露ajax您正在测试的实例上的方法。这意味着您不需要向模块本身注入任何内容,并且您不必考虑事后的清理:

// weather.js
export class Weather {
    constructor(latitude, longitude) {
        this.ajax = $.ajax;
        this.latitude  = latitude;
        this.longitude = longitude;
    }

    getWeather() {
        return this.ajax({ ...

// weather.test.js

it('should return a resolved promise if call is successful', (done) => {
    const weather = new Weather(43.65, -79.725);
    const data = '{"coord":{"lon":-79.73, ... }' // fill in
    weather.ajax = createStub(data);

我已经写了关于Sinon问题的这种技术的更详细的例子 https://github.com/sinonjs/sinon/issues/831#issuecomment-198081263追踪器。

还有另一种方法,更具侵入性,但可以让您通过直接修改模块的依赖关系来保持类代码不变:

在模块级别使用依赖注入

只需修改您的 Weather 类即可为您的依赖项导出 setter 接口,以便可以覆盖它们:

export const __setDeps(jQuery) => $ = jQuery;

现在您可以将测试简化为如下所示:

import weather from '../js/weather';
const Weather = weather.Weather;

const fakeJquery = {};
weather.__setDeps(fakeQuery);

const createStub = data => () => { promise: Promise.resolve(data) };

it('should return a resolved promise if call is successful', (done) => {
    const weather = new Weather(43.65, -79.725);
    const data = '{"coord":{"lon":-79.73, ... }' // fill in
    fakeQuery.ajax = createStub(data);

    weather.getWeather().then((data) => {
        expect(data.main.temp).to.equal(15.28);
        done();
    });
}

这种方法的一个问题是您正在篡改模块的内部结构,因此您需要恢复 jQuery 对象,以防您需要在其他测试中使用 Wea​​ther 类。当然,您也可以执行相反的操作:您可以导出actualjQuery 对象并修改ajax直接方法。然后,您将删除上面示例代码中的所有注入代码,并将其修改为类似的内容

// weather.js
export const __getDependencies() => { jquery: $ };


// weather.test.js

it('should return a resolved promise if call is successful', (done) => {
    const weather = new Weather(43.65, -79.725);
    const data = '{"coord":{"lon":-79.73, ... }' // fill in
    
    __getDependencies().jquery.ajax = createStub(data);

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

如何测试需要jquery的ES6类? 的相关文章

随机推荐

  • 如何将数据读入Tensorflow?

    我正在尝试将数据从 CSV 文件读取到张量流 https www tensorflow org versions r0 7 how tos reading data index html filenames shuffling and ep
  • 如何禁用 VS Code“扩展开发主机”中的所有无关扩展而不覆盖我的正常用户配置?

    我正在尝试在 VSCode 扩展上进行调试 开发 为此 我需要在调试 扩展开发主机 中禁用所有 许多 其他扩展 然而 这样做 saves我的用户首选项 然后导致 我所有其他 VScode 实例 停止拥有任何扩展 如何在 扩展开发主机 中禁用
  • 发送简单的文本(不是电子邮件)到 SpamAssassin

    我想知道是否可以向 SpamAssassin 发送简单的文本 我想将评论放入文本文件中并调用 spamc 我相信您可以禁用任何引用标头的 SA 规则 但由于 消息 格式错误 它可能仍然会中断 即使没有 SA 评分也过于依赖标头 因此在不检查
  • Meteor 服务器 Websocket

    我正在寻找在 Meteor 服务器 而不是客户端 上创建一个 websocket 以连接到外部网站 我知道我要访问的 URL 以及期望的数据 但我不清楚如何准确地创建 websocket 本身 我所做的所有搜索都为我提供了客户端解决方案 但
  • HTML5 WebStorage 数据是如何物理存储的?

    在使用 HTML5 WebStorage 功能时 我知道某些浏览器 例如 Chrome 具有开发人员工具 使用户能够浏览其 WebStorage 的内容以进行调试和故障排除 我想知道是否可以查看文件系统中网络存储的内容 此内容是否存储在文件
  • 在 WPF ComboBox 中设置默认值

    我正在使用 ComboBox ItemsSource 属性绑定来显示从列表到组合框的项目 以下是代码
  • 如何获取发送到数据库的准备好的查询

    当使用像这样的数据库库时pyodbc http code google com p pyodbc 实施Python 数据库 API 规范 http www python org dev peps pep 0249 应用参数替换后如何获得完全
  • 从 do 块返回查询

    我想做的就是能够使用do块设置一些变量 然后返回一个查询STDOUT使用这些变量 DO DECLARE book name TEXT DECLARE book slug TEXT BEGIN book name Ise Monogatari
  • Ruby Gem 开发 - 如何使用 ActiveRecord?

    我目前正在尝试开发我的第一个红宝石宝石 但我已经陷入困境 我使用 bundle gem 命令创建基本结构并阅读了一些教程 但我找不到如何集成 ActiveRecord 我在哪里创建迁移 我是在 lib 文件夹中还是在根目录中创建 db mi
  • UIButtons 的 IBOutletCollection - 更改按钮的选定状态

    我在视图中遇到多个 UIButton 的问题 我希望单独选择按钮 一次选择多个按钮 例如 10 个按钮 选择按钮 1 4 5 9 在我的标头中 我有一个 IBOutletCollection 属性 property retain nonat
  • 如果MySQL数据库没有关闭会发生什么?

    如果MySQL数据库没有关闭会发生什么 我们如何知道它是否正确关闭 我确实有一个页面 页面上有 11 个表 所以我所做的是在脚本开始之前在页面顶部打开数据库 并在脚本 PHP 结束的地方关闭 结尾是 mysql close db 这足够公平
  • UIBarButtonItem 如何禁用辅助功能 (iOS)

    SO 我正在尝试禁用已添加到 UINavigationController 的 leftBarButtonItems 中的 UIBarButtonItem 的 VoiceOver 可访问性 虽然我可以为没有标题的按钮禁用它 但我似乎无法为有
  • 如何在 symfony2 的表单类中隐藏标签?

    我知道您可以在树枝中拆分表单并选择不渲染特定字段的标签 但我忍不住认为您必须能够从表单类中执行此操作 选项数组中的 label 键允许您将此值更改为您喜欢的任何值 但传递 false 或空字符串只会返回字段名称 请参阅下面的示例 其中 ro
  • USB 驱动程序 华硕 Nexus 7 Windows 7

    我已经尝试了该网站和其他许多网站上的所有建议 但均无济于事 甚至可以在 Windows 上为 Nexus 7 进行 Android 开发吗 我试过从sdk管理器下载的usb驱动 华硕的那个 我已尝试将 USB 模式更改为 PTP 但仍然收到
  • 当您使用 Javascript 单击或停止悬停时,如何使 CSS 悬停内容保持在原位?

    我有一个想要实现的身体系统功能 当用户将鼠标悬停在身体 部位上时 它会突出显示并显示该特定身体部位的信息 我已经按照我想要的方式编写了 CSS 代码 但是我对 JavaScript 一无所知当单击身体部位或鼠标离开悬停状态时 获取要粘贴的信
  • MIPS 左加载字 (LWL) 和右加载字 (LWR) 指令的作用是什么?

    最近我一直在研究 MIPS 指令集 当时我遇到了两个在其他指令集中没有见过的不寻常指令 我环顾四周 想找到一个关于指令到底做什么的合理解释 但我所能弄清楚的是 它们在某种程度上与未对齐的内存访问有关 例如 维基百科说 https en wi
  • 膨胀类 android.widget.listview 时出错

    我浏览了很多其他人的问题和解释 但没有什么对我有用 我的程序的第一个活动 ListActivity 在膨胀其 xml 文件时遇到问题 LogCat 输出为 08 01 08 36 17 800 E AndroidRuntime 1935 F
  • statsmodels 如何编码以字符串形式输入的 endog 变量?

    我是使用 statsmodels 进行统计分析的新手 我大多数时候都会得到预期的答案 但有些事情我不太明白 statsmodels 在以字符串形式输入时定义逻辑回归的 endog 依赖 变量的方式 可以定义如下所示的示例 Pandas 数据
  • 在 asp.net mvc 项目中添加列到创建的标识表?

    我在我的 MVC 5 项目中使用 Identity 2 0 当我第一次在数据库中运行该项目时 已创建所有用于身份验证和授权的默认表 在 AspNetUsers 表中 我需要创建名为 LoyoutId 的整数类型的附加列 我的问题是如何向创建
  • 如何测试需要jquery的ES6类?

    我有一个需要 jquery 的 ES6 模块 import from jquery export class Weather Constructor for Weather class param latitude param longit