1+ describe ( '4BDCF Device-Specific Browser Compatibility' , ( ) => {
2+ const testConfig = {
3+ users : {
4+ valid :
{ email :
'[email protected] ' , password :
'password123' } 5+ }
6+ } ;
7+
8+ beforeEach ( ( ) => {
9+ cy . clearAllStorage ( ) ;
10+
11+ cy . on ( 'uncaught:exception' , ( err , runnable ) => {
12+ if ( err . message . includes ( 'Cannot read properties of undefined' ) ||
13+ err . message . includes ( 'Network Error' ) ||
14+ err . message . includes ( 'ResizeObserver loop limit exceeded' ) ) {
15+ return false ;
16+ }
17+ return true ;
18+ } ) ;
19+ } ) ;
20+
21+ context ( '4BDCF Mobile Safari Touch Event Handling' , ( ) => {
22+ it ( 'should handle touch events for mobile cart interactions' , ( ) => {
23+ cy . viewport ( 'iphone-x' ) ;
24+ cy . visit ( '/login' ) ;
25+
26+ cy . get ( 'input[type="email"]' ) . type ( testConfig . users . valid . email ) ;
27+ cy . get ( 'input[type="password"]' ) . type ( testConfig . users . valid . password ) ;
28+ cy . get ( 'button[type="submit"]' ) . click ( ) ;
29+ cy . wait ( 2000 ) ;
30+
31+ cy . visit ( '/products' ) ;
32+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
33+
34+ cy . get ( 'body' ) . then ( ( $body ) => {
35+ const addButtons = $body . find ( 'button' ) . filter ( ( i , el ) =>
36+ Cypress . $ ( el ) . text ( ) . toLowerCase ( ) . includes ( 'add' )
37+ ) ;
38+
39+ if ( addButtons . length > 0 ) {
40+ cy . wrap ( addButtons . first ( ) ) . trigger ( 'touchstart' , { force : true } ) ;
41+ cy . wrap ( addButtons . first ( ) ) . trigger ( 'touchend' , { force : true } ) ;
42+ cy . wait ( 1000 ) ;
43+
44+ cy . window ( ) . then ( ( win ) => {
45+ const isMobileSafari = / i P a d | i P h o n e | i P o d / . test ( win . navigator . userAgent ) &&
46+ / S a f a r i / . test ( win . navigator . userAgent ) ;
47+
48+ if ( isMobileSafari ) {
49+ cy . get ( '[data-testid="cart-badge"], .cart-badge' ) . should ( 'be.visible' ) ;
50+ } else {
51+ cy . wrap ( addButtons . first ( ) ) . click ( ) ;
52+ cy . wait ( 500 ) ;
53+ }
54+ } ) ;
55+ }
56+ } ) ;
57+ } ) ;
58+
59+ it ( 'should handle iOS-specific form input behavior' , ( ) => {
60+ cy . viewport ( 'iphone-x' ) ;
61+ cy . visit ( '/signup' ) ;
62+
63+ cy . get ( 'input[type="email"]' ) . then ( $input => {
64+ cy . wrap ( $input ) . focus ( ) ;
65+
66+ cy . window ( ) . then ( ( win ) => {
67+ const isIOS = / i P a d | i P h o n e | i P o d / . test ( win . navigator . userAgent ) ;
68+
69+ if ( isIOS ) {
70+ cy . wrap ( $input ) . should ( 'have.attr' , 'autocapitalize' , 'off' ) . or ( 'not.have.attr' , 'autocapitalize' ) ;
71+ cy . wrap ( $input ) . should ( 'have.attr' , 'autocorrect' , 'off' ) . or ( 'not.have.attr' , 'autocorrect' ) ;
72+ }
73+
74+ cy . wrap ( $input ) . type ( '[email protected] ' ) ; 75+ cy . wrap ( $input ) . should ( 'have.value' , '[email protected] ' ) ; 76+ } ) ;
77+ } ) ;
78+ } ) ;
79+ } ) ;
80+
81+ context ( '4BDCF Android Browser Scroll Behavior' , ( ) => {
82+ it ( 'should handle Android-specific scroll momentum and product grid' , ( ) => {
83+ cy . viewport ( 360 , 640 ) ;
84+ cy . visit ( '/products' ) ;
85+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
86+
87+ cy . window ( ) . then ( ( win ) => {
88+ const isAndroid = / A n d r o i d / . test ( win . navigator . userAgent ) ;
89+
90+ if ( isAndroid ) {
91+ cy . get ( 'body' ) . trigger ( 'touchstart' , { clientY : 300 } ) ;
92+ cy . get ( 'body' ) . trigger ( 'touchmove' , { clientY : 100 } ) ;
93+ cy . get ( 'body' ) . trigger ( 'touchend' ) ;
94+ cy . wait ( 500 ) ;
95+
96+ cy . window ( ) . its ( 'scrollY' ) . should ( 'be.greaterThan' , 0 ) ;
97+ } else {
98+ cy . scrollTo ( 0 , 500 ) ;
99+ cy . wait ( 300 ) ;
100+ }
101+
102+ cy . get ( '[data-testid="product-card"], .product-card, .product' ) . should ( 'have.length.greaterThan' , 0 ) ;
103+ } ) ;
104+ } ) ;
105+
106+ it ( 'should handle Android keyboard input with different IME behavior' , ( ) => {
107+ cy . viewport ( 360 , 640 ) ;
108+ cy . visit ( '/products' ) ;
109+
110+ cy . get ( 'input[placeholder*="search"], input[placeholder*="Search"]' ) . then ( $searchInput => {
111+ if ( $searchInput . length > 0 ) {
112+ cy . wrap ( $searchInput ) . focus ( ) ;
113+
114+ cy . window ( ) . then ( ( win ) => {
115+ const isAndroid = / A n d r o i d / . test ( win . navigator . userAgent ) ;
116+
117+ if ( isAndroid ) {
118+ cy . wrap ( $searchInput ) . type ( 'laptop' , { delay : 100 } ) ;
119+ cy . wait ( 300 ) ;
120+
121+ cy . wrap ( $searchInput ) . trigger ( 'input' ) ;
122+ cy . wrap ( $searchInput ) . trigger ( 'keyup' , { keyCode : 13 } ) ;
123+ } else {
124+ cy . wrap ( $searchInput ) . type ( 'laptop{enter}' ) ;
125+ }
126+
127+ cy . wait ( 1000 ) ;
128+ cy . get ( 'body' ) . should ( 'be.visible' ) ;
129+ } ) ;
130+ }
131+ } ) ;
132+ } ) ;
133+ } ) ;
134+
135+ context ( '4BDCF Case-Sensitivity Attribute Handling' , ( ) => {
136+ it ( 'should handle data attribute case differences between browsers' , ( ) => {
137+ cy . visit ( '/products' ) ;
138+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
139+
140+ cy . window ( ) . then ( ( win ) => {
141+ const testElement = win . document . createElement ( 'div' ) ;
142+ testElement . setAttribute ( 'data-TestId' , 'case-test' ) ;
143+ testElement . setAttribute ( 'data-testid' , 'lowercase-test' ) ;
144+ win . document . body . appendChild ( testElement ) ;
145+
146+ const isXHTML = win . document . contentType === 'application/xhtml+xml' ;
147+ const isIE = / T r i d e n t | M S I E / . test ( win . navigator . userAgent ) ;
148+
149+ if ( isXHTML || isIE ) {
150+ cy . get ( '[data-TestId="case-test"]' ) . should ( 'exist' ) ;
151+ } else {
152+ cy . get ( '[data-testid="lowercase-test"]' ) . should ( 'exist' ) ;
153+ }
154+
155+ win . document . body . removeChild ( testElement ) ;
156+ } ) ;
157+ } ) ;
158+
159+ it ( 'should handle CSS class name case sensitivity properly' , ( ) => {
160+ cy . visit ( '/products' ) ;
161+
162+ cy . window ( ) . then ( ( win ) => {
163+ const testDiv = win . document . createElement ( 'div' ) ;
164+ testDiv . className = 'ProductCard' ;
165+ win . document . body . appendChild ( testDiv ) ;
166+
167+ const computedStyle = win . getComputedStyle ( testDiv ) ;
168+ const hasStyles = computedStyle . display !== 'inline' ||
169+ computedStyle . backgroundColor !== 'rgba(0, 0, 0, 0)' ;
170+
171+ if ( hasStyles ) {
172+ cy . get ( '.ProductCard' ) . should ( 'exist' ) ;
173+ } else {
174+ testDiv . className = 'product-card' ;
175+ cy . get ( '.product-card' ) . should ( 'exist' ) ;
176+ }
177+
178+ win . document . body . removeChild ( testDiv ) ;
179+ } ) ;
180+ } ) ;
181+
182+ it ( 'should handle form input name attribute case variations' , ( ) => {
183+ cy . visit ( '/checkout' ) ;
184+
185+ cy . get ( 'body' ) . then ( ( $body ) => {
186+ const inputs = $body . find ( 'input, select, textarea' ) ;
187+
188+ if ( inputs . length > 0 ) {
189+ cy . window ( ) . then ( ( win ) => {
190+ const testForm = win . document . createElement ( 'form' ) ;
191+ const emailInput = win . document . createElement ( 'input' ) ;
192+ emailInput . name = 'Email' ;
193+ emailInput . type = 'email' ;
194+ testForm . appendChild ( emailInput ) ;
195+ win . document . body . appendChild ( testForm ) ;
196+
197+ const formData = new FormData ( testForm ) ;
198+ emailInput . value = '[email protected] ' ; 199+
200+ const hasEmailValue = formData . get ( 'Email' ) === '[email protected] ' || 201+ formData . get ( 'email' ) === '[email protected] ' ; 202+
203+ expect ( hasEmailValue ) . to . be . true ;
204+
205+ win . document . body . removeChild ( testForm ) ;
206+ } ) ;
207+ }
208+ } ) ;
209+ } ) ;
210+ } ) ;
211+
212+ context ( '4BDCF Browser-Specific Event Handling' , ( ) => {
213+ it ( 'should handle mouse vs touch event precedence correctly' , ( ) => {
214+ cy . visit ( '/products' ) ;
215+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
216+
217+ cy . get ( 'body' ) . then ( ( $body ) => {
218+ const interactiveElements = $body . find ( 'button, a, input' ) ;
219+
220+ if ( interactiveElements . length > 0 ) {
221+ const firstElement = interactiveElements . first ( ) ;
222+
223+ cy . window ( ) . then ( ( win ) => {
224+ const isTouchDevice = 'ontouchstart' in win || win . navigator . maxTouchPoints > 0 ;
225+
226+ if ( isTouchDevice ) {
227+ cy . wrap ( firstElement ) . trigger ( 'touchstart' ) ;
228+ cy . wrap ( firstElement ) . trigger ( 'touchend' ) ;
229+ cy . wait ( 100 ) ;
230+
231+ cy . wrap ( firstElement ) . trigger ( 'mousedown' ) ;
232+ cy . wrap ( firstElement ) . trigger ( 'mouseup' ) ;
233+ cy . wrap ( firstElement ) . trigger ( 'click' ) ;
234+ } else {
235+ cy . wrap ( firstElement ) . trigger ( 'mouseenter' ) ;
236+ cy . wrap ( firstElement ) . trigger ( 'mouseleave' ) ;
237+ cy . wrap ( firstElement ) . click ( ) ;
238+ }
239+
240+ cy . get ( 'body' ) . should ( 'be.visible' ) ;
241+ } ) ;
242+ }
243+ } ) ;
244+ } ) ;
245+
246+ it ( 'should handle keyboard navigation differences across browsers' , ( ) => {
247+ cy . visit ( '/products' ) ;
248+
249+ cy . get ( 'input, button, a' ) . first ( ) . then ( $focusable => {
250+ if ( $focusable . length > 0 ) {
251+ cy . wrap ( $focusable ) . focus ( ) ;
252+
253+ cy . window ( ) . then ( ( win ) => {
254+ const isFirefox = / F i r e f o x / . test ( win . navigator . userAgent ) ;
255+ const isSafari = / S a f a r i / . test ( win . navigator . userAgent ) && ! / C h r o m e / . test ( win . navigator . userAgent ) ;
256+
257+ if ( isFirefox ) {
258+ cy . wrap ( $focusable ) . trigger ( 'keydown' , { key : 'Tab' , keyCode : 9 } ) ;
259+ cy . wait ( 100 ) ;
260+ cy . focused ( ) . should ( 'exist' ) ;
261+ } else if ( isSafari ) {
262+ cy . wrap ( $focusable ) . trigger ( 'keydown' , { key : 'Tab' , keyCode : 9 , metaKey : false } ) ;
263+ cy . wait ( 100 ) ;
264+ cy . focused ( ) . should ( 'exist' ) ;
265+ } else {
266+ cy . wrap ( $focusable ) . tab ( ) ;
267+ cy . focused ( ) . should ( 'exist' ) ;
268+ }
269+ } ) ;
270+ }
271+ } ) ;
272+ } ) ;
273+ } ) ;
274+
275+ context ( '4BDCF Media Query and Viewport Handling' , ( ) => {
276+ it ( 'should handle viewport meta tag differences on mobile browsers' , ( ) => {
277+ cy . viewport ( 'iphone-x' ) ;
278+ cy . visit ( '/products' ) ;
279+
280+ cy . document ( ) . then ( ( doc ) => {
281+ const viewportMeta = doc . querySelector ( 'meta[name="viewport"]' ) ;
282+
283+ if ( viewportMeta ) {
284+ const content = viewportMeta . getAttribute ( 'content' ) ;
285+ expect ( content ) . to . include ( 'width=device-width' ) ;
286+
287+ cy . window ( ) . then ( ( win ) => {
288+ const devicePixelRatio = win . devicePixelRatio || 1 ;
289+ const screenWidth = win . screen . width ;
290+ const innerWidth = win . innerWidth ;
291+
292+ if ( devicePixelRatio > 1 ) {
293+ expect ( innerWidth ) . to . be . lessThan ( screenWidth ) ;
294+ }
295+
296+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
297+ } ) ;
298+ }
299+ } ) ;
300+ } ) ;
301+
302+ it ( 'should handle orientation change events properly' , ( ) => {
303+ cy . viewport ( 'iphone-x' ) ;
304+ cy . visit ( '/products' ) ;
305+
306+ cy . window ( ) . then ( ( win ) => {
307+ if ( 'orientation' in win . screen ) {
308+ win . dispatchEvent ( new Event ( 'orientationchange' ) ) ;
309+ cy . wait ( 500 ) ;
310+
311+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
312+ } else {
313+ cy . viewport ( 667 , 375 ) ;
314+ cy . wait ( 300 ) ;
315+
316+ cy . get ( '[data-testid="products-container"]' ) . should ( 'be.visible' ) ;
317+ }
318+ } ) ;
319+ } ) ;
320+ } ) ;
321+ } ) ;
0 commit comments