使用Jest进行React,TypeScript和RxJS测试不起作用

时间:2019-08-20 06:01:12

标签: reactjs typescript testing rxjs jestjs

我在React TypeScript中有一个简单的按钮组件,我使用fromEvent方法将点击事件转换为Observable的{​​{1}}包装器,它被定义为{ RxJS中的{1}}

RxJs

您会看到fromEvent(el:HTMLElement, eventType:string)方法,

  1. 我想用Jest测试此方法->如果我传递正确的type NullableObservarbel = Observable<any> | null type NUllabe = HTMLElement | null export const makeObservable = (el:NUllabe, eventType:string):NullableObservarbel => el ? fromEvent(el, eventType) : null; type Props = { interval?: number // timee interval in millisecond label?:string } const Button:SFC<Props> = ({label}:Props) => { const btn = useRef(null) useEffect(() => { if(btn.current !== null){ const observable = makeObservable(btn.current, 'click') } }, []) return <button ref={btn}>{label}</button> } 和字符串作为参数,它应该返回makeObservable
  2. 我想模拟点击事件,然后检查`返回的可观察对象是否正常工作,并且该可观察对象的订阅者正在触发。

但是此测试均未按预期运行。

这是测试第一个始终通过,即使他们没有通过,第二个总是失败。

HTMLElement

最大的问题是我无法从Observable获取import React from 'react' import { shallow, mount } from 'enzyme' import Button, {makeObservable} from './Button' import {Observable} from 'rxjs' describe('Observable', () => { it('should create observable', () => { const wrapper = shallow(<Button />) const el = wrapper.find('button') const observable = makeObservable(el, 'click') // here i have the issue expect(observable instanceof Observable).toBe(true) }) it('should create observable', () => { const wrapper = shallow(<Button />) const el = wrapper.find('button') const observable = makeObservable(el, 'click') let _six = 0; if(observable){ observable .pipe(map(e => 6)) .subscribe(s => { _six = s }) } el.simulate('click') expect(_six).toEqual(6) // fails always }) }) 类型,所以我只使用HTMLElement按钮并将结果作为元素传递,但是

wrapper如果我将find作为expect(observable instanceof Observable).toBe(true)null的参数传递,则此行始终是传递事件。

请帮助我正确测试这些情况。

1 个答案:

答案 0 :(得分:2)

您可以尝试使用testing-library/react而不是使用enzyme shallow,我已经向您的组件添加了data-testid="btn"属性,然后通过我使用的测试 testing-library/react渲染按钮,然后获得按钮的HTMLElement,我使用了testid属性。

它在测试和浏览器中按预期工作,请检查源代码。

Button.tsx

import React, { SFC, useRef, useEffect, useState, RefObject} from 'react'
import {fromEvent, Observable} from 'rxjs'
import {map, debounceTime} from 'rxjs/operators'

type NullableObservarbel = Observable<any> | null;
type NUllabe = HTMLButtonElement | null; // more precise type
export const makeObservable = (el:NUllabe, eventType:string):NullableObservarbel => el ? fromEvent(el, eventType) : null;

type Props = {
    interval?: number // timee interval in millisecond
    label?:string
}

export type Result = [RefObject<HTMLButtonElement>, number]

// decoupled it from Button function body because you can test this later.
export const useEls = ():Result => {
    const btn: RefObject<HTMLButtonElement> = useRef(null)
    const [count, updateCount] = useState<number>(0)
    useEffect(() => {
        const el = btn ? btn.current : null
        if(el){
            updateCount(1)
            let _count = count
            const observerble =  makeObservable(el, 'click');
            if(observerble){
                observerble.pipe(
                    map(e => _count++),
                    //debounceTime(400)
                ).subscribe(c => updateCount(c))
            }
        }
    }, [])
    return [btn, count]
} 

const Button:SFC<Props> = (props:Props) => {
    const [btn, count] = useEls()
    return <button data-testid="btn" ref={btn}>Hello {count}</button>
}


export default Button

Button.test.ts

import React from 'react'
import Button, {makeObservable} from './Button'
import {Observable} from 'rxjs'
import {map, debounceTime} from 'rxjs/operators'
import {render, fireEvent} from '@testing-library/react'

describe('Observable', () => {
    it('should create observable', () => {
        const {getByTestId} = render(<Button/>)
        const el = getByTestId('btn') as HTMLButtonElement
        const observable = makeObservable(el, 'click')
        expect(observable instanceof Observable).toBe(true)
    })

    it('should return false', () => {
        const observable = makeObservable(null, 'click')
        expect(observable instanceof Observable).toBe(false)
    })

    it('Should subscribe observable', (done) => {
        const {getByTestId} = render(<Button/>)
        const el = getByTestId('btn') as HTMLButtonElement
        const observerble =  makeObservable(el, 'click');
        if(observerble){
            let count = 1
            observerble
                .pipe(
                    map(e => count++),
                    debounceTime(400) // delay clicks if you want
                )
                .subscribe(s => {
                    expect(s).toEqual(6)// test just inside the subscription
                    done();
                })
            fireEvent.click(el)
            fireEvent.click(el)
            fireEvent.click(el)
            fireEvent.click(el)
            fireEvent.click(el)
            fireEvent.click(el)
        }
    })
})

该测试运行正常,带有模拟的点击和延迟。


React testing library