diff options
Diffstat (limited to 'spec/frontend/__helpers__/mock_dom_observer.js')
-rw-r--r-- | spec/frontend/__helpers__/mock_dom_observer.js | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/spec/frontend/__helpers__/mock_dom_observer.js b/spec/frontend/__helpers__/mock_dom_observer.js new file mode 100644 index 00000000000..1b93b81535d --- /dev/null +++ b/spec/frontend/__helpers__/mock_dom_observer.js @@ -0,0 +1,96 @@ +/* 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', () => { + * trigger(el, { options: { childList: true }, entry: { } }); + * }); + * }) + * ``` + * + * @param {String} key + */ +const useMockObserver = (key, createMock) => { + let mockObserver; + let origObserver; + + beforeEach(() => { + origObserver = global[key]; + global[key] = jest.fn().mockImplementation((...args) => { + mockObserver = createMock(...args); + return mockObserver; + }); + }); + + afterEach(() => { + mockObserver = null; + global[key] = origObserver; + }); + + const trigger = (...args) => { + if (!mockObserver) { + return; + } + + mockObserver.$_triggerObserve(...args); + }; + + const observersCount = () => mockObserver.$_observers.length; + + return { trigger, observersCount }; +}; + +export const useMockIntersectionObserver = () => + useMockObserver('IntersectionObserver', (...args) => new MockIntersectionObserver(...args)); + +export const useMockMutationObserver = () => + useMockObserver('MutationObserver', (...args) => new MockObserver(...args)); |