unit testing file upload in angular - javascript

I am using the nf-file-upload module to upload a file to my backend. The code for the file upload is as follows:
$scope.upload = function (file) {
console.log(file)
Upload.upload({
url: 'http://localhost:3000/fileupload',
data: {file: file[0]},
}).then(function (resp) {
console.log('Success ' + resp.config.data.file.name + ' uploaded. Response: ' + resp.data);
}
The file uploading works great. however, when I create my unit test:
it('should send file to backend for processing', function(){
var mockFile = {file:[{"name":"file.bin", "size":1018, "type":"application/binary"}]};
httpBackend.when('POST', 'http://localhost:3000/fileupload').respond(200, {"filePath":"http://localhost:3000/uploads/file.txt"});
scope.upload(mockFile);
httpBackend.flush();
});
I get an error:
TypeError: undefined is not an object (evaluating 'resp.config.data.file.name')
What am I doing wrong?

The then method using the resp argument. In the normal conditions, you'll receive a object that have the structure:
{
config:{
data: {
file:{
name: 'a name'}
}
}
}
but in your test you don't respond with the same structure.
EDIT:
Ok. I got this. the way that ng-file-uploader returns the data it's not mockable. You don't get the name of the file in the resp.data.config.file.name, Instead, saves the filename in a variable before upload the file.
Like this:
$scope.upload = function (file) {
var fileName = file.name;
Upload.upload({
url: 'http://localhost:3000/fileupload',
data: {file: file[0]},
})
.then(function (resp) {
console.log('Success ' + fileName + ' uploaded. Response: ' + resp.data);
});
};
Check this codepen codepen.io/gpincheiraa/pen/MyrvQK Good luck!

You need to run a digest cycle.
it('should send file to backend for processing', function(){
var mockFile = {file:[{"name":"file.bin", "size":1018, "type":"application/binary"}]};
httpBackend.when('POST', 'http://localhost:3000/fileupload').respond(200, {"filePath":"http://localhost:3000/uploads/file.txt"});
scope.upload(mockFile);
httpBackend.flush();
scope.$digest();
});
This will resolve the promise and trigger the return data.

Related

How to fix Uncaught (in promise) TypeError: Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'

I'm trying to save to a SharePoint folder a .pptx file generated using pptxgenjs library. I've generated the blob I need into the console but I haven't been able to save it to the folder once generated.
The script is run on a click event. I'm just including the last bit as the issue is there. I just don't know how to solve it.
var targetUrl = webUrl + "/" + documentLibrary + "/" + folderName;
var FullUrl = webUrl + "/_api/Web/GetFolderByServerRelativeUrl(#target)/Files/add(overwrite=true, url='" + fileName + "')?$expand=ListItemAllFields&#target='" + targetUrl + "'";
function getFileBuffer(uploadFile) {
var deferred = jQuery.Deferred();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(uploadFile);
return deferred.promise();
}
function uploadFileToFolder(fileObj, url, success, failure) {
var apiUrl = FullUrl;
var getFile = getFileBuffer(fileObj);
getFile.done(function (arrayBuffer) {
$.ajax({
url: apiUrl,
type: "POST",
data: arrayBuffer,
processData: false,
async: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
},
success: function (data) {
console.log(data);
//success(data);
},
error: function (data) {
console.log(data);
//failure(data);
}
});
});
}
pptx.save('jszip', function(file1) {
var newblob = file1;
getFileBuffer(newblob);
}, 'blob');
The .pptx should be generated and saved to the provided URL. I don't want the user to download the pptx file or do anything else. At the moment I get the download window with the pptx file working fine but in console, I get the following error:
Uncaught (in promise) TypeError: Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'.
Any help would be much appreciated!

Copy file from local to the server nodejs

I am using nodeJS and I would like to upload a file to the server.
I have pug page where the user fill all the information and choose a file with filechooser. Then I want to send all the information on the page to the server. Therefore, I am using ajax to send a json object and given that file object can not be send through a json object I convert the File object to a json object like this:
function uploadGenome() {
var file = $(':file')[0].files[0];
var fileObject = {
'lastMod': file.lastModified,
'lastModDate': file.lastModifiedDate,
'name': file.name,
'size': file.size,
'type': file.type
};
return fileObject;
}
Then I add everything in a Json object:
var data = {};
data.file = uploadGenome();
data.name = inputs[0].value;
data.description = inputs[1].value;
data.start = inputs[3].value;
data.end = inputs[4].value;
And finally, I send everything with ajax:
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: url,
success: function (data) {
console.log('success');
console.log(JSON.stringify(data));
if (data === 'done')
{
window.location.href = "/";
} else {
alert('Error Creating the Instance');
}
},
error: function () {
console.log('process error');
}
});
On the server side with NodeJS I get everything, but now how could I copy the file that I get in data.file on the server ? I mean create a copy on the project folder which is on a server.

Send file from javascript to Python via Ajax

I'm having a problem sending a file object to python through an ajax call.
I'm using Dropzone just as my "file uploader interface" and I'm sending a call when certain button is pressed.
In python when I try to process the file, it says " 'str' object has no attribute 'seek' "
My JS Code:
...
window.$form_add_file = $("#form_add_file");
var file = dropzone.files[0];
...
var formData = $form_add_file.serializeArray();
if(file){
$modal_add_file.find($drop_add_file).removeClass("error");
var filetype = file.type.split("/")[0].toLowerCase();
var hasFile = checkFileType(filetype);
if(!hasFile) { filetype = "file" }
formData.push(
{ name: "file", value: file },
{ name: "file_type", value: filetype },
{ name: "file_name", value: file.name },
{ name: "file_size", value: file.size }
);
} else {
error = true;
$modal_add_file.find($drop_add_file).addClass("error");
return false;
}
if(!error){
$.ajax({
method: "POST",
url: host + "json.references.new",
data: formData,
cache: false,
dataType: 'json',
success: function(data){
if(data){
if(data.error){
modalMessage($modal_add_file, data.error, "ok");
} else {
refreshData(data);
}
}
},
error: function(error){
modalMessage($modal_add_file, oops_message, "ok");
}
});
}
My Python Code:
try:
file_path = os.path.join(path, file_name)
temp_file_path = file_path + '~'
file.seek(0) # error happen here
with open(temp_file_path, 'wb') as output_file:
shutil.copyfileobj(file, output_file)
os.rename(temp_file_path, file_path)
I've been searching for this on the internet and found nothing yet.
Sorry for the poor english.
Thanks in advance!
seek is a method for file objects, not strings.
I think your code snippet is missing some lines, but if file is supposed to be the file pointed to by file_path then you should first open the file with file = open(file_path, 'rb'). New file objects should start reading at the 0th position, so file.seek(0) should be unnecessary.

AngularJS http post not working

I have created a service and I using that for my login:
EDIT: Added the 'success' and 'error' code.
EDIT 2: I am developing an iOS mobile application which includes Javascript/AngularJS. So is there a way to view errors as alerts..
.service('Login', function($http, $q, $httpParamSerializerJQLike) {
return {
loginUser: function(ipAdd, name, pw) {
var sendurl = 'http://' + ipAdd + ':8080/loginuser/user.cgi';
var postData = {
'ACTION' : 'login',
'LOGIN' : name,
'PASSWORD' : pw
};
//what is the mistake here?
return $http({
method : 'POST',
url : sendurl,
data : $httpParamSerializerJQLike(postData),
headers : { 'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(response) {
var x2js = new X2JS();
var jsonObj = x2js.xml_str2json(response.data);
if (typeof jsonObj === 'object') {
alert("here:1");
return jsonObj;
} else {
alert("here:2");
// invalid response
return $q.reject(jsonObj);
}
}).error(function(response) {
//do error
//comes here when no internet connection is found..
alert("here:3");
return $q.reject(response.data);
});
}
}
})
I have also included this in app.js:
var app = angular.module("myApp", ['starter.services'],function($httpProvider){
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
});
My actual url looks like this:
'http://' + ipAdd + ':8080/loginuser/user.cgi?ACTION=login&LOGIN=' + name + '&PASSWORD=' + pw;
I have tried this approach too: https://stackoverflow.com/a/25570077/5876598
My service is not returning anything..
I want to know if I'm doing mistake in my url formation, or while sending data.
Thanks.
The best way to know where the mistake comes from is to check the 'network' tab on your navigator developer console.
Assuming you are runing on linux or mac, you can also try to use CURL to have an idea of what return the url you are trying to reach.
We can't help you with the code only.
I added a deferred promise in my service.
I also changed "success().error()" to ".then(function(data, status, headers, config){}) . Don't know why it didn't work when I used success and error.
Actually previously I noticed some issue while rendering promise itself in service. Follow the below structure
.service('Login', function($http, $q, $httpParamSerializerJQLike) {
return {
loginUser: function(ipAdd, name, pw) {
var sendurl = 'http://' + ipAdd + ':8080/loginuser/user.cgi';
var postData = {
'ACTION' : 'login',
'LOGIN' : name,
'PASSWORD' : pw
};
//what is the mistake here?
return $http({
method : 'POST',
url : sendurl,
data : $httpParamSerializerJQLike(postData),
headers : { 'Content-Type': 'application/x-www-form-urlencoded'}
});
}
}
})
.controller('SomeCtrlName',function(Login){
//pass your parameter to below service.
Login.loginUser().then(function success(){
//write success code here
},function error(){
//write error code here
)};
})

$.ajax inside BeforeUpload Event - Plupload

This app is an image uploading tool that uploads images directly from client browser to Amazon S3 using Plupload. So far, everything is working good except this issue.
I've this code forBeforeUpload event.
init: {
BeforeUpload: function (up, file) {
$.ajax({
url: '/ServerTime.ashx',
dataType: 'text',
data: { format: "yyyy-MM-dd_HH.mm.ss.fffffff" },
type: 'POST',
cache: false
}).done(function (data) {
console.log("Before setting ImageName: " + data);
imageName = data + ".JPG";
console.log("After setting ImageName: " + imageName);
up.settings.multipart_params = {
'key': key,
'Filename': imageName,
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
});
}
}
However, I've this error when try to upload a file:
HTTP Error. Upload URL might be wrong or doesn't exist.
On Console, it is printing the expected result as follows:
Before setting ImageName: 2014-04-04_13.33.45.1155072
After setting ImageName: 2014-04-04_13.33.45.1155072.JPG
I guess there is something wrong maybe because I'm using AJAX to get time from server. On the other hand, trying the following code is working without any issue.
init: {
BeforeUpload: function (up, file) {
up.settings.multipart_params = {
'key': "This_Is_Folder_Name/This_Is_File_Name.JPG",
'Filename': "This_Is_File_Name.JPG",
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
}
}
Notice that, this time I'm using static names for Filename and key, and there is no AJAX either
I really need help with this issue. Please suggest me. What I'm doing wrong with using AJAX to get server time and use it as file name?
Thanks.
You might be able to override some of their code by doing the following:
init: {
BeforeUpload: function (up, file) {
$.ajax({
url: '/ServerTime.ashx',
dataType: 'text',
data: { format: "yyyy-MM-dd_HH.mm.ss.fffffff" },
type: 'POST',
cache: false
}).done(function (data) {
console.log("Before setting ImageName: " + data);
imageName = data + ".JPG";
console.log("After setting ImageName: " + imageName);
up.settings.multipart_params = {
'key': key,
'Filename': imageName,
'acl': 'public-read',
'success_action_status': '201',
'AWSAccessKeyId': accessKey,
'policy': policyDocument,
'signature': policySignature
};
file.status = plupload.UPLOADING;
up.trigger("UploadFile", file);
});
return false;
}
}
This would cancel their trigger, so you would have to trigger it yourself. Please note, I have not tested this.
EDIT: I'm not sure if up and file are out of scope though...
If you look in the Plupload source code you'll see this:
// Private methods
function uploadNext() {
var file, count = 0, i;
if (this.state == plupload.STARTED) {
// Find first QUEUED file
for (i = 0; i < files.length; i++) {
if (!file && files[i].status == plupload.QUEUED) {
file = files[i];
if (this.trigger("BeforeUpload", file)) {
file.status = plupload.UPLOADING;
this.trigger("UploadFile", file);
}
} else {
count++;
}
}
// All files are DONE or FAILED
if (count == files.length) {
if (this.state !== plupload.STOPPED) {
this.state = plupload.STOPPED;
this.trigger("StateChanged");
}
this.trigger("UploadComplete", files);
}
}
}
The line that says if (this.trigger("BeforeUpload", file)) { will determine whether the return of the trigger call is truthy or falsy. If truthy, it will next trigger "UploadFile". What that means is that the uploading of the file does not wait for asynchronous code to execute in your BeforeUpload function. As soon as that function returns, the upload can begin. Any async ajax call you make inside your BeforeUpload function will resolve after "UploadFile" is triggered.

Categories

Resources