2020-06-10 09:08:35 +00:00
|
|
|
/* eslint-disable class-methods-use-this, max-classes-per-file */
|
|
|
|
import { isMatch } from 'lodash';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class gives us a JSDom friendly DOM observer which we can manually trigger in tests
|
|
|
|
*
|
|
|
|
* Use this in place of MutationObserver or IntersectionObserver
|
|
|
|
*/
|
|
|
|
class MockObserver {
|
|
|
|
constructor(cb) {
|
|
|
|
this.$_cb = cb;
|
|
|
|
this.$_observers = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
observe(node, options = {}) {
|
|
|
|
this.$_observers.push([node, options]);
|
|
|
|
}
|
|
|
|
|
|
|
|
disconnect() {
|
|
|
|
this.$_observers = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
takeRecords() {}
|
|
|
|
|
|
|
|
// eslint-disable-next-line babel/camelcase
|
|
|
|
$_triggerObserve(node, { entry = {}, options = {} } = {}) {
|
|
|
|
if (this.$_hasObserver(node, options)) {
|
|
|
|
this.$_cb([{ target: node, ...entry }]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// eslint-disable-next-line babel/camelcase
|
|
|
|
$_hasObserver(node, options = {}) {
|
|
|
|
return this.$_observers.some(
|
|
|
|
([obvNode, obvOptions]) => node === obvNode && isMatch(options, obvOptions),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MockIntersectionObserver extends MockObserver {
|
|
|
|
unobserve(node) {
|
|
|
|
this.$_observers = this.$_observers.filter(([obvNode]) => node === obvNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use this function to setup a mock observer instance in place of the given DOM Observer
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* ```
|
|
|
|
* describe('', () => {
|
|
|
|
* const { trigger: triggerMutate } = useMockMutationObserver();
|
|
|
|
*
|
|
|
|
* it('test', () => {
|
2021-08-03 12:09:42 +00:00
|
|
|
* triggerMutate(el, { options: { childList: true }, entry: { } });
|
2020-06-10 09:08:35 +00:00
|
|
|
* });
|
|
|
|
* })
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* @param {String} key
|
|
|
|
*/
|
|
|
|
const useMockObserver = (key, createMock) => {
|
2021-08-03 12:09:42 +00:00
|
|
|
let mockObservers = [];
|
2020-06-10 09:08:35 +00:00
|
|
|
let origObserver;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
origObserver = global[key];
|
|
|
|
global[key] = jest.fn().mockImplementation((...args) => {
|
2021-08-03 12:09:42 +00:00
|
|
|
const mockObserver = createMock(...args);
|
|
|
|
mockObservers.push(mockObserver);
|
2020-06-10 09:08:35 +00:00
|
|
|
return mockObserver;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
2021-08-03 12:09:42 +00:00
|
|
|
mockObservers.forEach((x) => x.disconnect());
|
|
|
|
mockObservers = [];
|
2020-06-10 09:08:35 +00:00
|
|
|
global[key] = origObserver;
|
|
|
|
});
|
|
|
|
|
|
|
|
const trigger = (...args) => {
|
2021-08-03 12:09:42 +00:00
|
|
|
mockObservers.forEach((observer) => {
|
|
|
|
observer.$_triggerObserve(...args);
|
|
|
|
});
|
2020-06-10 09:08:35 +00:00
|
|
|
};
|
|
|
|
|
2021-08-03 12:09:42 +00:00
|
|
|
return { trigger };
|
2020-06-10 09:08:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export const useMockIntersectionObserver = () =>
|
|
|
|
useMockObserver('IntersectionObserver', (...args) => new MockIntersectionObserver(...args));
|
|
|
|
|
|
|
|
export const useMockMutationObserver = () =>
|
|
|
|
useMockObserver('MutationObserver', (...args) => new MockObserver(...args));
|