Commit ef3024ea authored by Tim Zallmann's avatar Tim Zallmann

Added Specs for navigation utility prefetching

parent 266d51b6
...@@ -15,16 +15,15 @@ export default function findAndFollowLink(selector) { ...@@ -15,16 +15,15 @@ export default function findAndFollowLink(selector) {
} }
export function prefetchDocument(url) { export function prefetchDocument(url) {
const newPrefetchLink = document.createElement("link"); const newPrefetchLink = document.createElement('link');
newPrefetchLink.rel = "prefetch"; newPrefetchLink.rel = 'prefetch';
newPrefetchLink.href = url; newPrefetchLink.href = url;
newPrefetchLink.as = "document"; newPrefetchLink.setAttribute('as', 'document');
document.head.appendChild(newPrefetchLink); document.head.appendChild(newPrefetchLink);
} }
export function initPrefetchLinks(selector) { export function initPrefetchLinks(selector) {
document.querySelectorAll(selector) document.querySelectorAll(selector).forEach((el) => {
.forEach((el) => {
let mouseOverTimer; let mouseOverTimer;
const mouseOutHandler = () => { const mouseOutHandler = () => {
...@@ -33,21 +32,21 @@ export function initPrefetchLinks(selector) { ...@@ -33,21 +32,21 @@ export function initPrefetchLinks(selector) {
mouseOverTimer = undefined; mouseOverTimer = undefined;
} }
}; };
const mouseOverHandler = () => { const mouseOverHandler = () => {
el.addEventListener('mouseout', mouseOutHandler, { passive: true }); el.addEventListener('mouseout', mouseOutHandler, { passive: true });
mouseOverTimer = setTimeout(() => { mouseOverTimer = setTimeout(() => {
if (el.href) prefetchDocument(el.href); if (el.href) prefetchDocument(el.href);
// Only execute once // Only execute once
el.removeEventListener('mouseover', mouseOverHandler, true); el.removeEventListener('mouseover', mouseOverHandler, true);
el.removeEventListener('mouseout', mouseOutHandler); el.removeEventListener('mouseout', mouseOutHandler);
mouseOverTimer = undefined; mouseOverTimer = undefined;
}, 100); }, 100);
}; };
el.addEventListener('mouseover', mouseOverHandler, { el.addEventListener('mouseover', mouseOverHandler, {
capture: true, capture: true,
passive: true, passive: true,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.issuable-main-info .issuable-main-info
.merge-request-title.title .merge-request-title.title
%span.merge-request-title-text.js-onboarding-mr-item %span.merge-request-title-text.js-onboarding-mr-item
= link_to merge_request.title, merge_request_path(merge_request) = link_to merge_request.title, merge_request_path(merge_request), class: 'js-prefetch-document'
- if merge_request.tasks? - if merge_request.tasks?
%span.task-status.d-none.d-sm-inline-block %span.task-status.d-none.d-sm-inline-block
   
......
import findAndFollowLink from '~/lib/utils/navigation_utility'; import findAndFollowLink from '~/lib/utils/navigation_utility';
import * as navigationUtils from '~/lib/utils/navigation_utility';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility'); jest.mock('~/lib/utils/url_utility');
...@@ -21,3 +22,92 @@ describe('findAndFollowLink', () => { ...@@ -21,3 +22,92 @@ describe('findAndFollowLink', () => {
expect(visitUrl).not.toHaveBeenCalled(); expect(visitUrl).not.toHaveBeenCalled();
}); });
}); });
describe('prefetchDocument', () => {
it('creates a prefetch link tag', () => {
const linkElement = document.createElement('link');
jest.spyOn(document, 'createElement').mockImplementation(() => linkElement);
jest.spyOn(document.head, 'appendChild');
navigationUtils.prefetchDocument('index.htm');
expect(document.head.appendChild).toHaveBeenCalledWith(linkElement);
expect(linkElement.href).toEqual('http://test.host/index.htm');
expect(linkElement.rel).toEqual('prefetch');
expect(linkElement.getAttribute('as')).toEqual('document');
});
});
describe('initPrefetchLinks', () => {
let newLink;
beforeEach(() => {
newLink = document.createElement('a');
newLink.href = 'index_prefetch.htm';
newLink.classList.add('js-test-prefetch-link');
document.body.appendChild(newLink);
});
it('adds to all links mouse out handlers when hovered', () => {
const mouseOverEvent = new Event('mouseover');
jest.spyOn(newLink, 'addEventListener');
navigationUtils.initPrefetchLinks('.js-test-prefetch-link');
newLink.dispatchEvent(mouseOverEvent);
expect(newLink.addEventListener).toHaveBeenCalled();
});
it('it is not fired when less then 100ms over link', () => {
const mouseOverEvent = new Event('mouseover');
const mouseOutEvent = new Event('mouseout');
jest.spyOn(newLink, 'addEventListener');
jest.spyOn(navigationUtils, 'prefetchDocument').mockImplementation(() => true);
navigationUtils.initPrefetchLinks('.js-test-prefetch-link');
newLink.dispatchEvent(mouseOverEvent);
newLink.dispatchEvent(mouseOutEvent);
expect(navigationUtils.prefetchDocument).not.toHaveBeenCalled();
});
describe('executes correctly when hovering long enough', () => {
const mouseOverEvent = new Event('mouseover');
beforeEach(() => {
jest.useFakeTimers();
jest.spyOn(global, 'setTimeout');
jest.spyOn(newLink, 'removeEventListener');
});
it('calls prefetchDocument which adds to document', () => {
jest.spyOn(document.head, 'appendChild');
navigationUtils.initPrefetchLinks('.js-test-prefetch-link');
newLink.dispatchEvent(mouseOverEvent);
jest.runAllTimers();
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 100);
expect(document.head.appendChild).toHaveBeenCalled();
});
it('removes Event Listener when fired so only done once', () => {
navigationUtils.initPrefetchLinks('.js-test-prefetch-link');
newLink.dispatchEvent(mouseOverEvent);
jest.runAllTimers();
expect(newLink.removeEventListener).toHaveBeenCalledWith(
'mouseover',
expect.any(Function),
true,
);
expect(newLink.removeEventListener).toHaveBeenCalledWith('mouseout', expect.any(Function));
});
});
});
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