لقد كتبت منشئ تقرير مخصص لـ Jest ونشرته على
GitHub . يُدعى "منشئ البيانات الخاص بي" Jest-snapshots-book ، وهو يُنشئ كتاب HTML يحتوي على لقطات لمكونات تطبيق React.

ستناقش المقالة ما هو Jest ، اختبار اللقطة ، والذي يتطلب بشكل عام منشئ تقرير إضافي وكيفية كتابته. بشكل أساسي ، كل هذا ينطبق على اختبار مكونات التفاعل ، ولكن من الناحية النظرية يمكن تطبيقه عند العمل مع أي بيانات قابلة للتسلسل.
مكون رد فعل Paginator
على سبيل المثال ، في المقالة سوف نقوم باختبار مكون
paginator (
Paginator ). إنه جزء من مشروعنا لإنشاء تطبيقات بدون خادم في AWS (
GitHub ). تتمثل مهمة هذا المكون في عرض الأزرار للتنقل عبر صفحات الجدول أو أي شيء آخر.
هذا مكون وظيفي بسيط بدون مكون عديم الحالة (مكون عديم الحالة). كمدخلات ، تتلقى من الدعائم إجمالي عدد الصفحات والصفحة الحالية ووظيفة معالج النقر على الصفحة. عند الإخراج ، ينتج المكون paginator المتشكل. لعرض الأزرار ، يتم استخدام مكون
زر تابع آخر. إذا كان هناك العديد من الصفحات ، فإن الصفحة لا تعرضها كلها ، وتجمعها وتعرضها في شكل قطع ناقص.

رمز مكون Paginatorimport React from 'react'; import classes from './Paginator.css'; import Button from '../../UI/Button/Button'; const Paginator = (props) => { const { tp, cp, pageClickHandler } = props; let paginator = null; if (tp !== undefined && tp > 0) { let buttons = []; buttons.push( <Button key={`pback`} disabled={cp === 1} clicked={(cp === 1 ? null : event => pageClickHandler(event, 'back'))}> ← </Button> ); const isDots = (i, tp, cp) => i > 1 && i < tp && (i > cp + 1 || i < cp - 1) && (cp > 4 || i > 5) && (cp < tp - 3 || i < tp - 4); let flag; for (let i = 1; i <= tp; i++) { const dots = isDots(i, tp, cp) && (isDots(i - 1, tp, cp) || isDots(i + 1, tp, cp)); if (flag && dots) { flag = false; buttons.push( <Button key={`p${i}`} className={classes.Dots} disabled={true}> ... </Button> ); } else if (!dots) { flag = true; buttons.push( <Button key={`p${i}`} disabled={i === cp} clicked={(i === cp ? null : event => pageClickHandler(event, i))}> {i} </Button> ); } } buttons.push( <Button key={`pforward`} disabled={cp === tp} clicked={(cp === tp ? null : event => pageClickHandler(event, 'forward'))}> → </Button> ); paginator = <div className={classes.Paginator}> {buttons} </div> } return paginator; } export default Paginator;
رمز مكون الزر import React from 'react'; import classes from './Button.css'; const button = (props) => ( <button disabled={props.disabled} className={classes.Button + (props.className ? ' ' + props.className : '')} onClick={props.clicked}> {props.children} </button> ); export default button;
دعابة
Jest هي مكتبة مفتوحة المصدر معروفة لاختبار الوحدة كود JavaScript. تم إنشاؤه وتطويره بفضل Facebook. مكتوب في Node.js.
بشكل عام ، يرجع معنى الاختبار إلى حقيقة أنك بحاجة إلى التوصل إلى معلمات إدخال للشفرة الخاصة بك ووصف المخرجات التي يجب أن تنتجها التعليمات البرمجية على الفور. عند إجراء الاختبارات ، ينفذ Jest شفرتك باستخدام معلمات الإدخال ويتحقق من النتيجة مقابل المعلمة المتوقعة. إذا تطابق ، سيجتاز الاختبار ، وإذا لم يكن كذلك ، فلن يمر.
مثال صغير من
jestjs.io .
لنفترض أن لدينا وحدة Node.js ، وهي وظيفة تضيف رقمين (ملف
sum.js ):
function sum(a, b) { return a + b; } module.exports = sum;
إذا تم حفظ الوحدة النمطية الخاصة بنا في ملف ، لاختبارها ، نحتاج إلى إنشاء ملف
sum.test.js لكتابة هذا الرمز للاختبار:
const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
في هذا المثال ، باستخدام وظيفة
الاختبار ، أنشأنا اختبارًا واحدًا يسمى
"يضيف 1 + 2 لتساوي 3" . المعلمة الثانية لوظيفة
الاختبار ، نقوم بتمرير وظيفة تؤدي الاختبار بالفعل.
يتكون الاختبار من حقيقة أننا ننفذ دالة
المجموع مع معلمات الإدخال
1 و
2 ، ونمرر النتيجة إلى دالة Jest
يتوقع () . بعد ذلك ، باستخدام
دالة Jest toBe () ، تتم مقارنة النتيجة المرسلة بالنتيجة المتوقعة (
3 ). تنتمي الدالة
toBe () إلى فئة وظائف اختبار
Jest (المطابقات) .
للاختبار ، ما عليك سوى الانتقال إلى مجلد المشروع واستدعاء
الدعابة في سطر الأوامر. سوف تجد
Jest الملف بالملحق
.test.js وتشغيل الاختبار. ها هي النتيجة التي سيخرجها:
PASS ./sum.test.js ✓ adds 1 + 2 to equal 3 (5ms)
اختبار انزيم و لقطة للمكونات
يعد اختبار اللقطة ميزة جديدة نسبيًا في Jest. النقطة هي أنه بمساعدة وظيفة اختبار خاصة ، نطلب من Jest حفظ لقطة لبنية بياناتنا على القرص ، وخلال عمليات الاختبار اللاحقة ، قارن اللقطات الجديدة مع اللقطات المحفوظة سابقًا.
اللقطة في هذه الحالة ليست أكثر من تمثيل نصي للبيانات. على سبيل المثال ، ستبدو لقطة لبعض الكائنات على النحو التالي (مفتاح المصفوفة هنا هو اسم الاختبار):
exports[`some test name`] = ` Object { "Hello": "world" } `;
هذا ما تبدو عليه وظيفة اختبار Jest ، والتي تقوم بمقارنة الصورة (معلمات اختيارية):
expect(value).toMatchSnapshot(propertyMatchers, snapshotName)
يمكن أن تكون
القيمة أي بنية بيانات قابلة للتسلسل. لأول مرة ، تقوم وظيفة
toMatchSnapshot () بكتابة اللقطة إلى القرص ؛ وفي الأوقات التالية ، ستقوم بالفعل بإجراء المقارنة.
في معظم الأحيان ، يتم استخدام تقنية الاختبار هذه خصيصًا لاختبار مكونات التفاعل ، وبشكل أكثر دقة ، لاختبار العرض الصحيح لمكونات التفاعل. للقيام بذلك ، تحتاج إلى تمرير المكون
كقيمة بعد التقديم.
إنزيم عبارة عن مكتبة تبسط بشكل كبير اختبار تطبيقات التفاعل من خلال توفير وظائف عرض مكون ملائمة. تم تطوير الإنزيم في Airbnb.
يتيح لك الإنزيم تقديم المكونات في التعليمات البرمجية. هناك العديد من الوظائف المناسبة لذلك والتي تؤدي خيارات عرض مختلفة:
- عرض كامل (كما هو الحال في المتصفح ، عرض DOM الكامل) ؛
- عرض مبسط (عرض ضحل) ؛
- عرض ثابت
لن نتعمق في خيارات العرض ، لاختبار اللقطة ، يكون العرض الثابت كافياً ، مما يسمح لك بالحصول على كود HTML ثابت للمكون ومكوناته الفرعية:
const wrapper = render(<Foo title="unique" />);
لذا ، نقوم
بعرض المكون الخاص بنا وتمرير النتيجة
لتوقع () ، ثم استدعاء دالة.
toMatchSnapshot () . إن وظيفة
it هي مجرد اختصار لوظيفة
الاختبار .
... const wrapper = render(<Paginator tp={tp} cp={cp} />); it(`Total = ${tp}, Current = ${cp}`, () => { expect(wrapper).toMatchSnapshot(); }); ...
في كل مرة يتم فيها
تشغيل الاختبار
، يقارن
toMatchSnapshot () لقطتين:
المتوقعة (التي تمت كتابتها سابقًا إلى القرص)
والحالية (التي تم الحصول عليها أثناء الاختبار الحالي).
إذا كانت الصور متطابقة ، يعتبر الاختبار ناجحًا. إذا كان هناك اختلاف في الصور ، يعتبر الاختبار غير ناجح ، ويظهر للمستخدم الفرق بين الصورتين في شكل فرق (كما هو الحال في أنظمة التحكم في الإصدار).
فيما يلي مثال على إخراج Jest عند فشل الاختبار. هنا نرى أن لدينا زر إضافي في الصورة الحالية.

في هذه الحالة ، يجب على المستخدم أن يقرر ما يجب فعله. إذا تم التخطيط للتغييرات في اللقطة بسبب التغييرات في كود المكون ، فيجب أن تستبدل اللقطة القديمة بأخرى جديدة. وإذا كانت التغييرات غير متوقعة ، فأنت بحاجة إلى البحث عن مشكلة في التعليمات البرمجية الخاصة بك.
سأعطي مثالا كاملا لاختبار paginator (ملف
Paginator.test.js ).
من أجل اختبار paginator أكثر ملاءمة ، قمت بإنشاء وظيفة
snapshoot (tp، cp) تأخذ معلمتين: العدد الإجمالي للصفحات والصفحة الحالية. ستقوم هذه الوظيفة بإجراء اختبار مع المعلمات المعطاة. كل ما تبقى هو استدعاء وظيفة
snapshoot () مع معلمات مختلفة (حتى في حلقة) واختبار واختبار ...
import React from 'react'; import { configure, render } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import Paginator from './Paginator'; configure({ adapter: new Adapter() }); describe('Paginator', () => { const snapshoot = (tp, cp) => { const wrapper = render(<Paginator tp={tp} cp={cp} />); it(`Total = ${tp}, Current = ${cp}`, () => { expect(wrapper).toMatchSnapshot(); }); } snapshoot(0, 0); snapshoot(1, -1); snapshoot(1, 1); snapshoot(2, 2); snapshoot(3, 1); for (let cp = 1; cp <= 10; cp++) { snapshoot(10, cp); } });
لماذا احتجت إلى منشئ تقارير إضافي
عندما بدأت العمل باستخدام تقنية الاختبار هذه ، لم يتركني الشعور بالنهج الأولي غير المكتمل. بعد كل شيء ، يمكن عرض الصور كنص فقط.
ولكن ماذا لو أنتج بعض المكونات الكثير من تعليمات HTML البرمجية عند العرض؟ هنا مكون مكون من 3 أزرار. ستبدو لقطة لمثل هذا المكون كما يلي:
exports[`Paginator Total = 1, Current = -1 1`] = ` <div class="Paginator" > <button class="Button" > ← </button> <button class="Button" > 1 </button> <button class="Button" > → </button> </div> `;
تحتاج أولاً إلى التأكد من تقديم النسخة الأصلية من المكون بشكل صحيح. ليس من السهل القيام بذلك ببساطة عن طريق عرض كود HTML في شكل نص. ولكن هذه ليست سوى ثلاثة أزرار. وإذا كنت بحاجة إلى اختبار ، على سبيل المثال ، طاولة أو شيء أكثر ضخامة؟ علاوة على ذلك ، لإجراء اختبار كامل ، تحتاج إلى عرض العديد من الصور. سيكون غير مريح وصعب.
بعد ذلك ، إذا فشل الاختبار ، فأنت بحاجة إلى فهم كيفية اختلاف مظهر المكونات. بالطبع ، سيسمح لك اختلاف كود HTML الخاص بهم بفهم ما تغير ، ولكن مرة أخرى ، لن تكون فرصة رؤية الفرق شخصيًا غير ضرورية.
بشكل عام ، اعتقدت أنه سيكون من الضروري حتى يمكن عرض الصور في المتصفح بنفس الشكل كما تبدو في التطبيق. بما في ذلك الأنماط المطبقة عليها. لذلك حصلت على فكرة لتحسين عملية اختبار اللقطة عن طريق كتابة أداة إنشاء تقارير إضافية لـ Jest.
بالنظر إلى المستقبل ، هذا ما حصلت عليه. في كل مرة أجري فيها الاختبارات ، يقوم المنشئ الخاص بي بتحديث كتاب اللقطة. مباشرة في المستعرض ، يمكنك عرض المكونات كما تبدو في التطبيق ، وكذلك إلقاء نظرة على الفور على التعليمات البرمجية المصدر للصور والاختلاف (إذا فشل الاختبار).

Jest Report Builders
قدم منشئو Jest الفرصة لكتابة منشئي تقارير إضافيين. يتم ذلك على النحو التالي. تحتاج إلى كتابة وحدة نمطية على Node.JS يجب أن يكون بها طريقة أو أكثر من هذه الطرق:
onRunStart ،
onTestStart ،
onTestResult ،
onRunComplete ، والتي تتوافق مع أحداث تقدم الاختبار المختلفة.
ثم تحتاج إلى توصيل الوحدة النمطية الخاصة بك في تكوين Jest. هناك توجيه خاص
للصحفيين . إذا كنت ترغب في تضمين المنشئ الخاص بك بالإضافة إلى ذلك ، فأنت بحاجة إلى إضافته إلى نهاية مجموعة
المراسلين .
بعد ذلك ، ستستدعي Jest طرقًا من الوحدة النمطية الخاصة بك في مراحل معينة من تنفيذ الاختبار ، لتمرير النتائج الحالية إلى الأساليب. في الواقع ، يجب أن تنشئ الشفرة في هذه الأساليب تقارير إضافية تحتاجها. لذلك بشكل عام ، يبدو إنشاء منشئي تقارير إضافيين.
كيف يعمل كتاب Jest-snapshots-book
لا أقوم بإدراج رمز الوحدة النمطية على وجه التحديد في المقالة ، حيث سأقوم بتحسينه بشكل أكبر. يمكن العثور عليه في GitHub الخاص بي ، وهذا هو
ملف src / index.js في صفحة المشروع.
يتم استدعاء منشئ التقرير الخاص بي عند الانتهاء من الاختبارات. أضع الكود في طريقة
onRunComplete (سياقات ، نتائج) . يعمل على النحو التالي.
في خاصية
results.testResults ، يمرر Jest صفيفًا من نتائج الاختبار إلى هذه الوظيفة. تتضمن كل نتيجة اختبار مسارًا لملف الاختبار ومجموعة من الرسائل مع النتائج. يبحث منشئ التقارير الخاص بي عن كل ملف اختبار يحتوي على ملف لقطة مناظر. إذا تم الكشف عن ملف لقطة ، يقوم منشئ التقرير بإنشاء صفحة HTML في كتاب اللقطة ويكتبها في مجلد كتاب اللقطات في المجلد الجذر للمشروع.
لإنشاء صفحة HTML ، يقوم منشئ التقرير ، باستخدام الدالة العودية
grabCSS (moduleName ، css = [] ، المستوى = 0) ، بجمع جميع الأنماط ، بدءًا من المكون قيد الاختبار ، ثم أسفل شجرة جميع المكونات التي يستوردها. وبالتالي ، تقوم الوظيفة بتجميع كافة الأنماط المطلوبة للمكون ليتم عرضها بشكل صحيح. تتم إضافة الأنماط التي تم جمعها إلى صفحة HTML لكتاب اللقطة.
أستخدم وحدات CSS في مشاريعي ، لذلك لست متأكدًا مما إذا كان هذا سيعمل إذا لم يتم استخدام وحدات CSS.
إذا نجح الاختبار ، يقوم المُنشئ بإدراج iFrame في صفحة HTML مع الصورة في خيارين للعرض: كود المصدر (الصورة كما هي) والمكون بعد التقديم. يتم تغيير خيار العرض في iFrame بالنقر فوق الماوس.
إذا لم يتم اجتياز الاختبار ، فإن كل شيء أكثر تعقيدًا. تقدم Jest في هذه الحالة فقط الرسالة التي تعرضها في وحدة التحكم (انظر لقطة الشاشة أعلاه).
يحتوي على اختلافات ومعلومات إضافية حول الاختبار الفاشل. في الواقع ، في هذه الحالة ، نحن نتعامل بشكل أساسي مع صورتين:
المتوقعة والفعلية . إذا كان لدينا المتوقع - يتم تخزينه على القرص في مجلد اللقطة ، فإن لقطة Jest الحالية لا توفر.
لذلك ، كان عليّ كتابة رمز يطبق الاختلاف Jest المأخوذ من الرسالة على اللقطة المتوقعة وإنشاء لقطة فعلية بناءً على المتوقع. بعد ذلك ، يعرض المنشئ بجانب iFrame لقطة iFrame المتوقعة للقطة الحالية ، والتي يمكن أن تغير محتوياتها بين ثلاثة خيارات: شفرة المصدر ، المكون بعد التقديم ، فرق.
هذا هو شكل مخرجات أداة إنشاء التقارير إذا قمت بتعيين الخيار المطوّل = true له.

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