reactjs - Jest ve Enzyme ile useEffect içindeki bir fonksiyon nasıl test edilir?


Bileşenlerimi jest ve enzyme kullanarak test ediyorum. Tüm sayfa yüklendiğinde bileşenimi yüklemek istiyorum, bu yüzden useEffect içinde load olayını kullanıyorum, işte kodum

const RatingsAndReviews = (props: RatingsAndReviewsProps) => {

const [pageLoaded, setPageLoaded] = useState<boolean>(false)

const handleLoad = () => {
    if (document.readyState === 'complete') {
      setTimeout(() => {
        setPageLoaded(true)
      }, 1500)
    }
}

React.useEffect(() => {
    window.addEventListener('load', handleLoad)
    return () => {
      window.removeEventListener('load', handleLoad)
    }
}, [])

return (...some code)
}

Bu handleLoad fonksiyonunu test etmek istiyorum ama bunu bileşenime nasıl geçireceğimi çözemedim çünkü bileşen zaten props bekliyor ve TypeScript olduğu için gerekli props dışında başka bir şey geçiremiyorum, işte test senaryom

it('Should run handleLoad function onMount', ()=>{
    jest.spyOn(React, 'useEffect').mockImplementation(f => f())
    const handleLoad = jest.fn();
    wrapper = mount(<RatingsAndReviews {...propObj} />)
    expect(handleLoad).toHaveBeenCalled();
})

Bu hatayı alıyorum expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

Cevap #1

Üçüncü taraf kütüphane fonksiyonunun taklidini yapmamaya çalışın, çünkü yanlış bir taklit uygulama onun işlevselliğini bozacaktır. Örneğin, useEffect(effect) react hook'u sadece effect fonksiyonunu çalıştırmaz. Düşünün,

React, tarayıcı boyamayı yaptıktan sonra useEffect çalıştırmayı erteler.

Bunu nasıl taklit edersiniz? Yanlış taklit beklenmedik davranışlara yol açacaktır. Testleriniz yanlış taklit uygulamasına dayanarak geçebilir, ancak kod aslında çalıştırıldığında başarısız olur. Bu yüzden üçüncü taraf kütüphaneyi taklit etmemeniz daha iyidir. Tabii ki, bu mutlak değildir. Üçüncü taraf kütüphanenin işlevleri basit ve kendi kendine yeterliyse onları taklit edebilirsiniz.

React Bileşeni için, yalnızca bileşenin davranışını ve işlevselliğini test eden, uygulanışı test etmeyen kara kutu testleri yapmalıyız. Bileşeni içindeki fonksiyon yerine bir birim olarak ele almalıyız.

pageLoaded durumu değiştiğinde ne işlendiğini test etmeliyiz.

Fonksiyon bileşeni içinde tanımlanan olay işleyicileri özeldir, dışarıdan (test kodundan) onlara erişemezsiniz. Yani bunları doğrudan çağırmanız mümkün değildir. Bunun yerine, kullanıcı olayıyla tetiklemelisiniz. Sizin durumunuz için load olayı.

Örn.

index.tsx:

import React from 'react';
import { useEffect, useState } from 'react';

export const RatingsAndReviews = (props) => {
  const [pageLoaded, setPageLoaded] = useState<boolean>(false);

  console.log('pageLoaded: ', pageLoaded);
  const handleLoad = () => {
    if (document.readyState === 'complete') {
      setTimeout(() => {
        setPageLoaded(true);
      }, 1500);
    }
  };

  useEffect(() => {
    window.addEventListener('load', handleLoad);
    return () => {
      window.removeEventListener('load', handleLoad);
    };
  }, []);

  return <div>{pageLoaded ? 'loaded' : 'not loaded'}</div>;
};

index.test.tsx:

import { mount } from 'enzyme';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { RatingsAndReviews } from '.';

describe('RatingsAndReviews', () => {
  it('Should run handleLoad function onMount', () => {
    jest.useFakeTimers();
    const wrapper = mount(<RatingsAndReviews />);
    window.dispatchEvent(new Event('load'));
    expect(wrapper.text()).toBe('not loaded');
    act(() => {
      jest.advanceTimersByTime(1500);
    });
    expect(wrapper.text()).toBe('loaded');
  });
});

Test sonucu:

 PASS  stackoverflow/71953030/index.test.tsx (11.883 s)
  RatingsAndReviews
    ✓ Should run handleLoad function onMount (47 ms)

  console.log
    pageLoaded:  false

      at RatingsAndReviews (stackoverflow/71953030/index.tsx:7:11)

  console.log
    pageLoaded:  true

      at RatingsAndReviews (stackoverflow/71953030/index.tsx:7:11)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |   93.33 |       75 |      80 |   92.86 |                   
 index.tsx |   93.33 |       75 |      80 |   92.86 | 19                
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        13.575 s, estimated 14 s

paket sürümleri:

"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"jest": "^26.6.3",