بيكاسو: كيفية اختبار مكتبة مكونة

نشرت: 2022-03-11

تم إصدار إصدار جديد من نظام تصميم Toptal مؤخرًا والذي تطلب منا إجراء تغييرات على كل مكون تقريبًا في Picasso ، مكتبة المكونات الداخلية الخاصة بنا. واجه فريقنا تحديًا: كيف نضمن عدم حدوث الانحدارات؟

الجواب القصير ، وليس من المستغرب إلى حد ما ، الاختبارات. الكثير من الاختبارات.

لن نراجع الجوانب النظرية للاختبار ولن نناقش أنواعًا مختلفة من الاختبارات ، أو فائدتها ، أو نوضح سبب وجوب اختبار الكود الخاص بك في المقام الأول. لقد غطت مدونتنا وغيرها بالفعل هذه المواضيع. بدلاً من ذلك ، سنركز فقط على الجوانب العملية للاختبار.

تابع القراءة لتتعلم كيف يكتب المطورون في Toptal الاختبارات. مستودعنا عام ، لذلك نستخدم أمثلة من العالم الحقيقي. لا يوجد أي تجريد أو تبسيط.

هرم الاختبار

ليس لدينا هرم اختبار محدد ، في حد ذاته ، ولكن إذا فعلنا ذلك فسيبدو كالتالي:

اختبار الرسم التوضيحي للهرم

يوضح هرم اختبار Toptal الاختبارات التي نؤكد عليها.

اختبارات الوحدة

اختبارات الوحدة واضحة في الكتابة وسهلة التشغيل. إذا كان لديك القليل من الوقت لكتابة الاختبارات ، فيجب أن تكون خيارك الأول.

ومع ذلك ، فهي ليست مثالية. بغض النظر عن مكتبة الاختبار التي تختارها (مكتبة Jest and React Testing Library [RTL] في حالتنا) ، فلن تحتوي على DOM حقيقي ولن تسمح لك بالتحقق من الوظائف في متصفحات مختلفة ، ولكنها ستسمح لك بالتخلص من بعيدًا عن التعقيد واختبر اللبنات الأساسية لمكتبتك.

لا تضيف اختبارات الوحدة قيمة فقط عن طريق اختبار سلوك الكود ولكن أيضًا عن طريق التحقق من قابلية الاختبار الكلية للشفرة. إذا لم تتمكن من كتابة اختبارات الوحدة بسهولة ، فمن المحتمل أن يكون لديك كود خاطئ.

اختبارات الانحدار البصري

حتى إذا كانت لديك تغطية اختبار وحدة بنسبة 100٪ ، فهذا لا يعني أن المكونات تبدو جيدة عبر الأجهزة والمتصفحات.

من الصعب تحديد الانحدار البصري من خلال الاختبار اليدوي. على سبيل المثال ، إذا تم نقل ملصق الزر بمقدار 1 بكسل ، فهل سيلاحظ مهندس ضمان الجودة؟ لحسن الحظ ، هناك العديد من الحلول لمشكلة الرؤية المحدودة. يمكنك اختيار الحلول المتكاملة على مستوى المؤسسات مثل LambdaTest أو Mabl. يمكنك دمج المكونات الإضافية ، مثل Percy ، في اختباراتك الحالية ، بالإضافة إلى حلول DIY من أمثال Loki أو Storybook (وهو ما استخدمناه قبل Picasso). جميعها لها عيوب: بعضها مكلف للغاية بينما البعض الآخر لديه منحنى تعليمي حاد أو يتطلب الكثير من الصيانة.

هابو للإنقاذ! إنه منافس مباشر لـ Percy ، لكنه أرخص بكثير ، ويدعم المزيد من المتصفحات ، وأسهل في الاستخدام. نقطة بيع كبيرة أخرى؟ يدعم تكامل Cypress ، وهو أمر مهم لأننا أردنا الابتعاد عن استخدام Storybook للاختبار المرئي. وجدنا أنفسنا في مواقف كان علينا فيها إنشاء قصص فقط حتى نتمكن من ضمان تغطية الاختبار المرئي ، وليس لأننا كنا بحاجة إلى توثيق حالة الاستخدام هذه. أدى ذلك إلى تلويث مستنداتنا وجعل فهمها أكثر صعوبة. أردنا عزل الاختبار البصري عن التوثيق المرئي.

اختبارات التكامل

حتى إذا كان هناك مكونان يحتويان على اختبارات وحدة واختبارات بصرية ، فهذا لا يضمن أنهما سيعملان معًا. على سبيل المثال ، وجدنا خطأً حيث لا يفتح تلميح الأدوات عند استخدامه في عنصر قائمة منسدلة ولكنه يعمل جيدًا عند استخدامه بمفرده.

لضمان تكامل المكونات جيدًا ، استخدمنا ميزة اختبار المكونات التجريبية في Cypress. في البداية ، كنا غير راضين عن الأداء الضعيف ، لكننا تمكنا من تحسينه من خلال تهيئة حزمة الويب المخصصة. النتائج؟ تمكنا من استخدام واجهة برمجة تطبيقات Cypress الممتازة لكتابة اختبارات الأداء التي تضمن عمل مكوناتنا بشكل جيد معًا.

تطبيق هرم الاختبار

كيف يبدو كل هذا في الحياة الحقيقية؟ دعونا نختبر مكون الأكورديون!

قد تكون غريزتك الأولى هي فتح المحرر الخاص بك والبدء في كتابة التعليمات البرمجية. نصيحتي؟ اقض بعض الوقت في فهم جميع ميزات المكون واكتب حالات الاختبار التي تريد تغطيتها.

مكتبة مكون بيكاسو GIF تجريبي

ماذا تختبر؟

فيما يلي تفصيل للحالات التي يجب أن تغطيها اختباراتنا:

  • الدول - يمكن توسيع الأكورديونات وطيها ، ويمكن تكوين حالتها الافتراضية ، ويمكن تعطيل هذه الميزة
  • الأنماط - يمكن أن يكون للأكورديون اختلافات حدودية
  • المحتوى - يمكنهم التكامل مع الوحدات الأخرى في المكتبة
  • التخصيص - يمكن أن يتم تجاوز أنماط المكون ويمكن أن يكون له رموز توسيع مخصصة
  • عمليات الاسترجاعات - في كل مرة تتغير فيها الحالة ، يمكن استدعاء رد الاتصال

مكتبة مكوّن بيكاسو التجريبي GIF - مكون أكورديون

كيف تختبر؟

الآن بعد أن عرفنا ما يجب علينا اختباره ، دعنا نفكر في كيفية القيام بذلك. لدينا ثلاثة خيارات من هرم الاختبار الخاص بنا. نريد تحقيق أقصى تغطية بأقل قدر من التداخل بين أقسام الهرم. ما هي أفضل طريقة لاختبار كل حالة اختبار؟

  • الولايات - يمكن أن تساعدنا اختبارات الوحدة في تقييم ما إذا كانت الحالات تتغير وفقًا لذلك ، ولكننا نحتاج أيضًا إلى اختبارات بصرية للتأكد من تقديم المكون بشكل صحيح في كل حالة
  • الأنماط - يجب أن تكون الاختبارات المرئية كافية للكشف عن انحدارات المتغيرات المختلفة
  • المحتوى - يُعد الجمع بين الاختبارات المرئية واختبارات التكامل هو الخيار الأفضل ، حيث يمكن استخدام الأكورديون مع العديد من المكونات الأخرى
  • التخصيص - يمكننا استخدام اختبار وحدة للتحقق مما إذا تم تطبيق اسم الفصل بشكل صحيح ، لكننا نحتاج إلى اختبار مرئي للتأكد من أن المكون والأنماط المخصصة تعمل جنبًا إلى جنب
  • عمليات الاسترجاعات - اختبارات الوحدة مثالية لضمان استدعاء عمليات الاسترجاعات الصحيحة

هرم اختبار الأكورديون

اختبارات الوحدة

يمكن العثور على المجموعة الكاملة من اختبارات الوحدة هنا. لقد غطينا جميع تغييرات الحالة ، والتخصيص ، وعمليات الاسترجاعات:

 it('toggles', async () => { const handleChange = jest.fn() const { getByText, getByTestId } = renderAccordion({ onChange: handleChange, expandIcon: <span data-test /> }) fireEvent.click(getByTestId('accordion-summary')) await waitFor(() => expect(getByText(DETAILS_TEXT)).toBeVisible()) fireEvent.click(getByTestId('trigger')) await waitFor(() => expect(getByText(DETAILS_TEXT)).not.toBeVisible()) fireEvent.click(getByText(SUMMARY_TEXT)) await waitFor(() => expect(getByText(DETAILS_TEXT)).toBeVisible()) expect(handleChange).toHaveBeenCalledTimes(3) })

اختبارات الانحدار البصري

تقع الاختبارات المرئية في كتلة وصف السرو هذه. يمكن العثور على لقطات الشاشة في لوحة معلومات هابو.

يمكنك رؤية جميع حالات المكونات المختلفة والمتغيرات والتخصيصات التي تم تسجيلها. في كل مرة يتم فيها فتح العلاقات العامة ، يقارن CI لقطات الشاشة التي قام هابو بتخزينها بتلك التي تم التقاطها في فرعك:

 it('renders', () => { mount( <TestingPicasso> <TestAccordion /> </TestingPicasso> ) cy.get('body').happoScreenshot() }) it('renders disabled', () => { mount( <TestingPicasso> <TestAccordion disabled /> <TestAccordion expandIcon={<Check16 />} /> </TestingPicasso> ) cy.get('body').happoScreenshot() }) it('renders border variants', () => { mount( <TestingPicasso> <TestAccordion borders='none' /> <TestAccordion borders='middle' /> <TestAccordion borders='all' /> </TestingPicasso> ) cy.get('body').happoScreenshot() })

اختبارات التكامل

كتبنا اختبار "مسار سيئ" في قالب وصف Cypress الذي يؤكد أن الأكورديون لا يزال يعمل بشكل صحيح وأنه يمكن للمستخدمين التفاعل مع المكون المخصص. أضفنا أيضًا تأكيدات بصرية لمزيد من الثقة:

 describe('Accordion with custom summary', () => { it('closes and opens', () => { mount(<AccordionCustomSummary />) toggleAccordion() getAccordionContent().should('not.be.visible') cy.get('[data-testid=accordion-custom-summary]').happoScreenshot() toggleAccordion() getAccordionContent().should('be.visible') cy.get('[data-testid=accordion-custom-summary]').happoScreenshot() }) // … })

التكامل المستمر

يعتمد بيكاسو بالكامل تقريبًا على إجراءات GitHub لضمان الجودة. بالإضافة إلى ذلك ، أضفنا Git hooks لفحوصات جودة التعليمات البرمجية للملفات المرحلية. لقد انتقلنا مؤخرًا من Jenkins إلى GHA ، لذلك لا يزال إعدادنا في مرحلة MVP.

يتم تشغيل سير العمل عند كل تغيير في الفرع البعيد بترتيب تسلسلي ، مع كون اختبارات التكامل والاختبارات المرئية هي المرحلة الأخيرة لأن تشغيلها هو الأكثر تكلفة (سواء فيما يتعلق بالأداء أو التكلفة المالية). ما لم تكتمل جميع الاختبارات بنجاح ، لا يمكن دمج طلب السحب.

هذه هي المراحل التي تمر بها إجراءات GitHub في كل مرة:

  1. تركيب التبعية
  2. التحكم في الإصدار - يتحقق من تطابق تنسيق الالتزامات وعنوان العلاقات العامة مع الالتزامات التقليدية
  3. Lint - تضمن ESlint كود الجودة الجيدة
  4. تجميع TypeScript - تحقق من عدم وجود أخطاء في النوع
  5. تجميع الحزم - إذا تعذر بناء الحزم ، فلن يتم إصدارها بنجاح ؛ تتوقع اختبارات Cypress لدينا أيضًا كودًا مجمعًا
  6. اختبارات الوحدة
  7. الاختبارات التكاملية والبصرية

يمكن العثور على سير العمل الكامل هنا. حاليًا ، يستغرق إكمال جميع المراحل أقل من 12 دقيقة.

قابلية الاختبار

مثل معظم مكتبات المكونات ، يحتوي Picasso على مكون جذر يجب أن يلتف جميع المكونات الأخرى ويمكن استخدامه لتعيين القواعد العامة. هذا يجعل من الصعب كتابة الاختبارات لسببين - التناقضات في نتائج الاختبار ، اعتمادًا على الدعائم المستخدمة في الغلاف ؛ ونماذج إضافية:

 import { render } from '@testing-library/react' describe('Form', () => { it('renders', () => { const { container } = render( <Picasso loadFavicon={false} environment='test'> <Form /> </Picasso> ) expect(container).toMatchSnapshot() }) })

لقد حللنا المشكلة الأولى من خلال إنشاء TestingPicasso الذي يشترط مسبقًا القواعد العالمية للاختبار. لكن من المزعج أن تضطر إلى إعلان ذلك في كل حالة اختبار. لهذا السبب أنشأنا وظيفة تصيير مخصصة تغلف المكون الذي تم تمريره في TestingPicasso وتعيد كل ما هو متاح من وظيفة تصيير RTL.

أصبحت اختباراتنا الآن أسهل في القراءة والكتابة مباشرة:

 import { render } from '@toptal/picasso/test-utils' describe('Form', () => { it('renders', () => { const { container } = render(<Form />) expect(container).toMatchSnapshot() }) })

خاتمة

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

مكتبات المكونات فريدة لأنها تخدم نوعين من الجماهير: المستخدمون النهائيون الذين يتفاعلون مع واجهة المستخدم والمطورين الذين يستخدمون الكود الخاص بك لإنشاء تطبيقاتهم الخاصة. إن استثمار الوقت في إطار اختبار قوي سيفيد الجميع. سوف يفيدك استثمار الوقت في تحسينات قابلية الاختبار بصفتك مشرفًا والمهندسين الذين يستخدمون (ويختبرون) مكتبتك.

لم نناقش أشياء مثل تغطية الكود والاختبارات الشاملة وسياسات الإصدار والإصدار. النصيحة القصيرة حول هذه الموضوعات هي: الإصدار كثيرًا ، وممارسة الإصدار الدلالي المناسب ، والشفافية في عملياتك ، وتحديد التوقعات للمهندسين الذين يعتمدون على مكتبتك. قد نعيد النظر في هذه المواضيع بمزيد من التفصيل في المنشورات اللاحقة.