Merge branch 'ce-attempt-to-fix-lazy_loader_spec-transient-failure' into 'master'
Attempt to fix lazy loader spec transient failure Closes #49511 See merge request gitlab-org/gitlab-ce!22918
This commit is contained in:
commit
ac12301445
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
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();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
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 });
|
||||
});
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue