diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000..17277f7
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+root: true
+extends: '@cordova/eslint-config/browser'
+
+overrides:
+ - files: [tests/**/*.js]
+ extends: '@cordova/eslint-config/node-tests'
diff --git a/.jscsrc b/.jscsrc
deleted file mode 100644
index 2656b94..0000000
--- a/.jscsrc
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "disallowMixedSpacesAndTabs": true,
- "disallowTrailingWhitespace": true,
- "validateIndentation": 4,
- "requireLineFeedAtFileEnd": true,
-
- "disallowSpaceAfterPrefixUnaryOperators": true,
- "disallowSpaceBeforePostfixUnaryOperators": true,
- "requireSpaceAfterLineComment": true,
- "requireCapitalizedConstructors": true,
-
- "disallowSpacesInNamedFunctionExpression": {
- "beforeOpeningRoundBrace": true
- },
-
- "requireSpaceAfterKeywords": [
- "if",
- "else",
- "for",
- "while",
- "do"
- ]
-}
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 93c3c13..0000000
--- a/.jshintrc
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "browser": true
- , "devel": true
- , "bitwise": true
- , "undef": true
- , "trailing": true
- , "quotmark": false
- , "indent": 4
- , "unused": "vars"
- , "latedef": "nofunc"
- , "globals": {
- "module": false,
- "exports": false,
- "require": false,
- "FileTransferError": true,
- "FileUploadResult": true,
- "resolveLocalFileSystemURI": false
- }
-}
diff --git a/package.json b/package.json
index 3766722..871efef 100644
--- a/package.json
+++ b/package.json
@@ -13,9 +13,8 @@
]
},
"scripts": {
- "test": "npm run lint && npm run style",
- "lint": "jshint www && jshint src && jshint tests",
- "style": "jscs tests/tests.js"
+ "test": "npm run lint",
+ "lint": "eslint ."
},
"repository": "github:apache/cordova-plugin-file-transfer",
"bugs": "https://github.com/apache/cordova-plugin-file-transfer/issues",
@@ -39,7 +38,6 @@
}
},
"devDependencies": {
- "jscs": "^2.6.0",
- "jshint": "^2.8.0"
+ "@cordova/eslint-config": "^3.0.0"
}
}
diff --git a/src/windows/FileTransferProxy.js b/src/windows/FileTransferProxy.js
index 01e6e7b..316779f 100644
--- a/src/windows/FileTransferProxy.js
+++ b/src/windows/FileTransferProxy.js
@@ -17,28 +17,25 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
+ */
-/*jshint -W030 */
-/*global Windows, WinJS*/
-/*global module, require*/
+/* global Windows, WinJS */
-var FTErr = require('./FileTransferError'),
- ProgressEvent = require('cordova-plugin-file.ProgressEvent'),
- FileUploadResult = require('cordova-plugin-file.FileUploadResult'),
- FileProxy = require('cordova-plugin-file.FileProxy');
+var FTErr = require('./FileTransferError');
+var ProgressEvent = require('cordova-plugin-file.ProgressEvent');
+var FileUploadResult = require('cordova-plugin-file.FileUploadResult');
+var FileProxy = require('cordova-plugin-file.FileProxy');
var appData = Windows.Storage.ApplicationData.current;
-var LINE_START = "--";
-var LINE_END = "\r\n";
+var LINE_START = '--';
+var LINE_END = '\r\n';
var BOUNDARY = '+++++';
var fileTransferOps = [];
// Some private helper functions, hidden by the module
-function cordovaPathToNative(path) {
-
+function cordovaPathToNative (path) {
var cleanPath = String(path);
// turn / into \\
cleanPath = cleanPath.replace(/\//g, '\\');
@@ -49,11 +46,11 @@ function cordovaPathToNative(path) {
return cleanPath;
}
-function nativePathToCordova(path) {
+function nativePathToCordova (path) {
return String(path).replace(/\\/g, '/');
}
-function alreadyCancelled(opId) {
+function alreadyCancelled (opId) {
var op = fileTransferOps[opId];
return op && op.state === FileTransferOperation.CANCELLED;
}
@@ -145,7 +142,7 @@ function doUpload (upload, uploadId, filePath, server, successCallback, errorCal
);
}
-function FileTransferOperation(state, promise) {
+function FileTransferOperation (state, promise) {
this.state = state;
this.promise = promise;
}
@@ -157,9 +154,8 @@ FileTransferOperation.CANCELLED = 2;
var HTTP_E_STATUS_NOT_MODIFIED = -2145844944;
module.exports = {
-
-/*
-exec(win, fail, 'FileTransfer', 'upload',
+ /*
+exec(win, fail, 'FileTransfer', 'upload',
[filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
*/
upload: function (successCallback, errorCallback, options) {
@@ -170,14 +166,14 @@ exec(win, fail, 'FileTransfer', 'upload',
var mimeType = options[4];
var params = options[5];
// var trustAllHosts = options[6]; // todo
- // var chunkedMode = options[7]; // todo
+ // var chunkedMode = options[7]; // todo
var headers = options[8] || {};
var uploadId = options[9];
var httpMethod = options[10];
- var isMultipart = typeof headers["Content-Type"] === 'undefined';
+ var isMultipart = typeof headers['Content-Type'] === 'undefined';
- function stringToByteArray(str) {
+ function stringToByteArray (str) {
var byteCharacters = atob(str);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
@@ -186,21 +182,21 @@ exec(win, fail, 'FileTransfer', 'upload',
return new Uint8Array(byteNumbers);
}
- if (!filePath || (typeof filePath !== 'string')) {
+ if (!filePath || typeof filePath !== 'string') {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, null, server));
return;
}
- if (filePath.indexOf("data:") === 0 && filePath.indexOf("base64") !== -1) {
- // First a DataWriter object is created, backed by an in-memory stream where
+ if (filePath.indexOf('data:') === 0 && filePath.indexOf('base64') !== -1) {
+ // First a DataWriter object is created, backed by an in-memory stream where
// the data will be stored.
var writer = Windows.Storage.Streams.DataWriter(new Windows.Storage.Streams.InMemoryRandomAccessStream());
writer.unicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.utf8;
writer.byteOrder = Windows.Storage.Streams.ByteOrder.littleEndian;
- var commaIndex = filePath.indexOf(",");
+ var commaIndex = filePath.indexOf(',');
if (commaIndex === -1) {
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR, fileName, server, null, null, "No comma in data: URI"));
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR, fileName, server, null, null, 'No comma in data: URI'));
return;
}
@@ -213,7 +209,7 @@ exec(win, fail, 'FileTransfer', 'upload',
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
uploader.method = httpMethod;
for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
uploader.setRequestHeader(header, headers[header]);
}
}
@@ -222,9 +218,9 @@ exec(win, fail, 'FileTransfer', 'upload',
// adding params supplied to request payload
var multipartParams = '';
for (var key in params) {
- if (params.hasOwnProperty(key)) {
+ if (Object.prototype.hasOwnProperty.call(params, key)) {
multipartParams += LINE_START + BOUNDARY + LINE_END;
- multipartParams += "Content-Disposition: form-data; name=\"" + key + "\"";
+ multipartParams += 'Content-Disposition: form-data; name="' + key + '"';
multipartParams += LINE_END + LINE_END;
multipartParams += params[key];
multipartParams += LINE_END;
@@ -232,13 +228,13 @@ exec(win, fail, 'FileTransfer', 'upload',
}
var multipartFile = LINE_START + BOUNDARY + LINE_END;
- multipartFile += "Content-Disposition: form-data; name=\"file\";";
- multipartFile += " filename=\"" + fileName + "\"" + LINE_END;
- multipartFile += "Content-Type: " + mimeType + LINE_END + LINE_END;
+ multipartFile += 'Content-Disposition: form-data; name="file";';
+ multipartFile += ' filename="' + fileName + '"' + LINE_END;
+ multipartFile += 'Content-Type: ' + mimeType + LINE_END + LINE_END;
var bound = LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END;
- uploader.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
+ uploader.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + BOUNDARY);
writer.writeString(multipartParams);
writer.writeString(multipartFile);
writer.writeBytes(stringToByteArray(fileDataString));
@@ -249,42 +245,142 @@ exec(win, fail, 'FileTransfer', 'upload',
var stream;
- // The call to store async sends the actual contents of the writer
+ // The call to store async sends the actual contents of the writer
// to the backing stream.
- writer.storeAsync().then(function () {
- // For the in-memory stream implementation we are using, the flushAsync call
- // is superfluous, but other types of streams may require it.
- return writer.flushAsync();
- }).then(function () {
- // We detach the stream to prolong its useful lifetime. Were we to fail
- // to detach the stream, the call to writer.close() would close the underlying
- // stream, preventing its subsequent use by the DataReader below. Most clients
- // of DataWriter will have no reason to use the underlying stream after
- // writer.close() is called, and will therefore have no reason to call
- // writer.detachStream(). Note that once we detach the stream, we assume
- // responsibility for closing the stream subsequently; after the stream
- // has been detached, a call to writer.close() will have no effect on the stream.
- stream = writer.detachStream();
- // Make sure the stream is read from the beginning in the reader
- // we are creating below.
- stream.seek(0);
- // Most DataWriter clients will not call writer.detachStream(),
- // and furthermore will be working with a file-backed or network-backed stream,
- // rather than an in-memory-stream. In such cases, it would be particularly
- // important to call writer.close(). Doing so is always a best practice.
- writer.close();
+ writer
+ .storeAsync()
+ .then(function () {
+ // For the in-memory stream implementation we are using, the flushAsync call
+ // is superfluous, but other types of streams may require it.
+ return writer.flushAsync();
+ })
+ .then(function () {
+ // We detach the stream to prolong its useful lifetime. Were we to fail
+ // to detach the stream, the call to writer.close() would close the underlying
+ // stream, preventing its subsequent use by the DataReader below. Most clients
+ // of DataWriter will have no reason to use the underlying stream after
+ // writer.close() is called, and will therefore have no reason to call
+ // writer.detachStream(). Note that once we detach the stream, we assume
+ // responsibility for closing the stream subsequently; after the stream
+ // has been detached, a call to writer.close() will have no effect on the stream.
+ stream = writer.detachStream();
+ // Make sure the stream is read from the beginning in the reader
+ // we are creating below.
+ stream.seek(0);
+ // Most DataWriter clients will not call writer.detachStream(),
+ // and furthermore will be working with a file-backed or network-backed stream,
+ // rather than an in-memory-stream. In such cases, it would be particularly
+ // important to call writer.close(). Doing so is always a best practice.
+ writer.close();
+
+ if (alreadyCancelled(uploadId)) {
+ errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
+ return;
+ }
+
+ // create download object. This will throw an exception if URL is malformed
+ var uri = new Windows.Foundation.Uri(server);
+
+ var createUploadOperation;
+ try {
+ createUploadOperation = uploader.createUploadFromStreamAsync(uri, stream);
+ } catch (e) {
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
+ return;
+ }
+
+ createUploadOperation.then(
+ function (upload) {
+ doUpload(upload, uploadId, filePath, server, successCallback, errorCallback);
+ },
+ function (err) {
+ var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
+ errorObj.exception = err;
+ errorCallback(errorObj);
+ }
+ );
+ });
+
+ return;
+ }
+
+ if (filePath.substr(0, 8) === 'file:///') {
+ filePath = appData.localFolder.path + filePath.substr(8).split('/').join('\\');
+ } else if (filePath.indexOf('ms-appdata:///') === 0) {
+ // Handle 'ms-appdata' scheme
+ filePath = filePath
+ .replace('ms-appdata:///local', appData.localFolder.path)
+ .replace('ms-appdata:///temp', appData.temporaryFolder.path);
+ } else if (filePath.indexOf('cdvfile://') === 0) {
+ filePath = filePath
+ .replace('cdvfile://localhost/persistent', appData.localFolder.path)
+ .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
+ }
+
+ // normalize path separators
+ filePath = cordovaPathToNative(filePath);
+
+ // Create internal download operation object
+ fileTransferOps[uploadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
+
+ Windows.Storage.StorageFile.getFileFromPathAsync(filePath).then(
+ function (storageFile) {
+ if (!fileName) {
+ fileName = storageFile.name;
+ }
+ if (!mimeType) {
+ // use the actual content type of the file, probably this should be the default way.
+ // other platforms probably can't look this up.
+ mimeType = storageFile.contentType;
+ }
if (alreadyCancelled(uploadId)) {
errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
return;
}
+ // setting request headers for uploader
+ var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
+ uploader.method = httpMethod;
+ for (var header in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
+ uploader.setRequestHeader(header, headers[header]);
+ }
+ }
+
// create download object. This will throw an exception if URL is malformed
var uri = new Windows.Foundation.Uri(server);
var createUploadOperation;
try {
- createUploadOperation = uploader.createUploadFromStreamAsync(uri, stream);
+ if (isMultipart) {
+ // adding params supplied to request payload
+ var transferParts = [];
+ for (var key in params) {
+ // Create content part for params only if value is specified because CreateUploadAsync fails otherwise
+ if (
+ Object.prototype.hasOwnProperty.call(params, key) &&
+ params[key] !== null &&
+ params[key] !== undefined &&
+ params[key].toString() !== ''
+ ) {
+ var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
+ contentPart.setHeader('Content-Disposition', 'form-data; name="' + key + '"');
+ contentPart.setText(params[key]);
+ transferParts.push(contentPart);
+ }
+ }
+
+ // Adding file to upload to request payload
+ var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
+ fileToUploadPart.setHeader('Content-Type', mimeType);
+ fileToUploadPart.setFile(storageFile);
+ transferParts.push(fileToUploadPart);
+
+ createUploadOperation = uploader.createUploadAsync(uri, transferParts);
+ } else {
+ createUploadOperation = WinJS.Promise.wrap(uploader.createUpload(uri, storageFile));
+ }
} catch (e) {
errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
return;
@@ -298,105 +394,17 @@ exec(win, fail, 'FileTransfer', 'upload',
var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
errorObj.exception = err;
errorCallback(errorObj);
- });
- });
-
- return;
- }
-
- if (filePath.substr(0, 8) === "file:///") {
- filePath = appData.localFolder.path + filePath.substr(8).split("/").join("\\");
- } else if (filePath.indexOf('ms-appdata:///') === 0) {
- // Handle 'ms-appdata' scheme
- filePath = filePath.replace('ms-appdata:///local', appData.localFolder.path)
- .replace('ms-appdata:///temp', appData.temporaryFolder.path);
- } else if (filePath.indexOf('cdvfile://') === 0) {
- filePath = filePath.replace('cdvfile://localhost/persistent', appData.localFolder.path)
- .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
- }
-
- // normalize path separators
- filePath = cordovaPathToNative(filePath);
-
- // Create internal download operation object
- fileTransferOps[uploadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
-
- Windows.Storage.StorageFile.getFileFromPathAsync(filePath)
- .then(function (storageFile) {
-
- if (!fileName) {
- fileName = storageFile.name;
- }
- if (!mimeType) {
- // use the actual content type of the file, probably this should be the default way.
- // other platforms probably can't look this up.
- mimeType = storageFile.contentType;
- }
-
- if (alreadyCancelled(uploadId)) {
- errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
- return;
- }
-
- // setting request headers for uploader
- var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
- uploader.method = httpMethod;
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- uploader.setRequestHeader(header, headers[header]);
- }
- }
-
- // create download object. This will throw an exception if URL is malformed
- var uri = new Windows.Foundation.Uri(server);
-
- var createUploadOperation;
- try {
- if (isMultipart) {
- // adding params supplied to request payload
- var transferParts = [];
- for (var key in params) {
- // Create content part for params only if value is specified because CreateUploadAsync fails otherwise
- if (params.hasOwnProperty(key) && params[key] !== null && params[key] !== undefined && params[key].toString() !== "") {
- var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
- contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\"");
- contentPart.setText(params[key]);
- transferParts.push(contentPart);
- }
}
-
- // Adding file to upload to request payload
- var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
- fileToUploadPart.setHeader("Content-Type", mimeType);
- fileToUploadPart.setFile(storageFile);
- transferParts.push(fileToUploadPart);
-
- createUploadOperation = uploader.createUploadAsync(uri, transferParts);
- } else {
- createUploadOperation = WinJS.Promise.wrap(uploader.createUpload(uri, storageFile));
- }
- } catch (e) {
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
- return;
+ );
+ },
+ function (err) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, fileName, server, null, null, err));
}
-
- createUploadOperation.then(
- function (upload) {
- doUpload(upload, uploadId, filePath, server, successCallback, errorCallback);
- },
- function (err) {
- var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
- errorObj.exception = err;
- errorCallback(errorObj);
- }
- );
- }, function (err) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, fileName, server, null, null, err));
- });
+ );
},
// [source, target, trustAllHosts, id, headers]
- download:function(successCallback, errorCallback, options) {
+ download: function (successCallback, errorCallback, options) {
var source = options[0];
var target = options[1];
var downloadId = options[3];
@@ -406,25 +414,27 @@ exec(win, fail, 'FileTransfer', 'upload',
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR));
return;
}
- if (target.substr(0, 8) === "file:///") {
- target = appData.localFolder.path + target.substr(8).split("/").join("\\");
+ if (target.substr(0, 8) === 'file:///') {
+ target = appData.localFolder.path + target.substr(8).split('/').join('\\');
} else if (target.indexOf('ms-appdata:///') === 0) {
// Handle 'ms-appdata' scheme
- target = target.replace('ms-appdata:///local', appData.localFolder.path)
- .replace('ms-appdata:///temp', appData.temporaryFolder.path);
+ target = target
+ .replace('ms-appdata:///local', appData.localFolder.path)
+ .replace('ms-appdata:///temp', appData.temporaryFolder.path);
} else if (target.indexOf('cdvfile://') === 0) {
- target = target.replace('cdvfile://localhost/persistent', appData.localFolder.path)
- .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
+ target = target
+ .replace('cdvfile://localhost/persistent', appData.localFolder.path)
+ .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
}
target = cordovaPathToNative(target);
- var path = target.substr(0, target.lastIndexOf("\\"));
- var fileName = target.substr(target.lastIndexOf("\\") + 1);
+ var path = target.substr(0, target.lastIndexOf('\\'));
+ var fileName = target.substr(target.lastIndexOf('\\') + 1);
if (path === null || fileName === null) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR));
return;
}
- // Download to a temp file to avoid the file deletion on 304
+ // Download to a temp file to avoid the file deletion on 304
// CB-7006 Empty file is created on file transfer if server response is 304
var tempFileName = '~' + fileName;
@@ -433,129 +443,136 @@ exec(win, fail, 'FileTransfer', 'upload',
// Create internal download operation object
fileTransferOps[downloadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
- var downloadCallback = function(storageFolder) {
- storageFolder.createFileAsync(tempFileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (storageFile) {
-
- if (alreadyCancelled(downloadId)) {
- errorCallback(new FTErr(FTErr.ABORT_ERR, source, target));
- return;
- }
-
- // if download isn't cancelled, contunue with creating and preparing download operation
- var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- downloader.setRequestHeader(header, headers[header]);
- }
- }
-
- // create download object. This will throw an exception if URL is malformed
- try {
- var uri = Windows.Foundation.Uri(source);
- download = downloader.createDownload(uri, storageFile);
- } catch (e) {
- // so we handle this and call errorCallback
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
- return;
- }
-
- var downloadOperation = download.startAsync();
- // update internal TransferOperation object with newly created promise
- fileTransferOps[downloadId].promise = downloadOperation;
-
- downloadOperation.then(function () {
-
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentDownloadOp = fileTransferOps[downloadId];
- if (currentDownloadOp) {
- currentDownloadOp.state = FileTransferOperation.DONE;
- currentDownloadOp.promise = null;
+ var downloadCallback = function (storageFolder) {
+ storageFolder.createFileAsync(tempFileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(
+ function (storageFile) {
+ if (alreadyCancelled(downloadId)) {
+ errorCallback(new FTErr(FTErr.ABORT_ERR, source, target));
+ return;
}
- storageFile.renameAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).done(function () {
- var nativeURI = storageFile.path.replace(appData.localFolder.path, 'ms-appdata:///local')
- .replace(appData.temporaryFolder.path, 'ms-appdata:///temp')
- .replace(/\\/g, '/');
+ // if download isn't cancelled, contunue with creating and preparing download operation
+ var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
+ for (var header in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
+ downloader.setRequestHeader(header, headers[header]);
+ }
+ }
- // Passing null as error callback here because downloaded file should exist in any case
- // otherwise the error callback will be hit during file creation in another place
- FileProxy.resolveLocalFileSystemURI(successCallback, null, [nativeURI]);
- }, function(error) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
- });
- }, function(error) {
+ // create download object. This will throw an exception if URL is malformed
+ try {
+ var uri = Windows.Foundation.Uri(source);
+ download = downloader.createDownload(uri, storageFile);
+ } catch (e) {
+ // so we handle this and call errorCallback
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
+ return;
+ }
- var getTransferError = new WinJS.Promise(function (resolve) {
- // Handle download error here. If download was cancelled,
- // message property will be specified
- if (error.message === 'Canceled') {
- resolve(new FTErr(FTErr.ABORT_ERR, source, target, null, null, error));
- } else if (error && error.number === HTTP_E_STATUS_NOT_MODIFIED) {
- resolve(new FTErr(FTErr.NOT_MODIFIED_ERR, source, target, 304, null, error));
- } else {
- // in the other way, try to get response property
- var response = download.getResponseInformation();
- if (!response) {
- resolve(new FTErr(FTErr.CONNECTION_ERR, source, target));
- } else {
- if (download.progress.bytesReceived === 0) {
- resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, null, error));
- return;
- }
- var reader = new Windows.Storage.Streams.DataReader(download.getResultStreamAt(0));
- reader.loadAsync(download.progress.bytesReceived).then(function (bytesLoaded) {
- var payload = reader.readString(bytesLoaded);
- resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, payload, error));
- });
+ var downloadOperation = download.startAsync();
+ // update internal TransferOperation object with newly created promise
+ fileTransferOps[downloadId].promise = downloadOperation;
+
+ downloadOperation.then(
+ function () {
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentDownloadOp = fileTransferOps[downloadId];
+ if (currentDownloadOp) {
+ currentDownloadOp.state = FileTransferOperation.DONE;
+ currentDownloadOp.promise = null;
}
+
+ storageFile.renameAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).done(
+ function () {
+ var nativeURI = storageFile.path
+ .replace(appData.localFolder.path, 'ms-appdata:///local')
+ .replace(appData.temporaryFolder.path, 'ms-appdata:///temp')
+ .replace(/\\/g, '/');
+
+ // Passing null as error callback here because downloaded file should exist in any case
+ // otherwise the error callback will be hit during file creation in another place
+ FileProxy.resolveLocalFileSystemURI(successCallback, null, [nativeURI]);
+ },
+ function (error) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
+ }
+ );
+ },
+ function (error) {
+ var getTransferError = new WinJS.Promise(function (resolve) {
+ // Handle download error here. If download was cancelled,
+ // message property will be specified
+ if (error.message === 'Canceled') {
+ resolve(new FTErr(FTErr.ABORT_ERR, source, target, null, null, error));
+ } else if (error && error.number === HTTP_E_STATUS_NOT_MODIFIED) {
+ resolve(new FTErr(FTErr.NOT_MODIFIED_ERR, source, target, 304, null, error));
+ } else {
+ // in the other way, try to get response property
+ var response = download.getResponseInformation();
+ if (!response) {
+ resolve(new FTErr(FTErr.CONNECTION_ERR, source, target));
+ } else {
+ if (download.progress.bytesReceived === 0) {
+ resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, null, error));
+ return;
+ }
+ var reader = new Windows.Storage.Streams.DataReader(download.getResultStreamAt(0));
+ reader.loadAsync(download.progress.bytesReceived).then(function (bytesLoaded) {
+ var payload = reader.readString(bytesLoaded);
+ resolve(
+ new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, payload, error)
+ );
+ });
+ }
+ }
+ });
+ getTransferError.then(function (fileTransferError) {
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentDownloadOp = fileTransferOps[downloadId];
+ if (currentDownloadOp) {
+ currentDownloadOp.state = FileTransferOperation.CANCELLED;
+ currentDownloadOp.promise = null;
+ }
+
+ // Cleanup, remove incompleted file
+ storageFile.deleteAsync().then(function () {
+ errorCallback(fileTransferError);
+ });
+ });
+ },
+ function (evt) {
+ var progressEvent = new ProgressEvent('progress', {
+ loaded: evt.progress.bytesReceived,
+ total: evt.progress.totalBytesToReceive,
+ target: evt.resultFile
+ });
+ // when bytesReceived == 0, BackgroundDownloader has not yet differentiated whether it could get file length or not,
+ // when totalBytesToReceive == 0, BackgroundDownloader is unable to get file length
+ progressEvent.lengthComputable = evt.progress.bytesReceived > 0 && evt.progress.totalBytesToReceive > 0;
+
+ successCallback(progressEvent, { keepCallback: true });
}
- });
- getTransferError.then(function (fileTransferError) {
-
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentDownloadOp = fileTransferOps[downloadId];
- if (currentDownloadOp) {
- currentDownloadOp.state = FileTransferOperation.CANCELLED;
- currentDownloadOp.promise = null;
- }
-
- // Cleanup, remove incompleted file
- storageFile.deleteAsync().then(function() {
- errorCallback(fileTransferError);
- });
- });
-
- }, function(evt) {
-
- var progressEvent = new ProgressEvent('progress', {
- loaded: evt.progress.bytesReceived,
- total: evt.progress.totalBytesToReceive,
- target: evt.resultFile
- });
- // when bytesReceived == 0, BackgroundDownloader has not yet differentiated whether it could get file length or not,
- // when totalBytesToReceive == 0, BackgroundDownloader is unable to get file length
- progressEvent.lengthComputable = (evt.progress.bytesReceived > 0) && (evt.progress.totalBytesToReceive > 0);
-
- successCallback(progressEvent, { keepCallback: true });
- });
- }, function(error) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
- });
+ );
+ },
+ function (error) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
+ }
+ );
};
- var fileNotFoundErrorCallback = function(error) {
+ var fileNotFoundErrorCallback = function (error) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
};
Windows.Storage.StorageFolder.getFolderFromPathAsync(path).then(downloadCallback, function (error) {
// Handle non-existent directory
if (error.number === -2147024894) {
- var parent = path.substr(0, path.lastIndexOf('\\')),
- folderNameToCreate = path.substr(path.lastIndexOf('\\') + 1);
+ var parent = path.substr(0, path.lastIndexOf('\\'));
+ var folderNameToCreate = path.substr(path.lastIndexOf('\\') + 1);
- Windows.Storage.StorageFolder.getFolderFromPathAsync(parent).then(function(parentFolder) {
+ Windows.Storage.StorageFolder.getFolderFromPathAsync(parent).then(function (parentFolder) {
parentFolder.createFolderAsync(folderNameToCreate).then(downloadCallback, fileNotFoundErrorCallback);
}, fileNotFoundErrorCallback);
} else {
@@ -577,7 +594,6 @@ exec(win, fail, 'FileTransfer', 'upload',
fileTransferOps[fileTransferOpId] = new FileTransferOperation(FileTransferOperation.CANCELLED, null);
}
}
-
};
-require("cordova/exec/proxy").add("FileTransfer",module.exports);
+require('cordova/exec/proxy').add('FileTransfer', module.exports);
diff --git a/tests/hooks/after_prepare.js b/tests/hooks/after_prepare.js
index 6101c62..7c5b34c 100644
--- a/tests/hooks/after_prepare.js
+++ b/tests/hooks/after_prepare.js
@@ -1,46 +1,48 @@
#!/usr/bin/env node
/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
var path = require('path');
var fs = require('fs');
-module.exports = function(context) {
- function main() {
+module.exports = function (context) {
+ function main () {
// get the file transfer server address from the specified variables
var fileTransferServerAddress = getFileTransferServerAddress(context) || getDefaultFileTransferServerAddress(context);
console.log('Tests will use the following file transfer server address: ' + fileTransferServerAddress);
- console.log('If you\'re using cordova@6.3.1 and the above address is wrong at "platform add", don\'t worry, it\'ll fix itself on "cordova run" or "cordova prepare".');
+ console.log(
+ 'If you\'re using cordova@6.3.1 and the above address is wrong at "platform add", don\'t worry, it\'ll fix itself on "cordova run" or "cordova prepare".'
+ );
// pass it to the tests
writeFileTransferOptions(fileTransferServerAddress, context);
}
- function getDefaultFileTransferServerAddress(context) {
+ function getDefaultFileTransferServerAddress (context) {
var address = null;
var configNodes = context.opts.plugin.pluginInfo._et._root._children;
for (var node in configNodes) {
- if (configNodes[node].attrib.name == 'FILETRANSFER_SERVER_ADDRESS') {
+ if (configNodes[node].attrib.name === 'FILETRANSFER_SERVER_ADDRESS') {
address = configNodes[node].attrib.default;
}
}
@@ -48,18 +50,28 @@ module.exports = function(context) {
return address;
}
- function getFileTransferServerAddress(context) {
- var platformJsonFile = path.join(context.opts.projectRoot, 'platforms', context.opts.platforms[0], context.opts.platforms[0] + '.json');
+ function getFileTransferServerAddress (context) {
+ var platformJsonFile = path.join(
+ context.opts.projectRoot,
+ 'platforms',
+ context.opts.platforms[0],
+ context.opts.platforms[0] + '.json'
+ );
var platformJson = JSON.parse(fs.readFileSync(platformJsonFile, 'utf8'));
- if (platformJson && platformJson.installed_plugins && platformJson.installed_plugins['cordova-plugin-file-transfer-tests'] && platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS) {
+ if (
+ platformJson &&
+ platformJson.installed_plugins &&
+ platformJson.installed_plugins['cordova-plugin-file-transfer-tests'] &&
+ platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS
+ ) {
return platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS;
} else {
return null;
}
}
- function writeFileTransferOptions(address, context) {
+ function writeFileTransferOptions (address, context) {
for (var p in context.opts.paths) {
var ftOpts = {
serverAddress: address
@@ -71,5 +83,4 @@ module.exports = function(context) {
}
main();
-
};
diff --git a/tests/tests.js b/tests/tests.js
index 63c9c1c..50b128a 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -1,44 +1,42 @@
/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
-/* global exports, cordova, FileTransfer, FileTransferError, FileUploadOptions, LocalFileSystem, WinJS */
-
-/* jshint jasmine: true */
+/* global cordova, FileTransfer, FileTransferError, FileUploadOptions, WinJS, LocalFileSystem */
exports.defineAutoTests = function () {
-
- "use strict";
+ 'use strict';
// constants
var ONE_SECOND = 1000; // in milliseconds
var GRACE_TIME_DELTA = 600; // in milliseconds
var DEFAULT_FILESYSTEM_SIZE = 1024 * 50; // filesystem size in bytes
- var UNKNOWN_HOST = "http://foobar.apache.org";
+ var UNKNOWN_HOST = 'http://foobar.apache.org';
var DOWNLOAD_TIMEOUT = 15 * ONE_SECOND;
var LONG_TIMEOUT = 60 * ONE_SECOND;
var UPLOAD_TIMEOUT = 15 * ONE_SECOND;
var ABORT_DELAY = 100; // for abort() tests
var LATIN1_SYMBOLS = '¥§©ÆÖÑøøø¼';
- var DATA_URI_PREFIX = "data:image/png;base64,";
- var DATA_URI_CONTENT = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ var DATA_URI_PREFIX = 'data:image/png;base64,';
+ var DATA_URI_CONTENT =
+ 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
var DATA_URI_CONTENT_LENGTH = 85; // bytes. (This is the raw file size: used https://en.wikipedia.org/wiki/File:Red-dot-5px.png from https://en.wikipedia.org/wiki/Data_URI_scheme)
var RETRY_COUNT = 100; // retry some flaky tests (yes, THIS many times, due to Heroku server instability)
var RETRY_INTERVAL = 100;
@@ -49,31 +47,29 @@ exports.defineAutoTests = function () {
// Will get it from the config
// you can specify it as a 'FILETRANSFER_SERVER_ADDRESS' variable upon test plugin installation
// or change the default value in plugin.xml
- var SERVER = "";
- var SERVER_WITH_CREDENTIALS = "";
+ var SERVER = '';
+ var SERVER_WITH_CREDENTIALS = '';
// flags
- var isWindows = cordova.platformId === "windows";
- var isBrowser = cordova.platformId === "browser";
+ var isWindows = cordova.platformId === 'windows';
+ var isBrowser = cordova.platformId === 'browser';
var isWindowsPhone = isWindows && WinJS.Utilities.isPhone;
- var isIE = isBrowser && navigator.userAgent.indexOf("Trident") >= 0;
- var isIos = cordova.platformId === "ios";
- var isIot = cordova.platformId === "android" && navigator.userAgent.indexOf("iot") >= 0;
+ var isIE = isBrowser && navigator.userAgent.indexOf('Trident') >= 0;
+ var isIos = cordova.platformId === 'ios';
+ var isIot = cordova.platformId === 'android' && navigator.userAgent.indexOf('iot') >= 0;
// tests
- describe("FileTransferError", function () {
-
- it("should exist", function () {
+ describe('FileTransferError', function () {
+ it('should exist', function () {
expect(FileTransferError).toBeDefined();
});
- it("should be constructable", function () {
+ it('should be constructable', function () {
var transferError = new FileTransferError();
expect(transferError).toBeDefined();
});
- it("filetransfer.spec.3 should expose proper constants", function () {
-
+ it('filetransfer.spec.3 should expose proper constants', function () {
expect(FileTransferError.FILE_NOT_FOUND_ERR).toBeDefined();
expect(FileTransferError.INVALID_URL_ERR).toBeDefined();
expect(FileTransferError.CONNECTION_ERR).toBeDefined();
@@ -88,41 +84,42 @@ exports.defineAutoTests = function () {
});
});
- describe("FileUploadOptions", function () {
-
- it("should exist", function () {
+ describe('FileUploadOptions', function () {
+ it('should exist', function () {
expect(FileUploadOptions).toBeDefined();
});
- it("should be constructable", function () {
+ it('should be constructable', function () {
var transferOptions = new FileUploadOptions();
expect(transferOptions).toBeDefined();
});
});
- describe("FileTransfer", function () {
+ describe('FileTransfer', function () {
this.persistentRoot = null;
- this.tempRoot = null;
+ this.tempRoot = null;
// named callbacks
var unexpectedCallbacks = {
- httpFail: function () {},
- httpWin: function () {},
- fileSystemFail: function () {},
- fileSystemWin: function () {},
+ httpFail: function () {},
+ httpWin: function () {},
+ fileSystemFail: function () {},
+ fileSystemWin: function () {},
fileOperationFail: function () {},
- fileOperationWin: function () {},
+ fileOperationWin: function () {}
};
var expectedCallbacks = {
unsupportedOperation: function (response) {
- console.log("spec called unsupported functionality; response:", response);
- },
+ console.log('spec called unsupported functionality; response:', response);
+ }
};
// helpers
var deleteFile = function (fileSystem, name, done) {
- fileSystem.getFile(name, null,
+ fileSystem.getFile(
+ name,
+ null,
function (fileEntry) {
fileEntry.remove(
function () {
@@ -140,15 +137,16 @@ exports.defineAutoTests = function () {
};
var writeFile = function (fileSystem, name, content, success, done) {
- var fileOperationFail = function() {
+ var fileOperationFail = function () {
unexpectedCallbacks.fileOperationFail();
done();
};
- fileSystem.getFile(name, { create: true },
+ fileSystem.getFile(
+ name,
+ { create: true },
function (fileEntry) {
fileEntry.createWriter(function (writer) {
-
writer.onwrite = function () {
success(fileEntry);
};
@@ -161,13 +159,12 @@ exports.defineAutoTests = function () {
throw new Error("aborted creating test file '" + name + "': " + evt);
};
- if (cordova.platformId === "browser") {
- var blob = new Blob([content + "\n"], { type: "text/plain" });
+ if (cordova.platformId === 'browser') {
+ var blob = new Blob([content + '\n'], { type: 'text/plain' });
writer.write(blob);
} else {
- writer.write(content + "\n");
+ writer.write(content + '\n');
}
-
}, fileOperationFail);
},
function () {
@@ -181,7 +178,7 @@ exports.defineAutoTests = function () {
expect(event.loaded).toBeGreaterThan(1);
expect(event.total).toBeGreaterThan(0);
expect(event.total).not.toBeLessThan(event.loaded);
- expect(event.lengthComputable).toBe(true, "lengthComputable");
+ expect(event.lengthComputable).toBe(true, 'lengthComputable');
} else {
// In IE, when lengthComputable === false, event.total somehow is equal to 2^64
if (isIE) {
@@ -194,12 +191,12 @@ exports.defineAutoTests = function () {
};
var getMalformedUrl = function () {
- if (cordova.platformId === "android") {
+ if (cordova.platformId === 'android') {
// bad protocol causes a MalformedUrlException on Android
- return "httpssss://example.com";
+ return 'httpssss://example.com';
} else {
// iOS doesn't care about protocol, space in hostname causes error
- return "httpssss://exa mple.com";
+ return 'httpssss://exa mple.com';
}
};
@@ -215,13 +212,15 @@ exports.defineAutoTests = function () {
beforeEach(function (done) {
var specContext = this;
- window.requestFileSystem(LocalFileSystem.PERSISTENT, DEFAULT_FILESYSTEM_SIZE,
+ window.requestFileSystem(
+ LocalFileSystem.PERSISTENT,
+ DEFAULT_FILESYSTEM_SIZE,
function (fileSystem) {
specContext.persistentRoot = fileSystem.root;
done();
},
function () {
- throw new Error("Failed to initialize persistent file system.");
+ throw new Error('Failed to initialize persistent file system.');
}
);
});
@@ -229,30 +228,31 @@ exports.defineAutoTests = function () {
beforeEach(function (done) {
var specContext = this;
- window.requestFileSystem(LocalFileSystem.TEMPORARY, DEFAULT_FILESYSTEM_SIZE,
+ window.requestFileSystem(
+ LocalFileSystem.TEMPORARY,
+ DEFAULT_FILESYSTEM_SIZE,
function (fileSystem) {
specContext.tempRoot = fileSystem.root;
done();
},
function () {
- throw new Error("Failed to initialize temporary file system.");
+ throw new Error('Failed to initialize temporary file system.');
}
);
});
// spy on all named callbacks
- beforeEach(function() {
-
+ beforeEach(function () {
// ignore the actual implementations of the unexpected callbacks
for (var callback in unexpectedCallbacks) {
- if (unexpectedCallbacks.hasOwnProperty(callback)) {
+ if (Object.prototype.hasOwnProperty.call(unexpectedCallbacks, callback)) {
spyOn(unexpectedCallbacks, callback);
}
}
// but run the implementations of the expected callbacks
- for (callback in expectedCallbacks) { // jshint ignore: line
- if (expectedCallbacks.hasOwnProperty(callback)) {
+ for (callback in expectedCallbacks) {
+ if (Object.prototype.hasOwnProperty.call(expectedCallbacks, callback)) {
spyOn(expectedCallbacks, callback).and.callThrough();
}
}
@@ -260,9 +260,9 @@ exports.defineAutoTests = function () {
// at the end, check that none of the unexpected callbacks got called,
// and act on the expected callbacks
- afterEach(function() {
+ afterEach(function () {
for (var callback in unexpectedCallbacks) {
- if (unexpectedCallbacks.hasOwnProperty(callback)) {
+ if (Object.prototype.hasOwnProperty.call(unexpectedCallbacks, callback)) {
expect(unexpectedCallbacks[callback]).not.toHaveBeenCalled();
}
}
@@ -272,11 +272,11 @@ exports.defineAutoTests = function () {
}
});
- it ("util spec: get file transfer server url", function () {
+ it('util spec: get file transfer server url', function () {
try {
// attempt to synchronously load medic config
var xhr = new XMLHttpRequest();
- xhr.open("GET", "../fileTransferOpts.json", false);
+ xhr.open('GET', '../fileTransferOpts.json', false);
xhr.send(null);
var parsedCfg = JSON.parse(xhr.responseText);
if (parsedCfg.serverAddress) {
@@ -284,27 +284,28 @@ exports.defineAutoTests = function () {
}
} catch (ex) {
console.error('Unable to load file transfer server url: ' + ex);
- console.error('Note: if you are testing this on cordova-ios with cordova-plugin-wkwebview-engine, that may be why you are getting this error. See https://issues.apache.org/jira/browse/CB-10144.');
+ console.error(
+ 'Note: if you are testing this on cordova-ios with cordova-plugin-wkwebview-engine, that may be why you are getting this error. See https://issues.apache.org/jira/browse/CB-10144.'
+ );
fail(ex);
}
});
- it("should initialise correctly", function() {
+ it('should initialise correctly', function () {
expect(this.persistentRoot).toBeDefined();
expect(this.tempRoot).toBeDefined();
});
- it("should exist", function () {
+ it('should exist', function () {
expect(FileTransfer).toBeDefined();
});
- it("filetransfer.spec.1 should be constructable", function () {
+ it('filetransfer.spec.1 should be constructable', function () {
var transfer = new FileTransfer();
expect(transfer).toBeDefined();
});
- it("filetransfer.spec.2 should expose proper functions", function () {
-
+ it('filetransfer.spec.2 should expose proper functions', function () {
var transfer = new FileTransfer();
expect(transfer.upload).toBeDefined();
@@ -314,24 +315,23 @@ exports.defineAutoTests = function () {
expect(transfer.download).toEqual(jasmine.any(Function));
});
- describe("methods", function() {
- this.transfer = null;
- this.root = null;
- this.fileName = null;
- this.localFilePath = null;
-
- beforeEach(function() {
+ describe('methods', function () {
+ this.transfer = null;
+ this.root = null;
+ this.fileName = null;
+ this.localFilePath = null;
+ beforeEach(function () {
this.transfer = new FileTransfer();
// assign onprogress handler
this.transfer.onprogress = defaultOnProgressHandler;
// spy on the onprogress handler, but still call through to it
- spyOn(this.transfer, "onprogress").and.callThrough();
+ spyOn(this.transfer, 'onprogress').and.callThrough();
- this.root = this.persistentRoot;
- this.fileName = "testFile.txt";
+ this.root = this.persistentRoot;
+ this.fileName = 'testFile.txt';
this.localFilePath = this.root.toURL() + this.fileName;
});
@@ -341,8 +341,7 @@ exports.defineAutoTests = function () {
// - 'httpssss://example.com'
// - 'apache.org', with subdomains="true"
// - 'cordova-filetransfer.jitsu.com'
- describe("download", function () {
-
+ describe('download', function () {
// helpers
var verifyDownload = function (fileEntry, specContext) {
expect(fileEntry.name).toBe(specContext.fileName);
@@ -353,431 +352,481 @@ exports.defineAutoTests = function () {
deleteFile(this.root, this.fileName, done);
});
- it("ensures that test file does not exist", function (done) {
+ it('ensures that test file does not exist', function (done) {
deleteFile(this.root, this.fileName, done);
});
- it("filetransfer.spec.4 should download a file", function (done) {
- var fileURL = SERVER + "/robots.txt";
- var specContext = this;
+ it(
+ 'filetransfer.spec.4 should download a file',
+ function (done) {
+ var fileURL = SERVER + '/robots.txt';
+ var specContext = this;
- var fileWin = function (blob) {
-
- if (specContext.transfer.onprogress.calls.any()) {
- var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
- expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
- } else {
- console.log("no progress events were emitted");
- }
-
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var downloadWin = function (entry) {
-
- verifyDownload(entry, specContext);
-
- // verify the FileEntry representing this file
- entry.file(fileWin, fileSystemFail);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT * 10); // to give Heroku server some time to wake up
-
- it("filetransfer.spec.4.1 should download a file using target name with space", function (done) {
-
- var fileURL = SERVER + "/robots.txt";
- this.fileName = "test file.txt";
- this.localFilePath = this.root.toURL() + this.fileName;
-
- var specContext = this;
-
- var fileWin = function (blob) {
-
- if (specContext.transfer.onprogress.calls.any()) {
- var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
- expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
- } else {
- console.log("no progress events were emitted");
- }
-
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var downloadWin = function (entry) {
-
- verifyDownload(entry, specContext);
-
- // verify the FileEntry representing this file
- entry.file(fileWin, fileSystemFail);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.5 should download a file using http basic auth", function (done) {
- var fileURL = SERVER_WITH_CREDENTIALS + "/download_basic_auth";
- var specContext = this;
-
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.6 should get 401 status on http basic auth failure", function (done) {
- // NOTE:
- // using server without credentials
- var fileURL = SERVER + "/download_basic_auth";
-
- var downloadFail = function (error) {
- expect(error.http_status).toBe(401);
- expect(error.http_status).not.toBe(404, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail, null,
- {
- headers: {
- "If-Modified-Since": "Thu, 19 Mar 2015 00:00:00 GMT"
+ var fileWin = function (blob) {
+ if (specContext.transfer.onprogress.calls.any()) {
+ var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
+ expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
+ } else {
+ console.log('no progress events were emitted');
}
- });
- }, DOWNLOAD_TIMEOUT);
- it("filetransfer.spec.7 should download a file using file:// (when hosted from file://)", function (done) {
- // for Windows platform it's ms-appdata:/// by default, not file://
- if (isWindows) {
- pending();
- return;
- }
-
- var fileURL = window.location.protocol + "//" + window.location.pathname.replace(/ /g, "%20");
- var specContext = this;
-
- if (!/^file:/.exec(fileURL)) {
- done();
- return;
- }
-
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.8 should download a file using https://", function (done) {
- var fileURL = "https://www.apache.org/licenses/";
- var specContext = this;
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var fileOperationFail = function() {
- unexpectedCallbacks.fileOperationFail();
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var fileWin = function (file) {
-
- var reader = new FileReader();
-
- reader.onerror = fileOperationFail;
- reader.onload = function () {
- expect(reader.result).toMatch(/The Apache Software Foundation/);
done();
};
- reader.readAsText(file);
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+
+ // verify the FileEntry representing this file
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT * 10
+ ); // to give Heroku server some time to wake up
+
+ it(
+ 'filetransfer.spec.4.1 should download a file using target name with space',
+ function (done) {
+ var fileURL = SERVER + '/robots.txt';
+ this.fileName = 'test file.txt';
+ this.localFilePath = this.root.toURL() + this.fileName;
+
+ var specContext = this;
+
+ var fileWin = function (blob) {
+ if (specContext.transfer.onprogress.calls.any()) {
+ var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
+ expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
+ } else {
+ console.log('no progress events were emitted');
+ }
+
+ done();
+ };
+
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+
+ // verify the FileEntry representing this file
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.5 should download a file using http basic auth',
+ function (done) {
+ var fileURL = SERVER_WITH_CREDENTIALS + '/download_basic_auth';
+ var specContext = this;
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.6 should get 401 status on http basic auth failure',
+ function (done) {
+ // NOTE:
+ // using server without credentials
+ var fileURL = SERVER + '/download_basic_auth';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).toBe(401);
+ expect(error.http_status).not.toBe(404, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail, null, {
+ headers: {
+ 'If-Modified-Since': 'Thu, 19 Mar 2015 00:00:00 GMT'
+ }
+ });
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.7 should download a file using file:// (when hosted from file://)',
+ function (done) {
+ // for Windows platform it's ms-appdata:/// by default, not file://
+ if (isWindows) {
+ pending();
+ return;
+ }
+
+ var fileURL = window.location.protocol + '//' + window.location.pathname.replace(/ /g, '%20');
+ var specContext = this;
+
+ if (!/^file:/.exec(fileURL)) {
+ done();
+ return;
+ }
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.8 should download a file using https://',
+ function (done) {
+ var fileURL = 'https://www.apache.org/licenses/';
+ var specContext = this;
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var fileOperationFail = function () {
+ unexpectedCallbacks.fileOperationFail();
+ done();
+ };
+
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var fileWin = function (file) {
+ var reader = new FileReader();
+
+ reader.onerror = fileOperationFail;
+ reader.onload = function () {
+ expect(reader.result).toMatch(/The Apache Software Foundation/);
+ done();
+ };
+
+ reader.readAsText(file);
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.11 should call the error callback on abort()',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/BlueZedEx.mp3';
+ fileURL = fileURL + '?q=' + new Date().getTime();
+ var specContext = this;
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, done);
+ setTimeout(function () {
+ specContext.transfer.abort();
+ }, ABORT_DELAY);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.9 should not leave partial file due to abort',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/logos_2.zip';
+ var specContext = this;
+
+ var fileSystemWin = function () {
+ unexpectedCallbacks.fileSystemWin();
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var downloadFail = function (error) {
+ var result = !!(error.code === FileTransferError.ABORT_ERR || error.code === FileTransferError.CONNECTION_ERR);
+ if (!result) {
+ fail(
+ 'Expected ' +
+ error.code +
+ ' to be ' +
+ FileTransferError.ABORT_ERR +
+ ' or ' +
+ FileTransferError.CONNECTION_ERR
+ );
+ }
+ expect(specContext.transfer.onprogress).toHaveBeenCalled();
+
+ // check that there is no file
+ specContext.root.getFile(specContext.fileName, null, fileSystemWin, done);
+ };
+
+ // abort at the first onprogress event
+ specContext.transfer.onprogress = function (event) {
+ if (event.loaded > 0) {
+ specContext.transfer.abort();
+ }
+ };
+
+ spyOn(specContext.transfer, 'onprogress').and.callThrough();
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.10 should be stopped by abort()',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/BlueZedEx.mp3';
+ fileURL = fileURL + '?q=' + new Date().getTime();
+ var specContext = this;
+
+ expect(specContext.transfer.abort).not.toThrow(); // should be a no-op.
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var downloadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.ABORT_ERR);
+
+ // delay calling done() to wait for the bogus abort()
+ setTimeout(done, GRACE_TIME_DELTA * 2);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ setTimeout(function () {
+ specContext.transfer.abort();
+ }, ABORT_DELAY);
+
+ // call abort() again, after a time greater than the grace period
+ setTimeout(function () {
+ expect(specContext.transfer.abort).not.toThrow();
+ }, GRACE_TIME_DELTA);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.12 should get http status on failure',
+ function (done) {
+ var fileURL = SERVER + '/404';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ expect(error.http_status).toBe(404);
+
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.13 should get http body on failure',
+ function (done) {
+ var fileURL = SERVER + '/404';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ expect(error.http_status).toBe(404);
+
+ expect(error.body).toBeDefined();
+ expect(error.body).toMatch('You requested a 404');
+
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it('filetransfer.spec.14 should handle malformed urls', function (done) {
+ var fileURL = getMalformedUrl();
+
+ var downloadFail = function (error) {
+ // Note: Android needs the bad protocol to be added to the access list
+ //