Commit 1877eb49 authored by Luke Bennett's avatar Luke Bennett Committed by Fatih Acet

Attempt to fix lazy loader spec transient failure

parent ceae9f52
......@@ -19,7 +19,7 @@ export default class LazyLoader {
}
searchLazyImages() {
requestIdleCallback(
window.requestIdleCallback(
() => {
const lazyImages = [].slice.call(document.querySelectorAll('.lazy'));
......@@ -107,7 +107,7 @@ export default class LazyLoader {
}
scrollCheck() {
requestAnimationFrame(() => this.checkElementsInView());
window.requestAnimationFrame(() => this.checkElementsInView());
}
checkElementsInView() {
......@@ -122,7 +122,7 @@ export default class LazyLoader {
const imgBound = imgTop + imgBoundRect.height;
if (scrollTop <= imgBound && visHeight >= imgTop) {
requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
LazyLoader.loadImage(selectedImage);
});
return false;
......
export default function scrollIntoViewPromise(intersectionTarget, timeout = 100, maxTries = 5) {
return new Promise((resolve, reject) => {
let intersectionObserver;
let retry = 0;
const intervalId = setInterval(() => {
if (retry >= maxTries) {
intersectionObserver.disconnect();
clearInterval(intervalId);
reject(new Error(`Could not scroll target into viewPort within ${timeout * maxTries} ms`));
}
retry += 1;
intersectionTarget.scrollIntoView();
}, timeout);
intersectionObserver = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
intersectionObserver.disconnect();
clearInterval(intervalId);
resolve();
}
});
intersectionObserver.observe(intersectionTarget);
intersectionTarget.scrollIntoView();
});
}
export default (domElement, attributes, timeout = 1500) =>
new Promise((resolve, reject) => {
let observer;
const timeoutId = setTimeout(() => {
observer.disconnect();
reject(new Error(`Could not see an attribute update within ${timeout} ms`));
}, timeout);
observer = new MutationObserver(() => {
clearTimeout(timeoutId);
observer.disconnect();
resolve();
});
observer.observe(domElement, { attributes: true, attributeFilter: attributes });
});
import LazyLoader from '~/lazy_loader';
import { TEST_HOST } from './test_constants';
let lazyLoader = null;
import scrollIntoViewPromise from './helpers/scroll_into_view_promise';
import waitForPromises from './helpers/wait_for_promises';
import waitForAttributeChange from './helpers/wait_for_attribute_change';
const execImmediately = callback => {
callback();
};
describe('LazyLoader', function() {
let lazyLoader = null;
preloadFixtures('issues/issue_with_comment.html.raw');
describe('with IntersectionObserver disabled', () => {
describe('without IntersectionObserver', () => {
beforeEach(function() {
loadFixtures('issues/issue_with_comment.html.raw');
......@@ -36,14 +39,15 @@ describe('LazyLoader', function() {
it('should copy value from data-src to src for img 1', function(done) {
const img = document.querySelectorAll('img[data-src]')[0];
const originalDataSrc = img.getAttribute('data-src');
img.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should lazy load dynamically added data-src images', function(done) {
......@@ -52,14 +56,18 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not alter normal images', function(done) {
......@@ -67,13 +75,15 @@ describe('LazyLoader', function() {
const testPath = `${TEST_HOST}/img/testimg.png`;
newImg.setAttribute('src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not load dynamically added pictures if content observer is turned off', done => {
......@@ -84,13 +94,15 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should load dynamically added pictures if content observer is turned off and on again', done => {
......@@ -102,17 +114,22 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
});
describe('with IntersectionObserver enabled', () => {
describe('with IntersectionObserver', () => {
beforeEach(function() {
loadFixtures('issues/issue_with_comment.html.raw');
......@@ -136,14 +153,15 @@ describe('LazyLoader', function() {
it('should copy value from data-src to src for img 1', function(done) {
const img = document.querySelectorAll('img[data-src]')[0];
const originalDataSrc = img.getAttribute('data-src');
img.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([scrollIntoViewPromise(img), waitForAttributeChange(img, ['data-src', 'src'])])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(img.getAttribute('src')).toBe(originalDataSrc);
expect(img).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should lazy load dynamically added data-src images', function(done) {
......@@ -152,14 +170,18 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg.getAttribute('src')).toBe(testPath);
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not alter normal images', function(done) {
......@@ -167,13 +189,15 @@ describe('LazyLoader', function() {
const testPath = `${TEST_HOST}/img/testimg.png`;
newImg.setAttribute('src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should not load dynamically added pictures if content observer is turned off', done => {
......@@ -184,13 +208,15 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
}, 50);
scrollIntoViewPromise(newImg)
.then(waitForPromises)
.then(() => {
expect(LazyLoader.loadImage).not.toHaveBeenCalled();
expect(newImg).not.toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
it('should load dynamically added pictures if content observer is turned off and on again', done => {
......@@ -202,13 +228,17 @@ describe('LazyLoader', function() {
newImg.className = 'lazy';
newImg.setAttribute('data-src', testPath);
document.body.appendChild(newImg);
newImg.scrollIntoView();
setTimeout(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
}, 50);
Promise.all([
scrollIntoViewPromise(newImg),
waitForAttributeChange(newImg, ['data-src', 'src']),
])
.then(() => {
expect(LazyLoader.loadImage).toHaveBeenCalled();
expect(newImg).toHaveClass('js-lazy-loaded');
done();
})
.catch(done.fail);
});
});
});
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