我正试着用Jest测试Flux和React应用程序。
我开始使用Scotch.io tutorial作为我的起点,并将创建一个完整的测试套件,以获得有关如何构建我的第一个真正的反应和通量应用程序的知识。
您可以find my code on github查看我的位置。
未运行的测试是FluxProduct-test.jsx
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
});
});
});
&#13;
它返回&#34; TypeError:无法读取属性&#39;来电&#39;未定义&#34;在第100行。
当我注销FluxActions时,它似乎没有被自动锁定,这就是mock未定义的原因,并且访问calls属性会引发错误。
fyi:Jest要求节点0.10,不能在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;
&#13;
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;
&#13;
这是我的package.json文件:
{
"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"
]
}
}
&#13;
我通过在app目录中运行npm test
来运行测试。
答案 0 :(得分:2)
我认为问题可能是您需要beforeEach
中的模拟,这可能会取消genMockFunction
为您做的自动jest
。我只是改变了我编写的一些测试,要求beforeEach
中的模块以相同的方式,并且它们也会破坏,就像函数不是模拟一样。
尝试在测试之外只需要依赖项。
var React = require('react/addons')
, TestUtils = React.addons.TestUtils
, FluxProduct = require('../FluxProduct')
, FluxCartActions = require('../../actions/FluxCartActions');
describe(...);
据推测,你这样做是为了“重置”模拟,以便测试没有副作用,但如果jest
还没有为你处理,那我会感到惊讶。
答案 1 :(得分:1)
与此同时,我通过手动模拟页面顶部的操作来解决问题:
jest.mock('../../actions/FluxCartActions');
在Jest中不是一个非常优雅的解决方案,但它有效。我认为你的意思是:
var addToCartBtn = getElementByTag(product, 'button');
而不是
var addToCartBtn = getElementByTag(product, 'select');
因此,您可以模拟按钮的单击并调用addToCart。