Merge branch 'development' into feature/emit-event-when-file-is-selected

This commit is contained in:
Adrian Fâciu
2017-10-07 11:53:53 +03:00
committed by GitHub
12 changed files with 341 additions and 68 deletions

View File

@@ -37,12 +37,15 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g
2. `authToken` - Auth token that will be applied as 'Authorization' header during file send. 2. `authToken` - Auth token that will be applied as 'Authorization' header during file send.
3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false. 3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false.
4. `itemAlias` - item alias (form name redefenition) 4. `itemAlias` - item alias (form name redefenition)
5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called.
6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false.
### Events ### Events
- `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out. - `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out.
See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and
[html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html)
- `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"`
# Troubleshooting # Troubleshooting

View File

@@ -61,8 +61,8 @@
<tbody> <tbody>
<tr *ngFor="let item of uploader.queue"> <tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td> <td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td> <td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.isHTML5"> <td *ngIf="uploader.options.isHTML5">
<div class="progress" style="margin-bottom: 0;"> <div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div> <div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
</div> </div>
@@ -115,4 +115,16 @@
</div> </div>
<br><br>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">Response</div>
<div class="panel-body">
{{ response }}
</div>
</div>
</div>
</div>
</div> </div>

View File

@@ -9,9 +9,36 @@ const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';
templateUrl: './simple-demo.html' templateUrl: './simple-demo.html'
}) })
export class SimpleDemoComponent { export class SimpleDemoComponent {
public uploader:FileUploader = new FileUploader({url: URL});
public hasBaseDropZoneOver:boolean = false; uploader:FileUploader;
public hasAnotherDropZoneOver:boolean = false; hasBaseDropZoneOver:boolean;
hasAnotherDropZoneOver:boolean;
response:string;
constructor (){
this.uploader = new FileUploader({
url: URL,
disableMultipart: true, // 'DisableMultipart' must be 'true' for formatDataFunction to be called.
formatDataFunctionIsAsync: true,
formatDataFunction: async (item) => {
return new Promise( (resolve, reject) => {
resolve({
name: item._file.name,
length: item._file.size,
contentType: item._file.type,
date: new Date()
});
});
}
});
this.hasBaseDropZoneOver = false;
this.hasAnotherDropZoneOver = false;
this.response = '';
this.uploader.response.subscribe( res => this.response = res );
}
public fileOverBase(e:any):void { public fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e; this.hasBaseDropZoneOver = e;

View File

@@ -25,6 +25,9 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u
1. `url` - URL of File Uploader's route 1. `url` - URL of File Uploader's route
2. `authToken` - auth token that will be applied as 'Authorization' header during file send. 2. `authToken` - auth token that will be applied as 'Authorization' header during file send.
3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false. 3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false.
4. `itemAlias` - item alias (form name redefenition)
5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called.
6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false.
## FileDrop API ## FileDrop API
@@ -37,3 +40,4 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u
- `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out. - `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out.
See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and
[html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html)
- `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"`

View File

@@ -3,7 +3,7 @@
"declaration": false, "declaration": false,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"noEmitHelpers" :true, "noEmitHelpers": false,
"lib": ["es6", "dom"], "lib": ["es6", "dom"],
"types": [ "types": [
"jasmine", "jasmine",

View File

@@ -6,31 +6,29 @@ const customLaunchers = require('./scripts/sauce-browsers').customLaunchers;
module.exports = function (config) { module.exports = function (config) {
const configuration = { const configuration = {
basePath: '', basePath: '',
frameworks: ['jasmine', 'angular-cli'], frameworks: ['jasmine', '@angular/cli'],
plugins: [ plugins: [
require('karma-jasmine'), require('karma-jasmine'),
require('karma-chrome-launcher'), require('karma-chrome-launcher'),
require('karma-remap-istanbul'), require('karma-coverage-istanbul-reporter'),
require('angular-cli/plugins/karma') require('@angular/cli/plugins/karma')
], ],
files: [ files: [
{pattern: './scripts/test.ts', watched: false} {pattern: './scripts/test.ts', watched: false}
], ],
preprocessors: { preprocessors: {
'./scripts/test.ts': ['angular-cli'] './scripts/test.ts': ['@angular/cli']
}, },
remapIstanbulReporter: { coverageIstanbulReporter: {
reports: { reports: [ 'html', 'lcovonly' ],
html: 'coverage', fixWebpackSourcePaths: false
lcovonly: './coverage/coverage.lcov'
}
}, },
angularCli: { angularCli: {
config: './angular-cli.json', config: './angular-cli.json',
environment: 'dev' environment: 'dev'
}, },
reporters: config.angularCli && config.angularCli.codeCoverage reporters: config.angularCli && config.angularCli.codeCoverage
? ['dots', 'karma-remap-istanbul'] ? ['dots', 'coverage-istanbul']
: ['dots'], : ['dots'],
port: 9876, port: 9876,
colors: true, colors: true,

View File

@@ -49,6 +49,7 @@
"@angular/core": "^2.3.1 || >=4.0.0" "@angular/core": "^2.3.1 || >=4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "1.0.0",
"@angular/common": "2.4.3", "@angular/common": "2.4.3",
"@angular/compiler": "2.4.3", "@angular/compiler": "2.4.3",
"@angular/compiler-cli": "2.4.3", "@angular/compiler-cli": "2.4.3",
@@ -64,7 +65,6 @@
"@types/marked": "0.0.28", "@types/marked": "0.0.28",
"@types/node": "7.0.0", "@types/node": "7.0.0",
"@types/webpack": "^2.2.1", "@types/webpack": "^2.2.1",
"@angular/cli": "1.0.0",
"bootstrap": "3.3.7", "bootstrap": "3.3.7",
"chokidar-cli": "1.2.0", "chokidar-cli": "1.2.0",
"classlist-polyfill": "1.0.3", "classlist-polyfill": "1.0.3",
@@ -87,6 +87,7 @@
"karma": "1.4.0", "karma": "1.4.0",
"karma-chrome-launcher": "^2.0.0", "karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1", "karma-cli": "^1.0.1",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.0.2", "karma-jasmine": "^1.0.2",
"karma-remap-istanbul": "0.4.0", "karma-remap-istanbul": "0.4.0",
"karma-sauce-launcher": "1.1.0", "karma-sauce-launcher": "1.1.0",
@@ -94,9 +95,9 @@
"lodash": "4.17.4", "lodash": "4.17.4",
"markdown-loader": "^0.1.7", "markdown-loader": "^0.1.7",
"marked": "0.3.6", "marked": "0.3.6",
"ngx-bootstrap": "1.6.6",
"ng2-page-scroll": "4.0.0-beta.2", "ng2-page-scroll": "4.0.0-beta.2",
"ngm-cli": "0.4.0", "ngm-cli": "0.4.0",
"ngx-bootstrap": "1.6.6",
"npm-run-all": "^4.0.1", "npm-run-all": "^4.0.1",
"pre-commit": "1.2.2", "pre-commit": "1.2.2",
"protractor": "5.0.0", "protractor": "5.0.0",

View File

@@ -1,29 +1,29 @@
import { Directive, EventEmitter, ElementRef, HostListener, Input, Output } from '@angular/core'; 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 { export class FileDropDirective {
@Input() public uploader:FileUploader; @Input() public uploader: FileUploader;
@Output() public fileOver:EventEmitter<any> = new EventEmitter(); @Output() public fileOver: EventEmitter<any> = new EventEmitter();
@Output() public onFileDrop:EventEmitter<File[]> = new EventEmitter<File[]>(); @Output() public onFileDrop: EventEmitter<File[]> = new EventEmitter<File[]>();
protected element:ElementRef; protected element: ElementRef;
public constructor(element:ElementRef) { public constructor(element: ElementRef) {
this.element = element; this.element = element;
} }
public getOptions():any { public getOptions(): FileUploaderOptions {
return this.uploader.options; return this.uploader.options;
} }
public getFilters():any { public getFilters(): any {
return {}; return {};
} }
@HostListener('drop', ['$event']) @HostListener('drop', [ '$event' ])
public onDrop(event:any):void { public onDrop(event: any): void {
let transfer = this._getTransfer(event); let transfer = this._getTransfer(event);
if (!transfer) { if (!transfer) {
return; return;
@@ -37,8 +37,8 @@ export class FileDropDirective {
this.onFileDrop.emit(transfer.files); this.onFileDrop.emit(transfer.files);
} }
@HostListener('dragover', ['$event']) @HostListener('dragover', [ '$event' ])
public onDragOver(event:any):void { public onDragOver(event: any): void {
let transfer = this._getTransfer(event); let transfer = this._getTransfer(event);
if (!this._haveFiles(transfer.types)) { if (!this._haveFiles(transfer.types)) {
return; return;
@@ -49,10 +49,10 @@ export class FileDropDirective {
this.fileOver.emit(true); this.fileOver.emit(true);
} }
@HostListener('dragleave', ['$event']) @HostListener('dragleave', [ '$event' ])
public onDragLeave(event:any):any { public onDragLeave(event: any): any {
if ((this as any).element) { if ((this as any).element) {
if (event.currentTarget === (this as any).element[0]) { if (event.currentTarget === (this as any).element[ 0 ]) {
return; return;
} }
} }
@@ -61,16 +61,16 @@ export class FileDropDirective {
this.fileOver.emit(false); this.fileOver.emit(false);
} }
protected _getTransfer(event:any):any { protected _getTransfer(event: any): any {
return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix; return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
} }
protected _preventAndStop(event:any):any { protected _preventAndStop(event: any): any {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} }
protected _haveFiles(types:any):any { protected _haveFiles(types: any): any {
if (!types) { if (!types) {
return false; return false;
} }
@@ -83,13 +83,4 @@ export class FileDropDirective {
return false; return false;
} }
} }
/*
_addOverClass(item:any):any {
item.addOverClass();
}
_removeOverClass(item:any):any {
item.removeOverClass();
}*/
} }

View File

@@ -4,31 +4,31 @@ import { FileUploader } from './file-uploader.class';
// todo: filters // todo: filters
@Directive({selector: '[ng2FileSelect]'}) @Directive({ selector: '[ng2FileSelect]' })
export class FileSelectDirective { export class FileSelectDirective {
@Input() public uploader:FileUploader; @Input() public uploader: FileUploader;
@Output() public onFileSelected:EventEmitter<File[]> = new EventEmitter<File[]>(); @Output() public onFileSelected:EventEmitter<File[]> = new EventEmitter<File[]>();
protected element:ElementRef; protected element: ElementRef;
public constructor(element:ElementRef) { public constructor(element: ElementRef) {
this.element = element; this.element = element;
} }
public getOptions():any { public getOptions(): any {
return this.uploader.options; return this.uploader.options;
} }
public getFilters():any { public getFilters(): any {
return void 0; return {};
} }
public isEmptyAfterSelection():boolean { public isEmptyAfterSelection(): boolean {
return !!this.element.nativeElement.attributes.multiple; return !!this.element.nativeElement.attributes.multiple;
} }
@HostListener('change', ['$event']) @HostListener('change', ['$event'])
public onChange():any { public onChange(): any {
// let files = this.uploader.isHTML5 ? this.element.nativeElement[0].files : this.element.nativeElement[0]; // let files = this.uploader.isHTML5 ? this.element.nativeElement[0].files : this.element.nativeElement[0];
let files = this.element.nativeElement.files; let files = this.element.nativeElement.files;
let options = this.getOptions(); let options = this.getOptions();

View File

@@ -1,3 +1,4 @@
import { EventEmitter } from '@angular/core';
import { FileLikeObject } from './file-like-object.class'; import { FileLikeObject } from './file-like-object.class';
import { FileItem } from './file-item.class'; import { FileItem } from './file-item.class';
import { FileType } from './file-type.class'; import { FileType } from './file-type.class';
@@ -32,6 +33,8 @@ export interface FileUploaderOptions {
itemAlias?: string; itemAlias?: string;
authTokenHeader?: string; authTokenHeader?: string;
additionalParameter?:{[key: string]: any}; additionalParameter?:{[key: string]: any};
formatDataFunction?:Function;
formatDataFunctionIsAsync?:boolean;
} }
export class FileUploader { export class FileUploader {
@@ -43,19 +46,23 @@ export class FileUploader {
public _nextIndex:number = 0; public _nextIndex:number = 0;
public autoUpload:any; public autoUpload:any;
public authTokenHeader: string; public authTokenHeader: string;
public response: EventEmitter<any>;
public options:FileUploaderOptions = { public options:FileUploaderOptions = {
autoUpload: false, autoUpload: false,
isHTML5: true, isHTML5: true,
filters: [], filters: [],
removeAfterUpload: false, removeAfterUpload: false,
disableMultipart: false disableMultipart: false,
formatDataFunction: function (item:FileItem) { return item._file; },
formatDataFunctionIsAsync: false
}; };
protected _failFilterIndex:number; protected _failFilterIndex:number;
public constructor(options:FileUploaderOptions) { public constructor(options:FileUploaderOptions) {
this.setOptions(options); this.setOptions(options);
this.response = new EventEmitter<any>();
} }
public setOptions(options:FileUploaderOptions):void { public setOptions(options:FileUploaderOptions):void {
@@ -291,6 +298,7 @@ export class FileUploader {
} }
protected _xhrTransport(item:FileItem):any { protected _xhrTransport(item:FileItem):any {
let that = this;
let xhr = item._xhr = new XMLHttpRequest(); let xhr = item._xhr = new XMLHttpRequest();
let sendable:any; let sendable:any;
this._onBeforeUploadItem(item); this._onBeforeUploadItem(item);
@@ -315,7 +323,7 @@ export class FileUploader {
}); });
} }
} else { } else {
sendable = item._file; sendable = this.options.formatDataFunction(item);
} }
xhr.upload.onprogress = (event:any) => { xhr.upload.onprogress = (event:any) => {
@@ -357,7 +365,18 @@ export class FileUploader {
if (this.authToken) { if (this.authToken) {
xhr.setRequestHeader(this.authTokenHeader, this.authToken); xhr.setRequestHeader(this.authTokenHeader, this.authToken);
} }
xhr.send(sendable); xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
that.response.emit(xhr.responseText)
}
}
if (this.options.formatDataFunctionIsAsync) {
sendable.then(
(result:any) => xhr.send(JSON.stringify(result))
);
} else {
xhr.send(sendable);
}
this._render(); this._render();
} }

View File

@@ -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 { inject, ComponentFixture, TestBed } from '@angular/core/testing';
import { FileUploader } from '../file-upload/file-uploader.class'; import { FileUploader } from '../file-upload/file-uploader.class';
import { FileUploadModule } from '../file-upload/file-upload.module'; import { FileUploadModule } from '../file-upload/file-upload.module';
import { FileDropDirective } from '../file-upload/file-drop.directive';
@Component({ @Component({
selector: 'container', selector: 'container',
template: `<input type="file" ng2FileSelect [uploader]="uploader" />` template: `<div type="file"
ng2FileDrop
[uploader]="uploader"
></div>`
}) })
export class ContainerComponent { 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', () => { describe('Directive: FileDropDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
let hostComponent: ContainerComponent;
let directiveElement: DebugElement;
let fileDropDirective: FileDropDirective;
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [FileUploadModule], imports: [ FileUploadModule ],
declarations: [ContainerComponent], declarations: [ ContainerComponent ],
providers: [ContainerComponent] providers: [ ContainerComponent ]
}); });
}); });
it('should be fine', inject([ContainerComponent], (fixture:ComponentFixture<ContainerComponent>) => { beforeEach(() => {
expect(fixture).not.toBeNull(); 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', getFakeEventData());
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(getFakeEventData());
const uploadedFiles = getFakeEventData().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', getFakeEventData());
expect(fileDropDirective.onDragOver).toHaveBeenCalled();
});
it('handles file over', () => {
let fileOverData;
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
fileDropDirective.onDragOver(getFakeEventData());
expect(fileOverData).toBeTruthy();
});
it('handles dragleave event', () => {
spyOn(fileDropDirective, 'onDragLeave');
directiveElement.triggerEventHandler('dragleave', getFakeEventData());
expect(fileDropDirective.onDragLeave).toHaveBeenCalled();
});
it('handles file over leave', () => {
let fileOverData;
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
fileDropDirective.onDragLeave(getFakeEventData());
expect(fileOverData).toBeFalsy();
});
}); });
function getFakeEventData(): any {
return {
dataTransfer: {
files: [ 'foo.bar' ],
types: [ 'Files' ]
},
preventDefault: () => undefined,
stopPropagation: () => undefined
}
}

View File

@@ -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: `<input type="file"
ng2FileSelect
[uploader]="uploader"
/>`
})
export class ContainerComponent {
public get url(): string { return 'localhost:3000'; }
public uploader: FileUploader = new FileUploader({ url: this.url });
}
describe('Directive: FileSelectDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
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);
});
});