Fix touch state not being activated in iOS Safari
This commit resolves the issue with the `:active` pseudo-class not
activating in mobile Safari on iOS devices. It introduces a workaround
specifically for mobile Safari on iOS/iPadOS to enable the `:active`
pseudo-class. This ensures a consistent and responsive user interface
in response to touch states on mobile Safari.
Other supporting changes:
- Introduce new test utility functions such as `createWindowEventSpies`
and `formatAssertionMessage` to improve code reusability and
maintainability.
- Improve browser detection:
- Add detection for iPadOS and Windows 10 Mobile.
- Add touch support detection to correctly determine iPadOS vs macOS.
- Fix misidentification of some Windows 10 Mobile platforms as Windows
Phone.
- Improve test coverage and refactor tests.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { BrowserTouchSupportAccessor, isTouchEnabledDevice } from '@/infrastructure/RuntimeEnvironment/TouchSupportDetection';
|
||||
|
||||
describe('TouchSupportDetection', () => {
|
||||
describe('isTouchEnabledDevice', () => {
|
||||
const testScenarios: ReadonlyArray<{
|
||||
readonly description: string;
|
||||
readonly accessor: BrowserTouchSupportAccessor;
|
||||
readonly expectedTouch: boolean;
|
||||
}> = [
|
||||
{
|
||||
description: 'detects no touch capabilities',
|
||||
accessor: createMockAccessor(),
|
||||
expectedTouch: false,
|
||||
},
|
||||
{
|
||||
description: 'detects touch capability with defined document.ontouchend',
|
||||
accessor: createMockAccessor({ documentOntouchend: () => 'not-undefined' }),
|
||||
expectedTouch: true,
|
||||
},
|
||||
{
|
||||
description: 'detects touch capability with navigator.maxTouchPoints > 0',
|
||||
accessor: createMockAccessor({ navigatorMaxTouchPoints: () => 1 }),
|
||||
expectedTouch: true,
|
||||
},
|
||||
{
|
||||
description: 'detects touch capability when matchMedia for pointer coarse is true',
|
||||
accessor: createMockAccessor({
|
||||
windowMatchMediaMatches: (query: string) => {
|
||||
return query === '(any-pointer: coarse)';
|
||||
},
|
||||
}),
|
||||
expectedTouch: true,
|
||||
},
|
||||
{
|
||||
description: 'detects touch capability with defined window.TouchEvent',
|
||||
expectedTouch: true,
|
||||
accessor: createMockAccessor({ windowTouchEvent: () => class {} }),
|
||||
},
|
||||
];
|
||||
testScenarios.forEach(({ description, accessor, expectedTouch }) => {
|
||||
it(`${description} - returns ${expectedTouch}`, () => {
|
||||
// act
|
||||
const isTouchDetected = isTouchEnabledDevice(accessor);
|
||||
// assert
|
||||
expect(isTouchDetected).to.equal(expectedTouch);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createMockAccessor(
|
||||
touchSupportFeatures: Partial<BrowserTouchSupportAccessor> = {},
|
||||
): BrowserTouchSupportAccessor {
|
||||
const defaultTouchSupport: BrowserTouchSupportAccessor = {
|
||||
navigatorMaxTouchPoints: () => undefined,
|
||||
windowMatchMediaMatches: () => false,
|
||||
documentOntouchend: () => undefined,
|
||||
windowTouchEvent: () => undefined,
|
||||
};
|
||||
return {
|
||||
...defaultTouchSupport,
|
||||
...touchSupportFeatures,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user