reactjs - 使用 Jest 进行 React、TypeScript 和 RxJS 测试不起作用
问题描述
我有一个简单的按钮组件React
TypeScript
,我使用fromEvent
方法将点击事件转换为它的Observable
包装器,在 RxJS 中定义RxJs
fromEvent(el:HTMLElement, eventType:string)
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
的方法,
- 我想用 Jest 测试这个方法——>如果我传递正确的
HTMLElement
字符串作为参数,它应该返回Observable
- 我想模拟点击事件,然后我想检查“返回的 observable 是否正常工作,并且该 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
如果我作为el
to的参数传递,这条线总是传递事件makeObservable
。
请帮助我正确测试这些场景。
解决方案
您可以尝试使用testing-library/react
而不是使用enzyme
shallow
,我已经data-testid="btn"
向您的组件添加了属性,然后从我
testing-library/react
用来呈现您的按钮的测试中获取您HTMLElement
的按钮,我使用了这个testid
属性。
它在测试和浏览器中按预期工作,请检查源代码。
按钮.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
按钮.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)
}
})
})
此测试在模拟点击和延迟的情况下按预期运行。
推荐阅读
- c# - 如何在 Web 服务 C# 的 ASMX 文件中隐藏一些声明的方法
- javascript - 找不到变量:geoplugin_countryCode - JavaScript
- android-studio - 如何在 android studio 上修复已弃用的协程异步、UI 和等待
- scala - 使用 Spark Scala 从字符串到数组 [Structype] 的模式转换
- reactjs - 在我创建 PWA 的 APK 后,我看到了浏览器的工具栏
- react-native - 如何修复 React Native 中的“找不到模块”.../template.config”错误
- javascript - 动态设置元标签 EJS
- javascript - header 和 location.href 不会加载另一个页面,而是使用根目录
- unity3d - Unity 项目无法使用 Mono 构建
- google-apps-script - 如何更改 new Date() 的格式并将结果与静态时间字符串组合