Commit 5fcb5055 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'tor/maintenance/intersection-observer' into 'master'

Add IntersectionObserver utilities

See merge request gitlab-org/gitlab!75067
parents 4c1a1d61 a192dc7e
import { memoize } from 'lodash';
import { uuids } from './uuids';
export const create = memoize((options = {}) => {
const id = uuids()[0];
return {
id,
observer: new IntersectionObserver((entries) => {
entries.forEach((entry) => {
entry.target.dispatchEvent(
new CustomEvent(`IntersectionUpdate`, { detail: { entry, observer: id } }),
);
if (entry.isIntersecting) {
entry.target.dispatchEvent(
new CustomEvent(`IntersectionAppear`, { detail: { observer: id } }),
);
} else {
entry.target.dispatchEvent(
new CustomEvent(`IntersectionDisappear`, { detail: { observer: id } }),
);
}
});
}, options),
};
});
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();
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment