无法在 CycleJs 测试中的模拟 DOM 源中流式传输事件
Unable to stream events within a mocked DOM source in CycleJs test
给定一个使用 CycleJs 构建的独立组件(该组件工作正常):
import isolate from '@cycle/isolate';
import { div, ul, li, a } from '@cycle/dom';
function intent(domSource){
const changeString$ = domSource
.select('.string').events('click')
.map( ev => ev.target.dataset.position);
return { changeString$ };
}
function model(actions, props$){
const { changeString$ } = actions;
return props$.map( props => {
return changeString$
.startWith(props.initialString)
.map( activePosition => ({ activePosition, preset : props.preset }));
}).flatten().remember();
}
function view(state$){
return state$.map( state => (
div(
ul(
state.preset.map( (string, position) => (
li(
a({
attrs : {
href : '#',
'data-pitch' : string.pitch,
'data-frequency' : string.frequency,
'data-position' : position,
class : ['string', parseInt(state.activePosition, 10) === position ? 'active' : ''].join(' ')
}
},
string.name)
)
))
)
)
));
}
function stringSelector(sources){
const actions = intent(sources.DOM);
const state$ = model(actions, sources.props);
const vdom$ = view(state$);
return {
DOM: vdom$,
value: state$
};
}
export default isolate(stringSelector, '.string-selector');
我已经尝试使用@cycle/time
测试行为:
import test from 'tape';
import xs from 'xstream';
import { mockDOMSource } from '@cycle/dom';
import { mockTimeSource } from '@cycle/time';
import stringSelector from '../../../src/js/component/stringSelector/index.js';
test('string selector', t => {
t.plan(1);
const Time = mockTimeSource();
const e2Click$ = Time.diagram('-------x-------|');
const a2Click$ = Time.diagram('---x------x----|');
const expectedState$ = Time.diagram('0--1---0--1----|');
const DOM = mockDOMSource({
'.string[data-picth=e2]': {
click: e2Click$
},
'.string[data-picth=a2]': {
click: a2Click$
},
});
const selector = stringSelector({
DOM,
props: xs.of({
preset: {
strings: [{
name: 'E',
pitch: 'e2',
frequency: 82.41
}, {
name: 'A',
pitch: 'a2',
frequency: 110.0
}]
},
initialString: 0
})
});
const activePosition$ = selector.value.map( state => state.activePosition );
Time.assertEqual(activePosition$, expectedState$);
Time.run(t.end.bind(t));
});
但是activePosition$
流直接结束了。我不知道它是来自 DOM 被嘲笑的方式(事件似乎没有被触发)还是我构建 activePosition$
流的方式?
当 运行 我的测试时,我收到以下消息:
Expected
0--1---0--1----|
Got
(0|)
Failed because:
* Length of actual and expected differs
* Expected type next at time 0 but got complete
* Expected stream to complete at 60 but completed at 0
我想我发现了问题。
事实是,对于模拟的 DOM 驱动程序,您需要为完全相同的 select 或 DOM.select('...').events
中使用的事件创建事件。
在您的情况下,您 select .string
但您在 .string[data-pitch=..]
上模拟了一个事件,这将在应用端不匹配。
请记住,测试方面没有真正的 DOM。
在您的情况下,当您在 select 或 .string
上假点击时,无论您的组件呈现什么,它都只会生成一个事件。
我想你想在这里实现的是伪造事件中的数据。
你或许可以这样做:
const clicks = Time.diagram('---0---1----0---|').map(position => {
// this will create a fake DOM event that contains the properties you are reading
return {target: {dataset: {position: position }}}
})
const DOM = mockDOMSource({
'.string': {
click: clicks
}
});
给定一个使用 CycleJs 构建的独立组件(该组件工作正常):
import isolate from '@cycle/isolate';
import { div, ul, li, a } from '@cycle/dom';
function intent(domSource){
const changeString$ = domSource
.select('.string').events('click')
.map( ev => ev.target.dataset.position);
return { changeString$ };
}
function model(actions, props$){
const { changeString$ } = actions;
return props$.map( props => {
return changeString$
.startWith(props.initialString)
.map( activePosition => ({ activePosition, preset : props.preset }));
}).flatten().remember();
}
function view(state$){
return state$.map( state => (
div(
ul(
state.preset.map( (string, position) => (
li(
a({
attrs : {
href : '#',
'data-pitch' : string.pitch,
'data-frequency' : string.frequency,
'data-position' : position,
class : ['string', parseInt(state.activePosition, 10) === position ? 'active' : ''].join(' ')
}
},
string.name)
)
))
)
)
));
}
function stringSelector(sources){
const actions = intent(sources.DOM);
const state$ = model(actions, sources.props);
const vdom$ = view(state$);
return {
DOM: vdom$,
value: state$
};
}
export default isolate(stringSelector, '.string-selector');
我已经尝试使用@cycle/time
测试行为:
import test from 'tape';
import xs from 'xstream';
import { mockDOMSource } from '@cycle/dom';
import { mockTimeSource } from '@cycle/time';
import stringSelector from '../../../src/js/component/stringSelector/index.js';
test('string selector', t => {
t.plan(1);
const Time = mockTimeSource();
const e2Click$ = Time.diagram('-------x-------|');
const a2Click$ = Time.diagram('---x------x----|');
const expectedState$ = Time.diagram('0--1---0--1----|');
const DOM = mockDOMSource({
'.string[data-picth=e2]': {
click: e2Click$
},
'.string[data-picth=a2]': {
click: a2Click$
},
});
const selector = stringSelector({
DOM,
props: xs.of({
preset: {
strings: [{
name: 'E',
pitch: 'e2',
frequency: 82.41
}, {
name: 'A',
pitch: 'a2',
frequency: 110.0
}]
},
initialString: 0
})
});
const activePosition$ = selector.value.map( state => state.activePosition );
Time.assertEqual(activePosition$, expectedState$);
Time.run(t.end.bind(t));
});
但是activePosition$
流直接结束了。我不知道它是来自 DOM 被嘲笑的方式(事件似乎没有被触发)还是我构建 activePosition$
流的方式?
当 运行 我的测试时,我收到以下消息:
Expected
0--1---0--1----|
Got
(0|)
Failed because:
* Length of actual and expected differs
* Expected type next at time 0 but got complete
* Expected stream to complete at 60 but completed at 0
我想我发现了问题。
事实是,对于模拟的 DOM 驱动程序,您需要为完全相同的 select 或 DOM.select('...').events
中使用的事件创建事件。
在您的情况下,您 select .string
但您在 .string[data-pitch=..]
上模拟了一个事件,这将在应用端不匹配。
请记住,测试方面没有真正的 DOM。
在您的情况下,当您在 select 或 .string
上假点击时,无论您的组件呈现什么,它都只会生成一个事件。
我想你想在这里实现的是伪造事件中的数据。
你或许可以这样做:
const clicks = Time.diagram('---0---1----0---|').map(position => {
// this will create a fake DOM event that contains the properties you are reading
return {target: {dataset: {position: position }}}
})
const DOM = mockDOMSource({
'.string': {
click: clicks
}
});