开玩笑不会自动嘲笑常见的js模块 [英] Jest not auto mocking common js modules
问题描述
我试图用Jest测试Flux和React应用程序.
I am trying to wrap my head around testing Flux and React applications using Jest.
我开始使用 Scotch.io教程作为我的起点,并将创建一个完整的测试套件,以获取有关如何构建我的第一个实际的React和Flux应用程序的知识.
I started using Scotch.io tutorial as my starting point and will be creating a full test suite to gain knowledge in how to structure my first real react and flux app.
您可以在github上找到我的代码看看我在哪里.
jest.dontMock('../FluxProduct');
var React
, TestUtils
, FluxProduct
, FluxCartActions;
describe('FluxProduct', function() {
var SAMPLE = {
product: {
id: '1',
name: 'Name',
image: 'image.png',
description: 'this description',
variants: [
{
sku: '123',
type: 'First',
price: 1.99,
inventory: 1
},
{
sku: '456',
type: 'Second',
price: 2.99,
inventory: 3
},
{
sku: '789',
type: 'Third',
price: 3.99,
inventory: 2
}
]
},
};
function getElement(product, className)
{
return product.getDOMNode().getElementsByClassName(className)[0];
}
function getElementByTag(product, tagName)
{
return product.getDOMNode().getElementsByTagName(tagName)[0];
}
function selectIsActive(select, text)
{
for( var i = 0; i < select.options.length; i++)
{
if (select.options[i].textContent == text)
{
return true
}
}
return false;
}
beforeEach(function(){
React = require('react/addons')
, TestUtils = React.addons.TestUtils
, FluxProduct = require('../FluxProduct')
, FluxCartActions = require('../../actions/FluxCartActions');
});
it('should have the display all of the fields', function() {
var cartItems = [];
var selected = SAMPLE.product.variants[1];
var product = TestUtils.renderIntoDocument(
<FluxProduct selected={selected} product={SAMPLE.product} cartitems={cartItems} />
);
expect(getElement(product, 'name').textContent).toEqual(SAMPLE.product.name);
expect(getElement(product, 'description').textContent).toEqual(SAMPLE.product.description);
expect(getElement(product, 'price').textContent).toEqual('Price: $' + selected.price);
expect(selectIsActive(getElementByTag(product, 'select'), selected.type)).toEqual(true);
});
it('should allow to add another variant', function() {
var cartItems = [];
var selected = SAMPLE.product.variants[1];
var targetVariantIndex = 2;
var targetVariant = SAMPLE.product.variants[targetVariantIndex];
var product = TestUtils.renderIntoDocument(
<FluxProduct selected={selected} product={SAMPLE.product} cartitems={cartItems} />
);
var selectElement = getElementByTag(product, 'select');
var addToCartBtn = getElementByTag(product, 'select');
TestUtils.Simulate.change(selectElement, { target: { value: targetVariantIndex } });
expect(selectIsActive(selectElement, targetVariant.type)).toEqual(true);
TestUtils.Simulate.click(addToCartBtn);
expect(FluxCartActions.addToCart.mock.calls.length).toBe(1);
expect(FluxCartActions.addToCart.mock.calls[0][0]).toBe(targetVariant.sku);
expect(FluxCartActions.addToCart.mock.calls[0][0]).toBe({
name: targetVariant.name,
type: targetVariant.type,
price: targetVariant.price
});
});
});
它在第100行返回"TypeError:无法读取未定义的属性'calls'".
It comes back with "TypeError: Cannot read property 'calls' of undefined" on line 100.
当我注销FluxActions时,似乎并没有对其进行自动模拟,这就是未定义模拟并且访问calls属性引发错误的原因.
When I log out FluxActions it seems that it is not being automocked, which is the reason mock is undefined and accessing the calls property is throwing the error.
fyi:Jest需要Node 0.10,不能在0.12上运行
fyi: Jest requires Node 0.10, does not run on 0.12
有用的参考文件:
var React = require('react');
var FluxCartActions = require('../actions/FluxCartActions');
// Flux product view
var FluxProduct = React.createClass({
// Add item to cart via Actions
addToCart: function(event){
var sku = this.props.selected.sku;
var update = {
name: this.props.product.name,
type: this.props.selected.type,
price: this.props.selected.price
}
FluxCartActions.addToCart(sku, update);
FluxCartActions.updateCartVisible(true);
},
// Select product variation via Actions
selectVariant: function(event){
FluxCartActions.selectProduct(event.target.value);
},
// Render product View
render: function() {
var ats = (this.props.selected.sku in this.props.cartitems) ?
this.props.selected.inventory - this.props.cartitems[this.props.selected.sku].quantity :
this.props.selected.inventory;
return (
<div className="flux-product">
<img src={'assets/' + this.props.product.image}/>
<div className="flux-product-detail">
<h1 className="name">{this.props.product.name}</h1>
<p className="description">{this.props.product.description}</p>
<p className="price">Price: ${this.props.selected.price}</p>
<select onChange={this.selectVariant}>
{this.props.product.variants.map(function(variant, index){
return (
<option key={index} value={index}>{variant.type}</option>
)
})}
</select>
<button type="button" onClick={this.addToCart} disabled={ats > 0 ? '' : 'disabled'}>
{ats > 0 ? 'Add To Cart' : 'Sold Out'}
</button>
</div>
</div>
);
},
});
module.exports = FluxProduct;
var AppDispatcher = require('../dispatcher/AppDispatcher');
var FluxCartConstants = require('../constants/FluxCartConstants');
// Define action methods
var FluxCartActions = {
// Receive inital product data
receiveProduct: function(data) {
AppDispatcher.handleAction({
actionType: FluxCartConstants.RECEIVE_DATA,
data: data
})
},
// Set currently selected product variation
selectProduct: function(index) {
AppDispatcher.handleAction({
actionType: FluxCartConstants.SELECT_PRODUCT,
data: index
})
},
// Add item to cart
addToCart: function(sku, update) {
AppDispatcher.handleAction({
actionType: FluxCartConstants.CART_ADD,
sku: sku,
update: update
})
},
// Remove item from cart
removeFromCart: function(sku) {
AppDispatcher.handleAction({
actionType: FluxCartConstants.CART_REMOVE,
sku: sku
})
},
// Update cart visibility status
updateCartVisible: function(cartVisible) {
AppDispatcher.handleAction({
actionType: FluxCartConstants.CART_VISIBLE,
cartVisible: cartVisible
})
}
};
module.exports = FluxCartActions;
这是我的package.json文件:
Here is my package.json file:
{
"name": "flux-pricing",
"version": "0.0.1",
"description": "Pricing component with flux",
"main": "app/assets/javascripts/cart.js",
"dependencies": {
"flux": "^2.0.0",
"react": "^0.12.0",
"underscore": "^1.7.0"
},
"devDependencies": {
"browserify": "~>6.3.0",
"envify": "~3.0.0",
"jest-cli": "^0.4.0",
"react-tools": "^0.12.2",
"reactify": "^1.0",
"watchify": "~2.1.0"
},
"scripts": {
"start": "watchify -o app/assets/javascripts/app.js -v -d .",
"build": "browserify . | uglifyjs -cm > app/assets/javascripts/app.min.js",
"test": "jest"
},
"jest": {
"rootDir": "app/assets/javascripts",
"scriptPreprocessor": "<rootDir>/__tests__/preprocessor.js",
"testFileExtensions": [
"js",
"jsx"
],
"unmockedModulePathPatterns": ["react"],
"testPathIgnorePatterns": [
"preprocessor.js",
"node_modules"
]
},
"browserify": {
"transform": [
"reactify",
"envify"
]
}
}
我通过在应用目录中运行npm test
来运行测试.
I run tests by running npm test
in the app directory.
推荐答案
我认为问题可能是您需要beforeEach
中的模拟,这可能会取消执行jest
的auto- genMockFunction
为你做.我只是更改了一些编写的测试,以相同的方式要求使用beforeEach
的模块,并且它们也坏了,就好像这些函数不是模拟的一样.
I think the issue could be that you are requiring the mocks in beforeEach
, which could be un-doing the auto-genMockFunction
that jest
does for you. I just changed some tests I had written to require the modules in the beforeEach
the same way, and they broke as well, as if the functions weren't mocks.
尝试在测试之外只要求依赖项.
Try just requiring the dependencies once outside the tests.
var React = require('react/addons')
, TestUtils = React.addons.TestUtils
, FluxProduct = require('../FluxProduct')
, FluxCartActions = require('../../actions/FluxCartActions');
describe(...);
想必您正在执行此操作以重置"模拟,以便测试不会产生副作用,但是如果jest
尚未为您处理,我会感到惊讶.
Presumably, you are doing this to "reset" the mocks so that tests don't have side-effects, but I'd be surprised if jest
doesn't already handle that for you.
这篇关于开玩笑不会自动嘲笑常见的js模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!