Jest가 모든 비동기 코드의 실행이 완료될 때까지 기다렸다가 어설션을 기대하는 방법
React 어플리케이션 통합 테스트(많은 컴포넌트를 함께 테스트하는 테스트)를 작성 중입니다.외부 서비스에 대한 콜은 모두 모의하고 싶습니다.
문제는 비동기 콜백이 실행되기 전에 테스트가 실행되는 것처럼 보여 테스트가 실패한다는 것입니다.
이 근처에 다른 방법이 있나요?콜 비동기 코드가 종료될 때까지 기다려도 될까요?
여기 내 요점을 설명하기 위한 몇 가지 나쁜 의사 코드가 있다.
Parent를 마운트할 때 Child 컴포넌트가 외부 서비스에서 반환된 콘텐츠를 렌더링하는지 테스트하고 싶습니다.이거는 모킹하겠습니다.
class Parent extends component {
render() {
<div>
<Child />
</div>;
}
}
class Child extends component {
DoStuff() {
aThingThatReturnsAPromise().then((result) => {
Store.Result = result;
});
}
render() {
DoStuff();
return <div>{Store.Result}</div>;
}
}
function aThingThatReturnsAPromise() {
return new Promise((resolve) => {
eternalService.doSomething(function callback(result) {
resolve(result);
});
});
}
테스트에서 이 작업을 수행하면 콜백이 실행되기 전에 실행되기 때문에 실패합니다.
jest.mock('eternalService', () => {
return jest.fn(() => {
return { doSomething: jest.fn((cb) => cb('fakeReturnValue');
});
});
describe('When rendering Parent', () => {
var parent;
beforeAll(() => {
parent = mount(<Parent />)
});
it('should display Child with response of the service', () => {
expect(parent.html()).toMatch('fakeReturnValue')
});
});
이거 어떻게 테스트해요?각도가 zonejs를 통해 해결되는 것으로 알고 있습니다. React에서도 이와 동등한 접근 방식이 있습니까?
Jest 27+용으로 갱신
농담 27+의 경우 프로세스를 사용할 수도 있습니다.nextTick:
await new Promise(process.nextTick);
(Adrian Godong 댓글에 감사)
원답
보류 중인 약속이 해결될 때까지 기다리는 스니펫을 다음에 나타냅니다.
const flushPromises = () => new Promise(setImmediate);
setImediate는 비표준 기능이며 표준이 될 것으로 예상되지 않습니다.그러나 테스트 환경에 충분한 경우, 좋은 솔루션이 될 수 있습니다.설명:
이 메서드는 브라우저가 이벤트 및 디스플레이 업데이트 등의 다른 조작을 완료한 직후에 장시간 실행 중인 조작을 해제하고 콜백 기능을 실행하기 위해 사용됩니다.
비동기/대기 기능을 사용하는 방법은 대략 다음과 같습니다.
it('is an example using flushPromises', async () => {
const wrapper = mount(<App/>);
await flushPromises();
wrapper.update(); // In my experience, Enzyme didn't always facilitate component updates based on state changes resulting from Promises -- hence this forced re-render
// make assertions
});
이 프로젝트에서 실제 사례를 원하시면 많이 사용하였습니다.
그flushPromises
어떤 시나리오에서 접근법이 깨진 것 같습니다.
간단하게 사용await Promise.resolve()
대신:
const component = mount(<App/>);
component.find('<button>').simulate('click');
// State changes
await Promise.resolve();
// Assert changes that occurred on the component
수출하는 것을 추천합니다.aThingThatReturnsAPromise()
모듈 또는 파일에서 테스트 케이스로 Import합니다.
부터aThingThatReturnsAPromise()
는 약속을 반환합니다.Jest의 비동기 테스트 기능을 사용할 수 있습니다.농담은 당신의 약속이 해결되기를 기다렸다가 당신의 주장을 할 수 있습니다.
describe('When rendering Parent', () => {
var parent;
beforeAll(() => {
parent = mount(<Parent />)
});
it('should display Child with response of the service', () => {
expect.assertions(1);
return aThingThatReturnsAPromise().then( () => {
expect(parent.html()).toMatch('fakeReturnValue');
});
});
});
자세한 내용은 여기를 참조하십시오.Jest Docs에서 Promise를 사용하여 Jest 테스트 사례를 처리하는 방법을 참조하십시오.
다른 응답에 기재되어 있는 몇 가지 기술 대신 npm 모듈플래시 프로미스를 사용할 수도 있습니다.2개의 테스트를 포함한 테스트 스위트의 예를 다음에 나타냅니다(참조 URL에도 나타나 있습니다).
const flushPromises = require('flush-promises');
describe('Async Promise Test Suite', () => {
it('A test involving flushPromises', async () => {
const wrapper = mount(<App/>);
await flushPromises();
// more code
});
it('Will not work correctly without flushing promises', async () => {
let a;
let b;
Promise.resolve().then(() => {
a = 1;
}).then(() => {
b = 2;
})
await flushPromises();
expect(a).toBe(1);
expect(b).toBe(2);
});
});
난 리액트가 원하는 걸 성취할 수 있는 건 아무것도 몰라
그러나 셋업이 완료된 후 All()의 @done을 호출하여 비슷한 코드로 이 작업을 수행할 수 있었습니다.코드 변경 내용은 다음과 같습니다.
let setupComplete;
jest.mock('eternalService', () => {
return jest.fn(() => {
return { doSomething: jest.fn((cb) => { cb('fakeReturnValue'); setupComplete(); }) };
});
.
.
.
beforeAll(done => {
parent = mount(<Parent />)
setupComplete = done;
});
});
사용한 적은 없지만, 잠재적인 관심사는 Jest의 runAllTicks와 runAllImediates입니다.
, 의사 는 리액트 라이프 사이클에 할 수 (「Resact Lifecycle를 사용합니다).componentWillMount()
componentDidMount()
것 같아요코드 되지 않은 롭게 할 수 .움이이됐됐!
describe('When rendering Parent', () => {
it('should display Child with the response of the service', function(done) => {
const parent = mount(<Parent />);
expect(parent.html()).toMatch('fakeReturnValue');
done();
});
});
기본적으로 "새로운 약속을 만들고 그것이 정착되기를 기다려라"로 요약되는 다른 대답은 좋지 않다.그들은 현재 진행 중인 약속들이 타결되기를 기다릴 뿐이지만, 만약 현재 진행 중인 약속들의 타결로 인해 새로운 보류 중인 약속들이 만들어지면?약속을 한 판만 커버할 수 있습니다.
await Promise.resolve();
은 '보다 낫다'를 입니다.render
await act
다음과 같이 테스트 라이브러리에서 가져옵니다.
let component;
await act(()=>{
component = render(<Whatever />);
});
후, 임의의 에서 useEffect
'스위치', '스위치'까지useEffect
하는(「(」에 응답)fetch
es을 더 많이 시킨다.useEffect
많은 하는 경우: " " "fetch
what - es 또는 기타 없이 준비가 .waitFor
,findBy*
등등.
언급URL : https://stackoverflow.com/questions/44741102/how-to-make-jest-wait-for-all-asynchronous-code-to-finish-execution-before-expec
'programing' 카테고리의 다른 글
SQL Server SELECT IN @variable? (0) | 2023.04.08 |
---|---|
react.default.createContext는 react-redux를 사용할 때 함수가 아닙니다. (0) | 2023.04.03 |
react.js와 Ajax의 차이점 (0) | 2023.04.03 |
AngularJS : jQuery로 변경 시 ng-model 바인딩이 업데이트되지 않음 (0) | 2023.04.03 |
키가 존재하는지 확인하고 Python을 사용하여 JSON 어레이를 반복합니다. (0) | 2023.04.03 |