അതൊരു സ്ലാക്ക് (Slack) സന്ദേശത്തിലൂടെയാണ് തുടങ്ങുന്നത്. ബിൽഡ് പരാജയപ്പെട്ട നിലയിലാണ് (red). നിങ്ങൾ പരാജയങ്ങൾ പരിശോധിക്കുന്നു, നെറ്റി ചുളിക്കുന്നു, എന്നിട്ട് അതേ ടെസ്റ്റ് നിങ്ങളുടെ ലാപ്ടോപ്പിൽ വീണ്ടും റൺ ചെയ്യുന്നു. വിജയിക്കുന്നു (green). നിങ്ങൾ CI ജോബ് വീണ്ടും ശ്രമിക്കുന്നു. ഒരുപക്ഷേ അതൊരു ചെറിയ പിശക് മാത്രമായിരിക്കാം എന്ന് നിങ്ങൾ കരുതുന്നു. എന്നാൽ പരാജയം വീണ്ടും വരുന്നു; സെർവറിൽ അത് ആവർത്തിച്ചു സംഭവിക്കുന്നുണ്ടെങ്കിലും നിങ്ങൾക്ക് അത് കണ്ടെത്താൻ കഴിയുന്നില്ല.

CI-യിൽ പരാജയപ്പെടുകയും എന്നാൽ ലോക്കലിൽ വിജയിക്കുകയും ചെയ്യുന്ന ഒരു ബ്രൗസർ ടെസ്റ്റ് വെറുമൊരു അസ്വസ്ഥത മാത്രമല്ല. അത് അവിശ്വാസം വളർത്തുന്നു. ടീമുകൾ സമയക്രമത്തെ (timing) കുറ്റപ്പെടുത്താൻ തുടങ്ങുന്നു. അവർ താൽക്കാലിക പരിഹാരങ്ങൾ നടപ്പിലാക്കുന്നു, അവ ഒരിക്കലും നീക്കം ചെയ്യപ്പെടുന്നില്ല. ഇവിടെ ഒരു setTimeout, അവിടെ ഒരു .wait(5000). ടെസ്റ്റ് സ്യൂട്ട് സാവധാനത്തിലാകുന്നു. പരാജയങ്ങൾ വീണ്ടും വരാൻ തുടങ്ങുന്നു. ആ അസ്ഥിരമായ (flaky) ടെസ്റ്റുകൾ സ്ഥിരമായ പ്രശ്നങ്ങളായി മാറുന്നു, ഒടുവിൽ എല്ലാവരും പരാജയപ്പെട്ട ഒരു പൈപ്പ്‌ലൈനിനെ (red pipeline) വെറുമൊരു പശ്ചാത്തല ശബ്ദമായി കാണാൻ തുടങ്ങുന്നു.

അത് അപകടകരമാണ്. തെറ്റായ മുന്നറിയിപ്പുകൾ നൽകുന്ന ഒരു ടെസ്റ്റ് സ്യൂട്ട് നിങ്ങൾക്ക് ആവശ്യമില്ല.

CI തകരാറിലല്ല; അത് വെറുതെ വ്യത്യസ്തമാണ്

CI എൻവയോൺമെന്റുകൾ യാദൃശ്ചികമല്ല. അവ കൃത്യമായ രീതിയിൽ പ്രവർത്തിക്കുന്നവയാണ് (deterministic). പ്രശ്നം എന്തെന്നാൽ, നിങ്ങളുടെ മാക്ബുക്കോ ലിനക്സ് വർക്ക്സ്റ്റേഷനോ അല്ലാത്ത ഒരു സിസ്റ്റത്തെക്കുറിച്ചാണ് അവ കൃത്യമായി പ്രവർത്തിക്കുന്നത് എന്നതാണ്. നിങ്ങളുടെ ലോക്കൽ സെറ്റപ്പ് മറച്ചുവെക്കുന്ന വ്യത്യാസങ്ങൾ ഒരു ക്ലീൻ CI റണ്ണർ ഉടൻ തന്നെ വെളിപ്പെടുത്തുന്നു.

എത്രയധികം ഘടകങ്ങൾ വ്യത്യാസപ്പെടുന്നു എന്ന് ചിന്തിച്ചു നോക്കൂ. നിങ്ങളുടെ ലോക്കൽ മെഷീൻ 'ഹോട്ട് മോഡ്യൂൾ റീലോഡിംഗ്' (hot module reloading) ഉള്ള ഒരു ഡെവലപ്‌മെന്റ് സെർവർ പ്രവർത്തിപ്പിച്ചേക്കാം, എന്നാൽ CI ഒരു പ്രൊഡക്ഷൻ ആർട്ടീഫാക്റ്റ് (production artifact) ആണ് നിർമ്മിക്കുന്നത്, അതിൽ 'ട്രീ ഷേക്കിംഗും' (tree shaking) 'മിനിഫിക്കേഷനും' (minification) ഉണ്ടാകും. ഇത് കോഡ് പാത്തുകളെ മാറ്റാനോ എക്സിക്യൂഷൻ ക്രമം മാറ്റാനോ കാരണമായേക്കാം. ഡിപെൻഡൻസി ട്രീകൾ (Dependency trees) മാറുന്നു. പാക്കേജ് മാനേജർ പതിപ്പിൽ ചെറിയ മാറ്റം വന്നാൽ പോലും ഒരേപോലെ തോന്നിക്കുന്ന ഒരു ലോക്ക് ഫയൽ (lockfile) വ്യത്യസ്തമായി പ്രവർത്തിച്ചേക്കാം. നെറ്റ്‌വർക്ക് ക്രമീകരണങ്ങളും മാറുന്നു. നിങ്ങളുടെ ഓഫീസിലെ വൈഫൈ ഒരു സ്റ്റേജിംഗ് API വേഗത്തിൽ കണക്ട് ചെയ്തേക്കാം; എന്നാൽ CI റണ്ണർ ഒരു ലോഡ് ബാലൻസറിന് പിന്നിലെ മറ്റൊരു ക്ലസ്റ്ററിലേക്ക് കണക്ട് ചെയ്യുമ്പോൾ നിങ്ങൾ കാണാത്ത ലേറ്റൻസി (latency) ഉണ്ടാകാം.

ബ്രൗസറുകൾ തന്നെ ഓരോ എൻവയോൺമെന്റിലും വ്യത്യസ്തമായി പെരുമാറുന്നു. നിങ്ങളുടെ ലോക്കൽ ക്രോം (Chrome) ബ്രൗസറിൽ എക്സ്റ്റൻഷനുകൾ, കാഷഡ് ക്രെഡൻഷ്യലുകൾ, പെർസിസ്റ്റന്റ് ലോക്കൽ സ്റ്റോറേജ്, ഹാർഡ്‌വെയർ ആക്സിലറേഷൻ ഉള്ള ഒരു GPU എന്നിവ ഉണ്ടാകാം. എന്നാൽ CI ഓരോ തവണ റൺ ചെയ്യുമ്പോഴും ഒരു ബ്ലാങ്ക് പ്രൊഫൈലിൽ നിന്നാണ് തുടങ്ങുന്നത്. ബ്രൗസർ ലൈഫ് സൈക്കിളുകളും റെൻഡറിംഗ് പാത്തുകളും വ്യത്യാസപ്പെടുന്നു. നിങ്ങളുടെ സിസ്റ്റത്തിലുള്ള ഫോണ്ടുകൾ CI-യിൽ ലഭ്യമായിരിക്കില്ല. വ്യൂപോർട്ട് സൈസിംഗും (viewport sizing) ഡിവൈസ് പിക്സൽ റേഷ്യോകളും മാറുന്നത് റെസ്പോൺസീവ് ബ്രേക്ക്പോയിന്റുകളെയും ലേസി-ലോഡിംഗ് (lazy-loading) രീതിയെയും ബാധിച്ചേക്കാം.

ഈ വ്യത്യാസങ്ങൾ യഥാർത്ഥമാണ്. അവ സാങ്കേതികമായ കാരണങ്ങളാലാണ് സംഭവിക്കുന്നത്. അവ യാദൃശ്ചികമാണെന്ന് കരുതി അവ ഇല്ലാതാകില്ല.

പ്രിവ്യൂ എൻവയോൺമെന്റുകൾ കള്ളം പറയുന്നു

പ്രിവ്യൂ എൻവയോൺമെന്റുകൾ പ്രശ്നം കൂടുതൽ സങ്കീർണ്ണമാക്കുന്നു. അവ മനുഷ്യർക്ക് പരിശോധിക്കാൻ ഉപകരിക്കുമെങ്കിലും അവ പ്രൊഡക്ഷൻ എൻവയോൺമെന്റല്ല. അവ പലപ്പോഴും യഥാർത്ഥ API ഹോസ്റ്റിന് പകരം api-staging-ലേക്ക് ആണ് പോയിന്റ് ചെയ്യുന്നത്. ഫീച്ചർ ഫ്ലാഗുകൾ (Feature flags) എല്ലാ പരീക്ഷണങ്ങൾക്കും 'ട്രൂ' (true) ആയിരിക്കാം, ഇത് പ്രൊഡക്ഷനിൽ പ്രവർത്തിക്കുന്ന കണ്ടീഷണൽ ലോജിക് മറച്ചുവെക്കുന്നു. ഓതന്റിക്കേഷൻ ഒരു ഘട്ടം ഒഴിവാക്കിയേക്കാം അല്ലെങ്കിൽ ഒരു മോക്ക് ടോക്കൺ (mock token) ഉപയോഗിച്ചേക്കാം. കുക്കികൾ ലളിതമായ പോളിസികൾ ഉപയോഗിച്ചേക്കാം. ഡാറ്റാസെറ്റ് വളരെ ചെറുതായിരിക്കാം, ഇത് പേജിനേഷൻ (pagination), സെർച്ച് റാങ്കിംഗ്, അല്ലെങ്കിൽ വിർച്വലൈസേഷൻ ലോജിക് എന്നിവ ശരിയായി പരിശോധിക്കപ്പെടുന്നില്ലെന്ന് അർത്ഥമാക്കുന്നു.

നിങ്ങളുടെ ടെസ്റ്റ് ഒരു പ്രിവ്യൂ URL-ൽ വിജയിക്കുകയും എന്നാൽ പ്രൊഡക്ഷനിൽ പരാജയപ്പെടുകയും ചെയ്യുന്നുവെങ്കിൽ, ടെസ്റ്റിലല്ല പ്രശ്നം, മറിച്ച് എൻവയോൺമെന്റിലാണ്.

ഊഹിക്കുന്നതിന് മുമ്പ് ലോഗ് ചെയ്യുക

ഒരു പരാജയം ആദ്യം കാണുമ്പോൾ, ടെസ്റ്റിൽ ചെറിയ മാറ്റങ്ങൾ വരുത്തി വിജയിക്കുമെന്ന് പ്രതീക്ഷിക്കുന്ന ശീലം ഒഴിവാക്കുക. ഊഹിക്കുന്നത് നിർത്തുക. വിജയിച്ച ഒരു റണ്ണും പരാജയപ്പെട്ട ഒരു റണ്ണും തമ്മിൽ താരതമ്യം ചെയ്യാൻ സാഹചര്യങ്ങൾ കൃത്യമായി രേഖപ്പെടുത്തേണ്ടതുണ്ട്.

പ്രധാനപ്പെട്ട കാര്യങ്ങൾ ലോഗ് ചെയ്യുക. പരാജയം സംഭവിക്കുന്ന സമയത്തെ പേജ് URL, ബിൽഡ് ID, കമിറ്റ് SHA (commit SHA) എന്നിവ രേഖപ്പെടുത്തുക. നിലവിലുള്ള ഫീച്ചർ ഫ്ലാഗുകൾ ശ്രദ്ധിക്കുക. API ഹോസ്റ്റ്, കൃത്യമായ ബ്രൗസർ പതിപ്പ്, വ്യൂപോർട്ട് സൈസ് എന്നിവ ശേഖരിക്കുക. ഈ വിവരങ്ങൾ ഒരു നിഗൂഢമായ പരാജയത്തെ നമുക്ക് വീണ്ടും ആവർത്തിച്ചുണ്ടാക്കാൻ കഴിയുന്ന ഒരു സാഹചര്യമാക്കി മാറ്റുന്നു.

സ്ക്രീൻഷോട്ടുകളെ മാത്രം ആശ്രയിക്കരുത്. രണ്ട് പേജുകൾ കാഴ്ചയിൽ ഒരേപോലെ ഇരിക്കാമെങ്കിലും അവ തികച്ചും വ്യത്യസ്തമായ ജാവാസ്ക്രിപ്റ്റ് (JavaScript) റൺ ചെയ്തേക്കാം. CI ബണ്ടിലിൽ ഒരു അധിക പോളിഫിൽ (polyfill) ഉൾപ്പെട്ടിട്ടുണ്ടോ അല്ലെങ്കിൽ ലോക്കൽ ബണ്ടിലിൽ ബ്രൗസർ കാഷെ കാരണം ചില ഭാഗങ്ങൾ ഒഴിവാക്കപ്പെട്ടോ എന്ന് ഒരു സ്ക്രീൻഷോട്ട് പറയില്ല.

കൂടാതെ, ഡെവ് ടൂൾസ് (DevTools) തുറക്കുന്നത് സമയക്രമത്തെ (timing) മാറ്റുന്നു എന്ന് ഓർക്കുക. ഡെവ് ടൂൾസ് ഗാർബേജ് കളക്ഷനെ (garbage collection) വൈകിപ്പിക്കാനും, നെറ്റ്‌വർക്ക് മുൻഗണന മാറ്റാനും, ചില റെൻഡറിംഗ് ഒപ്റ്റിമൈസേഷനുകൾ പ്രവർത്തനരഹിതമാക്കാനും കാരണമായേക്കാം. നിങ്ങൾ DOM പരിശോധിക്കുമ്പോൾ വിജയിക്കുന്ന ഒരു ടെസ്റ്റ്, പാനൽ അടച്ച് ഹെഡ്‌ലെസ്സ് (headless) ആയി റൺ ചെയ്യുമ്പോൾ പരാജയപ്പെട്ടേക്കാം. ഡീബഗ്ഗർ ഒരു ഉപയോഗപ്രദമായ ഉപകരണമാണ്, പക്ഷേ അത് നിഷ്പക്ഷമായ ഒരു നിരീക്ഷകനല്ല.

സാഹചര്യം പുനഃസൃഷ്ടിക്കുക

പരാജയം കൃത്യമായി പുനരാവിഷ്കരിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, നിങ്ങളുടെ ലോക്കൽ ഡെവലപ്‌മെന്റ് സെർവർ മാത്രം പ്രവർത്തിപ്പിച്ചാൽ പോരാ. CI-യുടെ കൃത്യമായ സാഹചര്യങ്ങൾ തന്നെ നിങ്ങൾ പുനഃസൃഷ്ടിക്കേണ്ടതുണ്ട്.

CI നിർമ്മിച്ച അതേ ആർട്ടിഫാക്റ്റ് (artifact) തന്നെ നിർമ്മിക്കുക. വേണമെങ്കിൽ അത് ഡൗൺലോഡ് ചെയ്യുക. Vite അല്ലെങ്കിൽ Webpack ഡെവ് മിഡിൽവെയർ ഉപയോഗിക്കാതെ, ഒരു ലളിതമായ സ്റ്റാറ്റിക് ഫയൽ സെർവർ ഉപയോഗിച്ച് ആ ആർട്ടിഫാക്റ്റ് ലോക്കലായി സർവ് ചെയ്യുക. CI ഇൻജക്റ്റ് ചെയ്ത അതേ എൻവയോൺമെന്റ് വേരിയബിളുകൾ തന്നെ ഉപയോഗിക്കുക. ബ്രൗസർ വേർഷൻ കൃത്യമായി പൊരുത്തപ്പെടണം. ഹെഡഡ് (headed) അല്ലെങ്കിൽ ഹെഡ്‌ലെസ്സ് (headless) ഏത് മോഡിലാണോ ഉപയോഗിക്കുന്നത് അത് തന്നെ ഉപയോഗിക്കുക, കാരണം ഫോക്കസ് ഇവന്റുകൾ (focus events), മീഡിയ ക്വറികൾ (media queries), ഓട്ടോപ്ലേ പോളിസികൾ (autoplay policies) എന്നിവ രണ്ടിനും ഇടയിൽ സൂക്ഷ്മമായ വ്യത്യാസങ്ങൾ ഉണ്ടാകാം. നിങ്ങളുടെ CI ഒരു Docker കണ്ടെയ്നർ ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, അതേ ഇമേജ് തന്നെ ലോക്കലായി റൺ ചെയ്യുക. നിങ്ങളുടെ പേഴ്സണൽ ബ്രൗസർ പ്രൊഫൈൽ പൂർണ്ണമായും നീക്കം ചെയ്യുക.

ലോക്കൽ റീപ്രൊഡക്ഷൻ (local reproduction) ഒടുവിൽ പരാജയപ്പെടുമ്പോൾ, നിങ്ങൾക്ക് യഥാർത്ഥ ഡിബഗ്ഗിംഗ് സെഷൻ ലഭിക്കുന്നു. അതുവരെ, നിങ്ങൾ വെറുതെ നിഴലുകളെ പിന്തുടരുകയാണ്.

ഉറങ്ങുന്നത് നിർത്തി, കാത്തിരിക്കാൻ തുടങ്ങുക

ഒരു ഫ്ലേക്കി ബ്രൗസർ ടെസ്റ്റിന് (flaky browser test) സാധാരണയായി നൽകുന്ന പ്രതികരണം ഡിലേ (delay) ചേർക്കുക എന്നതാണ്. അഞ്ച് സെക്കൻഡ് കാത്തിരിക്കുക. പത്ത് സെക്കൻഡ് കാത്തിരിക്കുക. ഇതൊരു പരിഹാരമല്ല. ഇതൊരു കീഴടങ്ങലാണ്. അനാവശ്യമായ ഡിലേകൾ നിങ്ങളുടെ ടെസ്റ്റ് സ്യൂട്ടിനെ സാവധാനത്തിലാക്കുകയും, തെറ്റായ ആത്മവിശ്വാസം നൽകുകയും ചെയ്യും; കൂടാതെ നെറ്റ്‌വർക്ക് തടസ്സങ്ങൾ ഉണ്ടാകുമ്പോൾ ഇവ പരാജയപ്പെടുകയും ചെയ്യും.

പകരം, സ്റ്റേറ്റിന്റെ (state) തെളിവുകൾക്കായി കാത്തിരിക്കുക. ഒരു ഫോം സബ്മിഷന് ശേഷം ഒരു നോട്ടിഫിക്കേഷൻ വരണമെങ്കിൽ, സമയം കടന്നുപോകുന്നതിനായി കാത്തിരിക്കരുത്. DOM-ൽ ഒരു പ്രത്യേക നോട്ടിഫിക്കേഷൻ ID ഉണ്ടോ എന്ന് നോക്കി കാത്തിരിക്കുക. ഒരു കൗണ്ടർ വർദ്ധിക്കണമെങ്കിൽ, ടെക്സ്റ്റ് മാറുന്നത് വരെ കാത്തിരിക്കുക. ഒരു ലോഡിംഗ് സ്റ്റേറ്റ് ഇന്ററാക്ഷൻ തടയുന്നുണ്ടെങ്കിൽ, ലോഡിംഗ് മാർക്കർ അപ്രത്യക്ഷമാകുന്നതുവരെ കാത്തിരിക്കുക. നിങ്ങൾ ഒരു WebSocket അല്ലെങ്കിൽ server-sent events ഉപയോഗിക്കുകയാണെങ്കിൽ, നെറ്റ്‌വർക്ക് സ്ട്രീം ഒരു പ്രത്യേക ഇവന്റ് ഉൽപ്പാദിപ്പിക്കുന്നത് വരെ കാത്തിരിക്കുക.

എക്സ്പ്ലിസിറ്റ് വെയിറ്റുകൾ (Explicit waits) നിങ്ങളുടെ ടെസ്റ്റിനെ ഒരു ഊഹക്കളിയിൽ നിന്ന് ഒരു കരാറാക്കി മാറ്റുന്നു. ടെസ്റ്റ് പറയുന്നത് ഇതാണ്: "ആപ്ലിക്കേഷൻ തയ്യാറാണെന്ന് സ്ഥിരീകരിച്ചാൽ മാത്രമേ ഞാൻ മുന്നോട്ട് പോകൂ." "മതിയായ സെക്കൻഡുകൾ കഴിഞ്ഞാൽ ഞാൻ മുന്നോട്ട് പോകും" എന്ന് പറയുന്നതിനേക്കാൾ ശക്തമാണ് ഇത്.

ഹൈഡ്രേഷനും (Hydration) അപ്രത്യക്ഷമാകുന്ന ബട്ടണും

ആധുനിക React ആപ്ലിക്കേഷനുകളിൽ, ഹൈഡ്രേഷൻ (hydration) ലോക്കൽ ഡെവ് സെർവറുകൾ പലപ്പോഴും മറച്ചുവെക്കുന്ന ഒരു പ്രത്യേക തരം പരാജയങ്ങൾക്ക് കാരണമാകുന്നു. സെർവർ HTML അയക്കുന്നു. ബ്രൗസറിൽ React പ്രവർത്തിച്ച് ഇവന്റ് ലിസനറുകൾ (event listeners) ഘടിപ്പിക്കുന്നു. ആ സമയത്തിനിടയിൽ നിങ്ങളുടെ ടെസ്റ്റ് ഒരു ബട്ടണിൽ ക്ലിക്ക് ചെയ്തേക്കാം. ഹൈഡ്രേഷൻ സമയത്ത് React ആ DOM നോഡ് മാറ്റുകയോ പുനഃക്രമീകരിക്കുകയോ ചെയ്യുന്നു. നിങ്ങളുടെ ടെസ്റ്റ് ഫ്രെയിംവർക്ക് പിടിച്ചിരുന്ന എലമെന്റ് ഹാൻഡിൽ ഇപ്പോൾ ഒരു ഡിറ്റാച്ച്ഡ് നോഡിലേക്ക് (detached node) വിരൽ ചൂണ്ടുന്നു, തൽഫലമായി നീക്കം ചെയ്ത ഒരു എലമെന്റുമായി ഇടപഴകുന്നു എന്ന എറർ നിങ്ങൾക്ക് ലഭിക്കുന്നു.

കോംപോണന്റ് ട്രീയിലേക്ക് (component tree) ആഴ്ന്നിറങ്ങുന്ന കൂടുതൽ സങ്കീർണ്ണമായ ഒരു സെലക്ടർ (selector) എഴുതുന്നതല്ല ഇതിനുള്ള പരിഹാരം. റെഡിനസ് സിഗ്നലുകൾ (readiness signals) ശ്രദ്ധിക്കുന്നതാണ് പരിഹാരം. ഒരു റൂട്ട് എലമെന്റിന് ഹൈഡ്രേറ്റഡ് അറ്റ്രിബ്യൂട്ട് (hydrated attribute) അല്ലെങ്കിൽ അറിയപ്പെടുന്ന ഒരു ഡാറ്റാ പ്രോപ്പർട്ടി ലഭിക്കുന്നത് വരെ കാത്തിരിക്കുക. ഒരു സ്കെലിറ്റൺ ലോഡർ (skeleton loader) അപ്രത്യക്ഷമാകുന്നതുവരെ കാത്തിരിക്കുക. ഒരു ക്ലയന്റ് സൈഡ് ഇവന്റ് ഹാൻഡ്‌ലർ (client-side event handler) സജീവമാകുന്നതുവരെ കാത്തിരിക്കുക. ക്ലിക്കുകൾ ചെയ്യുന്നതിന് മുമ്പ് ആപ്ലിക്കേഷൻ അത് സ്റ്റേബിൾ ആണെന്ന് അറിയിക്കാൻ അനുവദിക്കുക.

ഒളിഞ്ഞിരിക്കുന്ന കുറ്റവാളികൾ: ഡിപെൻഡൻസികളും തേർഡ് പാർട്ടി സ്ക്രിപ്റ്റുകളും

ചിലപ്പോൾ നിങ്ങളുടെ ആപ്ലിക്കേഷൻ കോഡ് മാറുന്നില്ലെങ്കിലും എൻവയോൺമെന്റ് മാറാം. നിങ്ങളുടെ node_modules-ൽ മൂന്ന് ലെവലുകൾ താഴെയുള്ള ഒരു ചെറിയ യൂട്ടിലിറ്റി ലൈബ്രറിയിലെ ഒരു ട്രാൻസിറ്റീവ് അപ്‌ഡേറ്റ് (transitive update) ബ്രൗസർ പെരുമാറ്റത്തിൽ മാറ്റം വരുത്തിയേക്കാം. പ്രോമിസുകൾ (promises) എങ്ങനെ റിസോൾവ് ചെയ്യുന്നുവെന്നോ, സ്റ്റൈലുകൾ എങ്ങനെ ഇൻജക്റ്റ് ചെയ്യുന്നുവെന്നോ, അല്ലെങ്കിൽ മോക്കുകൾ (mocks) എങ്ങനെ റിക്വസ്റ്റുകൾ തടയുന്നുവെന്നോ ഇത് മാറ്റിയേക്കാം. പതിവ് ഡിപെൻഡൻസി അപ്‌ഡേറ്റിന് ശേഷം ടെസ്റ്റുകൾ പരാജയപ്പെടാൻ തുടങ്ങുമ്പോൾ, നിങ്ങളുടെ പാക്കേജ് മാനേജർ വേർഷനും ലോക്ക് ഫയൽ ചെക്ക്സം (lockfile checksum) ഉം രേഖപ്പെടുത്തുക. കഴിഞ്ഞ ആഴ്ച നിങ്ങൾ കണ്ട അതേ ട്രീ ആണോ ഇപ്പോൾ നോക്കുന്നത് എന്ന് നിങ്ങൾക്ക് അറിയേണ്ടതുണ്ട്.

തേർഡ് പാർട്ടി സ്ക്രിപ്റ്റുകൾ മറ്റൊരു പ്രധാന പ്രശ്നമാണ്. അനലിറ്റിക്സ് ട്രാക്കറുകൾ, പേയ്‌മെന്റ് SDK-കൾ, ചാറ്റ് വിഡ്ജറ്റുകൾ എന്നിവ അസിൻക്രണസ് ആയി (asynchronously) ലോഡ് ആകുന്നു. അവ ഐഫ്രെയിമുകൾ (iframes) ഇൻജക്റ്റ് ചെയ്യുകയോ, ലേഔട്ട് മാറ്റുകയോ, അല്ലെങ്കിൽ നിങ്ങളുടെ ടെസ്റ്റ് പ്രതീക്ഷിക്കാത്ത സമയത്ത് ഫോക്കസ് മാറ്റുകയോ ചെയ്തേക്കാം. CI-യിൽ, ഈ സ്ക്രിപ്റ്റുകൾ സാവധാനം ലോഡ് ചെയ്തേക്കാം, അല്ലെങ്കിൽ നെറ്റ്‌വർക്ക് നിയന്ത്രണങ്ങൾ കാരണം അവ ലോഡ് ആകാതിരിക്കുകയും ചെയ്യാം, ഇത് നിങ്ങളുടെ ആപ്ലിക്കേഷൻ മറ്റൊരു എറർ ഹാൻഡ്‌ലിംഗ് പാത പിന്തുടരാൻ കാരണമാകും. ഏതെല്ലാം തേർഡ് പാർട്ടി റിസോഴ്‌സുകളാണ് ലോഡ് ആയതെന്നും അവയുടെ HTTP സ്റ്റാറ്റസ് എന്താണെന്നും ലോഗ് ചെയ്യുക. CI-യിൽ ഒരു പേയ്‌മെന്റ് ഐഫ്രെയിം ലോഡ് ആകാൻ മൂന്ന് സെക്കൻഡ് എടുക്കുമ്പോൾ നിങ്ങളുടെ വേഗതയേറിയ ലോക്കൽ കണക്ഷനിൽ അത് ഉടൻ ലോഡ് ആകുന്നുണ്ടെങ്കിൽ, നിങ്ങളുടെ "element not clickable" എന്ന എററിന് പെട്ടെന്ന് ഒരു കാരണം ലഭിക്കുന്നു.

കൂടാതെ "element not clickable" എന്നത് ഒരിക്കലും ഒരു രോഗനിർണ്ണയമല്ല. അതൊരു ലക്ഷണമാണ്. കാരണത്തെ ചികിത്സിക്കുക.

ഒരു എവിഡൻസ് കിറ്റ് (Evidence Kit) നിർമ്മിക്കുക

ഓരോ CI പരാജയവും നടപടിയെടുക്കാൻ കഴിയുന്നതാകണം (actionable). ഒരു സ്റ്റാക്ക് ട്രാസ് (stack trace) മാത്രം മതിയാകില്ല. മറ്റൊരു എഞ്ചിനീയർക്കോ അല്ലെങ്കിൽ അടുത്ത മാസം നിങ്ങളോ നടന്ന കാര്യങ്ങൾ പുനർനിർമ്മിക്കാൻ സഹായിക്കുന്ന ഒരു എവിഡൻസ് കിറ്റ് നിങ്ങൾക്ക് ആവശ്യമാണ്.

പരാജയപ്പെട്ട റണ്ണിൽ നിന്നുള്ള സ്ക്രീൻഷോട്ടുകളും വീഡിയോ റെക്കോർഡിംഗുകളും സൂക്ഷിക്കുക. ബ്രൗസർ കൺസോൾ ഔട്ട്‌പുട്ട് പൂർണ്ണമായും ക്യാപ്‌ചർ ചെയ്യുക, എററുകൾ മാത്രമല്ല, വാർണിംഗുകളും കൂടി ഉൾപ്പെടുത്തുക. 404s, CORS റിജക്ഷനുകൾ, ഡ്രോപ്പ് ചെയ്ത കണക്ഷനുകൾ എന്നിവയുൾപ്പെടെയുള്ള നെറ്റ്‌വർക്ക് പരാജയങ്ങൾ ലോഗ് ചെയ്യുക. ആ സമയത്ത് സജീവമായിരുന്ന ബിൽഡ് ഐഡികളും (build IDs) ഫീച്ചർ ഫ്ലാഗുകളും (feature flags) സംരക്ഷിക്കുക. അസർഷൻ (assertion) പരാജയപ്പെട്ട കൃത്യസമയത്ത് ഒരു DOM സ്നാപ്പ്ഷോട്ട് എടുക്കുക. ഒരു സ്നാപ്പ്ഷോട്ട് ഉപയോഗിച്ച് നിങ്ങൾക്ക് സംഭവത്തിന് ശേഷം HTML ഘടന പരിശോധിക്കാം, rather