How I can encode with Protobuf a Cypress stub response? - cypress

I have some fixtures to stub a server that encode the messages with protobuf (I'm using protobufjs). I'd like to have the fixtures decoded to easily manipulate them and let Cypress encode the stub body before sending the response to the client, how can I do it?

[UPDATE] it's now available as a Cypress plugin
That's my solution:
cypress/plugins/protobufjs/index.js file (where the protobuf definitions are imported)
const path = require("path");
const protobufjs = require("protobufjs");
const definition = path.join(__dirname, "../../../public/escrow/ui.proto");
const proto = protobufjs.loadSync(definition);
module.exports = {
Status: proto.lookupType("escrow.Status"),
};
cypress/plugins/index.js file (where the encoding happens with a custom Cypress task)
const { StringDecoder } = require("string_decoder");
const Messages = require("./protobufjs");
module.exports = on => {
on("task", {
protobufEncode: ({ data, encoderName }) => {
const decoder = new StringDecoder("utf8");
const bufferValue = Messages[encoderName].encode(data).finish();
return decoder.end(Buffer.from(bufferValue));
}
});
};
in your test
cy.fixture("YOUR_FIXTURE.json").then(async json => {
cy.task("protobufEncode", { encoderName: "Status", data: json }).then(result => {
cy.route({
headers: {
"content-type": "application/octet-stream"
},
method: "GET",
response: result,
status: 200,
url: `**/YOUR_URL`
}).as("route_status_one_usb_key");
});
});

Related

Posting image from expo and axios to spring boot server returns error

I wanna send an axios request with photo data to my Spring Boot server but it does not work.
Here is the code:
const updateUserProfile = dispatch => async ({categories, phoneNumber, photo}) => {
try {
const id = await SecureStore.getItemAsync('user_id');
const formData = new FormData()
formData.append("file", {
uri: photo,
name: `${id}_photo`,
type: 'image/png'
})
await request.post(
`/photos/${id}`,
formData,
{
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`
},
},
)
dispatch({type: 'update_user_profile', payload: response.data})
} catch (e) {
dispatch({type: 'add_error', payload: 'UPDATE_USER_PROFILE_ERROR'})
}
}
The file URI looks like that and I think its correct:
file:///data/user/0/[...]/ImagePicker/e9255306-dca9-486e-a9
05-e4e1c619b766.jpg
And here is the Spring Boot Controller
#PostMapping("/{userId}")
public void saveObject(#RequestParam(value = "file") MultipartFile file, #PathVariable Long userId) {
photoService.uploadFile(file, userId);
}
Spring Boot works great when I send request with photo from postman but when I want to send the request from updateUserProfile method above, I receive this error:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]
Okay, finally after many hours I fixed the problem. This github issue helped me a lot https://github.com/axios/axios/issues/4412
So I installed form-data package
npm i form-data
and in the updateUserProfile method added this line just before appending data to formData
FormData.prototype[Symbol.toStringTag] = 'FormData';
so the full method looks like that now:
const updateUserProfile = dispatch => async ({categories, phoneNumber, photo}) => {
try {
const id = await SecureStore.getItemAsync('user_id');
const extenstion = photo.substring(photo.lastIndexOf('.') + 1)
const fileName = photo.replace(/^.*[\\\/]/, '')
const formData = new FormData()
FormData.prototype[Symbol.toStringTag] = 'FormData';
formData.append("file", {
uri: photo,
name: fileName,
type: `image/${extenstion}`
})
await request.post(
`/photos/${id}`,
formData,
{
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`
},
},
)
dispatch({type: 'update_user_profile', payload: response.data})
} catch (e) {
dispatch({type: 'add_error', payload: 'UPDATE_USER_PROFILE_ERROR'})
}
}

How to take a photo and upload it to the server with Nativecript-camera

I am new to Nativescript Vue development, I am trying to take a photo and send it to the server. My code works fine on Android, but when I run on iOS, errors occur, the image doesn’t even paste onto the page and doesn’t upload to the server.
import * as camera from "nativescript-camera";
import * as bghttp from "nativescript-background-http";
const firebase = require("nativescript-plugin-firebase");
var session = bghttp.session("image-upload");
takePicture() {
camera.requestPermissions()
.then(() => {
camera.takePicture({ width: 300, height: 300, keepAspectRatio: true, saveToGallery:true })
.then(imageAsset => {
this.img = imageAsset.android;
})
.catch(e => {
console.log('error:', e);
});
})
.catch(e => {
console.log('Error requesting permission');
});
}
upload() {
var file = this.img;
var url = "https://bocorp.ru/assets/mobileNewOrder.php";
var name = file.substr(file.lastIndexOf("/") + 1);
// upload configuration
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
"File-Name": name,
},
content: JSON.stringify({
Title: title
}),
description: "Uploading " + name
};
var task = session.uploadFile(file, request);
I understand that another code should be used in "this.img = imageAsset.android;" but I don’t understand how can I get a photo from the Iphone camera. I will be glad to any prompt
We save our images to the device, and then upload later as a multipart upload. You might be able to skip the file saving part, but it does allow us to keep from reading in the entire image for uploading later in our app flow (I guess if you already have the image source for display you could reuse it for upload on the same page).
Hope you find this helpful.
const imageSource = require('tns-core-modules/image-source')
// ...
camera.takePicture(cameraOpts)
.then(imageAsset => {
return imageSource.fromAsset(imageAsset)
})
.then(imageSource => {
let pathDest = '/path/on/device' // you define
console.log(`Created image source with width=${imageSource.width} height=${imageSource.height} at ${pathDest}`)
imageSource.saveToFile(pathDest, 'jpg', 50)
return pathDest // save this to look up later
})
Then when we need to upload
const mime = require('mime-types')
import * as bghttp from 'nativescript-background-http'
...
let session = bghttp.session('image-upload')
let request = {
url: 'https://yourendpoint.com/here',
method: 'POST',
androidAutoDeleteAfterUpload: true,
headers: {
'Content-Type': 'application/octet-stream',
}
}
// photoPath is known somehow. We use Vuex, but somehow it makes it to this page
let params = [
{ name: 'photo1', filename: photoPath, mimeType: mime.lookup(photoPath) }
]
return new Promise((resolve, reject) => {
let task = session.multipartUpload(params, request)
task.on('error', (e) => {
reject(e)
})
task.on('complete', res => {
resolve()
})
})

Error during upload image to imgur - inavlid URL

i have some troubles with imgur api. I converted image to base64 code and tried upload it to imgur api. Unfortuatelly I'm receiving an error:
"error": "Invalid URL (data:image/png;base64,iVBORw0KGgoAA..."
Here's my function:
uploadImageToImgur: function (file) {
const url = 'https://api.imgur.com/3/image',
reader = new FileReader();
reader.onloadend = async function () {
let { result } = reader;
try {
const request = await fetch(url, {
method: 'POST',
headers: {
"Authorization": 'my client key',
},
body: result
});
const response = await request.json();
console.log(response);
} catch (e) {
throw new Error(e);
}
}
if (file) {
reader.readAsDataURL(file);
}
}
You need to cut this part out.
You are missing some parameters. Also, make sure your headers have the Client-ID key.
const request = await fetch(url, {
method: 'POST',
headers: {
"Authorization": 'Client-ID {yourKey}',
},
form: {
"image": result,
"type": "base64"
}
});

How to parse binary data ("multipart/form-data") in KOA?

If I send POST-query with text options, all OK:
query from front-end:
const request = require("request")
const options = {
method: 'POST',
url: 'http://localhost:4000/user',
headers: form: { data: '12345' }
}
On server-side (KOA) I can get parsed data of a.m.query:
ctx.request.method: "POST"
ctx.request.originalUrl: "user"
ctx.request.body.data: "12345"
But if I send a POST query with binary data (file):
const fs = require("fs");
const request = require("request");
const options = { method: 'POST',
url: 'http://localhost:4000/user',
headers:
{
'content-type': 'multipart/form-data},
formData:
{ '':
{ value: 'fs.createReadStream("F:\\image.jpg")',
options:
{ filename: 'F:\\image.jpg',
contentType: null }
} } };
I don't know, how can I access for this binary data ("image.jpg) on server-part (KOA), in ctx.request have any field with this data...
You can use busboy for this. I wrote a gist for doing this, but I'm going to embed it here with some comments.
Let's create a helper for parsing out the file in a promise-friendly way.
// parse.js
import Busboy from 'busboy'
/**
* Parses a single file from a Node request.
*
* #param {http.IncommingRequest} req
* #return {Promise<{ file: Stream, filename: string>}
*/
export default function parse (req) {
return new Promise((resolve, reject) => {
const busboy = new Busboy({
headers: req.headers,
limits: {
files: 1 // allow only a single upload at a time.
}
})
busboy.once('file', _onFile)
busboy.once('error', _onError)
req.pipe(busboy)
function _cleanup () {
busboy.removeListener('file', _onFile)
busboy.removeListener('error', _onError)
}
function _onFile (fieldname, file, filename) {
_cleanup()
resolve({ file, filename })
}
function _onError (err) {
_cleanup()
reject(err)
}
})
}
Now we need to use it. Let's assume you want to upload to AWS S3.
import Koa from 'koa'
import parse from './busboy'
import AWS from 'aws-sdk'
const app = new Koa()
const s3 = new AWS.S3({
params: { Bucket: 'myBucket' }
})
// Assuming this is a route handler.
app.use(async (ctx) => {
const { file, filename } = await parse(ctx.req)
// `file` is a Stream. Pass this to S3, Azure Blob Storage or whatever you want.
// `filename` is the file name specified by the client.
const result = await s3.upload({
Key: filename,
Body: file
}).promise()
ctx.body = result
})
For brevity's sake, this is how you upload the file using axios on the client.
// `file` is a DOM File object.
function upload (file) {
const data = new window.FormData()
data.append('file', file, file.name)
return axios.post('/upload', data)
}

Unit Testing the promises in JEST

The issue is regarding the unit testing using JEST.
How to test the a function X which is returning a promise which is making an async HTTP request.
Function X
import httpHelper from './httpHelper';
function fetchMoxtraAccessToken(userEWAToken, successCallback, failureCallback) {
const httpObj = {
url: '/getAccessToken',
headers: { Authorization: userEWAToken },
};
return httpHelper(httpObj, successCallback, failureCallback);
}
How to unit test the function X on the basis of the response?
The easiest way is to mock httpHelper so it just returns a spy on which you can test that is was called with the correct parameter:
jest.mock('./httpHelper', () = > jest.fn()) //Path must be relative to test file
import httpHelper from './httpHelper'
describe(('fetchMoxtraAccessToken') => {
it(('makes correct http request') => {
const userEWAToken = 'someUserEWAToken'
const successCallback = jest.fn()
const failureCallback = jest.fn()
fetchMoxtraAccessToken(userEWAToken, successCallback, failureCallback)
expect(httpHelper).toHaveBeenCalledWith({
url: '/getAccessToken',
headers: {
Authorization: 'someUserEWAToken'
},
}, successCallback, failureCallback)
})
})

Resources