UNPKG

2.38 kBJavaScriptView Raw
1/* global jest, beforeEach, afterEach */
2/* eslint-disable class-methods-use-this, max-classes-per-file, camelcase */
3import isMatch from 'lodash/isMatch';
4
5/**
6 * This class gives us a JSDom friendly DOM observer which we can manually trigger in tests
7 *
8 * Use this in place of MutationObserver or IntersectionObserver
9 *
10 * This class is largely influenced from [a test helper][1] in the main GitLab project
11 *
12 * [1]: https://gitlab.com/gitlab-org/gitlab/blob/a123813c63147392b95cd03c4744ae9db0575b0f/spec/frontend/helpers/mock_dom_observer.js#L95
13 */
14class MockObserver {
15 constructor(cb) {
16 this.$_cb = cb;
17 this.$_observers = [];
18 }
19
20 observe(node, options = {}) {
21 this.$_observers.push([node, options]);
22 }
23
24 disconnect() {
25 this.$_observers = [];
26 }
27
28 takeRecords() {}
29
30 // eslint-disable-next-line camelcase
31 $_triggerObserve(nodeParam, { entry = {}, options = {} } = {}) {
32 const nodes = this.$_getNodesFromParam(nodeParam);
33
34 nodes.forEach((node) => {
35 if (this.$_hasObserver(node, options)) {
36 this.$_cb([{ target: node, ...entry }]);
37 }
38 });
39 }
40
41 // eslint-disable-next-line camelcase
42 $_hasObserver(node, options = {}) {
43 return this.$_observers.some(
44 ([obvNode, obvOptions]) => node === obvNode && isMatch(options, obvOptions)
45 );
46 }
47
48 $_getNodesFromParam(nodeParam) {
49 if (!nodeParam) {
50 return this.$_observers.map(([node]) => node);
51 }
52 if (!Array.isArray(nodeParam)) {
53 return [nodeParam];
54 }
55
56 return nodeParam;
57 }
58}
59
60class MockIntersectionObserver extends MockObserver {
61 unobserve(node) {
62 this.$_observers = this.$_observers.filter(([obvNode]) => node !== obvNode);
63 }
64}
65
66export const useMockIntersectionObserver = () => {
67 let instances;
68 let origObserver;
69
70 beforeEach(() => {
71 instances = [];
72 origObserver = global.IntersectionObserver;
73 global.IntersectionObserver = jest.fn().mockImplementation((...args) => {
74 const mockObserver = new MockIntersectionObserver(...args);
75
76 instances.push(mockObserver);
77
78 return mockObserver;
79 });
80 });
81
82 afterEach(() => {
83 instances = [];
84 global.IntersectionObserver = origObserver;
85 });
86
87 const trigger = (observer, ...args) => {
88 observer.$_triggerObserve(...args);
89 };
90
91 const getInstances = () => {
92 return instances;
93 };
94
95 return { getInstances, trigger };
96};