gpt4 book ai didi

reactjs - 使用 Karma、Mocha 和 React 16.5 诊断重复的规范报告

转载 作者:行者123 更新时间:2023-12-03 14:31:25 26 4
gpt4 key购买 nike

我有一个使用 React 作为 View 层的项目。为了测试它,我使用了 mocha、karma、karma-webpack 等。出于某种原因,在 React 16+ 中,karma 报告 afterEach 对于两个规范运行了 3 次。这种情况在 React 16+ 中发生,并且process.env.NODE_ENVdevelopment不是时发生 生产

在之前对此问题的探索中,规范失败的原因可能会级联并污染后续规范。为了帮助确定根本原因,这是我能找到的最简单的示例。

我试图追踪这种行为,但被 karma 和套接字内部及其周围的复杂性所困扰。考虑下面的示例,目前可在https://github.com/jneander/react-mocha获取.

Example.js

import React, {Component} from 'react'

export default class Example extends Component {
render() {
try {
return (
<div>{this.props.foo.bar}</div>
)
} catch(e) {
console.log(e) // for logging purposes
throw e
}
}
}

Example.spec.js

import {expect} from 'chai'
import React from 'react'
import ReactDOM from 'react-dom'

class ExampleWrapper extends React.Component {
constructor(props) {
super(props)

this.state = {
error: false
}
}

componentDidCatch(error) {
console.log('there was a problem')
this.setState({
error: true
})
}

render() {
console.log('rendering!')
if (this.state.error) {
console.log('- rendering the error version')
return <div>An error occurred during render</div>
}

console.log('- rendering the real version')
return (
<Example {...this.props} />
)
}
}

import Example from './Example'

describe('Example', () => {
let $container

beforeEach(() => {
console.log('beforeEach')
$container = document.createElement('div')
document.body.appendChild($container)
})

afterEach(() => {
console.log('afterEach')
ReactDOM.unmountComponentAtNode($container)
$container.remove()
})

async function mount(props) {
return new Promise((resolve, reject) => {
const done = () => {
console.log('done rendering')
resolve()
}
ReactDOM.render(<ExampleWrapper {...props} />, $container, done)
})
}

it('fails this spec', async () => {
console.log('start test 1')
await mount({})
expect(true).to.be.true
})

it('also fails, but because of the first spec', async () => {
console.log('start test 2')
await mount({foo: {}})
expect(true).to.be.true
})
})

规范输出如下:

LOG LOG: 'beforeEach'
LOG LOG: 'start test 1'
LOG LOG: 'rendering!'
LOG LOG: '- rendering the real version'

Example
✗ fails this spec
Error: Uncaught TypeError: Cannot read property 'bar' of undefined (src/Example.spec.js:35380)
at Object.invokeGuardedCallbackDev (src/Example.spec.js:16547:16)
at invokeGuardedCallback (src/Example.spec.js:16600:31)
at replayUnitOfWork (src/Example.spec.js:31930:5)
at renderRoot (src/Example.spec.js:32733:11)
at performWorkOnRoot (src/Example.spec.js:33572:7)
at performWork (src/Example.spec.js:33480:7)
at performSyncWork (src/Example.spec.js:33452:3)
at requestWork (src/Example.spec.js:33340:5)
at scheduleWork (src/Example.spec.js:33134:5)

ERROR LOG: 'The above error occurred in the <Example> component:
in Example (created by ExampleWrapper)
in ExampleWrapper

React will try to recreate this component tree from scratch using the error boundary you provided, ExampleWrapper.'
LOG LOG: 'there was a problem'
LOG LOG: 'done rendering'
LOG LOG: 'rendering!'
LOG LOG: '- rendering the error version'
LOG LOG: 'afterEach'
LOG LOG: 'beforeEach'
LOG LOG: 'start test 2'
LOG LOG: 'rendering!'
LOG LOG: '- rendering the real version'
LOG LOG: 'done rendering'
✓ also fails, but because of the first spec
✓ also fails, but because of the first spec
LOG LOG: 'afterEach'
LOG LOG: 'afterEach'

Chrome 69.0.3497 (Mac OS X 10.13.6): Executed 3 of 2 (1 FAILED) (0.014 secs / NaN secs)
TOTAL: 1 FAILED, 2 SUCCESS


1) fails this spec
Example
Error: Uncaught TypeError: Cannot read property 'bar' of undefined (src/Example.spec.js:35380)
at Object.invokeGuardedCallbackDev (src/Example.spec.js:16547:16)
at invokeGuardedCallback (src/Example.spec.js:16600:31)
at replayUnitOfWork (src/Example.spec.js:31930:5)
at renderRoot (src/Example.spec.js:32733:11)
at performWorkOnRoot (src/Example.spec.js:33572:7)
at performWork (src/Example.spec.js:33480:7)
at performSyncWork (src/Example.spec.js:33452:3)
at requestWork (src/Example.spec.js:33340:5)
at scheduleWork (src/Example.spec.js:33134:5)

是什么导致重复报告?

为什么在 React 16+ 中会发生这种情况,而在 React 15 中却不会?

我该如何解决这个问题?

最佳答案

可能存在竞争条件,因为 Promise 是通过 ref 函数解决的。已收到组件引用并不意味着初始渲染已完成。

the reference州,

If you need a reference to the root ReactComponent instance, the preferred solution is to attach a callback ref to the root element.

解决 Promise 的正确方法是使用 render 回调参数,

If the optional callback is provided, it will be executed after the component is rendered or updated.

应该是:

async function mount(props) {
return new Promise(resolve => {
ReactDOM.render(<Example {...props} />, $container, resolve)
})
}

该问题不会出现在第二次测试中,它会出现在第一次测试中,无论是否有第二次测试,并且不是 React 16.5 特有的。 它特定于 React 开发模式的工作原理

这是a simplified demo排除 Mocha 因素。预期错误是 console.warn 输出,但两个 Error: Cannot read property 'bar' of undefined 错误是 console.error,它们由自己使用react。 ReactDOM.render 运行组件 render 函数两次,并异步输出第一次测试的错误。

The same demo React 的生产版本显示一个 Error: Cannot read property 'bar' of undefined 同步错误,正如预期的那样。失败的渲染不会使 ReactDOM 渲染被拒绝,错误可能是 caught by error boundary component if needed :

class EB extends Component {
componentDidCatch(err) {
this.props.onCatch(err);
}

render() {
return this.props.children;
}
}

async function mount(props) {
return new Promise((resolve, reject) => {
ReactDOM.render(<EB onCatch={reject}><Example {...props} /></EB>, $container, resolve)
})
}

在单元测试中不依赖 React DOM 渲染器是一个很好的做法。 Enzyme 可以实现此目的,并允许单独同步测试组件,shallow wrapper特别是。

关于reactjs - 使用 Karma、Mocha 和 React 16.5 诊断重复的规范报告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52224807/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com