أتمِت الأساسيات: استخدِم الرموز البرمجية لرصد الأخطاء البسيطة.
بعد أن عرفت حالات التعذّر التي تريد رصدها باستخدام عمليات التقييم المستندة إلى القواعد، حان الوقت لتنفيذ دوال التقييم المناسبة:
evalDataFormat(): يتحقّق من صحة تنسيق البيانات. ويشمل ذلك ملف JSON صالحًا، وجميع المفاتيح متوفرة، ولا توجد قيم فارغة، والشعار يتألف من أقل من ست كلمات، وألوان سداسية عشرية.evalContrastRatio(): يتحقّق من إمكانية الوصول إلى نسبة تباين الألوان بين النص والخلفية.
تنفيذ عمليات التقييم المستندة إلى القواعد
اختيار طريقة تسجيل النقاط
معايير التقييم ثنائية. يجب أن تنتج دوال التقييم المستندة إلى القواعد مخرجات ثنائية، مثل التصنيف PASS أو FAIL.
- ناتج تطبيق ThemeBuilder (عنصر المظهر الكامل) →
evalDataFormat()→ التصنيفPASSأوFAILPASSإذا كان تنسيق البيانات يستوفي جميع القيودFAILفي الحالات الأخرى. - ناتج تطبيق ThemeBuilder (عنصر لوحة الألوان) →
evalContrastRatio()→ التصنيفPASSأوFAILPASSإذا كانت النسبة > 4.5FAILفي الحالات الأخرى.
تحديد نوع التقييمات
المقياس PASS أو FAIL هو قيمة منطقية، ولكن يمكنك اختياره كتصنيف سلسلة (فئة) لتسهيل قراءته.
للحفاظ على البساطة، يمكنك استخدام نوع TypeScript نفسه لكل من التقييمات المستندة إلى القواعد والتقييمات المستندة إلى نموذج اللغة الكبير التي ستنفّذها لاحقًا. أنشئ نوع EvalResult يضم فئة ثنائية EvalLabel وحقل rationale لنموذج التقييم من أجل شرح تقييمه.
enum EvalLabel {
PASS = "PASS",
FAIL = "FAIL"
}
interface EvalResult {
label: EvalLabel;
rationale?: string;
}
تنفيذ أدوات التقييم
Zod هي أداة رائعة للتحقّق من صحة المخطط، لأنّها تتعامل مع بنية JSON والقواعد المخصّصة. وهي
توضيحية، ما يجعل رمز التحقّق سهل القراءة. تحديد تقارير مفصّلة عن الأخطاء تتضمّن مسارات وأسباب محدّدة لحدوثها، وذلك لتسهيل تحديد المشاكل وحلّها
import { z } from 'zod';
import { MAX_WORD_COUNT } from './app.config';
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
// Reusable schema for hex colors
const HexColor = z.string().regex(hexColorRegex, { message: "Invalid hex color code" });
// zod schema definition for AppOutput
export const AppOutputSchema = z.object({
motto: z.string().min(1, { message: "Motto is missing or empty" }).refine((val) => {
const words = val.replace(/[^\w\s]|_/g, "").trim();
const count = words ? words.split(/\s+/).length : 0;
return count > 0 && count <= MAX_WORD_COUNT;
}, { message: `Motto must be between 1 and ${MAX_WORD_COUNT} words` }),
colorPalette: z.object({
textColor: HexColor,
backgroundColor: HexColor,
primary: HexColor,
secondary: HexColor
}).catchall(HexColor)
});
نسبة التباين
احتفِظ بمنطق النطاق، مثل حسابات نسبة التباين، في دوال مساعدة منفصلة.
/*
* Input: ColorPalette {"textColor":"#333333","backgroundColor":"#000000", ...}
* Output: EvalResult {"status":"FAIL","rationale":"Contrast ratio is 1.66:1 (must be >= 4.5:1)."}
* minContrastRatio is an app config variable, MIN_CONTRAST_RATIO = 4.5
*/
export function evalContrastRatio(colorPalette: ColorPalette, minContrastRatio: number): EvalResult {
if (!colorPalette || !colorPalette.textColor || !colorPalette.backgroundColor) {
return { status: EvalLabel.FAIL, rationale: "Missing textColor or backgroundColor." };
}
try {
const ratio = getContrastRatio(colorPalette.textColor, colorPalette.backgroundColor);
const rationale = `Contrast ratio is ${ratio.toFixed(2)}:1 (must be >= ${minContrastRatio}:1).`;
if (ratio < minContrastRatio) {
return { status: EvalLabel.FAIL, rationale };
}
return { status: EvalLabel.PASS, rationale };
} catch (e) {
return { status: EvalLabel.FAIL, rationale: "Could not calculate contrast ratio (invalid hex?)." };
}
}
يمكنك الاطّلاع على رمز المقيّم
لـ evalDataFormat() وevalContrastRatio().
اختبار التقييمات المستندة إلى القواعد
تكون التقييمات المستندة إلى القواعد قطعية، لذا يمكنك تنفيذ اختبارات الوحدات الكلاسيكية للتحقّق من سلوكها. أنشئ اختباراتك لتشغيل نواتج مختلفة من خلال أدوات التقييم، وتأكَّد مما إذا كانت تعرض التصنيف PASS أو FAIL الذي توقعته.
إذا كانت حالة الاختبار تتوقّع أن يعرض المقيم القيمة FAIL وقد فعل ذلك، ستعرض حالة الاختبار القيمة PASS لأنّ المقيم تصرّف على النحو المطلوب.
import { MIN_CONTRAST_RATIO } from '../src/app.config'; // 4.5
const testCases = [
{
// ...
appOutput: {
motto: "Test motto",
colorPalette: {
textColor: "#333333",
backgroundColor: "#000000",
primary: "#FF0000",
secondary: "#333333"
}
},
expected: {
// Dark grey on black (low contrast): FAIL
contrast: EvalLabel.FAIL
}
}
// ... more test cases
];
testCases.forEach((testCase) => {
const result = evalContrastRatio(
testCase.appOutput.colorPalette as any, MIN_CONTRAST_RATIO
);
const actualEvalLabel = result.label;
const expectedEvalLabel = testCase.expected.contrast;
const isSuccess = actualEvalLabel === expectedEvalLabel;
// ...
});