Skip to content

Commit df4dcf2

Browse files
author
Jack Matthews
authored
Merge pull request #3 from thisissoon/feature/load-event
Feature/load event
2 parents 8dc2455 + 31aee45 commit df4dcf2

File tree

12 files changed

+263
-12
lines changed

12 files changed

+263
-12
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ script:
1818
- npm run test -- --no-progress --code-coverage --single-run --browser=ChromeNoSandbox
1919
- npm run e2e -- --no-progress
2020
- npm run coverage
21+
addons:
22+
apt:
23+
sources:
24+
- google-chrome
25+
packages:
26+
- google-chrome-stable

e2e/app.e2e-spec.ts

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { browser } from 'protractor';
44
describe('ImageLoader Lib E2E Tests', function () {
55
let page: AppPage;
66

7+
const browserWaitTimeout = 10000;
8+
79
beforeEach(() => page = new AppPage());
810

911
beforeEach(() => page.navigateTo());
@@ -16,6 +18,18 @@ describe('ImageLoader Lib E2E Tests', function () {
1618
});
1719
});
1820

21+
describe('placeholder image', () => {
22+
beforeEach(() => page.setWindowSize(300, 580));
23+
24+
it('should load placeholder image', () => {
25+
expect(page.getImageElement().getAttribute('src')).toEqual('http://via.placeholder.com/35x15?text=placeholder');
26+
});
27+
28+
it('should update placeholder loaded boolean on init', () => {
29+
expect(page.getplaceholderBooleanElement().getText()).toEqual('true');
30+
});
31+
});
32+
1933
describe('lazy load image', () => {
2034
beforeEach(() => page.setWindowSize(300, 580));
2135

@@ -25,34 +39,94 @@ describe('ImageLoader Lib E2E Tests', function () {
2539
expect(imageLoaderCompClass).toContain('sn-image-not-loaded');
2640
expect(imgSrc).toEqual('http://via.placeholder.com/35x15?text=placeholder');
2741

28-
page.scrollTo(0, 580 * 1.5);
42+
page.scrollTo(0, 580 * 1.5)
43+
.then(() => {
44+
browser.wait(() => page.getLoadedImageElement());
45+
});
46+
2947
imageLoaderCompClass = page.getImageLoaderComp().getAttribute('class');
3048
imgSrc = page.getImageElement().getAttribute('srcset');
3149
expect(imageLoaderCompClass).toContain('sn-image-loaded');
3250
expect(imgSrc).toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x');
51+
52+
});
53+
54+
it('should update full res image event count on when in viewport', () => {
55+
expect(page.getFullResCountElement().getText()).toEqual('0');
56+
57+
page.scrollTo(0, 580 * 1.5)
58+
.then(() => {
59+
browser.wait(() => page.getLoadedImageElement());
60+
});
61+
62+
expect(page.getFullResCountElement().getText()).toEqual('1');
3363
});
64+
3465
});
3566

3667
describe('responsive image', () => {
3768
beforeEach(() => page.setWindowSize(300, 580));
3869

3970
it('should load correct image for device size', () => {
40-
page.scrollTo(0, 580 * 1.5);
71+
page.scrollTo(0, 580 * 1.5)
72+
.then(() => {
73+
browser.wait(() => page.getLoadedImageElement());
74+
});
4175

4276
const imageLoaderCompClass = page.getImageLoaderComp().getAttribute('class');
4377
let imgSrc = page.getImageElement().getAttribute('srcset');
44-
4578
expect(imageLoaderCompClass).toContain('sn-image-loaded');
4679
expect(imgSrc).toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x');
4780

48-
page.setWindowSize(768, 580);
81+
page.setWindowSize(768, 580)
82+
.then(() => {
83+
browser.wait(() => page.getLoadedImageElementBySrcSet(
84+
'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x'
85+
), browserWaitTimeout);
86+
});
87+
4988
imgSrc = page.getImageElement().getAttribute('srcset');
5089
expect(imgSrc).toEqual('http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x');
5190

52-
page.setWindowSize(1024, 580);
91+
page.setWindowSize(1024, 580)
92+
.then(() => {
93+
browser.wait(() => page.getLoadedImageElementBySrcSet(
94+
'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x'
95+
), browserWaitTimeout);
96+
});
97+
5398
imgSrc = page.getImageElement().getAttribute('srcset');
5499
expect(imgSrc).toEqual('http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x');
55100
});
101+
102+
it('should update image loaded event count on window resize when image in viewport', () => {
103+
expect(page.getFullResCountElement().getText()).toEqual('0');
104+
105+
page.scrollTo(0, 580 * 1.5)
106+
.then(() => {
107+
browser.wait(() => page.getLoadedImageElement());
108+
});
109+
110+
expect(page.getFullResCountElement().getText()).toEqual('1');
111+
112+
page.setWindowSize(768, 580)
113+
.then(() => {
114+
browser.wait(() => page.getLoadedImageElementBySrcSet(
115+
'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x'
116+
), browserWaitTimeout);
117+
});
118+
expect(page.getFullResCountElement().getText()).toEqual('2');
119+
120+
page.setWindowSize(1024, 580)
121+
.then(() => {
122+
browser.wait(() => page.getLoadedImageElementBySrcSet(
123+
'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x'
124+
), browserWaitTimeout);
125+
});
126+
expect(page.getFullResCountElement().getText()).toEqual('3');
127+
});
128+
56129
});
130+
57131
});
58132

e2e/app.po.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ export class AppPage {
66
}
77

88
scrollTo(x: number = 0, y: number = 0) {
9-
browser.executeScript(`window.scrollTo(${x}, ${y})`);
10-
browser.sleep(200);
9+
return browser.executeScript(`window.scrollTo(${x}, ${y})`);
1110
}
1211

1312
setWindowSize(x: number, y: number) {
14-
browser.driver.manage().window().setSize(x, y);
15-
browser.sleep(200);
13+
return browser.driver.manage().window().setSize(x, y);
1614
}
1715

1816
getImageLoaderComp() {
@@ -22,4 +20,20 @@ export class AppPage {
2220
getImageElement() {
2321
return element(by.css('sn-image-loader .foo'));
2422
}
23+
24+
getLoadedImageElement() {
25+
return element(by.css('.sn-image-loaded')).isPresent();
26+
}
27+
28+
getLoadedImageElementBySrcSet(srcSet) {
29+
return element(by.css(`img[srcSet="${srcSet}"]`)).isPresent();
30+
}
31+
32+
getplaceholderBooleanElement() {
33+
return element(by.css('.placeholder-boolean'));
34+
}
35+
36+
getFullResCountElement() {
37+
return element(by.css('.full-res-count'));
38+
}
2539
}

package-lock.json

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"codelyzer": "^4.0.1",
6868
"core-js": "^2.4.1",
6969
"coveralls": "^3.0.0",
70+
"cz-conventional-changelog": "^2.1.0",
7071
"jasmine-core": "~2.6.2",
7172
"jasmine-spec-reporter": "~4.1.0",
7273
"karma": "~1.7.0",
@@ -84,5 +85,10 @@
8485
"tslint": "~5.7.0",
8586
"typescript": "~2.4.2",
8687
"zone.js": "^0.8.14"
88+
},
89+
"config": {
90+
"commitizen": {
91+
"path": "./node_modules/cz-conventional-changelog"
92+
}
8793
}
8894
}

src/app/app.component.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
<h1>Scroll down ↓</h1>
2+
<h3>Placeholder image loaded: <span class="placeholder-boolean">{{ imagePlaceholderLoaded }}</span></h3>
23
<div class="spacer"></div>
4+
<h3>imageLoaded event count: <span class="full-res-count">{{ imageLoadedEventCount }}</span></h3>
35
<sn-image-loader
46
[image]="image"
57
[sizes]="sizes"
68
imgClass="foo"
9+
alt="lorem ipsum"
10+
(imagePlaceholderLoaded)="onPlaceholderLoad($event)"
11+
(imageLoaded)="onFullResLoad($event)"
712
></sn-image-loader>
813
<div class="spacer"></div>

src/app/app.component.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Component } from '@angular/core';
22
import { ResponsiveImage, Breakpoint, Size } from './image-loader';
3+
import { ImageLoadedEvent } from './image-loader/shared';
34

45
@Component({
56
selector: 'sn-root',
@@ -29,4 +30,40 @@ export class AppComponent {
2930
'@2x': 'http://via.placeholder.com/1400x800?text=lg+2x'
3031
}
3132
};
33+
34+
/**
35+
* Set to true on placeholder loaded event.
36+
*
37+
* @type {boolean}
38+
* @memberof AppComponent
39+
*/
40+
imagePlaceholderLoaded = false;
41+
42+
/**
43+
* Incremented on each image load event.
44+
*
45+
* @type {number}
46+
* @memberof AppComponent
47+
*/
48+
imageLoadedEventCount = 0;
49+
50+
/**
51+
* Increments event count on each image loaded event.
52+
* Counter displayed in component template.
53+
*
54+
* @memberof AppComponent
55+
*/
56+
public onPlaceholderLoad(imageLoadedEvent: ImageLoadedEvent) {
57+
this.imagePlaceholderLoaded = true;
58+
}
59+
60+
/**
61+
* Increments event count on each image loaded event.
62+
* Counter displayed in component template.
63+
*
64+
* @memberof AppComponent
65+
*/
66+
public onFullResLoad(imageLoadedEvent: ImageLoadedEvent) {
67+
this.imageLoadedEventCount++;
68+
}
3269
}

src/app/image-loader/image-loader.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
[class]="imgClass"
77
inViewport
88
(inViewportChange)="onInViewportChange($event)"
9-
[debounce]="0">
9+
[debounce]="0"
10+
(load)="onImageLoad($event)">
1011

1112
<img
1213
#dummyImg

src/app/image-loader/image-loader.component.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { TestBed, async, ComponentFixture } from '@angular/core/testing';
22
import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3+
import { By } from '@angular/platform-browser';
34

45
import { ImageLoaderComponent } from './image-loader.component';
56
import { Breakpoint, ResponsiveImage } from './shared/image.model';
7+
import { ImageLoadedEvent } from './index';
68

79
describe('ImageLoaderComponent', () => {
810
let fixture: ComponentFixture<ImageLoaderComponent>;
@@ -56,6 +58,14 @@ describe('ImageLoaderComponent', () => {
5658
expect(spy).toHaveBeenCalled();
5759
});
5860

61+
it('should set fire placeholder loaded event on image load when loaded is false', () => {
62+
const spy = spyOn(component.imagePlaceholderLoaded, 'emit');
63+
component.loaded = false;
64+
const imageElement = fixture.debugElement.query(By.css('img'));
65+
imageElement.triggerEventHandler('load', null);
66+
expect(spy).toHaveBeenCalled();
67+
});
68+
5969
it('should set supportsSrcSet value', () => {
6070
component.supportsSrcSet = false;
6171
const img = document.createElement('img');
@@ -145,6 +155,14 @@ describe('ImageLoaderComponent', () => {
145155
.toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x');
146156
});
147157

158+
it('should emit a full res loaded event on image load when loaded is true', () => {
159+
const spy = spyOn(component.imageLoaded, 'emit');
160+
component.loaded = true;
161+
const imageElement = fixture.debugElement.query(By.css('img'));
162+
imageElement.triggerEventHandler('load', null);
163+
expect(spy).toHaveBeenCalled();
164+
});
165+
148166
it('should complete observable', () => {
149167
const spy = spyOn(component.ngUnsubscribe$, 'complete');
150168
component.ngOnDestroy();

0 commit comments

Comments
 (0)