我有一个使用<canvas>进行用户交互的React组件。我没有使用react-canvas或react-art或类似的东西;相反,我只是在componentDidMount和componentDidUpdate中绘制画布的2D上下文。
我将尽可能多的逻辑提取到两个独立的模块中:一个包含完全纯函数,并提供独立于React的核心操作,另一个提供附加到React组件的事件处理程序和生命周期混合。我可以很容易地测试第一个,第二个用一点模拟。
然而,我也想对主画布组件进行最小限度的测试,以确保它可以在给定一些合理的属性集的情况下无错误地呈现。这被证明是相当困难的,因为componentDidMount调用this.refs.canvas.getContext('2d'),它似乎不是在节点环境中定义的。因此,我想出了下面这个我不太喜欢的解决方案;它涉及到修补React.createElement和创建一个假的上下文对象:
// file: test/components/MyCanvasTest.jsx
import {describe, it} from 'mocha';
import {expect} from 'chai';
import React, {Component} from 'react';
import {declareMochaMock} from '../TestUtils';
import {
renderIntoDocument,
scryRenderedDOMComponentsWithTag,
} from 'react-addons-test-utils';
import MyCanvas from '../../src/components/MyCanvas';
describe('MyCanvas', () => {
const noop = () => {};
// These things are used in my component
// but I don't want them to actually do anything,
// so I mock them as no-ops.
const propsToMockAsNoop = [
'addEventListener',
'removeEventListener',
'setInterval',
'clearInterval',
];
propsToMockAsNoop.forEach(prop => declareMochaMock(window, prop, noop));
// This thing is used in my component
// and I need it to return a dummy value.
declareMochaMock(window, 'getComputedStyle', () => ({ width: "720px" }));
// This class replaces <canvas> elements.
const canvasMockClassName = 'mocked-canvas-component';
class CanvasMock extends Component {
render() {
return <div className={canvasMockClassName} />;
}
constructor() {
super();
this.width = 720;
this.height = 480;
}
getContext() {
// Here I have to include all the methods
// that my component calls on the canvas context.
return {
arc: noop,
beginPath: noop,
canvas: this,
clearRect: noop,
fill: noop,
fillStyle: '',
fillText: noop,
lineTo: noop,
measureText: () => 100,
moveTo: noop,
stroke: noop,
strokeStyle: '',
textAlign: 'left',
textBaseline: 'baseline',
};
}
}
const originalCreateElement = React.createElement;
declareMochaMock(React, 'createElement', (...args) => {
const newArgs = args[0] === 'canvas' ?
[CanvasMock, ...args.slice(1)] :
args;
return originalCreateElement.apply(React, newArgs);
});
it("should render a <canvas>", () => {
const element = <MyCanvas />;
const component = renderIntoDocument(element);
expect(scryRenderedDOMComponentsWithTag
(component, canvasMockClassName)).to.have.length(1);
});
});declareMochaMock函数的定义如下
// file: test/TestUtils.js
export function declareMochaMock(target, propertyName, newValue) {
let oldExisted;
let oldValue;
before(`set up mock for '${propertyName}'`, () => {
oldValue = target[propertyName];
oldExisted = Object.prototype.hasOwnProperty.call(
target, propertyName);
target[propertyName] = newValue;
});
after(`tear down mock for '${propertyName}'`, () => {
if (oldExisted) {
target[propertyName] = oldValue;
} else {
delete target[propertyName];
}
});
}我不能使用浅渲染器,因为我的组件通过ref访问画布,而浅渲染器还不支持ref。
有没有一种方法可以用我当前的单元测试框架(即不添加Jest或类似的东西)来处理这个测试,同时减少测试工具需要了解的数量?
(完整的画布组件可从here获得。)
发布于 2016-11-11 23:53:44
您应该能够使用:
https://www.npmjs.com/package/canvas#installation和JSDOM.(确保遵循适用于您的操作系统的安装过程)
示例测试:
import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import { jsdom } from 'jsdom';
import Chart from '../../src/index';
const createDOM = () => jsdom('<!doctype html><html><body><div></div></body></html>');
describe('<Chart />', () => {
let DOM;
const data = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(255,99,132,0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1,
hoverBackgroundColor: 'rgba(255,99,132,0.4)',
hoverBorderColor: 'rgba(255,99,132,1)',
data: [65, 59, 80, 81, 56, 55, 40]
}
]
};
const mountComponent = props => mount(
<Chart data={data} {...props} />,
{ attachTo: DOM.body.firstChild }
);
beforeEach(() => {
DOM = createDOM();
});
it('renders', () => {
const wrapper = mountComponent();
console.log(wrapper.html());
expect(true).to.be.true;
});
});它正在测试挂载到canvas元素上的Chart.js。我正在使用mocha和enzyme,但对于你正在使用的w/e测试套件,应该没有什么不同。
发布于 2020-04-30 01:28:42
我在使用AVA测试Lottie动画时遇到了这个问题。在gor181的解决方案的帮助下,这里是我如何使用2020年的最新版本的JSDOM 16.2.1使其工作的。
首先安装canvas和JSDOM npm i canvas jsdom --save-dev
以下是使用JSDOM进行测试的示例:
import { mount } from 'enzyme';
import { JSDOM } from 'jsdom';
const DOM = new JSDOM('<!doctype html><html><body><div></div></body></html>');
const mountComponent = props =>
mount(<AnimationComponent options={defaultOptions} />, {
attachTo: DOM.body
});
test('Animation', t => {
const wrapper = mountComponent();
console.log(wrapper.html());
t.is(wrapper.find('div').length, 2);
});您可以对DOM执行console.log操作,以查看要在mountComponent中附加哪些元素
console.log('DOM:', DOM);希望这能有所帮助!
https://stackoverflow.com/questions/34504766
复制相似问题