planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

6
node_modules/consolidated-events/__tests__/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"env": {
"jasmine": true,
"jest": true
}
}

View File

@@ -0,0 +1,196 @@
import TargetEventHandlers from '../src/TargetEventHandlers';
class MockTarget {
constructor() {
this.addEventListener = jest.fn();
this.removeEventListener = jest.fn();
}
}
describe('#add()', () => {
it('adds a single event listener to the target the first time', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
eventHandlers.add('scroll', listener);
expect(target.addEventListener).toHaveBeenCalledTimes(1);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('does not add an event listener to the target the second time', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('scroll', listener2);
expect(target.addEventListener).toHaveBeenCalledTimes(1);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('adds an event listener for each set of options', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('scroll', listener2, { passive: true });
expect(target.addEventListener).toHaveBeenCalledTimes(2);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
});
it('adds an event listener for each event type', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const listener = () => {};
const listener2 = () => {};
eventHandlers.add('scroll', listener);
eventHandlers.add('resize', listener2);
expect(target.addEventListener).toHaveBeenCalledTimes(2);
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.addEventListener)
.toHaveBeenCalledWith('resize', jasmine.any(Function), undefined);
});
it('returns an unsubscribe function', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
expect(typeof remove).toBe('function');
});
it('unsubscribe deletes the event listener when the only handler is removed', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('unsubscribe does not throw when called twice', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
remove();
expect(remove).not.toThrow();
});
it('unsubscribe does not delete the event listener when there are more handlers left', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
eventHandlers.add('scroll', () => {});
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
});
it('unsubscribe called multiple times does not delete the event listener when there are more handlers left', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
eventHandlers.add('scroll', () => {});
remove();
remove();
expect(target.removeEventListener).toHaveBeenCalledTimes(0);
});
it('unsubscribe deletes the event listener when all handlers are removed', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
const remove2 = eventHandlers.add('scroll', () => {});
remove();
remove2();
expect(target.removeEventListener).toHaveBeenCalledTimes(1);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
});
it('unsubscribe handles different options separately', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const remove = eventHandlers.add('scroll', () => {});
const remove2 = eventHandlers.add('scroll', () => {}, { passive: true });
remove();
remove2();
expect(target.removeEventListener).toHaveBeenCalledTimes(2);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), undefined);
expect(target.removeEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), { passive: true });
});
});
describe('#handleEvent', () => {
it('calls each handler', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const handlers = [jest.fn(), jest.fn(), jest.fn()];
handlers.forEach((handler) => {
eventHandlers.add('scroll', handler);
});
const event = {};
eventHandlers.handleEvent('scroll', undefined, event);
handlers.forEach((handler) => {
expect(handler).toHaveBeenCalledTimes(1);
expect(handler).toHaveBeenCalledWith(event);
});
});
it('calls each handler even when one is removed when called', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
let remove;
const firstHandler = jest.fn(() => remove());
remove = eventHandlers.add('scroll', firstHandler);
const secondHandler = jest.fn();
eventHandlers.add('scroll', secondHandler);
const event = {};
eventHandlers.handleEvent('scroll', undefined, event);
expect(firstHandler).toHaveBeenCalledTimes(1);
expect(firstHandler).toHaveBeenCalledWith(event);
expect(secondHandler).toHaveBeenCalledTimes(1);
expect(secondHandler).toHaveBeenCalledWith(event);
});
it('calls each handler with options', () => {
const target = new MockTarget();
const eventHandlers = new TargetEventHandlers(target);
const handlers = [jest.fn(), jest.fn(), jest.fn()];
handlers.forEach((handler) => {
eventHandlers.add('scroll', handler, { passive: true });
});
const event = {};
eventHandlers.handleEvent('scroll', { passive: true }, event);
handlers.forEach((handler) => {
expect(handler).toHaveBeenCalledTimes(1);
expect(handler).toHaveBeenCalledWith(event);
});
});
});

View File

@@ -0,0 +1,97 @@
import wrap from 'jest-wrap';
let canUsePassiveEventListeners;
beforeEach(() => {
jest.resetModules();
canUsePassiveEventListeners = require('../src/canUsePassiveEventListeners').default; // eslint-disable-line global-require
});
describe('when not canUseDOM', () => {
beforeEach(() => {
jest.mock('../src/canUseDOM', () => ({ default: false }));
});
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
});
wrap()
.withGlobal('window', () => ({
addEventListener() {},
removeEventListener() {},
}))
.describe('when canUseDOM', () => {
beforeEach(() => {
jest.mock('../src/canUseDOM', () => ({ default: true }));
});
wrap()
.withOverride(() => window, 'addEventListener', () => null)
.describe('when addEventListener is not present', () => {
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
});
wrap()
.withOverrides(() => window, () => ({
addEventListener: jest.fn(),
removeEventListener: null,
}))
.describe('when removeEventListener is not present', () => {
it('returns false', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('returns false multiple times', () => {
expect(canUsePassiveEventListeners()).toEqual(false);
expect(canUsePassiveEventListeners()).toEqual(false);
});
it('does not call addEventListener', () => {
canUsePassiveEventListeners();
expect(window.addEventListener).toHaveBeenCalledTimes(0);
});
});
wrap()
.withOverrides(() => window, () => ({
addEventListener: jest.fn(),
}))
.describe('when addEventListener and removeEventListener are present', () => {
it('calls addEventListener', () => {
canUsePassiveEventListeners();
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
});
wrap()
.withOverride(
() => window,
'addEventListener',
() => jest.fn((event, listener, options) => options.passive /* invoke a getter */),
)
.describe('when "passive" property is accessed', () => {
it('returns true', () => {
expect(canUsePassiveEventListeners()).toEqual(true);
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
it('is memoized', () => {
expect(canUsePassiveEventListeners()).toEqual(true);
expect(canUsePassiveEventListeners()).toEqual(true);
expect(window.addEventListener).toHaveBeenCalledTimes(1);
});
});
});

View File

@@ -0,0 +1,71 @@
import eventOptionsKey from '../src/eventOptionsKey';
it('treats undefined and false the same', () => {
expect(eventOptionsKey(undefined))
.toBe(eventOptionsKey(false));
});
it('treats false and empty objects the same', () => {
expect(eventOptionsKey(false))
.toBe(eventOptionsKey({}));
});
it('treats empty objects and true differently', () => {
expect(eventOptionsKey({}))
.not.toBe(eventOptionsKey(true));
});
it('treats empty objects and a good option differently', () => {
expect(eventOptionsKey({}))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats true and a good option differently', () => {
expect(eventOptionsKey(true))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture and passive differently', () => {
expect(eventOptionsKey({ capture: true }))
.not.toBe(eventOptionsKey({ passive: true }));
});
it('treats capture and only differently', () => {
expect(eventOptionsKey({ capture: true }))
.not.toBe(eventOptionsKey({ only: true }));
});
it('treats passive and only differently', () => {
expect(eventOptionsKey({ passive: true }))
.not.toBe(eventOptionsKey({ only: true }));
});
it('treats capture/passive differently from capture', () => {
expect(eventOptionsKey({ capture: true, passive: true }))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture/once differently from capture', () => {
expect(eventOptionsKey({ capture: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true }));
});
it('treats capture/once differently from capture/passive', () => {
expect(eventOptionsKey({ capture: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
});
it('treats capture/passive/once differently from capture/passive', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, passive: true }));
});
it('treats capture/passive/once differently from capture/once', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.not.toBe(eventOptionsKey({ capture: true, once: true }));
});
it('does not care about the order of options', () => {
expect(eventOptionsKey({ capture: true, passive: true, once: true }))
.toBe(eventOptionsKey({ passive: true, once: true, capture: true }));
});

View File

@@ -0,0 +1,34 @@
import { addEventListener } from '../src';
import TargetEventHandlers from '../src/TargetEventHandlers';
class MockTarget {
constructor() {
this.addEventListener = jest.fn();
}
}
const EVENT_HANDLERS_KEY = '__consolidated_events_handlers__';
describe('addEventListener()', () => {
it('initializes an instance of TargetEventHandlers on new targets', () => {
const target = new MockTarget();
addEventListener(target, 'scroll', () => {});
expect(target[EVENT_HANDLERS_KEY]).toBeInstanceOf(TargetEventHandlers);
expect(target[EVENT_HANDLERS_KEY].target).toBe(target);
});
it('normalizes event options', () => {
const target = new MockTarget();
addEventListener(target, 'scroll', () => {}, { capture: true });
expect(target.addEventListener)
.toHaveBeenCalledWith('scroll', jasmine.any(Function), true);
});
it('returns an unsubscribe function', () => {
const target = new MockTarget();
const remove = addEventListener(target, 'scroll', () => {}, { capture: true });
expect(typeof remove).toBe('function');
});
});

View File

@@ -0,0 +1,52 @@
/* eslint-disable import/first */
jest.mock('../src/canUsePassiveEventListeners');
import canUsePassiveEventListeners from '../src/canUsePassiveEventListeners';
import normalizeEventOptions from '../src/normalizeEventOptions';
it('is undefined when event options are undefined', () => {
expect(normalizeEventOptions(undefined)).toBe(undefined);
});
it('is undefined when event options are null', () => {
expect(normalizeEventOptions(null)).toBe(undefined);
});
it('is undefined when event options are false', () => {
expect(normalizeEventOptions(false)).toBe(undefined);
});
describe('when able to use passive event listeners', () => {
beforeEach(() => {
canUsePassiveEventListeners.mockImplementation(() => true);
});
it('passes the eventOptions object through', () => {
expect(normalizeEventOptions({ passive: true }))
.toEqual({ passive: true });
expect(normalizeEventOptions({ capture: true }))
.toEqual({ capture: true });
expect(normalizeEventOptions({ capture: true, passive: true }))
.toEqual({ capture: true, passive: true });
});
});
describe('when not able to use passive event listeners', () => {
beforeEach(() => {
canUsePassiveEventListeners.mockImplementation(() => false);
});
it('is true when the capture option is on', () => {
expect(normalizeEventOptions({ capture: true })).toBe(true);
});
it('is false when the capture option is off', () => {
expect(normalizeEventOptions({ capture: false })).toBe(false);
});
it('is false when the capture option is missing', () => {
expect(normalizeEventOptions({ passive: true })).toBe(false);
});
});