From 43e7e1dd4c905f66af5a0bbe11b5f2875f17effb Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Tue, 12 Dec 2017 12:30:18 +0000 Subject: [PATCH 01/10] feat(ImageLoader): implemented output event for image loaded. --- .travis.yml | 6 ++ e2e/app.e2e-spec.ts | 62 +++++++++++++++++-- e2e/app.po.ts | 14 +++-- src/app/app.component.html | 2 + src/app/app.component.ts | 18 ++++++ .../image-loader/image-loader.component.html | 3 +- .../image-loader.component.spec.ts | 9 +++ .../image-loader/image-loader.component.ts | 31 +++++++++- 8 files changed, 134 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0d4e9c2..5ecd176 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,3 +18,9 @@ script: - npm run test -- --no-progress --code-coverage --single-run --browser=ChromeNoSandbox - npm run e2e -- --no-progress - npm run coverage +addons: + apt: + sources: + - google-chrome + packages: + - google-chrome-stable diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts index 9de7cc5..1c1f2ff 100644 --- a/e2e/app.e2e-spec.ts +++ b/e2e/app.e2e-spec.ts @@ -25,11 +25,16 @@ describe('ImageLoader Lib E2E Tests', function () { expect(imageLoaderCompClass).toContain('sn-image-not-loaded'); expect(imgSrc).toEqual('http://via.placeholder.com/35x15?text=placeholder'); - page.scrollTo(0, 580 * 1.5); + page.scrollTo(0, 580 * 1.5) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + imageLoaderCompClass = page.getImageLoaderComp().getAttribute('class'); imgSrc = page.getImageElement().getAttribute('srcset'); expect(imageLoaderCompClass).toContain('sn-image-loaded'); expect(imgSrc).toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x'); + }); }); @@ -37,22 +42,69 @@ describe('ImageLoader Lib E2E Tests', function () { beforeEach(() => page.setWindowSize(300, 580)); it('should load correct image for device size', () => { - page.scrollTo(0, 580 * 1.5); + + page.scrollTo(0, 580 * 1.5) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); const imageLoaderCompClass = page.getImageLoaderComp().getAttribute('class'); let imgSrc = page.getImageElement().getAttribute('srcset'); - expect(imageLoaderCompClass).toContain('sn-image-loaded'); expect(imgSrc).toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x'); - page.setWindowSize(768, 580); + page.setWindowSize(768, 580) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + imgSrc = page.getImageElement().getAttribute('srcset'); expect(imgSrc).toEqual('http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x'); - page.setWindowSize(1024, 580); + page.setWindowSize(1024, 580) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + imgSrc = page.getImageElement().getAttribute('srcset'); expect(imgSrc).toEqual('http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x'); }); + }); + + describe('iamge loaded', () => { + beforeEach(() => page.setWindowSize(300, 580)); + + it('should fire an event on placeholder image load', () => { + expect(page.getCountElement().getText()).toEqual('1'); + }); + + it('should update image loaded event count on when image in viewport', () => { + page.scrollTo(0, 580 * 1.5) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + expect(page.getCountElement().getText()).toEqual('2'); + }); + + it('should update image loaded event count on image load on window resize when image in viewport', () => { + + page.scrollTo(0, 580 * 1.5) + .then(() => page.setWindowSize(768, 580)) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + expect(page.getCountElement().getText()).toEqual('3'); + + page.setWindowSize(1024, 580) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + expect(page.getCountElement().getText()).toEqual('4'); + + }); + + }); + }); diff --git a/e2e/app.po.ts b/e2e/app.po.ts index d4a290f..b987f5c 100644 --- a/e2e/app.po.ts +++ b/e2e/app.po.ts @@ -6,13 +6,11 @@ export class AppPage { } scrollTo(x: number = 0, y: number = 0) { - browser.executeScript(`window.scrollTo(${x}, ${y})`); - browser.sleep(200); + return browser.executeScript(`window.scrollTo(${x}, ${y})`); } setWindowSize(x: number, y: number) { - browser.driver.manage().window().setSize(x, y); - browser.sleep(200); + return browser.driver.manage().window().setSize(x, y); } getImageLoaderComp() { @@ -22,4 +20,12 @@ export class AppPage { getImageElement() { return element(by.css('sn-image-loader .foo')); } + + getLoadedImageElement() { + return element(by.css('.sn-image-loaded')).isPresent(); + } + + getCountElement() { + return element(by.css('.count')); + } } diff --git a/src/app/app.component.html b/src/app/app.component.html index 31a64f7..9412007 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,8 +1,10 @@

Scroll down ↓

+

imageLoaded event count: {{ imageLoadedEventCount }}

diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 896de39..fbf5af2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -29,4 +29,22 @@ export class AppComponent { '@2x': 'http://via.placeholder.com/1400x800?text=lg+2x' } }; + + /** + * Incremented on each image load event. + * + * @type {number} + * @memberof ImageLoaderComponent + */ + imageLoadedEventCount = 0; + + /** + * Increments event count on each image loaded event. + * Counter displayed in component template. + * + * @memberof ImageLoaderComponent + */ + public onImageLoad(event) { + this.imageLoadedEventCount++; + } } diff --git a/src/app/image-loader/image-loader.component.html b/src/app/image-loader/image-loader.component.html index 6496ac3..8353b5f 100644 --- a/src/app/image-loader/image-loader.component.html +++ b/src/app/image-loader/image-loader.component.html @@ -6,7 +6,8 @@ [class]="imgClass" inViewport (inViewportChange)="onInViewportChange($event)" - [debounce]="0"> + [debounce]="0" + (load)="onImageLoad(image)"> { .toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x'); }); + it('should emit an event on image load', () => { + const spy = spyOn(component.imageLoaded, 'emit'); + const imageElement = fixture.debugElement.query(By.css('img')); + imageElement.triggerEventHandler('load', null); + expect(spy).toHaveBeenCalled(); + expect(spy).toHaveBeenCalledWith(image); + }); + it('should complete observable', () => { const spy = spyOn(component.ngUnsubscribe$, 'complete'); component.ngOnDestroy(); diff --git a/src/app/image-loader/image-loader.component.ts b/src/app/image-loader/image-loader.component.ts index 5390485..88d8714 100644 --- a/src/app/image-loader/image-loader.component.ts +++ b/src/app/image-loader/image-loader.component.ts @@ -1,4 +1,16 @@ -import { Component, Input, OnInit, HostBinding, HostListener, AfterViewInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; +import { + Component, + Input, + Output, + EventEmitter, + OnInit, + HostBinding, + HostListener, + AfterViewInit, + OnDestroy, + ViewChild, + ElementRef +} from '@angular/core'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/operator/takeUntil'; import 'rxjs/add/operator/debounceTime'; @@ -134,6 +146,15 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { * @memberof ImageLoaderComponent */ public supportsSrcSet = false; + /** + * Output for image loaded event. + * Event payload is object representation of loaded image. + * + * @type {EventEmitter} + * @memberof ImageLoaderComponent + */ + @Output() + public imageLoaded: EventEmitter = new EventEmitter(); /** * If true means the image has not been loaded yet and * the placeholder image is currently displayed @@ -255,6 +276,14 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { this.preloadSrc = ''; this.loaded = true; } + /** + * When the main `img` element has loaded + * + * @memberof ImageLoaderComponent + */ + public onImageLoad(image: ResponsiveImage): void { + this.imageLoaded.emit(image); + } /** * Trigger `ngUnsubscribe` complete on * component destroy lifecycle hook From 8ea17499a574a8ac9743b2c41dfc73c5ca6488ff Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 11:37:03 +0000 Subject: [PATCH 02/10] feat(image-loaded-event.model.ts): image loaded event model added for use by the image loader compon --- src/app/image-loader/shared/image-loaded-event.model.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/app/image-loader/shared/image-loaded-event.model.ts diff --git a/src/app/image-loader/shared/image-loaded-event.model.ts b/src/app/image-loader/shared/image-loaded-event.model.ts new file mode 100644 index 0000000..7ee1ab7 --- /dev/null +++ b/src/app/image-loader/shared/image-loaded-event.model.ts @@ -0,0 +1,5 @@ +export interface ImageLoadedEvent { + $event: Event; + src: string; + srcset: string; +} From 1c0653a07155388208a374178f73f94d3cd361e8 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 11:37:58 +0000 Subject: [PATCH 03/10] feat(image-loader component): installed commitizen config module --- package-lock.json | 37 +++++++++++++++++++++++++++++++++++++ package.json | 6 ++++++ 2 files changed, 43 insertions(+) diff --git a/package-lock.json b/package-lock.json index dd130e6..1c0af56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1819,6 +1819,12 @@ } } }, + "conventional-commit-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.2.0.tgz", + "integrity": "sha1-XblXOdbCEqy+e29lahG5QLqmiUY=", + "dev": true + }, "conventional-commits-filter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-1.1.0.tgz", @@ -2222,6 +2228,19 @@ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", "dev": true }, + "cz-conventional-changelog": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz", + "integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=", + "dev": true, + "requires": { + "conventional-commit-types": "2.2.0", + "lodash.map": "4.6.0", + "longest": "1.0.1", + "right-pad": "1.0.1", + "word-wrap": "1.2.3" + } + }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", @@ -6491,6 +6510,12 @@ "lodash.isarray": "3.0.4" } }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -9194,6 +9219,12 @@ "align-text": "0.1.4" } }, + "right-pad": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", + "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", + "dev": true + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -11659,6 +11690,12 @@ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", diff --git a/package.json b/package.json index f172ef2..3458df5 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "codelyzer": "^4.0.1", "core-js": "^2.4.1", "coveralls": "^3.0.0", + "cz-conventional-changelog": "^2.1.0", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", @@ -84,5 +85,10 @@ "tslint": "~5.7.0", "typescript": "~2.4.2", "zone.js": "^0.8.14" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } } } From f564434d445f232e0d4d77ae6d6d56b127a55395 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 11:46:43 +0000 Subject: [PATCH 04/10] feat(image-loader component): Event outputs from image loader component added for placeholder image BREAKING CHANGE: The inputs and outputs to the image-loader component have changed --- .../image-loader/image-loader.component.html | 2 +- .../image-loader/image-loader.component.ts | 30 +++++++++++++++---- src/app/image-loader/shared/index.ts | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/app/image-loader/image-loader.component.html b/src/app/image-loader/image-loader.component.html index 8353b5f..2d56348 100644 --- a/src/app/image-loader/image-loader.component.html +++ b/src/app/image-loader/image-loader.component.html @@ -7,7 +7,7 @@ inViewport (inViewportChange)="onInViewportChange($event)" [debounce]="0" - (load)="onImageLoad(image)"> + (load)="onImageLoad($event)"> lorem ipsum * * ``` @@ -147,14 +149,21 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { */ public supportsSrcSet = false; /** - * Output for image loaded event. - * Event payload is object representation of loaded image. + * Output for placeholder image loaded event. * * @type {EventEmitter} * @memberof ImageLoaderComponent */ @Output() - public imageLoaded: EventEmitter = new EventEmitter(); + public placeholderLoaded: EventEmitter = new EventEmitter(); + /** + * Output for full res image loaded event. + * + * @type {EventEmitter} + * @memberof ImageLoaderComponent + */ + @Output() + public fullResLoaded: EventEmitter = new EventEmitter(); /** * If true means the image has not been loaded yet and * the placeholder image is currently displayed @@ -281,8 +290,17 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { * * @memberof ImageLoaderComponent */ - public onImageLoad(image: ResponsiveImage): void { - this.imageLoaded.emit(image); + public onImageLoad($event: Event): void { + const eventData = { + $event, + src: this.src, + srcset: this.srcset + }; + if (!this.loaded) { + this.placeholderLoaded.emit(eventData); + return; + } + this.fullResLoaded.emit(eventData); } /** * Trigger `ngUnsubscribe` complete on diff --git a/src/app/image-loader/shared/index.ts b/src/app/image-loader/shared/index.ts index 59f023e..9f8cd37 100644 --- a/src/app/image-loader/shared/index.ts +++ b/src/app/image-loader/shared/index.ts @@ -1,3 +1,4 @@ export * from './classes'; export * from './events'; export * from './image.model'; +export * from './image-loaded-event.model'; From 38d452f863411b6bce964c6a250c651904e6f3c9 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 12:01:23 +0000 Subject: [PATCH 05/10] test(image-loader component): updated tests for updated component --- .../image-loader/image-loader.component.spec.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/app/image-loader/image-loader.component.spec.ts b/src/app/image-loader/image-loader.component.spec.ts index d9dd04b..65aa7eb 100644 --- a/src/app/image-loader/image-loader.component.spec.ts +++ b/src/app/image-loader/image-loader.component.spec.ts @@ -4,6 +4,7 @@ import { By } from '@angular/platform-browser'; import { ImageLoaderComponent } from './image-loader.component'; import { Breakpoint, ResponsiveImage } from './shared/image.model'; +import { ImageLoadedEvent } from './index'; describe('ImageLoaderComponent', () => { let fixture: ComponentFixture; @@ -57,6 +58,14 @@ describe('ImageLoaderComponent', () => { expect(spy).toHaveBeenCalled(); }); + it('should set fire placeholder loaded event on image load when loaded is false', () => { + const spy = spyOn(component.placeholderLoaded, 'emit'); + component.loaded = false; + const imageElement = fixture.debugElement.query(By.css('img')); + imageElement.triggerEventHandler('load', null); + expect(spy).toHaveBeenCalled(); + }); + it('should set supportsSrcSet value', () => { component.supportsSrcSet = false; const img = document.createElement('img'); @@ -146,12 +155,12 @@ describe('ImageLoaderComponent', () => { .toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x'); }); - it('should emit an event on image load', () => { - const spy = spyOn(component.imageLoaded, 'emit'); + it('should emit a full res loaded event on image load when loaded is true', () => { + const spy = spyOn(component.fullResLoaded, 'emit'); + component.loaded = true; const imageElement = fixture.debugElement.query(By.css('img')); imageElement.triggerEventHandler('load', null); expect(spy).toHaveBeenCalled(); - expect(spy).toHaveBeenCalledWith(image); }); it('should complete observable', () => { From b420de745e7d222c0f3f3e43ae025631c61dcb30 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 12:03:20 +0000 Subject: [PATCH 06/10] feat(app component): updated app component implementation of image-loader component to match updated BREAKING CHANGE: image-loader components updated inputs and outputs implemented --- src/app/app.component.html | 7 +++++-- src/app/app.component.ts | 29 ++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 9412007..f7e3711 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,10 +1,13 @@

Scroll down ↓

+

Placeholder image loaded: {{ placeholderLoaded }}

-

imageLoaded event count: {{ imageLoadedEventCount }}

+

fullResLoaded event count: {{ fullResLoadedEventCount }}

diff --git a/src/app/app.component.ts b/src/app/app.component.ts index fbf5af2..c50abfd 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { ResponsiveImage, Breakpoint, Size } from './image-loader'; +import { ImageLoadedEvent } from './image-loader/shared'; @Component({ selector: 'sn-root', @@ -30,21 +31,39 @@ export class AppComponent { } }; + /** + * Set to true on placeholder loaded event. + * + * @type {boolean} + * @memberof AppComponent + */ + placeholderLoaded = false; + /** * Incremented on each image load event. * * @type {number} - * @memberof ImageLoaderComponent + * @memberof AppComponent */ - imageLoadedEventCount = 0; + fullResLoadedEventCount = 0; + + /** + * Increments event count on each image loaded event. + * Counter displayed in component template. + * + * @memberof AppComponent + */ + public onPlaceholderLoad(imageLoadedEvent: ImageLoadedEvent) { + this.placeholderLoaded = true; + } /** * Increments event count on each image loaded event. * Counter displayed in component template. * - * @memberof ImageLoaderComponent + * @memberof AppComponent */ - public onImageLoad(event) { - this.imageLoadedEventCount++; + public onFullResLoad(imageLoadedEvent: ImageLoadedEvent) { + this.fullResLoadedEventCount++; } } From 454aa090554a9c13ad1224d375fbc25c4a0fd346 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 12:04:21 +0000 Subject: [PATCH 07/10] test(end to end): updated ene to end tests to match updated app and image-loader component functiona --- e2e/app.e2e-spec.ts | 48 ++++++++++++++++++++++++++++----------------- e2e/app.po.ts | 8 ++++++-- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts index 1c1f2ff..a0d660d 100644 --- a/e2e/app.e2e-spec.ts +++ b/e2e/app.e2e-spec.ts @@ -16,6 +16,18 @@ describe('ImageLoader Lib E2E Tests', function () { }); }); + describe('placeholder image', () => { + beforeEach(() => page.setWindowSize(300, 580)); + + it('should load placeholder image', () => { + expect(page.getImageElement().getAttribute('src')).toEqual('http://via.placeholder.com/35x15?text=placeholder'); + }); + + it('should update placeholder loaded boolean on init', () => { + expect(page.getplaceholderBooleanElement().getText()).toEqual('true'); + }); + }); + describe('lazy load image', () => { beforeEach(() => page.setWindowSize(300, 580)); @@ -36,13 +48,24 @@ describe('ImageLoader Lib E2E Tests', function () { expect(imgSrc).toEqual('http://via.placeholder.com/150x350?text=xs+1x 1x, http://via.placeholder.com/300x700?text=xs+2x 2x'); }); + + it('should update full res image event count on when in viewport', () => { + expect(page.getFullResCountElement().getText()).toEqual('0'); + + page.scrollTo(0, 580 * 1.5) + .then(() => { + browser.wait(() => page.getLoadedImageElement()); + }); + + expect(page.getFullResCountElement().getText()).toEqual('1'); + }); + }); describe('responsive image', () => { beforeEach(() => page.setWindowSize(300, 580)); it('should load correct image for device size', () => { - page.scrollTo(0, 580 * 1.5) .then(() => { browser.wait(() => page.getLoadedImageElement()); @@ -70,38 +93,27 @@ describe('ImageLoader Lib E2E Tests', function () { expect(imgSrc).toEqual('http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x'); }); - }); - - describe('iamge loaded', () => { - beforeEach(() => page.setWindowSize(300, 580)); + it('should update image loaded event count on window resize when image in viewport', () => { + expect(page.getFullResCountElement().getText()).toEqual('0'); - it('should fire an event on placeholder image load', () => { - expect(page.getCountElement().getText()).toEqual('1'); - }); - - it('should update image loaded event count on when image in viewport', () => { page.scrollTo(0, 580 * 1.5) .then(() => { browser.wait(() => page.getLoadedImageElement()); }); - expect(page.getCountElement().getText()).toEqual('2'); - }); - it('should update image loaded event count on image load on window resize when image in viewport', () => { + expect(page.getFullResCountElement().getText()).toEqual('1'); - page.scrollTo(0, 580 * 1.5) - .then(() => page.setWindowSize(768, 580)) + page.setWindowSize(768, 580) .then(() => { browser.wait(() => page.getLoadedImageElement()); }); - expect(page.getCountElement().getText()).toEqual('3'); + expect(page.getFullResCountElement().getText()).toEqual('2'); page.setWindowSize(1024, 580) .then(() => { browser.wait(() => page.getLoadedImageElement()); }); - expect(page.getCountElement().getText()).toEqual('4'); - + expect(page.getFullResCountElement().getText()).toEqual('3'); }); }); diff --git a/e2e/app.po.ts b/e2e/app.po.ts index b987f5c..3c70ea4 100644 --- a/e2e/app.po.ts +++ b/e2e/app.po.ts @@ -25,7 +25,11 @@ export class AppPage { return element(by.css('.sn-image-loaded')).isPresent(); } - getCountElement() { - return element(by.css('.count')); + getplaceholderBooleanElement() { + return element(by.css('.placeholder-boolean')); + } + + getFullResCountElement() { + return element(by.css('.full-res-count')); } } From 39be8890439060481ff8d5ae7acc51324cdd6a3e Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 12:44:48 +0000 Subject: [PATCH 08/10] test(end to end): Added function to wait for loading of specific image by srcSet attribute. Prevents tests from running before the next image is loaded. --- e2e/app.e2e-spec.ts | 16 ++++++++++++---- e2e/app.po.ts | 4 ++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts index a0d660d..2cc6d9a 100644 --- a/e2e/app.e2e-spec.ts +++ b/e2e/app.e2e-spec.ts @@ -78,7 +78,9 @@ describe('ImageLoader Lib E2E Tests', function () { page.setWindowSize(768, 580) .then(() => { - browser.wait(() => page.getLoadedImageElement()); + browser.wait(() => page.getLoadedImageElementBySrcSet( + 'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x' + ), 5000); }); imgSrc = page.getImageElement().getAttribute('srcset'); @@ -86,7 +88,9 @@ describe('ImageLoader Lib E2E Tests', function () { page.setWindowSize(1024, 580) .then(() => { - browser.wait(() => page.getLoadedImageElement()); + browser.wait(() => page.getLoadedImageElementBySrcSet( + 'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x' + ), 5000); }); imgSrc = page.getImageElement().getAttribute('srcset'); @@ -105,13 +109,17 @@ describe('ImageLoader Lib E2E Tests', function () { page.setWindowSize(768, 580) .then(() => { - browser.wait(() => page.getLoadedImageElement()); + browser.wait(() => page.getLoadedImageElementBySrcSet( + 'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x' + ), 5000); }); expect(page.getFullResCountElement().getText()).toEqual('2'); page.setWindowSize(1024, 580) .then(() => { - browser.wait(() => page.getLoadedImageElement()); + browser.wait(() => page.getLoadedImageElementBySrcSet( + 'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x' + ), 5000); }); expect(page.getFullResCountElement().getText()).toEqual('3'); }); diff --git a/e2e/app.po.ts b/e2e/app.po.ts index 3c70ea4..90f6728 100644 --- a/e2e/app.po.ts +++ b/e2e/app.po.ts @@ -25,6 +25,10 @@ export class AppPage { return element(by.css('.sn-image-loaded')).isPresent(); } + getLoadedImageElementBySrcSet(srcSet) { + return element(by.css(`img[srcSet="${srcSet}"]`)).isPresent(); + } + getplaceholderBooleanElement() { return element(by.css('.placeholder-boolean')); } From 44b154fc4c7997c1768b2b4154bf0737bd155c3b Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 12:50:11 +0000 Subject: [PATCH 09/10] test(end to end): variable for browser wait timeout value --- e2e/app.e2e-spec.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/e2e/app.e2e-spec.ts b/e2e/app.e2e-spec.ts index 2cc6d9a..bf242c4 100644 --- a/e2e/app.e2e-spec.ts +++ b/e2e/app.e2e-spec.ts @@ -4,6 +4,8 @@ import { browser } from 'protractor'; describe('ImageLoader Lib E2E Tests', function () { let page: AppPage; + const browserWaitTimeout = 10000; + beforeEach(() => page = new AppPage()); beforeEach(() => page.navigateTo()); @@ -80,7 +82,7 @@ describe('ImageLoader Lib E2E Tests', function () { .then(() => { browser.wait(() => page.getLoadedImageElementBySrcSet( 'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x' - ), 5000); + ), browserWaitTimeout); }); imgSrc = page.getImageElement().getAttribute('srcset'); @@ -90,7 +92,7 @@ describe('ImageLoader Lib E2E Tests', function () { .then(() => { browser.wait(() => page.getLoadedImageElementBySrcSet( 'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x' - ), 5000); + ), browserWaitTimeout); }); imgSrc = page.getImageElement().getAttribute('srcset'); @@ -111,7 +113,7 @@ describe('ImageLoader Lib E2E Tests', function () { .then(() => { browser.wait(() => page.getLoadedImageElementBySrcSet( 'http://via.placeholder.com/350x250?text=md+1x 1x, http://via.placeholder.com/700x500?text=md+2x 2x' - ), 5000); + ), browserWaitTimeout); }); expect(page.getFullResCountElement().getText()).toEqual('2'); @@ -119,7 +121,7 @@ describe('ImageLoader Lib E2E Tests', function () { .then(() => { browser.wait(() => page.getLoadedImageElementBySrcSet( 'http://via.placeholder.com/700x400?text=lg+1x 1x, http://via.placeholder.com/1400x800?text=lg+2x 2x' - ), 5000); + ), browserWaitTimeout); }); expect(page.getFullResCountElement().getText()).toEqual('3'); }); From 31aee4587a6924d04e4a5c0ce6b0cb66a9afa9a6 Mon Sep 17 00:00:00 2001 From: Jack Matthews Date: Wed, 13 Dec 2017 14:26:43 +0000 Subject: [PATCH 10/10] refactor(image-loader component): Name change, placeholderLoaded and fullResLoaded updated to imageL BREAKING CHANGE: Variable name changes affect the image-loader component API --- src/app/app.component.html | 8 ++++---- src/app/app.component.ts | 8 ++++---- src/app/image-loader/image-loader.component.spec.ts | 4 ++-- src/app/image-loader/image-loader.component.ts | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index f7e3711..ae7e872 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,13 +1,13 @@

Scroll down ↓

-

Placeholder image loaded: {{ placeholderLoaded }}

+

Placeholder image loaded: {{ imagePlaceholderLoaded }}

-

fullResLoaded event count: {{ fullResLoadedEventCount }}

+

imageLoaded event count: {{ imageLoadedEventCount }}

diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c50abfd..77595b7 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -37,7 +37,7 @@ export class AppComponent { * @type {boolean} * @memberof AppComponent */ - placeholderLoaded = false; + imagePlaceholderLoaded = false; /** * Incremented on each image load event. @@ -45,7 +45,7 @@ export class AppComponent { * @type {number} * @memberof AppComponent */ - fullResLoadedEventCount = 0; + imageLoadedEventCount = 0; /** * Increments event count on each image loaded event. @@ -54,7 +54,7 @@ export class AppComponent { * @memberof AppComponent */ public onPlaceholderLoad(imageLoadedEvent: ImageLoadedEvent) { - this.placeholderLoaded = true; + this.imagePlaceholderLoaded = true; } /** @@ -64,6 +64,6 @@ export class AppComponent { * @memberof AppComponent */ public onFullResLoad(imageLoadedEvent: ImageLoadedEvent) { - this.fullResLoadedEventCount++; + this.imageLoadedEventCount++; } } diff --git a/src/app/image-loader/image-loader.component.spec.ts b/src/app/image-loader/image-loader.component.spec.ts index 65aa7eb..2683657 100644 --- a/src/app/image-loader/image-loader.component.spec.ts +++ b/src/app/image-loader/image-loader.component.spec.ts @@ -59,7 +59,7 @@ describe('ImageLoaderComponent', () => { }); it('should set fire placeholder loaded event on image load when loaded is false', () => { - const spy = spyOn(component.placeholderLoaded, 'emit'); + const spy = spyOn(component.imagePlaceholderLoaded, 'emit'); component.loaded = false; const imageElement = fixture.debugElement.query(By.css('img')); imageElement.triggerEventHandler('load', null); @@ -156,7 +156,7 @@ describe('ImageLoaderComponent', () => { }); it('should emit a full res loaded event on image load when loaded is true', () => { - const spy = spyOn(component.fullResLoaded, 'emit'); + const spy = spyOn(component.imageLoaded, 'emit'); component.loaded = true; const imageElement = fixture.debugElement.query(By.css('img')); imageElement.triggerEventHandler('load', null); diff --git a/src/app/image-loader/image-loader.component.ts b/src/app/image-loader/image-loader.component.ts index 6f72b87..ad32929 100644 --- a/src/app/image-loader/image-loader.component.ts +++ b/src/app/image-loader/image-loader.component.ts @@ -29,8 +29,8 @@ import { ImageLoadedEvent, ResponsiveImage, RetinaImage, Size, Breakpoint, Retin * [image]="image" * [sizes]="sizes" * imgClass="foo" - * (placeholderLoaded)="onPlaceholderLoad($event)" - * (fullResLoaded)="onFullResLoad($event)" + * (imagePlaceholderLoaded)="onPlaceholderLoad($event)" + * (imageLoaded)="onFullResLoad($event)" * alt="lorem ipsum"> * * ``` @@ -155,7 +155,7 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { * @memberof ImageLoaderComponent */ @Output() - public placeholderLoaded: EventEmitter = new EventEmitter(); + public imagePlaceholderLoaded: EventEmitter = new EventEmitter(); /** * Output for full res image loaded event. * @@ -163,7 +163,7 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { * @memberof ImageLoaderComponent */ @Output() - public fullResLoaded: EventEmitter = new EventEmitter(); + public imageLoaded: EventEmitter = new EventEmitter(); /** * If true means the image has not been loaded yet and * the placeholder image is currently displayed @@ -297,10 +297,10 @@ export class ImageLoaderComponent implements OnInit, AfterViewInit, OnDestroy { srcset: this.srcset }; if (!this.loaded) { - this.placeholderLoaded.emit(eventData); + this.imagePlaceholderLoaded.emit(eventData); return; } - this.fullResLoaded.emit(eventData); + this.imageLoaded.emit(eventData); } /** * Trigger `ngUnsubscribe` complete on