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:
7
tests/shared/FormatAssertionMessage.ts
Normal file
7
tests/shared/FormatAssertionMessage.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function formatAssertionMessage(lines: readonly string[]) {
|
||||
return [ // Using many newlines so `vitest` output looks good
|
||||
'\n---',
|
||||
...lines,
|
||||
'---\n\n',
|
||||
].join('\n');
|
||||
}
|
||||
67
tests/shared/Spies/WindowEventSpies.ts
Normal file
67
tests/shared/Spies/WindowEventSpies.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export type EventName = keyof WindowEventMap;
|
||||
|
||||
export function createWindowEventSpies(restoreCallback: (restoreFunc: () => void) => void) {
|
||||
const originalAddEventListener = window.addEventListener;
|
||||
const originalRemoveEventListener = window.removeEventListener;
|
||||
|
||||
const currentListeners = new Array<Parameters<typeof window.addEventListener>>();
|
||||
|
||||
const addEventListenerCalls = new Array<Parameters<typeof window.addEventListener>>();
|
||||
const removeEventListenerCalls = new Array<Parameters<typeof window.removeEventListener>>();
|
||||
|
||||
window.addEventListener = (
|
||||
...args: Parameters<typeof window.addEventListener>
|
||||
): ReturnType<typeof window.addEventListener> => {
|
||||
addEventListenerCalls.push(args);
|
||||
currentListeners.push(args);
|
||||
return originalAddEventListener.call(window, ...args);
|
||||
};
|
||||
|
||||
window.removeEventListener = (
|
||||
...args: Parameters<typeof window.removeEventListener>
|
||||
): ReturnType<typeof window.removeEventListener> => {
|
||||
removeEventListenerCalls.push(args);
|
||||
const [type, listener] = args;
|
||||
const registeredListener = findCurrentListener(type as EventName, listener);
|
||||
if (registeredListener) {
|
||||
const index = currentListeners.indexOf(registeredListener);
|
||||
if (index > -1) {
|
||||
currentListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return originalRemoveEventListener.call(window, ...args);
|
||||
};
|
||||
|
||||
function findCurrentListener(
|
||||
type: EventName,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
): Parameters<typeof window.addEventListener> | undefined {
|
||||
return currentListeners.find((args) => {
|
||||
const [eventType, eventListener] = args;
|
||||
return eventType === type && listener === eventListener;
|
||||
});
|
||||
}
|
||||
|
||||
restoreCallback(() => {
|
||||
window.addEventListener = originalAddEventListener;
|
||||
window.removeEventListener = originalRemoveEventListener;
|
||||
});
|
||||
|
||||
return {
|
||||
isAddEventCalled(eventType: EventName): boolean {
|
||||
const call = addEventListenerCalls.find((args) => {
|
||||
const [type] = args;
|
||||
return type === eventType;
|
||||
});
|
||||
return call !== undefined;
|
||||
},
|
||||
isRemoveEventCalled(eventType: EventName) {
|
||||
const call = removeEventListenerCalls.find((args) => {
|
||||
const [type] = args;
|
||||
return type === eventType;
|
||||
});
|
||||
return call !== undefined;
|
||||
},
|
||||
currentListeners,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user