Skip to content

Commit bf66ae9

Browse files
committed
bugfix: async issue when updating src after state change + tests
1 parent 9305755 commit bf66ae9

File tree

2 files changed

+61
-33
lines changed

2 files changed

+61
-33
lines changed

src/components/IKImage/index.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ class IKImage extends ImageKitComponent {
117117
triggerOriginalImageLoad() {
118118
var img = new Image();
119119
img.onload = () => {
120-
this.setState({ originalSrcLoaded: true });
121-
this.updateImageUrl();
120+
this.setState({ originalSrcLoaded: true }, () => {
121+
this.updateImageUrl();
122+
});
122123
}
123124
img.src = this.state.originalSrc;
124125
}
@@ -136,10 +137,11 @@ class IKImage extends ImageKitComponent {
136137
const imageObserver = new IntersectionObserver(entries => {
137138
const el = entries[0];
138139
if (el && el.isIntersecting) {
139-
this.setState({ intersected: true });
140-
if (lqip && lqip.active) this.triggerOriginalImageLoad();
141-
imageObserver.disconnect();
142-
this.updateImageUrl();
140+
this.setState({ intersected: true }, () => {
141+
if (lqip && lqip.active) this.triggerOriginalImageLoad();
142+
imageObserver.disconnect();
143+
this.updateImageUrl();
144+
});
143145
}
144146
}, {
145147
rootMargin: `${rootMargin} 0px ${rootMargin} 0px`
@@ -150,9 +152,10 @@ class IKImage extends ImageKitComponent {
150152
})
151153
} else {
152154
// Load original image right away
153-
this.setState({ intersected: true });
154-
if (lqip && lqip.active) this.triggerOriginalImageLoad();
155-
this.updateImageUrl();
155+
this.setState({ intersected: true }, () => {
156+
if (lqip && lqip.active) this.triggerOriginalImageLoad();
157+
this.updateImageUrl();
158+
});
156159
}
157160
}
158161

src/test/IKImage.test.js

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ describe('IKImage', () => {
262262
const observeSpy = sinon.spy();
263263
let intersectionObserverSpy;
264264
let originalNavigatorPrototype;
265+
let originalWindowPrototype;
265266

266267
const mockNavigator = (effectiveType = '4g') => {
267268
// backup original connection value
@@ -285,6 +286,15 @@ describe('IKImage', () => {
285286
Object.defineProperty(global.Navigator.prototype, 'connection', navigatorConnection);
286287
}
287288

289+
const removeIntersectionObserverMock = () => {
290+
originalWindowPrototype = Object.getOwnPropertyDescriptor(window, 'IntersectionObserver');
291+
delete window['IntersectionObserver'];
292+
};
293+
294+
const restoreIntersectionObserverMock = () => {
295+
Object.defineProperty(window, 'IntersectionObserver', originalWindowPrototype);
296+
};
297+
288298
beforeEach(() => {
289299
IntersectionObserverMock({ observe: observeSpy });
290300
intersectionObserverSpy = sinon.spy(window, 'IntersectionObserver');
@@ -420,6 +430,45 @@ describe('IKImage', () => {
420430

421431
restoreNavigator();
422432
});
433+
434+
// covers 'else' condition when checking for presence of IntersectionObserver in 'window'
435+
test('should set original src if IntersectionObserver is not present', () => {
436+
removeIntersectionObserverMock();
437+
438+
const ikImage = mount(
439+
<IKImage
440+
urlEndpoint={urlEndpoint}
441+
path={relativePath}
442+
loading="lazy"
443+
/>
444+
);
445+
446+
expect(ikImage.find('img').prop('src')).toEqual(`${urlEndpoint}/${relativePath}?${global.SDK_VERSION}`);
447+
448+
restoreIntersectionObserverMock();
449+
});
450+
451+
// covers 'else' condition for observer disconnection in non-lazyload cases
452+
test('should unmount properly when lazyload is not enabled', () => {
453+
const ikImage = shallow(
454+
<IKImage
455+
urlEndpoint={urlEndpoint}
456+
path={relativePath}
457+
/>
458+
);
459+
// spies
460+
const spy = sinon.spy(ikImage.instance(), 'componentWillUnmount');
461+
expect(spy.called).toEqual(false);
462+
463+
// trigger unmount
464+
ikImage.unmount();
465+
466+
// verify spies
467+
expect(spy.calledOnce).toEqual(true);
468+
spy.restore();
469+
470+
expect(ikImage.find('img').length).toEqual(0);
471+
});
423472
});
424473

425474
describe('LQIP', () => {
@@ -529,29 +578,5 @@ describe('IKImage', () => {
529578
expect(ikImage.find('img').prop('src')).toBeUndefined();
530579
});
531580
});
532-
533-
describe('Miscellaneous', () => {
534-
// covers 'else' condition for observer disconnection in non-lazyload cases
535-
test('IKImage should unmount properly', () => {
536-
const ikImage = shallow(
537-
<IKImage
538-
urlEndpoint={urlEndpoint}
539-
path={relativePath}
540-
/>
541-
);
542-
// spies
543-
const spy = sinon.spy(ikImage.instance(), 'componentWillUnmount');
544-
expect(spy.called).toEqual(false);
545-
546-
// trigger unmount
547-
ikImage.unmount();
548-
549-
// verify spies
550-
expect(spy.calledOnce).toEqual(true);
551-
spy.restore();
552-
553-
expect(ikImage.find('img').length).toEqual(0);
554-
});
555-
});
556581
});
557582
});

0 commit comments

Comments
 (0)