【问题标题】:How to use mockDOMSource to test a stream of actions in Cycle.js?如何使用 mockDOMSource 测试 Cycle.js 中的动作流?
【发布时间】:2017-02-17 22:04:45
【问题描述】:

我意识到使用周期/时间可能有更好的方法,但我只是想了解基础知识。不知何故,我的 action$ 流似乎没有运行;我尝试使用 xs.periodic 构建多个模拟 dom。测试框架是 mocha。

import 'mocha';
import {expect} from 'chai';
import xs from 'xstream';
import Stream from 'xstream';
import {mockDOMSource, DOMSource} from '@cycle/dom';
import {HTTPSource} from '@cycle/http';
import XStreamAdapter from '@cycle/xstream-adapter';

export interface Props {
  displayAbs: boolean
}

export interface ISources {
  DOM: DOMSource;
  http: HTTPSource;
}

function testIntent(sources: ISources):Stream<Props> {
  return  xs.merge<Props>(
      sources.DOM
          .select('.absShow').events('click')
          .mapTo( { displayAbs: true } ),
      sources.DOM
          .select('.absHide').events('click')
          .mapTo( { displayAbs: false } )
  ).startWith( {displayAbs: false } );
}

describe( 'Test', ()=>{

  describe( 'intent()', ()=>{

    it('should change on click to shows and hides', () => {
      let listenerGotEnd = false;

      const mDOM$: Stream<DOMSource> = xs.periodic(1000).take(6).map(ii => {
        if (ii % 2 == 0) {
          return mockDOMSource(XStreamAdapter, {
            '.absShow': {'click': xs.of({target: {}})}
          })
        }
        else {
          return mockDOMSource(XStreamAdapter, {
            '.absHide': {'click': xs.of({target: {}})}
          })
        }
      });

      const action$ = mDOM$.map(mDOM => testIntent({
        DOM: mDOM,
        http: {} as HTTPSource,
      })).flatten();


      action$.addListener({
        next: (x) => {
          console.log("x is " + x.displayAbs);
        },
        error: (err) => {
          console.log("error is:" + err);
            throw err;
        },
        complete: () => { listenerGotEnd = true; }
      });
      expect(listenerGotEnd).to.equal(true);
    });

  });/* end of describe intent */

});

【问题讨论】:

    标签: javascript typescript mocha.js cyclejs


    【解决方案1】:

    测试没有运行的主要原因是因为它是异步的,所以在 mocha 中我们需要接受done 回调,然后在我们的测试完成时调用它。

    不使用@cycle/time,我会这样写这个测试:

    import 'mocha';
    import {expect} from 'chai';
    import xs, {Stream} from 'xstream';
    import {mockDOMSource, DOMSource} from '@cycle/dom';
    import XStreamAdapter from '@cycle/xstream-adapter';
    
    export interface Props {
      displayAbs: boolean
    }
    
    export interface ISources {
      DOM: DOMSource;
    }
    
    function testIntent(sources: ISources):Stream<Props> {
      return  xs.merge<Props>(
          sources.DOM
              .select('.absShow').events('click')
              .mapTo( { displayAbs: true } ),
          sources.DOM
              .select('.absHide').events('click')
              .mapTo( { displayAbs: false } )
      ).startWith( {displayAbs: false } );
    }
    
    describe('Test', () => {
      describe('intent()', () => {
        it('should change on click to shows and hides', (done) => {
          const show$ = xs.create();
          const hide$ = xs.create();
    
          const DOM = mockDOMSource(XStreamAdapter, {
            '.absShow': {
              'click': show$
            },
    
            '.absHide': {
              'click': hide$
            }
          });
    
          const intent$ = testIntent({DOM});
    
          const expectedValues = [
            {displayAbs: false},
            {displayAbs: true},
            {displayAbs: false},
          ]
    
          intent$.take(expectedValues.length).addListener({
            next: (x) => {
              expect(x).to.deep.equal(expectedValues.shift());
            },
            error: done,
            complete: done
          });
    
          show$.shamefullySendNext({});
          hide$.shamefullySendNext({});
        });
      });
    });
    

    这个测试在 11 毫秒内运行,这比使用 xs.periodic(1000).take(6) 快​​一点

    为了比较,下面是我用@cycle/time 编写它的方式:

    import {mockTimeSource} from '@cycle/time'
    
    describe('Test', () => {
      describe('intent()', () => {
        it('should change on click to shows and hides', (done) => {
          const Time = mockTimeSource();
    
          const show$     = Time.diagram('---x-----');
          const hide$     = Time.diagram('------x--');
          const expected$ = Time.diagram('f--t--f--', {f: false, t: true});
    
          const DOM = mockDOMSource({
            '.absShow': {
              'click': show$
            },
    
            '.absHide': {
              'click': hide$
            }
          });
    
          const intent$ = testIntent({DOM}).map(intent => intent.displayAbs);
    
          Time.assertEqual(intent$, expected$);
    
          Time.run(done);
        });
      });
    });
    

    第一个版本实际上是 @cycle/time 在后台为您所做的,这只是一种更好的编写方式。有更好的错误消息也很好。

    【讨论】:

      猜你喜欢
      • 2023-01-14
      • 1970-01-01
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      • 1970-01-01
      相关资源
      最近更新 更多