gpt4 book ai didi

javascript - 如何测试需要 jquery 的 ES6 类?

转载 作者:行者123 更新时间:2023-11-29 21:05:19 25 4
gpt4 key购买 nike

我有一个需要 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 即可运行测试。

当做 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,为什么会发生这种情况?

最佳答案

这里有两个主要问题。第一个当然是您需要解决导入问题,但这与测试无关。在进行测试之前,您需要解决这个问题,这可能与构建工具的配置和在 Node.js 中运行有关。你应该为此打开一个单独的问题,although this might be of help .可能您需要做的就是将导入替换为此 import * as jQuery from 'jquery';

另一个大问题是您在 Node 中运行它(使用触发 Mocha 的 npm test),而您的代码需要浏览器。 Sinon 的假服务器实现旨在用于浏览器环境,而您正在服务器环境中运行测试。这意味着 jQuery 和伪造的服务器设置都不起作用,因为 Node 没有 XHR object .

因此,尽管 Sinon XHR 设置看起来不错,但除非您愿意更改测试运行器以在浏览器环境中运行测试(Karma 非常适合从 CLI 执行此操作!),否则您需要处理此问题用另一种方式。我很少去伪造 XHR,而是在更高层次上消除依赖关系。 @CarlMarkham 的回答涉及到这一点,但他没有详细说明这将如何与您的代码一起工作。

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

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

诗乃主页有a good article by Morgan Roderick在第一个选项,以及几个links to other articles elsewhere on the net ,但没有说明如何执行第一个选项。当我有时间的时候我应该写一篇......但是这里是:

在实例级别使用依赖注入(inject)

侵入性最小的方法是只在您正在测试的实例上公开 ajax 方法。这意味着您不需要向模块本身注入(inject)任何东西,也不必考虑事后清理:

// 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);

我写了a more elaborate example of this technique on the Sinon issue跟踪器。

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

在模块级别使用依赖注入(inject)

只需修改您的 Weather 类,为您的依赖项导出一个 setter 接口(interface),以便它们可以被覆盖:

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 类。当然,您也可以反过来做:您可以导出实际 jQuery 对象并直接修改ajax 方法,而不是注入(inject)伪造的jQuery 对象。然后,您将删除上面示例代码中的所有注入(inject)代码,并将其修改为类似于

// 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

关于javascript - 如何测试需要 jquery 的 ES6 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44397639/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com