ఇది ఒక Slack మెసేజ్‌తో మొదలవుతుంది. బిల్డ్ రెడ్‌గా (red) ఉంది. మీరు ఫెయిల్యూర్స్‌ను స్క్రోల్ చేస్తారు, ముఖం చిట్లించి, మీ లాప్‌టాప్‌లో అదే టెస్ట్‌ను మళ్ళీ రన్ చేస్తారు. గ్రీన్ (Green). మీరు CI జాబ్‌ను మళ్ళీ ప్రయత్నిస్తారు. బహుశా అది ఏదో చిన్న పొరపాటు కావచ్చు అని అనుకుంటారు. కానీ ఆ ఫెయిల్యూర్ మళ్ళీ మళ్ళీ వస్తూనే ఉంది; సర్వర్‌లో అది పదేపదే జరుగుతోంది కానీ మీకు మాత్రం కనిపించడం లేదు.

CIలో పాస్ అయ్యి, లోకల్‌లో ఫెయిల్ అయ్యే బ్రౌజర్ టెస్ట్ అనేది కేవలం ఒక ఇబ్బంది మాత్రమే కాదు. అది నమ్మకాన్ని తగ్గిస్తుంది. టీమ్‌లు టైమింగ్‌ను నిందించడం ప్రారంభిస్తాయి. వారు తాత్కాలిక పరిష్కారాలను (temporary fixes) అమలు చేస్తారు, అవి ఎప్పటికీ అలాగే ఉండిపోతాయి. ఇక్కడ ఒక setTimeout, అక్కడ ఒక .wait(5000). టెస్ట్ సూట్ నెమ్మదిస్తుంది. ఫెయిల్యూర్లు మళ్ళీ మళ్ళీ వస్తూనే ఉంటాయి. ఆ ఫ్లేకీ (flaky) టెస్టులు శాశ్వత సమస్యలుగా మారిపోతాయి, మరియు చివరికి ప్రతి ఒక్కరూ రెడ్ పైప్‌లైన్‌ను ఒక సాధారణ శబ్దంగా (background noise) పరిగణించడం ప్రారంభిస్తారు.

అది ప్రమాదకరం. నమ్మదగని హెచ్చరికలు చేసే టెస్ట్ సూట్ మీకు వద్దు.

CI పాడైపోలేదు; అది కేవలం భిన్నంగా ఉంటుంది

CI ఎన్విరాన్‌మెంట్లు యాదృచ్ఛికమైనవి కావు. అవి నిర్దిష్టమైనవి (deterministic). సమస్య ఏమిటంటే, అవి మీ MacBook లేదా మీ Linux వర్క్‌స్టేషన్ కాని ఒక సిస్టమ్ గురించి నిర్దిష్టంగా ఉంటాయి. మీ లోకల్ సెటప్ కొన్ని తేడాలను దాచిపెడుతుంది, కానీ ఒక క్లీన్ CI రన్నర్ వాటిని వెంటనే బయటపెడుతుంది.

ఎన్ని అంశాలు (moving parts) ఒకదానికొకటి భిన్నంగా మారుతున్నాయో ఆలోచించండి. మీ లోకల్ మెషీన్ 'hot module reloading'తో కూడిన డెవలప్‌మెంట్ సర్వర్‌ను రన్ చేయవచ్చు, అదే సమయంలో CI, tree shaking మరియు minificationతో కూడిన ప్రొడక్షన్ ఆర్టిఫాక్ట్‌ను బిల్డ్ చేస్తుంది. అది మాత్రమే కోడ్ పాత్‌లను తొలగించగలదు లేదా ఎగ్జిక్యూషన్ ఆర్డర్‌ను మార్చగలదు. డిపెండెన్సీ ట్రీలు (Dependency trees) మారుతాయి. ప్యాకేజీ మేనేజర్ వెర్షన్ ఒక చిన్న రిలీజ్ తేడా ఉన్నా, ఒకేలా కనిపించే lockfile కూడా భిన్నంగా రిజాల్వ్ కావచ్చు. నెట్‌వర్క్ క్రమాలు మారుతాయి. మీ ఆఫీస్ Wi-Fi ఒకేసారి స్టేజింగ్ APIని రిజాల్వ్ చేయవచ్చు; కానీ CI రన్నర్ లోడ్ బ్యాలెన్సర్ వెనుక ఉన్న వేరే క్లస్టర్‌ను హిట్ చేయవచ్చు, దీనివల్ల మీకు ఎప్పుడూ తెలియని లాటెన్సీ (latency) ఏర్పడవచ్చు.

బ్రౌజర్‌లు కూడా వివిధ ఎన్విరాన్‌మెంట్‌లలో భిన్నంగా ప్రవర్తిస్తాయి. మీ లోకల్ Chromeలో ఎక్స్‌టెన్షన్లు, క్యాష్ చేయబడిన క్రెడెన్షియల్స్, పర్సిస్టెంట్ లోకల్ స్టోరేజ్ మరియు హార్డ్‌వేర్ యాక్సిలరేషన్‌తో కూడిన GPU ఉంటాయి. CI ప్రతి రన్‌లో ఒక ఖాళీ ప్రొఫైల్‌తో ప్రారంభమవుతుంది. బ్రౌజర్ లైఫ్‌సైకిల్స్ భిన్నంగా ఉంటాయి. రెండరింగ్ పాత్‌లు భిన్నంగా ఉంటాయి. మీ సిస్టమ్‌లో ఉన్న ఫాంట్‌లు CIలో భిన్నమైన వాటితో భర్తీ చేయబడవచ్చు. వ్యూపోర్ట్ సైజింగ్ (Viewport sizing) మరియు డివైజ్ పిక్సెల్ రేషియోలు మారుతుంటాయి, ఇది రెస్పాన్సివ్ బ్రేక్‌పాయింట్‌లను మార్చవచ్చు లేదా లేజీ-లోడింగ్ (lazy-loading) ప్రవర్తనను మార్చవచ్చు.

ఈ తేడాలు నిజమైనవి. ఇవి యాంత్రికమైనవి. ఇవి యాదృచ్ఛికంగా (random) జరుగుతున్నాయని నమ్మడం వల్ల సమస్య పరిష్కారం కాదు.

ప్రివ్యూ ఎన్విరాన్‌మెంట్లు తప్పుదారి పట్టిస్తాయి

ప్రివ్యూ ఎన్విరాన్‌మెంట్లు ఈ సమస్యను మరింత క్లిష్టతరం చేస్తాయి. అవి మానవ సమీక్షకు ఉపయోగపడతాయి కానీ, అవి ప్రొడక్షన్ కాదు. అవి తరచుగా నిజమైన API హోస్ట్‌కు బదులుగా api-stagingను సూచిస్తాయి. ఫీచర్ ఫ్లాగ్స్ (Feature flags) ప్రతి ప్రయోగం కోసం 'true'గా ఉంటాయి, దీనివల్ల ప్రొడక్షన్‌లో అమలు చేయబడే కండిషనల్ లాజిక్ దాగిపోతుంది. అథెంటికేషన్ ఒక స్టెప్‌ను స్కిప్ చేయవచ్చు లేదా ఒక మాక్ టోకెన్‌ను (mock token) ఇన్‌జెక్ట్ చేయవచ్చు. కుకీలు రిలాక్స్‌డ్ పాలసీలను ఉపయోగించవచ్చు. డేటాసెట్ కేవలం పది వరుసలు మాత్రమే ఉండవచ్చు, పదివేల వరుసలు కాకపోవచ్చు, దీనివల్ల పేజినేషన్, సెర్చ్ ర్యాంకింగ్ లేదా వర్చువలైజేషన్ లాజిక్ ఎప్పుడూ పరీక్షించబడదు.

మీ టెస్ట్ ప్రివ్యూ URLలో పాస్ అయ్యి, ప్రొడక్షన్‌లో ఫెయిల్ అయితే, లేదా దీనికి విరుద్ధంగా జరిగితే, సమస్య టెస్ట్‌లో లేదు, ఎన్విరాన్‌మెంట్‌లో ఉంది.

ఊహించే ముందు లాగ్ (Log) చేయండి

ఫెయిల్యూర్ మొదటిసారి కనిపించినప్పుడు, వెంటనే టెస్ట్‌ను మార్చి సరిపోతుందని ఆశించకండి. ఊహించడం ఆపండి. పాస్ అయిన రన్‌ను, ఫెయిల్ అయిన రన్‌తో పోల్చడానికి మీరు ఆ సందర్భాన్ని (context) ఖచ్చితంగా నమోదు చేయాలి.

స్పష్టంగా కనిపిస్తున్న కారణాలను లాగ్ చేయండి. ఫెయిల్యూర్ జరిగిన సమయంలో పేజీ URL, బిల్డ్ ID, మరియు కమిట్ SHAను రికార్డ్ చేయండి. యాక్టివ్ ఫీచర్ ఫ్లాగ్స్‌ను గమనించండి. API హోస్ట్, ఖచ్చితమైన బ్రౌజర్ వెర్షన్ మరియు వ్యూపోర్ట్ సైజును కూడా నమోదు చేయండి. ఈ వివరాలు ఒక రహస్యమైన ఫెయిల్యూర్‌ను మళ్ళీ పునరావృతం చేయగల (reproducible) పరిస్థితిగా మారుస్తాయి.

కేవలం స్క్రీన్‌షాట్‌లపై మాత్రమే ఆధారపడకండి. రెండు పేజీలు చూడటానికి ఒకేలా ఉన్నప్పటికీ, అవి పూర్తిగా వేర్వేరు జావాస్క్రిప్ట్‌ను రన్ చేయవచ్చు. CI బండిల్‌లో అదనపు పాలిఫిల్ (polyfill) చేర్చబడిందని లేదా లోకల్ బండిల్ మీ బ్రౌజర్ క్యాష్‌లో ఉన్నందున ఒక చంక్‌ను స్కిప్ చేసిందని స్క్రీన్‌షాట్ మీకు చెప్పలేదు.

అలాగే, DevTools ఓపెన్ చేయడం వల్ల టైమింగ్ మారుతుందని గుర్తుంచుకోండి. DevTools గార్బేజ్ కలెక్షన్‌ను ఆలస్యం చేయవచ్చు, నెట్‌వర్క్ ప్రాధాన్యతలను మార్చవచ్చు మరియు కొన్ని రెండరింగ్ ఆప్టిమైజేషన్‌లను నిలిపివేయవచ్చు. మీరు DOMను పరిశీలిస్తున్నప్పుడు పాస్ అయ్యే టెస్ట్, మీరు ప్యానెల్‌ను మూసివేసి హెడ్‌లెస్ (headless) మోడ్‌లో రన్ చేసిన వెంటనే ఫెయిల్ కావచ్చు. డీబగ్గర్ ఒక ఉపయోగకరమైన సాధనం, కానీ అది తటస్థ పరిశీలకుడు కాదు.

నేర స్థలాన్ని (Crime Scene) మళ్ళీ సృష్టించండి

మీరు ఫెయిల్యూర్‌ను ఖచ్చితంగా రీప్రొడ్యూస్ చేయాలనుకుంటే, కేవలం మీ లోకల్ డెవలప్‌మెంట్ సర్వర్‌ను రన్ చేసి ఫలితం కోసం ఎదురుచూడలేరు. మీరు the_CI's_ ఖచ్చితమైన పరిస్థితులను అనుకరించాలి.

CI ఉత్పత్తి చేసిన ఖచ్చితమైన ఆర్టిఫ్యాక్ట్‌ను (artifact) బిల్డ్ చేయండి. అవసరమైతే దానిని డౌన్‌లోడ్ చేసుకోండి. ఆ ఆర్టిఫ్యాక్ట్‌ను Vite లేదా Webpack డెవ్ మిడిల్‌వేర్‌తో కాకుండా, ఒక సాధారణ స్టాటిక్ ఫైల్ సర్వర్‌తో లోకల్‌గా సర్వ్ చేయండి. CI ఇంజెక్ట్ చేసిన అదే ఎన్విరాన్‌మెంట్ వేరియబుల్స్‌ను ఉపయోగించండి. బ్రౌజర్ వెర్షన్‌ను ఖచ్చితంగా మ్యాచ్ చేయండి. దానిని అదే మోడ్‌లో (headed లేదా headless) రన్ చేయండి, ఎందుకంటే ఫోకస్ ఈవెంట్‌లు, మీడియా క్వెరీస్ మరియు ఆటోప్లే పాలసీలు ఈ రెండింటి మధ్య సూక్ష్మమైన మార్గాల్లో భిన్నంగా ఉంటాయి. మీ CI ఒక Docker కంటైనర్‌ను ఉపయోగిస్తుంటే, అదే ఇమేజ్‌ను లోకల్‌గా రన్ చేయండి. మీ వ్యక్తిగత బ్రౌజర్ ప్రొఫైల్‌ను పూర్తిగా తొలగించండి.

లోకల్ రీప్రొడక్షన్ (reproduction) చివరకు ఫెయిల్ అయినప్పుడు, మీకు నిజమైన డీబగ్గింగ్ సెషన్ లభిస్తుంది. అంతవరకు, మీరు కేవలం నీడలను వెంటాడుతున్నట్లే.

నిద్రపోవడం ఆపి, వేచి ఉండటం ప్రారంభించండి

ఫ్లేకీ (flaky) బ్రౌజర్ టెస్ట్‌కు అత్యంత సాధారణ స్పందన ఏమిటంటే ఆలస్యాన్ని (delay) జోడించడం. ఐదు సెకన్లు ఆగండి. పది సెకన్లు ఆగండి. ఇది పరిష్కారం కాదు. ఇది లొంగిపోవడం. ఇష్టానుసారంగా ఇచ్చే ఈ ఆలస్యాలు మీ టెస్ట్ సూట్‌ను నెమ్మదింపజేస్తాయి, తప్పుడు నమ్మకాన్ని కలిగిస్తాయి మరియు నెట్‌వర్క్ సమస్యలు వచ్చినప్పుడు లోడ్ కింద ఇంకా ఫెయిల్ అవుతాయి.

దానికి బదులుగా, స్టేట్ (state) యొక్క ఆధారాల కోసం వేచి ఉండండి. ఒక ఫారమ్ సబ్మిషన్ తర్వాత నోటిఫికేషన్ రావాల్సి ఉంటే, సమయం గడిచే వరకు వేచి ఉండకండి. DOMలో ఒక నిర్దిష్ట నోటిఫికేషన్ ID ఉండటం కోసం వేచి ఉండండి. ఒక కౌంటర్ పెరగాల్సి ఉంటే, టెక్స్ట్ విలువ మారే వరకు వేచి ఉండండి. లోడింగ్ స్టేట్ ఇంటరాక్షన్‌ను