اختبار رد فعل مكونات واجهة المستخدم

ماذا افعل الان


أقوم حاليًا بإجراء اختبار لتطبيق الكود. تنقطع هذه الاختبارات في كل مرة بعد إعادة البناء ، خاصة في مكونات واجهة المستخدم. نتيجةً لذلك ، أقضي وقتًا طويلاً في البحث في ملفات .test.js ، متابعًا الرقم السحري البالغ 80٪ لـ Test Coverage .


ماذا علي أن أفعل؟


عند كتابة أي نوع من الاختبارات ، بما في ذلك اختبار الوحدة ، يجب أن أقل تفكيرًا في الكود الذي أختبره ، والمزيد حول ما يفعله هذا الكود. هذا يعني كتابة الاختبارات التي تحاكي سلوك المستخدم. حتى في أدنى مستوى.


مثال


تخيل مكون الأكورديون yuy القياسية. عند الضغط عليه ، يتم فتحه أو إغلاقه. يتم تمرير المحتوى إلى المكون children .


صورة


وظائف مكون الاختبار لدينا هي كما يلي:


  • يتم نشر الأكورديون 3 الأولى ، كل ما تبقى مغلقة.
  • عند النقر فوق الأكورديون ، يتم publishAccordionAnalytics الوحدة النمطية publishAccordionAnalytics ، التي تتعقب التحليلات. نحن نستورد هذه الوحدة من حزمة @myProject/analyticsHelpers
  • إذا نقر المستخدم على الأكورديون المخفي في الجزء السفلي من التطبيق ، وبعد فتح محتوى الأكورديون ليس في مجال رؤية المستخدم ، يتم تشغيل الرسوم المتحركة وينتقل محتوى المكون إلى الجزء المرئي من الشاشة.

 ... import { publishAccordeonAnalytics } from '@myProject/analyticsHelpers'; class Accordion extends Component { positionReference: RefObjectType; constructor(props) { super(props); this.positionReference = React.createRef(); } scrollToRef = (ref) => { const wrapper = document.querySelector('.app'); return isInViewPort(ref, wrapper) ? null : setTimeout(() => { return ref.current && wrapper && wrapper.scrollTo(wrapper.scrollTop, wrapper.scrollTop + ref.current.offsetTop) }, 300); }; render() { const { headerName, children, index } = this.props; const { scrollToRef, positionReference } = this; const defaultOpenAccordions = index >= 3; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordionAnalytics(open, headerName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={headerName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); } } 

كيف سأكتب اختبار الآن:


 jest.mock('@myProject/analyticsHelpers'); describe('', () => { test(' ', () => { const jsx = ( <Accordion headerName=" "> <div>Test</div> </Accordion> ); const tree = renderer .create(jsx) .toJSON(); expect(tree).toMatchSnapshot(); }); test(' ', () => { const wrapper = mount( <Accordion headerName=" " index={1}> <div>Test</div> </Accordion> ); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); }); test(' scrollToRef ', () => { const wrapper = shallow( <Accordion headerName=" " index={7}> <div>Test</div> </Accordion>); const component = wrapper.instance(); component.scrollToRef = jest.fn(); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); expect(component.scrollToRef).toHaveBeenCalled(); }) }); 

أقوم باختبار بنية المكون باستخدام لقطات ، وكذلك استدعاءات الوظائف عند النقر.


هذا الأكورديون يفي بالكامل بالوظائف المتوقعة وتؤكد الاختبارات ذلك. ولكن الآن سوف أقوم بعملية إعادة البناء ، واستبدل React.Component functional component ، scrollToRef مكون scrollToRef في وظيفة منفصلة.


 function Accordion ({ marketName, children, index }) { const positionReference = React.createRef(); const defaultOpenAccordions = index >= config.defaultOpenAccordions; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordeonAnalytics(open, marketName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={marketName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); } 

سقطت اختباراتي ... فشل اختبار ' scrollToRef ' لأنه لم تعد وظيفة scrollToRef طريقة خاصة للمكون. سيحدث نفس الشيء مع اختبار ' ' ، لكنه استيراد من الوحدة النمطية ، لذا فقد أصبح الآن ناجحًا.


لكتابة اختبار جيد ، أحتاج إلى فهم كيفية استخدام المستخدم لمكوني. مستخدم:


  1. العثور على الأكورديون الذي يحتوي على المعلومات التي يحتاجها
  2. النقر على اسم الأكورديون لفتحه
  3. قرأت ifna
  4. الأكورديون مغلقة


أدركت أنه لا يهتم بما يطلق عليه المكون الخاص بي وما ينقر عليه وما إلى ذلك. باتباع هذا المبدأ ، يجب أن أكتب شيئًا مثل هذا:


 import '@testing-library/jest-dom/extend-expect'; import { render, fireEvent, screen } from '@testing-library/react'; jest.mock('@myProject/analyticsHelpers'); describe('', () => { test('  ', () => { const child = <div></div>; //  № 10   const { getByText } = render( <Accordion headerName="  10" index={9}> {child} </Accordion> ); //   fireEvent.click(getByText(/  10/i)); expect(publishAccordeonAnalytics).toHaveBeenCalled(); expect(screen.queryByText('')).toBeInTheDocument(); expect(screen.getByTestId('referenced-div')).toBeInTheDocument(); //   fireEvent.click(getByText(/  10/i)); expect(publishAccordeonAnalytics).toHaveBeenCalled(); }); }); 

الآن لقد استنسخت سلوك المستخدم. لقد وجدت الأكورديون العاشر ، نقرت عليه ، قرأت المحتوى ، أغلقته - هذا كل شيء!


هذا الاختبار أنظف كثيرًا ، ويمكن أن يصمد أمام إعادة البناء ويحاكي تفاعل المستخدم. وكان من الأسهل بالنسبة لي أن أكتبها.


باستخدام هذا النمط ، يمكننا تجنب استخدام instance() Enzyme الأصلي instance() ، state() ، find('ComponentName') والوظائف الأخرى التي تختبر تطبيق الكود.


للاختبار الجديد ، اعتدت


Source: https://habr.com/ru/post/ar485438/


All Articles