gitlab-ce/spec/frontend/rapid_diffs/web_components/diff_file_spec.js

182 lines
5.1 KiB
JavaScript

import { DiffFile } from '~/rapid_diffs/web_components/diff_file';
import { DIFF_FILE_MOUNTED } from '~/rapid_diffs/dom_events';
import { CLICK, INVISIBLE, MOUNTED, VISIBLE } from '~/rapid_diffs/adapter_events';
describe('DiffFile Web Component', () => {
const fileData = JSON.stringify({ viewer: 'current', custom: 'bar' });
const html = `
<diff-file data-file-data='${fileData}' id="fileHash">
<div id="foo">
<button data-click="foo"></button>
</div>
</diff-file>
`;
let app;
let adapter;
let adapterMountedCleanup;
const getDiffElement = () => document.querySelector('[id=foo]');
const getWebComponentElement = () => document.querySelector('diff-file');
const triggerVisibility = (isIntersecting) => {
const target = getWebComponentElement();
// eslint-disable-next-line no-unused-expressions
isIntersecting ? target.onVisible({}) : target.onInvisible({});
};
const createDefaultAdapter = () => ({
[CLICK]: jest.fn(),
clicks: {
foo: jest.fn(),
},
[VISIBLE]: jest.fn(),
[INVISIBLE]: jest.fn(),
[MOUNTED]: jest.fn((onUnmounted) => {
adapterMountedCleanup = jest.fn();
onUnmounted(adapterMountedCleanup);
}),
});
const initRapidDiffsApp = (currentAdapter = createDefaultAdapter(), appData = {}) => {
adapter = currentAdapter;
app = {
adapterConfig: { current: [currentAdapter] },
appData,
observe: jest.fn(),
unobserve: jest.fn(),
};
};
const delegatedClick = (element) => {
let event;
element.addEventListener(
'click',
(e) => {
event = e;
},
{ once: true },
);
element.click();
getWebComponentElement().onClick(event);
};
const mount = (customAdapter) => {
initRapidDiffsApp(customAdapter);
document.body.innerHTML = html;
getWebComponentElement().mount(app);
};
const getContext = () => ({
appData: app.appData,
diffElement: getDiffElement(),
data: {
custom: 'bar',
viewer: 'current',
},
sink: {},
trigger: expect.any(Function),
replaceWith: expect.any(Function),
});
beforeAll(() => {
customElements.define('diff-file', DiffFile);
});
beforeEach(() => {
adapterMountedCleanup = undefined;
});
it('observes diff element', () => {
mount();
expect(app.observe).toHaveBeenCalledWith(getWebComponentElement());
});
it('triggers mounted event', () => {
let emitted = false;
document.addEventListener(DIFF_FILE_MOUNTED, () => {
emitted = true;
});
mount();
expect(adapter[MOUNTED]).toHaveBeenCalled();
expect(adapter[MOUNTED].mock.instances[0]).toStrictEqual(getContext());
expect(emitted).toBe(true);
});
it('properly unmounts', () => {
mount();
const element = getWebComponentElement();
document.body.innerHTML = '';
expect(app.unobserve).toHaveBeenCalledWith(element);
expect(adapterMountedCleanup).toHaveBeenCalled();
});
it('can self replace', () => {
const focusFirstButton = jest.fn();
const mockNode = { focusFirstButton };
mount({
[MOUNTED]() {
this.replaceWith(mockNode);
},
});
expect(focusFirstButton).toHaveBeenCalled();
});
it('#selectFile', () => {
mount();
const spy = jest.spyOn(getWebComponentElement(), 'scrollIntoView');
getWebComponentElement().selectFile();
expect(spy).toHaveBeenCalled();
});
describe('when visible', () => {
beforeEach(() => {
mount();
});
it('handles all clicks', () => {
triggerVisibility(true);
delegatedClick(getDiffElement());
expect(adapter[CLICK]).toHaveBeenCalledWith(expect.any(MouseEvent));
expect(adapter[CLICK].mock.instances[0]).toStrictEqual(getContext());
});
it('handles specific clicks', () => {
triggerVisibility(true);
const clickTarget = getDiffElement().querySelector('[data-click=foo]');
delegatedClick(clickTarget);
expect(adapter.clicks.foo).toHaveBeenCalledWith(expect.any(MouseEvent), clickTarget);
expect(adapter.clicks.foo.mock.instances[0]).toStrictEqual(getContext());
});
it('handles visible event', () => {
triggerVisibility(true);
expect(adapter[VISIBLE]).toHaveBeenCalled();
expect(adapter[VISIBLE].mock.instances[0]).toStrictEqual(getContext());
});
it('handles invisible event', () => {
triggerVisibility(false);
expect(adapter[INVISIBLE]).toHaveBeenCalled();
expect(adapter[INVISIBLE].mock.instances[0]).toStrictEqual(getContext());
});
});
describe('static methods', () => {
it('#findByFileHash', () => {
expect(DiffFile.findByFileHash('fileHash')).toBeInstanceOf(DiffFile);
});
it('#getAll', () => {
document.body.innerHTML = `
<diff-file data-file-data="{}"><div></div></diff-file>
<diff-file data-file-data="{}"><div></div></diff-file>
`;
const instances = DiffFile.getAll();
expect(instances).toHaveLength(2);
instances.forEach((instance) => expect(instance).toBeInstanceOf(DiffFile));
// properly run destruction callbacks
instances.forEach((instance) => instance.mount(app));
});
});
});