如何使用mockDOMSource测试Cycle.js中的一系列动作?

时间:2017-02-17 22:04:45

标签: javascript typescript mocha cyclejs

我意识到使用周期/时间可能有更好的方法,但我只是想了解基础知识。不知怎的,我的动作$ stream似乎没有运行;我尝试使用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 */

});

1 个答案:

答案 0 :(得分:4)

测试未运行的主要原因是因为它是异步的,所以在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为你做的事情,这只是一个更好的写作方式。有更好的错误消息也很好。