في حين أن Codest هو في المقام الأول متجر روبي، فإن أحد المشاريع العديدة التي نبنيها هو في JavaScript. إنها مكتبة من جانب العميل، والتي تعمل في بيئة صعبة للغاية: يجب أن تدعم كل متصفح موجود تقريبًا، بما في ذلك المتصفحات القديمة جدًا، وفوق كل ذلك تتفاعل مع مجموعة من البرامج النصية والخدمات الخارجية. إنها ممتعة للغاية.
الحالة الغريبة للتبعيات غير المجمعة
مع المتطلبات المذكورة أعلاه تأتي مجموعة كاملة من التحديات التي لا توجد عادةً في جانب العميل المشروعوتتعلق إحدى فئات تلك المشكلات بالاختبار. بالطبع، لدينا بالطبع مجموعة لا تشوبها شائبة من اختبارات الوحدة ونقوم بتشغيلها ضد مصفوفة كبيرة جدًا من مجموعات المتصفحات/أنظمة التشغيل في بيئة CI/CD الخاصة بنا، ولكن هذا وحده لا يستكشف كل ما يمكن أن يحدث من أخطاء.
نظرًا للبنية الشاملة للنظام البيئي الذي نعمل فيه، فإننا نعتمد على بعض المكتبات الخارجية التي يتم تحميلها جنبًا إلى جنب مع مكتباتنا - أي أننا لا نجمعها مع الكود؛ لا يمكننا ولا يوجد شيء يمكن القيام به حيال ذلك. وهذا يمثل تحديًا مثيرًا للاهتمام، لأن تلك المكتبات:
- قد لا تكون موجودة - إذا أفسد أحدهم تنفيذ مكتبتنا,
- قد تكون موجودة، ولكن في إصدارات خاطئة/غير متوافقة,
- قد يكون قد تم تعديله من قبل بعض الشيفرات البرمجية الأخرى التي تتماشى مع تنفيذ معين.
هذا يوضح بوضوح لماذا لا تكفي اختبارات الوحدة: فهي تختبر بمعزل عن العالم الحقيقي. لنفترض أننا نحاكي جزءًا ما من واجهة برمجة التطبيقات العامة لمكتبة خارجية، بناءً على ما اكتشفناه في مستنداتها، ونجري اختبار وحدة ضد ذلك. ماذا يثبت ذلك؟
قد تميل إلى القول "هذا يعني أنه يعمل مع واجهة برمجة التطبيقات الخاصة بالمكتبة الخارجية"، لكنك ستكون - للأسف - مخطئًا. هذا يعني فقط أنه يتفاعل بشكل صحيح مع مجموعة فرعية من واجهة برمجة التطبيقات العامة للمكتبة الخارجية، وحتى ذلك الحين فقط مع الإصدار الذي قمنا بتكوينه.
ماذا لو تغيرت المكتبة حرفيًا من تحتنا؟ ماذا لو - هناك في البرية - حصلت على بعض الاستجابات الغريبة التي تجعلها تصطدم بمسار كود مختلف غير موثق؟ هل يمكننا حتى الحماية من ذلك؟
حماية معقولة
ليس 100%، لا - فالبيئة معقدة جدًا لذلك. ولكن يمكننا أن نتأكد بشكل معقول من أن كل شيء يعمل بالطريقة المفترضة مع بعض الأمثلة المعممة لما قد يحدث لشيفرتنا في البرية: يمكننا إجراء اختبارات التكامل. تضمن اختبارات الوحدة أن شيفرتنا تعمل بشكل صحيح داخليًا، ويجب أن تضمن اختبارات التكامل أننا "نتحدث" بشكل صحيح مع المكتبات التي لا يمكننا التحكم فيها. وليس مع بذرة منها أيضًا، بل مع المكتبات الفعلية الحية.
يمكننا فقط استخدام أحد أطر عمل اختبار التكامل المتاحة من أجل JavaScriptوإنشاء صفحة HTML بسيطة، وإجراء بعض المكالمات إلى مكتبتنا والمكتبات البعيدة عليها، وإعطائها تمرينًا جيدًا. ولكننا لا نريد إغراق أي من نقاط نهاية الخدمات البعيدة بالمكالمات التي تم إنشاؤها بواسطة بيئات CI / CD الخاصة بنا. سيؤدي ذلك إلى العبث ببعض الإحصائيات، وربما كسر بعض الأشياء، وأخيرًا وليس آخرًا، لن يكون من الجيد أن نجعل إنتاج شخص ما جزءًا من اختباراتنا.
ولكن هل كان اختبار التكامل أمرًا معقدًا للغاية؟ نظرًا لأن روبي هو عشقنا الأول والأهم من كل شيء، فقد عدنا إلى خبرتنا وبدأنا في التفكير في الطريقة التي نقوم بها عادةً باختبار التكامل مع الخدمات عن بُعد في مشاريع روبي. قد نستخدم شيئًا مثل vcr جوهرة لتسجيل ما يحدث مرة واحدة، ثم الاستمرار في إعادة تشغيله لاختباراتنا كلما دعت الحاجة.
أدخل الوكيل
يحقق ذلك داخلياً vcr عن طريق توكيل الطلبات. كانت هذه لحظتنا المذهلة. كنا بحاجة إلى توكيل كل طلب لا ينبغي أن يصل إلى أي شيء على الإنترنت "الحقيقي" إلى بعض الاستجابات المبنية على الروتين. ثم يتم تسليم تلك البيانات الواردة إلى المكتبة الخارجية وتعمل شفرتنا كالمعتاد.
عند وضع نماذج أولية لشيء يبدو معقدًا، غالبًا ما نعود إلى روبي كطريقة موفرة للوقت. قررنا أن نصنع نموذجًا أوليًا لاختبار تسخير JavaScript في روبي لنرى مدى نجاح فكرة الوكيل قبل الالتزام ببناء شيء أكثر تعقيدًا في JavaScript (ربما). اتضح أنها بسيطة بشكل مدهش. في الواقع إنه بسيط جدًا لدرجة أننا سنبني واحدًا في هذه المقالة معًا 🙂.
الأضواء، الكاميرا... انتظر، لقد نسينا الدعائم!
بالطبع لن نتعامل بالطبع مع "الشيء الحقيقي" - فشرح حتى القليل مما نبنيه يتجاوز نطاق منشور مدونة. يمكننا أن نبني شيئًا سريعًا وسهلًا للوقوف على المكتبات المعنية ثم نركز أكثر على الجزء الخاص بـ Ruby.
أولاً، نحن بحاجة إلى شيء يحل محل المكتبة الخارجية التي نتعامل معها. نحن بحاجة إلى أن تظهر بعض السلوكيات: يجب أن تتصل بخدمة خارجية، وأن تصدر حدثًا هنا وهناك، والأهم من ذلك كله - ألا تكون مبنية مع مراعاة سهولة التكامل 🙂
إليك ما سنستخدمه:
/* global XMLHttpRequest, Event */
const URL = 'https://poloniex.com/public/?command=returnTicker'
const METHOD = 'GET'
module.exports = {
fetch: function () {
var req = new XMLHttpRequest()
req.responseType = 'json'
req.open(METHOD, URL, true)
var doneEvent = new Event('example:fetched')
req.onreadystatechange = function (aEvt) {
if (req.readyState === 4) {
if (req.status === 200) {
this.data = req.response
} else {
this.error = true
}
window.dispatchEvent(doneEvent)
}
}.bind(this)
req.send(null)
},
error: false,
data: {}
}
ستلاحظ أنه يستدعي واجهة برمجة تطبيقات مفتوحة لبعض البيانات - في هذه الحالة بعض أسعار صرف العملات الرقمية، لأن هذا هو السائد في الوقت الحاضر لا تعرض واجهة برمجة التطبيقات هذه صندوق رمل وهي محدودة المعدل، مما يجعلها مثالًا رئيسيًا على شيء لا ينبغي أن يتم ضربه بالفعل في الاختبارات.
قد تلاحظ أن هذا في الواقع وحدة متوافقة مع NPM، بينما ألمح إلى أن النص البرمجي الذي نتعامل معه عادةً غير متوفر على NPM لسهولة التجميع. بالنسبة لهذا العرض التوضيحي يكفي أنه يعرض سلوكًا معينًا، وأفضّل سهولة الشرح هنا على حساب التبسيط الزائد.
دعوة الممثلين
نحتاج الآن أيضًا إلى شيء ما يحل محل مكتبتنا. مرة أخرى، سنبقي المتطلبات بسيطة: يجب أن تستدعي مكتبتنا "الخارجية" وتفعل شيئًا ما بالمخرجات. من أجل الحفاظ على بساطة الجزء "القابل للاختبار"، سنجعلها أيضًا تقوم بتسجيل مزدوج: إلى وحدة التحكم، وهو أمر يصعب قراءته في المواصفات، وإلى مصفوفة متاحة عالميًا.
Window.Remote.Remote = يتطلب('Remote-calling-example')
window.failedMiserably = صحيح
window.logs = []
دالة سجل (رسالة) {
window.logs.logs.push(message)
console.log(message)
}
windows.addEventEventListener('example:fetched'، دالة () {
إذا (window.remote.error) {
سجل('[مثال] فشل الجلب عن بعد')
window.failedMiserably = صحيح
) أخرى { {
سجل ('[مثال] تم الجلب عن بعد بنجاح')
log([EXAMPLE] BTC إلى ETH: ${window.remote.data.data.BTC_ETH.last})
}
})
window.remote.fetch()
أحافظ أيضًا على بساطة السلوك بشكل مذهل عن قصد. كما هو الحال، لا يوجد سوى مسارين برمجيين مثيرين للاهتمام بالفعل للمواصفات، لذا لن ننجرف تحت سيل من المواصفات أثناء تقدمنا في البناء.
كل شيء يستقر مع بعضه البعض
سنطرح صفحة HTML بسيطة:
<code> <!DOCTYPE html>
<html>
<head>
<title>مثال على الصفحة</title>
<script type="text/javascript" src="./index.js"></script>
</head>
<body></body>
</html>
لأغراض هذا العرض التوضيحي سنقوم بتجميع HTML وJavaScript معًا مع الطرودبسيطة للغاية تطبيق الويب المُجمِّع. أحب Parcel كثيرًا في مثل هذه الأوقات، عندما أقوم بتجميع مثال سريع أو أخترق فكرة فصل دراسي على ظهر اليقظة. عندما تفعل شيئًا بسيطًا جدًا بحيث يستغرق تكوين Webpack وقتًا أطول من كتابة الشيفرة التي تريدها، فهو الأفضل.
كما أنها غير مزعجة بما فيه الكفاية لدرجة أنني عندما أريد التبديل إلى شيء أكثر اختبارًا في المعركة، لا يتعين علي القيام بأي تراجع تقريبًا من Parcel، وهو أمر لا يمكن أن تقوله عن Webpack. ومع ذلك، هناك ملاحظة تحذيرية - لا يزال Parcel قيد التطوير المكثف ويمكن أن تظهر المشكلات وستظهر؛ لقد واجهت مشكلة حيث كان إخراج JavaScript المنقول غير صالح على Node.js. خلاصة القول: لا تجعلها جزءًا من خط إنتاجك بعد، ولكن جربها مع ذلك.
تسخير قوة التكامل
يمكننا الآن إنشاء حزام الاختبار الخاص بنا.
بالنسبة لإطار عمل المواصفات نفسه، استخدمنا ص سبيك. في بيئات التطوير التي نختبرها باستخدام متصفح كروم الفعلي غير مقطوع الرأس - تقع مهمة تشغيله والتحكم فيه على عاتق الوتير (وصاحبه الموثوق به watir-rspec). بالنسبة لوكيلنا، قمنا بدعوة نفخ بيلي و الرف إلى الحفلة. أخيرًا، نريد إعادة تشغيل بناء JavaScript في كل مرة نقوم فيها بتشغيل المواصفات، ويتحقق ذلك باستخدام الكوكايين.
هذه مجموعة كاملة من الأجزاء المتحركة، وبالتالي فإن مساعد المواصفات لدينا متورط إلى حد ما حتى في هذا المثال البسيط. دعونا نلقي نظرة عليه ونفصله.
Dir["./spec/support/*/.rb"].each { |f| تتطلب f }
TEST_LOGGER = Logger.new(STDOUT)
RSpec.configure.configure do |config|
config.before(:suite) { Cocaine::CommandLine.new('npm', 'run build', logger: TEST_LOGGER).run }
config.include config.include Watir::RSpec::Helper
config.include config.include Watir::RSpec::Matchers
التهيئة.تضمين ProxySupport
config.order = :عشوائي
BrowserSupport.configure(config)
إنهاء
تكوين بيلي.config do |c|
c.c.cache = خطأ
ج.c.c.cacherequestchequestheaders = خطأ
c.persistcache = خطأ
c.recordstubrequests = صحيح
c.logger = Logger.new(File.expandpath('../log/billy.log، FILE))
نهاية
قبل المجموعة بأكملها نقوم بتشغيل أمر البناء المخصص لدينا من خلال الكوكايين. قد يكون ثابت TEST_LOGGER مبالغًا فيه بعض الشيء، ولكننا لسنا مهتمين جدًا بعدد الكائنات هنا. نحن بالطبع نقوم بتشغيل المواصفات بترتيب عشوائي، ونحتاج إلى تضمين جميع الأشياء الجيدة من watir-rspec. نحتاج أيضًا إلى إعداد بيلي بحيث لا يقوم بالتخزين المؤقت، ولكننا نحتاج أيضًا إلى تسجيل واسع النطاق إلى المواصفات/السجل/سجل/بيلي
. إذا كنت لا تعرف ما إذا كان الطلب قد تم إيقافه بالفعل أو أنه يصل إلى خادم مباشر (عفوًا!)، فإن هذا السجل هو الذهب الخالص.
أنا متأكد من أن عينيك الثاقبة قد رصدت بالفعل ProxySupport و BrowserSupport. قد تعتقد أن الأشياء الجيدة المخصصة لدينا موجودة هناك... وستكون محقًا تمامًا! دعنا نرى ما يفعله BrowserSupport أولاً.
متصفح متحكم فيه
أولاً، دعنا نقدم لك متصفح TempBrowser
:
فئة TempBrowser
تعريف الحصول على
متصفح ||= Watir::Browser.new(web_driver)
نهاية
ديف قتل
إغلاق @المتصفح إذا كان @المتصفح
@المتصفح = لا شيء
إنهاء
خاص
تعريف web_driver
Selenium::WebDriver.for(:chrome, options: options)
نهاية
تعريف الخيارات
Selenium::WebDriver::Chrome::Options.new.tap do |options|
options.addargugument "---تلقائي-فتح-أدوات-التطوير-لعلامات التبويب
options.addargugument "-خادم الوكيل=#{Billy.proxy.host}:#{Billy.proxy.port}"
نهاية
النهاية
النهاية
بالعمل إلى الوراء من خلال شجرة الاستدعاء، يمكننا أن نرى أننا نقوم بإعداد مجموعة خيارات متصفح سيلينيوم لمتصفح كروم. أحد الخيارات التي نقوم بتمريرها إليه أساسي في إعدادنا: فهو يوجه مثيل كروم إلى توكيل كل شيء من خلال مثيل Puffing Billy الخاص بنا. الخيار الآخر هو مجرد خيار لطيف - كل مثيل نقوم بتشغيله ليس مقطوع الرأس ستفتح أدوات الفحص تلقائيًا. وهذا يوفر علينا كميات لا تُحصى من Cmd+Alt+I في اليوم الواحد 😉
بعد أن نقوم بإعداد المتصفح بهذه الخيارات، نمرره إلى واتر وهذا كل شيء تقريبًا. إن القتل
هو عبارة عن القليل من السكر الذي يتيح لنا إيقاف برنامج التشغيل وإعادة تشغيله مرارًا وتكرارًا إذا احتجنا إلى ذلك دون التخلص من مثيل TempBrowser.
يمكننا الآن أن نعطي أمثلة rspec بعض القوى الخارقة. أولًا، نحصل على خاصية أنيقة المتصفح
طريقة المساعد التي ستدور مواصفاتنا حولها في الغالب. يمكننا أيضًا أن نستفيد من طريقة مفيدة لإعادة تشغيل المتصفح لمثال معين إذا كنا نقوم بشيء فائق الحساسية. بالطبع، نريد أيضًا أن نوقف المتصفح بعد انتهاء مجموعة الاختبارات، لأننا لا نريد تحت أي ظرف من الظروف أن تبقى مثيلات Chrome باقية - من أجل ذاكرة الوصول العشوائي الخاصة بنا.
الوحدة النمطية BrowserSupport
تعريف المتصفح الذاتي
@ متصفح ||= TempBrowser.new
إنهاء
تعريف self.configure(config)
config.around(:كل) القيام ب |المثال |
BrowserSupport.browser.kill إذا كان المثال.metadata[:نظيف]
متصفح @browserSupport.browser.get = BrowserSupport.browser.get
@browser.cookies.clear
@browser.driver.manager.timeouts.implicit_wait.implicit_wait = 30
example.run
إنهاء
config.after(:suite) do
BrowserSupport.browser.kill
إنهاء
النهاية
النهاية
توصيل الأسلاك بالوكيل
لقد قمنا بإعداد المتصفح ومساعدي المواصفات، ونحن مستعدون لبدء إرسال الطلبات إلى وكيلنا. لكن انتظر، لم نقم بإعداده بعد! يمكننا إجراء مكالمات متكررة لـ "بيلي" لكل مثال، ولكن من الأفضل أن نحصل لأنفسنا على طريقتين مساعدتين ونوفر بضعة آلاف من ضغطات المفاتيح. هذا ما دعم البروكسي
يفعل.
الطريقة التي نستخدمها في إعداد الاختبار لدينا أكثر تعقيدًا بعض الشيء، ولكن إليك فكرة عامة:
متجمد متجمد: صحيح
تتطلب 'json'
الوحدة النمطية ProxySupport
الرؤوس = {
'Access-Control-Allow-Allow-Methods' => 'GET',
'Access-Control-Allow-Allow-Headers' => 'X-Requected-With, X-Prototype-Version, Content-Type',
'Access-Control-Allow-Allow-Origin' => '*'
}.freeze
تعريف stubjson(url، ملف)
بيلي.proxy.stub(url).andreturn({
الجسم: فتح(ملف).read,
الرمز: 200,
الرؤوس: HEADERS.dup
})
النهاية
def stubstatus(url، الحالة)
بيلي. proxy.proxy.stub(url).andreturn({
الجسم: '',
الرمز: الحالة,
الرؤوس: HEADERS.dup
})
نهاية
def stubpage(url، ملف)
بيلي.proxy.stub(url).andreturn(
body: open(file).read,
نوع المحتوى: 'text/html',
الرمز: 200
)
النهاية
تعريف stubjs(url، ملف)
بيلي.proxy.stub(url).andreturn(
الجسم: open(file).read,
نوع المحتوى: 'تطبيق/جافا سكريبت',
الرمز: 200
)
النهاية
النهاية
يمكننا أن نتعقب:
- طلبات صفحة HTML - لصفحة "الملعب" الرئيسية لدينا,
- طلبات JS - لخدمة مكتبتنا المجمعة,
- طلبات JSON - لتكثيف الطلب إلى واجهة برمجة التطبيقات البعيدة,
- ومجرد طلب "أيًا كان" حيث نهتم فقط بإرجاع استجابة HTTP معينة غير 200.
هذا سيفي بالغرض في مثالنا البسيط. بالحديث عن الأمثلة - يجب علينا إعداد مثالين!
اختبار الجانب الجيد
نحتاج أولاً إلى توصيل بعض "المسارات" للوكيل الخاص بنا:
دع(:pageurl) { 'http://myfancypage.local/index.html' }
دعنا(:jsurl) { 'http://myfancypage.local/dist/remote-caller-example.js' }
دع((:pagepath) { ' ./dist/index.html' }
Let(:jspath) { ' './dist/remote-caller-example.js' }
قبل القيام
ستاببيج صفحة الصفحة، مسار الصفحة
stubjs jsurl, jspath
نهاية
تجدر الإشارة إلى أنه من وجهة نظر rspec، تشير المسارات النسبية هنا إلى دليل المشروع الرئيسي، لذلك نقوم بتحميل HTML وJS مباشرةً من التوزيع
الدليل - كما تم إنشاؤه بواسطة Parcel. يمكنك أن ترى بالفعل كيف أن تلك كعب_المقعد*
المساعدين في متناول اليد.
وتجدر الإشارة أيضًا إلى أننا نضع موقعنا الإلكتروني "المزيف" على موقع محلي
TLD. وبهذه الطريقة يجب ألا تفلت أي طلبات هاربة من بيئتنا المحلية في حالة حدوث خطأ ما. كممارسة عامة، أوصي على الأقل بعدم استخدام أسماء النطاقات "الحقيقية" في النطاقات الفرعية إلا في حالة الضرورة القصوى.
هناك ملاحظة أخرى يجب أن ندلي بها هنا حول عدم تكرار أنفسنا. عندما يصبح توجيه الوكيل أكثر تعقيدًا، مع وجود الكثير من المسارات وعناوين URL، ستكون هناك قيمة حقيقية في استخراج هذا الإعداد إلى سياق مشترك وتضمينه ببساطة حسب الحاجة.
يمكننا الآن تحديد كيف يجب أن يبدو مسارنا "الجيد":
السياق "مع الاستجابة الصحيحة" تفعل
قبل القيام
stubjson %r{http://poloniex.com/public(.*)}, './spec/fixtures/remote.json'
goto pageurl
Watir::Wait.until { browser.execute_script('return window.logs.length === 2')}
نهاية
فإنه 'سجلات البيانات المناسبة' تفعل
توقّع (browser.execute_script('return window.logs'))).to(
eq(["[EXAMPLE] نجاح عملية الجلب عن بُعد"، "[EXAMPLE] BTC إلى ETH: 0.03619999"])
)
النهاية
النهاية
هذا بسيط جدًا، أليس كذلك؟ المزيد من الإعدادات هنا - نرتكز على استجابة JSON من واجهة برمجة التطبيقات البعيدة باستخدام أداة التثبيت، وننتقل إلى عنوان URL الرئيسي ثم... ننتظر.
أطول فترة انتظار
الانتظارات هي طريقة للتغلب على أحد القيود التي واجهناها مع واتر - لا يمكننا انتظار أحداث JavaScript على سبيل المثال بشكل موثوق، لذا نحتاج إلى الغش قليلًا و"الانتظار" حتى تنقل النصوص البرمجية بعض الكائنات التي يمكننا الوصول إليها إلى حالة تهمنا. الجانب السلبي هو أنه إذا لم تأتِ تلك الحالة أبدًا (بسبب خطأ ما، على سبيل المثال) نحتاج إلى انتظار انتهاء وقت انتظار الواتر. هذا يؤدي إلى زيادة وقت المواصفات قليلًا. ومع ذلك لا تزال المواصفات تفشل بشكل موثوق.
بعد أن "تستقر" الصفحة على الحالة التي نهتم بها، يمكننا تنفيذ المزيد من JavaScript في سياق الصفحة. هنا نستدعي السجلات المكتوبة إلى المصفوفة العامة ونتحقق مما إذا كانت كما توقعنا.
كملاحظة جانبية - هنا حيث يضيء تكبير الطلب عن بُعد حقًا. تعتمد الاستجابة التي يتم تسجيلها إلى وحدة التحكم على سعر الصرف الذي تُرجعه واجهة برمجة التطبيقات عن بُعد، لذا لا يمكننا اختبار محتويات السجل بشكل موثوق إذا استمرت في التغيير. هناك طرق للتغلب على ذلك بالطبع ولكنها ليست أنيقة للغاية.
اختبار الفرع السيئ
شيء آخر يجب اختباره: فرع "الفشل".
السياق "مع استجابة فاشلة" تفعل
قبل القيام
stubstatus %r{http://poloniex.com/public(.*)}، 404
اذهب إلى pageurl
Watir::Wait.until { browser.execute_script('return window.logs.length === 1') }
نهاية
يقوم 'فشل السجلات' بما يلي
توقّع (browser.execute_script('return window.logs'))).to(
eq(['[EXAMPLE] فشل الجلب عن بعد']))
)
النهاية
إنهاء
إنه مشابه جدًا لما سبق، والفرق هو أننا نرتكز على الاستجابة لإرجاع رمز الحالة 404 HTTP ونتوقع سجلًا مختلفًا.
دعنا نجري المواصفات الآن.
% حزمة تنفيذ % rspec
عشوائي مع البذرة 63792
I, [2017-12-21T14:26:26:08.680953 #7303] INFO -- : الأمر :: npm run build
استدعاء عن بعد
مع استجابة صحيحة
يسجل البيانات الصحيحة
مع استجابة فاشلة
سجلات الفشل
انتهى في 23.56 ثانية (استغرق تحميل الملفات 0.86547 ثانية)
2 أمثلة، 0 حالات فشل
مرحى!
الخاتمة
لقد ناقشنا بإيجاز كيف يمكن اختبار تكامل JavaScript مع روبي. في حين أنه كان يعتبر في الأصل أكثر من مجرد حل مؤقت، إلا أننا سعداء جدًا بنموذجنا الأولي الصغير الآن. بالطبع ما زلنا نفكر في حل JavaScript النقي بالطبع، ولكن في الوقت الحالي لدينا طريقة بسيطة وعملية لإعادة إنتاج واختبار بعض المواقف المعقدة للغاية التي واجهناها في البرية.
إذا كنت تفكر في بناء شيء مماثل بنفسك، فيجب ملاحظة أنه لا يخلو من القيود. على سبيل المثال إذا كان ما تختبره ثقيلًا جدًا على AJAX، سيستغرق Puffing Billy وقتًا طويلاً للاستجابة. أيضًا إذا كان عليك أن ترتكز على بعض مصادر SSL فستكون هناك حاجة إلى المزيد من العبث - انظر إلى وثائق watir إذا كان هذا أحد متطلباتك. سنستمر بالتأكيد في الاستكشاف والبحث عن أفضل الطرق للتعامل مع حالة الاستخدام الفريدة الخاصة بنا - وسنحرص على إعلامك بما اكتشفناه أيضًا.