summaryrefslogtreecommitdiff
path: root/spec/frontend/lib/utils/intersection_observer_spec.js
blob: 71b1daffe0dc3d751fff1ddce85bbd31b119aa93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { create } from '~/lib/utils/intersection_observer';

describe('IntersectionObserver Utility', () => {
  beforeAll(() => {
    global.IntersectionObserver = class MockIntersectionObserver {
      constructor(callback) {
        this.callback = callback;

        this.entries = [];
      }

      addEntry(entry) {
        this.entries.push(entry);
      }

      trigger() {
        this.callback(this.entries);
      }
    };
  });
  describe('create', () => {
    describe('memoization', () => {
      const options = { rootMargin: '1px 1px 1px 1px' };
      let expectedOutput;

      beforeEach(() => {
        create.cache.clear();
        expectedOutput = create(options);
      });

      it('returns the same Observer for the same options input', () => {
        expect(expectedOutput.id).toBe(create(options).id);
      });

      it('creates a new Observer for unique input options', () => {
        expect(expectedOutput.id).not.toBe(create({ rootMargin: '1px 2px 3px 4px' }));
      });

      it('creates a new Observer for the same input options in different object references', () => {
        expect(expectedOutput.id).not.toBe(create({ rootMargin: '1px 1px 1px 1px' }));
      });
    });
  });

  describe('Observer behavior', () => {
    let observer = null;
    let id = null;

    beforeEach(() => {
      create.cache.clear();
      ({ observer, id } = create());
    });

    it.each`
      isIntersecting | event
      ${false}       | ${'IntersectionDisappear'}
      ${true}        | ${'IntersectionAppear'}
    `(
      'should emit the correct event on the entry target based on the computed Intersection',
      async ({ isIntersecting, event }) => {
        const target = document.createElement('div');
        observer.addEntry({ target, isIntersecting });

        target.addEventListener(event, (e) => {
          expect(e.detail.observer).toBe(id);
        });

        observer.trigger();
      },
    );

    it('should always emit an Update event with the entry and the observer', () => {
      const target = document.createElement('div');
      const entry = { target };

      observer.addEntry(entry);

      target.addEventListener('IntersectionUpdate', (e) => {
        expect(e.detail.observer).toBe(id);
        expect(e.detail.entry).toStrictEqual(entry);
      });

      observer.trigger();
    });
  });
});