Jest test working fine but not updating data in wrapper after await - vue.js

I am writing my first test in Vue and using jest, the issue I am facing is my function works and I am able to console log the data and see it in the console but the wrapper data has not been updated.
async loadcsv(element=null) {
const reader = new FileReader()
let file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
//Normalising headers
const results = e.target.result
let resultSplit = results.split('\n')
const header = resultSplit[0]
.toLowerCase()
.replace(/[^a-zA-Z,]/g, '')
.trim()
resultSplit[0] = header
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table) //wrapper data does not update after this line, anything before reflects
await Promise.all(
rows.map(async (row) => {
this.collections.push(row)
}),
)
this.inlineVisibility = false
this.toggleLoading()
this.$refs.modal.hide()
} catch (err) {
this.toggleLoading()
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
}
reader.readAsText(file)
},
}
However data in the wrapper.vm.$data is still empty
collection = []
where as in the console, it shows
collection = [{my test data}]
with at mockConstructor.reader.onload
at the end
How do I get the array that shows I the console?
workingCSV is a string of my CSV file
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', async () => {
const localVue = createLocalVue()
const wrapper = mount(ModalAddCollectionCSV, {
localVue,
propsData: {
visible: true,
},
})
const readAsTextMock = jest.fn()
const dataRead = jest.spyOn(global, 'FileReader').mockImplementation(function () {
const self = this
this.readAsText = readAsTextMock.mockImplementation(() => {
self.onload({ target: { result: workingCSV } })
})
})
const data = wrapper.vm.loadcsv()
expect(wrapper.vm.$data).toContain(data)
})

Related

Vue test method function which changes data

I just want to test a particular function that changes the data of the Vue component and doesn't return anything
data() {
return {
collections: [],
inlineSubtitle: '',
loading: false,
}
},
async loadcsv(element) {
const reader = new FileReader()
const file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
const results = e.target.result
let resultSplit = results.split('\n')
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table)
await Promise.all(
rows.map(async (row) => {
if (!(this.getSerial(row).length == 12)) {
if (!this.getName(row)) {
throw `Please enter Serial number`
}
if (!row.country) {
throw `Country for ${this.getName(
row,
)} is empty.`
}
//Adding row to collections
}
} catch (err) {
this.toggleLoading()
this.collections = []
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
I want to check in the unit test if the length of the collection array increase upon the right csv input or if there's an error if the notification fails
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', async () => {
const localVue = createLocalVue()
const wrapper = mount(ModalAddCollectionCSV, {
localVue,
propsData: {
visible: true,
},
})
const fileDict = [{ file: new Blob([wrongDateFormat], { type: 'text/csv;charset=utf-8;' }) }]
await wrapper.vm.loadcsv(fileDict)
expect(wrapper.vm.inlineSubtitle).toContain('Error')
})
})

vue unit test get data of component

I am testing if a function works,
The function doesn't return anything but infact changes the data in the component
This is the test I am trying to write
describe('ModalAddCollectionCSV', () => {
it('Test load csv function', () => {
const localVue = createLocalVue()
const wrapper = shallowMount(AddCSV, {
localVue,
propsData: {
visible: true,
},
})
var fileDict = [{ file: new Blob([wrongDateFormat]) }]
wrapper.vm.loadcsv(fileDict)
expect(wrapper.html()).toContain('error')
})
})
I am expecting some changes to the data of the component
data() {
return {
collections: [],
inlineVisibility: false,
inlineTitle: '',
inlineSubtitle: '',
inlineKind: 'info',
loading: false,
}
},
This is the function I am testing in unit test, as you see it doesn't return anything just changes the data at the end of it
async loadcsv(element) {
const reader = new FileReader()
const file = element[0].file
this.toggleLoading()
reader.onload = async (e) => {
try {
//Normalising headers
const results = e.target.result
let resultSplit = results.split('\n')
const header = resultSplit[0]
.toLowerCase()
.replace(/[^a-zA-Z,]/g, '')
.trim()
resultSplit[0] = header
let table = resultSplit.join('\n')
const rows = await d3.csvParse(table)
await Promise.all(
rows.map(async (row) => {
if (!(this.getSerial(row).length == 9)) {
if (!this.getName(row)) {
throw `Please enter Person of interest`
}
if (!row.country) {
throw `Country for ${this.getName(
row,
)} is empty`
}
}
)
this.inlineVisibility = false
this.$emit('rowEmit', {
collections: this.row,
})
this.toggleLoading()
this.collections = []
this.$refs.modal.hide()
} catch (err) {
this.collections = []
this.inlineNotification('error', 'Unable to process CSV', `${err}.`)
}
}
reader.readAsText(file)
},
Is there a way to check emit action or error action?
I tried wrapper.text()
Wrapper.html()
but no difference

stream s3 to dynamodb with fast-csv : not all data inserted

When a csv file is uploaded on my s3 bucket, my lambda will be triggered to insert my data into DynamoDB.
I need a stream because the file is too large to be downloaded as full object.
const batchWrite = async (clientDynamoDB, itemsToProcess) => {
const ri = {};
ri[TABLE_DYNAMO] = itemsToProcess.map((itm) => toPutRequest(itm));
const params = { RequestItems: ri };
await clientDynamoDB.batchWriteItem(params).promise();
};
function runStreamPromiseAsync(stream, clientDynamoDB) {
return new Promise((resolve, reject) => {
const sizeChunk = 25;
let itemsToProcess = [];
stream
.pipe(fastCsv.parse({headers: Object.keys(schemaGeData), trim: true}))
.on("data", (row) => {
stream.pause();
itemsToProcess.push(row);
if (itemsToProcess.length === sizeChunk) {
batchWrite(clientDynamoDB, itemsToProcess).finally(() => {
stream.resume();
});
itemsToProcess = [];
}
})
.on("error", (err) => {
console.log(err);
reject("Error");
})
.on("end", () => {
stream.pause();
console.log("end");
batchWrite(clientDynamoDB, itemsToProcess).finally(() => {
resolve("OK");
});
});
});
}
module.exports.main = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const object = event.Records[0].s3;
const bucket = object.bucket.name;
const file = object.object.key;
const agent = new https.Agent({
keepAlive: true
});
const client = new AWS.DynamoDB({
httpOptions: {
agent
}
});
try {
//get Stream csv data
const stream = s3
.getObject({
Bucket: bucket,
Key: file
})
.createReadStream()
.on('error', (e) => {
console.log(e);
});
await runStreamPromiseAsync(stream, client);
} catch (e) {
console.log(e);
}
};
When my file is 1000 lines everything is inserted but when I have 5000 lines, my function insert only around 3000 lines and this number is random... Sometimes more sometimes less..
So I'd like to understand what am I missing here ?
I also read this article but to be honest even if you pause the second stream, the first one is still running.. So if someone have any ideas on how to do this, it would be greatly appreciated !
Thanks
I found out why It was not fully processed, it's because the callback of batchWriteItem can return unprocess Items. So I change the function batchWrite and also the runPromiseStreamAsync a little bit because i might not have all the items processed from itemsToProcess.
Anyway here is the full code :
const batchWrite = (client, itemsToProcess) => {
const ri = {};
ri[TABLE_DYNAMO] = itemsToProcess.map((itm) => toPutRequest(itm));
const items = { RequestItems: ri };
const processItemsCallback = function(err, data) {
return new Promise((resolve, reject) => {
if(!data || data.length === 0){
return resolve();
}
if(err){
return reject(err);
}
let params = {};
params.RequestItems = data.UnprocessedItems;
return client.batchWriteItem(params, processItemsCallback);
});
};
return client.batchWriteItem(items, processItemsCallback );
};
function runStreamPromiseAsync(stream, clientDynamoDB) {
return new Promise((resolve, reject) => {
const sizeChunk = 25;
let itemsToProcess = [];
let arrayPromise = [];
stream
.pipe(fastCsv.parse({headers: Object.keys(schemaGeData), trim: true}))
.on("error", (err) => {
console.log(err);
reject("Error");
})
.on('data', data => {
itemsToProcess.push(data);
if(itemsToProcess.length === sizeChunk){
arrayPromise.push(batchWrite(clientDynamoDB, itemsToProcess));
itemsToProcess = [];
}
})
.on('end', () => {
if(itemsToProcess.length !== 0){
arrayPromise.push(batchWrite(clientDynamoDB, itemsToProcess));
}
resolve(Promise.all(arrayPromise).catch(e => {
reject(e)
}));
});
});
}

not playing audio from buffer stored in the database

I've spent 2 days with this thing and couldn't find a solution but seems like im getting closer. The goal is to record audio in the browser and store in the the database and get it whenever i need it.
I encoded the audio to base64 and sent it to the server stored as binary in the mongodb, created a get route in which i find the audio by id and send the buffer via res.send() along with the content type set to audio/webm (default mime type)
but the thing is I'm getting this blank video, seems like it's not knowing how to decode it or something. There might be something wrong with the content type.
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then((mediaRecorderObj) => {
let mediaRecorder = new MediaRecorder(mediaRecorderObj, { mimType: 'audio/webm;base64' })
const m = mediaRecorder;
let chunk = []
startBtn.addEventListener('click', () => {
mediaRecorder.start()
console.log('started recording..');
})
endBtn.addEventListener('click', () => {
mediaRecorder.stop()
console.log('just stopped recording');
})
//-----When Data Is Available
mediaRecorder.ondataavailable = (e) => {
chunk.push(e.data);
}
//--------When finished adding it to chunk
mediaRecorder.onstop = () => {
const blob = new Blob(chunk, { 'type': 'audio/webm' })
chunk = []
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onloadend = async () => {
const buffer = reader.result
const bodyObj = {
voice: buffer
}
await fetch('http://localhost:3000/upload-spoken-bio', {
method: 'post',
body: JSON.stringify(bodyObj),
headers: { 'Content-Type': 'application/json' }
})
}
}
})
and this is the server side
//----------Upload
spokenBio.post('/upload-spoken-bio', async (req, res) => {
const buffer = req.body
try {
const newBuffer = new SpokenCon(buffer)
await newBuffer.save()
}
catch (err) {
console.log(err.message);
}
})
//----------Retrieve
spokenBio.get('/get-spoken-bio/:id', async (req, res) => {
const id = req.params.id
try {
const field = await SpokenCon.findById(id)
const binary = field.voice
res.set({ 'Content-Type': 'audio/webm' })
res.send(binary)
}
catch (err) {
console.log(err.message);
}
})

How to test FileReader wrapped inside promise?

Current code:
export const readFilePromise = file => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = error => {
reject(error);
};
});
};
I am able to test the onload method
it('readFilePromise method', async () => {
const fileContentsEncodedInHex = [
'\x45\x6e\x63\x6f\x64\x65\x49\x6e\x48\x65\x78\x42\x65\x63\x61\x75\x73\x65\x42\x69\x6e\x61\x72\x79\x46\x69\x6c\x65\x73\x43\x6f\x6e\x74\x61\x69\x6e\x55\x6e\x70\x72\x69\x6e\x74\x61\x62\x6c\x65\x43\x68\x61\x72\x61\x63\x74\x65\x72\x73'
];
const blob = new Blob(fileContentsEncodedInHex);
const result = readFilePromise(blob);
const output = await result;
const expectedOutput =
'data:;base64,RW5jb2RlSW5IZXhCZWNhdXNlQmluYXJ5RmlsZXNDb250YWluVW5wcmludGFibGVDaGFyYWN0ZXJz';
expect(output).toEqual(expectedOutput);
});
I wonder how do I test the onerror?
If you had something like below because of this
reader.onerror = () => {
reject(reader.error);
};
Then the below should work.
Just know beforehand error message for passing empty file or nothing. I just wanted to create a scenario
describe('Error Case', () => {
it('should return error message for empty file', () => {
const result = readFilePromise();
const n = () => {};
return result.then(n, (errorMessage) => {
expect('your error message here').to.equal(errorMessage);
});
});