【问题标题】:Unable to stream events within a mocked DOM source in CycleJs test无法在 CycleJs 测试中的模拟 DOM 源中流式传输事件
【发布时间】:2018-12-11 12:06:26
【问题描述】:

给定一个用 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

【问题讨论】:

标签: javascript cyclejs xstream-js


【解决方案1】:

我想我发现了问题所在。

问题是,使用模拟的 DOM 驱动程序,您需要为与 DOM.select('...').events 中使用的选择器完全相同的选择器创建事件。

在您的情况下,您选择了.string,但您在.string[data-pitch=..] 上模拟了一个事件,这将在应用程序端不匹配。

请记住,测试方面不涉及真正的 DOM。 在您的情况下,当您伪造点击选择器.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
    }
});

【讨论】:

  • 知道了,但是在第一个值之后流仍然关闭并且事件从未触发。我觉得和隔离有关,我已经试过mockDOMSource({ '.string-selector': { '.string': { click: clicks } } });
  • 我还看到mockDOMSource 有一个isloateSource 方法,但没有找到如何实际实现它。
  • 哦哦,我明白了,我错过了你 isolate 来自组件的事实!这是你不想做的事情。隔离应该在组件的消费者端。组件本身不应该意识到任何隔离
  • 消费者可能想用不同的名字隔离,或者只隔离几个驱动程序......所以要解决你的问题,你应该从导出中删除isolate
  • 这就是问题所在。看来我在cyclejs方面还有很多东西要学
猜你喜欢
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
相关资源
最近更新 更多