From eca11298ee0b16ff731566f8ef68aa58878d98d1 Mon Sep 17 00:00:00 2001 From: Adrian Date: Tue, 26 Sep 2017 21:40:55 +0300 Subject: [PATCH 1/4] Fixed karma config --- karma.conf.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 1a74f89..2d7216a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,18 +6,18 @@ const customLaunchers = require('./scripts/sauce-browsers').customLaunchers; module.exports = function (config) { const configuration = { basePath: '', - frameworks: ['jasmine', 'angular-cli'], + frameworks: ['jasmine', '@angular/cli'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-remap-istanbul'), - require('angular-cli/plugins/karma') + require('@angular/cli/plugins/karma') ], files: [ {pattern: './scripts/test.ts', watched: false} ], preprocessors: { - './scripts/test.ts': ['angular-cli'] + './scripts/test.ts': ['@angular/cli'] }, remapIstanbulReporter: { reports: { From 6bdf60fac4db801ff4ccd3089a801833551990ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Tue, 26 Sep 2017 23:04:21 +0300 Subject: [PATCH 2/4] Adding tests for file drop directive --- src/file-upload/file-drop.directive.ts | 47 ++++----- src/spec/file-drop.directive.spec.ts | 137 +++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 37 deletions(-) diff --git a/src/file-upload/file-drop.directive.ts b/src/file-upload/file-drop.directive.ts index 6c1c4ff..b04ae51 100644 --- a/src/file-upload/file-drop.directive.ts +++ b/src/file-upload/file-drop.directive.ts @@ -1,29 +1,29 @@ import { Directive, EventEmitter, ElementRef, HostListener, Input, Output } from '@angular/core'; -import { FileUploader } from './file-uploader.class'; +import { FileUploader, FileUploaderOptions } from './file-uploader.class'; -@Directive({selector: '[ng2FileDrop]'}) +@Directive({ selector: '[ng2FileDrop]' }) export class FileDropDirective { - @Input() public uploader:FileUploader; - @Output() public fileOver:EventEmitter = new EventEmitter(); - @Output() public onFileDrop:EventEmitter = new EventEmitter(); + @Input() public uploader: FileUploader; + @Output() public fileOver: EventEmitter = new EventEmitter(); + @Output() public onFileDrop: EventEmitter = new EventEmitter(); - protected element:ElementRef; + protected element: ElementRef; - public constructor(element:ElementRef) { + public constructor(element: ElementRef) { this.element = element; } - public getOptions():any { + public getOptions(): FileUploaderOptions { return this.uploader.options; } - public getFilters():any { + public getFilters(): any { return {}; } - @HostListener('drop', ['$event']) - public onDrop(event:any):void { + @HostListener('drop', [ '$event' ]) + public onDrop(event: any): void { let transfer = this._getTransfer(event); if (!transfer) { return; @@ -37,8 +37,8 @@ export class FileDropDirective { this.onFileDrop.emit(transfer.files); } - @HostListener('dragover', ['$event']) - public onDragOver(event:any):void { + @HostListener('dragover', [ '$event' ]) + public onDragOver(event: any): void { let transfer = this._getTransfer(event); if (!this._haveFiles(transfer.types)) { return; @@ -49,10 +49,10 @@ export class FileDropDirective { this.fileOver.emit(true); } - @HostListener('dragleave', ['$event']) - public onDragLeave(event:any):any { + @HostListener('dragleave', [ '$event' ]) + public onDragLeave(event: any): any { if ((this as any).element) { - if (event.currentTarget === (this as any).element[0]) { + if (event.currentTarget === (this as any).element[ 0 ]) { return; } } @@ -61,16 +61,16 @@ export class FileDropDirective { this.fileOver.emit(false); } - protected _getTransfer(event:any):any { + protected _getTransfer(event: any): any { return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix; } - protected _preventAndStop(event:any):any { + protected _preventAndStop(event: any): any { event.preventDefault(); event.stopPropagation(); } - protected _haveFiles(types:any):any { + protected _haveFiles(types: any): any { if (!types) { return false; } @@ -83,13 +83,4 @@ export class FileDropDirective { return false; } } - - /* - _addOverClass(item:any):any { - item.addOverClass(); - } - - _removeOverClass(item:any):any { - item.removeOverClass(); - }*/ } diff --git a/src/spec/file-drop.directive.spec.ts b/src/spec/file-drop.directive.spec.ts index 6b5a268..5734bd8 100644 --- a/src/spec/file-drop.directive.spec.ts +++ b/src/spec/file-drop.directive.spec.ts @@ -1,28 +1,147 @@ -import { Component } from '@angular/core'; +import { Component, DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; import { inject, ComponentFixture, TestBed } from '@angular/core/testing'; import { FileUploader } from '../file-upload/file-uploader.class'; import { FileUploadModule } from '../file-upload/file-upload.module'; +import { FileDropDirective } from '../file-upload/file-drop.directive'; @Component({ selector: 'container', - template: `` + template: `` }) export class ContainerComponent { - public uploader:FileUploader = new FileUploader({url: 'localhost:3000'}); + public get url(): string { return 'localhost:3000'; } + public uploader: FileUploader = new FileUploader({ url: this.url }); } describe('Directive: FileSelectDirective', () => { + let fixture: ComponentFixture; + let hostComponent: ContainerComponent; + let directiveElement: DebugElement; + let fileDropDirective: FileDropDirective; + beforeEach(() => { TestBed.configureTestingModule({ - imports: [FileUploadModule], - declarations: [ContainerComponent], - providers: [ContainerComponent] + imports: [ FileUploadModule ], + declarations: [ ContainerComponent ], + providers: [ ContainerComponent ] }); }); - it('should be fine', inject([ContainerComponent], (fixture:ComponentFixture) => { - expect(fixture).not.toBeNull(); - })); + beforeEach(() => { + fixture = TestBed.createComponent(ContainerComponent); + hostComponent = fixture.componentInstance; + + fixture.detectChanges(); + + directiveElement = fixture.debugElement.query(By.directive(FileDropDirective)); + fileDropDirective = directiveElement.injector.get(FileDropDirective) as FileDropDirective; + }); + + it('can be initialized', () => { + expect(fixture).toBeDefined(); + expect(hostComponent).toBeDefined(); + expect(fileDropDirective).toBeDefined(); + }); + + it('can set file uploader', () => { + expect(fileDropDirective.uploader).toBe(hostComponent.uploader); + }); + + it('can get uploader options', () => { + const options = fileDropDirective.getOptions(); + + // Check url set through binding + expect(options.url).toBe(hostComponent.url); + + // Check default options + expect(options.autoUpload).toBeFalsy(); + expect(options.isHTML5).toBeTruthy(); + expect(options.removeAfterUpload).toBeFalsy(); + expect(options.disableMultipart).toBeFalsy(); + }); + + it('can get filters', () => { + const filters = fileDropDirective.getFilters(); + + // TODO: Update test once implemented + expect(filters).toEqual({}); + }); + + it('handles drop event', () => { + spyOn(fileDropDirective, 'onDrop'); + + directiveElement.triggerEventHandler('drop', getFakeEvent()); + + expect(fileDropDirective.onDrop).toHaveBeenCalled(); + }); + + it('adds file to upload', () => { + spyOn(fileDropDirective.uploader, 'addToQueue'); + + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + let fileDropData; + fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data); + + fileDropDirective.onDrop(getFakeEvent()); + + const uploadedFiles = getFakeEvent().dataTransfer.files; + const expectedArguments = [ uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters() ]; + + expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); + expect(fileOverData).toBeFalsy(); + expect(fileDropData).toEqual(uploadedFiles); + }); + + it('handles dragover event', () => { + spyOn(fileDropDirective, 'onDragOver'); + + directiveElement.triggerEventHandler('dragover', getFakeEvent()); + + expect(fileDropDirective.onDragOver).toHaveBeenCalled(); + }); + + it('handles file over', () => { + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + fileDropDirective.onDragOver(getFakeEvent()); + + expect(fileOverData).toBeTruthy(); + }); + + it('handles dragleave event', () => { + spyOn(fileDropDirective, 'onDragLeave'); + + directiveElement.triggerEventHandler('dragleave', getFakeEvent()); + + expect(fileDropDirective.onDragLeave).toHaveBeenCalled(); + }); + + it('handles file over leave', () => { + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + fileDropDirective.onDragLeave(getFakeEvent()); + + expect(fileOverData).toBeFalsy(); + }); }); + +function getFakeEvent(): any { + return { + dataTransfer: { + files: [ 'foo.bar' ], + types: [ 'Files' ] + }, + preventDefault: () => undefined, + stopPropagation: () => undefined + } +} From 0df30f996fd9c1f3e46bf70829e98187b55ae061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Sun, 1 Oct 2017 17:07:54 +0300 Subject: [PATCH 3/4] Fixing test execution on CI --- karma.conf.js | 12 +++++------- package.json | 5 +++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 2d7216a..152285d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -10,7 +10,7 @@ module.exports = function (config) { plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), - require('karma-remap-istanbul'), + require('karma-coverage-istanbul-reporter'), require('@angular/cli/plugins/karma') ], files: [ @@ -19,18 +19,16 @@ module.exports = function (config) { preprocessors: { './scripts/test.ts': ['@angular/cli'] }, - remapIstanbulReporter: { - reports: { - html: 'coverage', - lcovonly: './coverage/coverage.lcov' - } + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: false }, angularCli: { config: './angular-cli.json', environment: 'dev' }, reporters: config.angularCli && config.angularCli.codeCoverage - ? ['dots', 'karma-remap-istanbul'] + ? ['dots', 'coverage-istanbul'] : ['dots'], port: 9876, colors: true, diff --git a/package.json b/package.json index 30f6f7e..f8dbcb1 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@angular/core": "^2.3.1 || >=4.0.0" }, "devDependencies": { + "@angular/cli": "1.0.0", "@angular/common": "2.4.3", "@angular/compiler": "2.4.3", "@angular/compiler-cli": "2.4.3", @@ -64,7 +65,6 @@ "@types/marked": "0.0.28", "@types/node": "7.0.0", "@types/webpack": "^2.2.1", - "@angular/cli": "1.0.0", "bootstrap": "3.3.7", "chokidar-cli": "1.2.0", "classlist-polyfill": "1.0.3", @@ -87,6 +87,7 @@ "karma": "1.4.0", "karma-chrome-launcher": "^2.0.0", "karma-cli": "^1.0.1", + "karma-coverage-istanbul-reporter": "^1.3.0", "karma-jasmine": "^1.0.2", "karma-remap-istanbul": "0.4.0", "karma-sauce-launcher": "1.1.0", @@ -94,9 +95,9 @@ "lodash": "4.17.4", "markdown-loader": "^0.1.7", "marked": "0.3.6", - "ngx-bootstrap": "1.6.6", "ng2-page-scroll": "4.0.0-beta.2", "ngm-cli": "0.4.0", + "ngx-bootstrap": "1.6.6", "npm-run-all": "^4.0.1", "pre-commit": "1.2.2", "protractor": "5.0.0", From 048f534aa23c54bd66a9c739485e1e56e93679f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Sun, 1 Oct 2017 17:33:38 +0300 Subject: [PATCH 4/4] Adding tests for file select directive --- src/file-upload/file-select.directive.ts | 18 ++--- src/spec/file-drop.directive.spec.ts | 22 +++--- src/spec/file-select.directive.spec.ts | 99 ++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 src/spec/file-select.directive.spec.ts diff --git a/src/file-upload/file-select.directive.ts b/src/file-upload/file-select.directive.ts index ed84cba..8060647 100644 --- a/src/file-upload/file-select.directive.ts +++ b/src/file-upload/file-select.directive.ts @@ -4,30 +4,30 @@ import { FileUploader } from './file-uploader.class'; // todo: filters -@Directive({selector: '[ng2FileSelect]'}) +@Directive({ selector: '[ng2FileSelect]' }) export class FileSelectDirective { - @Input() public uploader:FileUploader; + @Input() public uploader: FileUploader; - protected element:ElementRef; + protected element: ElementRef; - public constructor(element:ElementRef) { + public constructor(element: ElementRef) { this.element = element; } - public getOptions():any { + public getOptions(): any { return this.uploader.options; } - public getFilters():any { - return void 0; + public getFilters(): any { + return {}; } - public isEmptyAfterSelection():boolean { + public isEmptyAfterSelection(): boolean { return !!this.element.nativeElement.attributes.multiple; } @HostListener('change') - public onChange():any { + public onChange(): any { // let files = this.uploader.isHTML5 ? this.element.nativeElement[0].files : this.element.nativeElement[0]; let files = this.element.nativeElement.files; let options = this.getOptions(); diff --git a/src/spec/file-drop.directive.spec.ts b/src/spec/file-drop.directive.spec.ts index 5734bd8..58bca0e 100644 --- a/src/spec/file-drop.directive.spec.ts +++ b/src/spec/file-drop.directive.spec.ts @@ -8,17 +8,17 @@ import { FileDropDirective } from '../file-upload/file-drop.directive'; @Component({ selector: 'container', - template: `` + >` }) export class ContainerComponent { public get url(): string { return 'localhost:3000'; } public uploader: FileUploader = new FileUploader({ url: this.url }); } -describe('Directive: FileSelectDirective', () => { +describe('Directive: FileDropDirective', () => { let fixture: ComponentFixture; let hostComponent: ContainerComponent; @@ -76,7 +76,7 @@ describe('Directive: FileSelectDirective', () => { it('handles drop event', () => { spyOn(fileDropDirective, 'onDrop'); - directiveElement.triggerEventHandler('drop', getFakeEvent()); + directiveElement.triggerEventHandler('drop', getFakeEventData()); expect(fileDropDirective.onDrop).toHaveBeenCalled(); }); @@ -90,9 +90,9 @@ describe('Directive: FileSelectDirective', () => { let fileDropData; fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data); - fileDropDirective.onDrop(getFakeEvent()); + fileDropDirective.onDrop(getFakeEventData()); - const uploadedFiles = getFakeEvent().dataTransfer.files; + const uploadedFiles = getFakeEventData().dataTransfer.files; const expectedArguments = [ uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters() ]; expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); @@ -103,7 +103,7 @@ describe('Directive: FileSelectDirective', () => { it('handles dragover event', () => { spyOn(fileDropDirective, 'onDragOver'); - directiveElement.triggerEventHandler('dragover', getFakeEvent()); + directiveElement.triggerEventHandler('dragover', getFakeEventData()); expect(fileDropDirective.onDragOver).toHaveBeenCalled(); }); @@ -112,7 +112,7 @@ describe('Directive: FileSelectDirective', () => { let fileOverData; fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); - fileDropDirective.onDragOver(getFakeEvent()); + fileDropDirective.onDragOver(getFakeEventData()); expect(fileOverData).toBeTruthy(); }); @@ -120,7 +120,7 @@ describe('Directive: FileSelectDirective', () => { it('handles dragleave event', () => { spyOn(fileDropDirective, 'onDragLeave'); - directiveElement.triggerEventHandler('dragleave', getFakeEvent()); + directiveElement.triggerEventHandler('dragleave', getFakeEventData()); expect(fileDropDirective.onDragLeave).toHaveBeenCalled(); }); @@ -129,13 +129,13 @@ describe('Directive: FileSelectDirective', () => { let fileOverData; fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); - fileDropDirective.onDragLeave(getFakeEvent()); + fileDropDirective.onDragLeave(getFakeEventData()); expect(fileOverData).toBeFalsy(); }); }); -function getFakeEvent(): any { +function getFakeEventData(): any { return { dataTransfer: { files: [ 'foo.bar' ], diff --git a/src/spec/file-select.directive.spec.ts b/src/spec/file-select.directive.spec.ts new file mode 100644 index 0000000..dfddc52 --- /dev/null +++ b/src/spec/file-select.directive.spec.ts @@ -0,0 +1,99 @@ +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { Component, DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +import { FileUploadModule } from '../file-upload/file-upload.module'; +import { FileSelectDirective } from '../file-upload/file-select.directive'; +import { FileUploader } from '../file-upload/file-uploader.class'; + +@Component({ + selector: 'container', + template: `` +}) +export class ContainerComponent { + public get url(): string { return 'localhost:3000'; } + public uploader: FileUploader = new FileUploader({ url: this.url }); +} + +describe('Directive: FileSelectDirective', () => { + let fixture: ComponentFixture; + let hostComponent: ContainerComponent; + let directiveElement: DebugElement; + let fileSelectDirective: FileSelectDirective; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ FileUploadModule ], + declarations: [ ContainerComponent ], + providers: [ ContainerComponent ] + }); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ContainerComponent); + hostComponent = fixture.componentInstance; + + fixture.detectChanges(); + + directiveElement = fixture.debugElement.query(By.directive(FileSelectDirective)); + fileSelectDirective = directiveElement.injector.get(FileSelectDirective) as FileSelectDirective; + }); + + it('can be initialized', () => { + expect(fixture).toBeDefined(); + expect(hostComponent).toBeDefined(); + expect(fileSelectDirective).toBeDefined(); + }); + + it('can set file uploader', () => { + expect(fileSelectDirective.uploader).toBe(hostComponent.uploader); + }); + + it('can get uploader options', () => { + const options = fileSelectDirective.getOptions(); + + // Check url set through binding + expect(options.url).toBe(hostComponent.url); + + // Check default options + expect(options.autoUpload).toBeFalsy(); + expect(options.isHTML5).toBeTruthy(); + expect(options.removeAfterUpload).toBeFalsy(); + expect(options.disableMultipart).toBeFalsy(); + }); + + it('can get filters', () => { + const filters = fileSelectDirective.getFilters(); + + // TODO: Update test once implemented + expect(filters).toEqual({}); + }); + + it('can check if element is empty', () => { + const isElementEmpty = fileSelectDirective.isEmptyAfterSelection(); + + expect(isElementEmpty).toBeFalsy(); + }); + + it('can listed on change event', () => { + spyOn(fileSelectDirective, 'onChange'); + + directiveElement.triggerEventHandler('change', {}); + + expect(fileSelectDirective.onChange).toHaveBeenCalled(); + }); + + it('handles change event', () => { + spyOn(fileSelectDirective.uploader, 'addToQueue'); + + fileSelectDirective.onChange(); + + const expectedArguments = [ directiveElement.nativeElement.files, + fileSelectDirective.getOptions(), + fileSelectDirective.getFilters() ]; + expect(fileSelectDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); + }); +});