Vue Jest Testing await in loop - vue.js

I'm pretty new in unit testing and I'm having some issues writing a function test for await in a loop.
code to test:
export default {
name: 'MyComponent',
setup() {
const count = ref<number>(0);
function foo(count: number, delay: number): Promise<void> {
const resolver = async (resolve: () => void) => {
count.value = count;
while (count.value >= 0) {
await yoo();
await wait(delay);
count.value -= 1;
}
}
return new Promise<void>(resolver);
}
async function yoo() {
// something
await koo();
// something else
}
function wait(waitTime: number): Promise<void> {
const resolver = (resolve: () => void) => {
setTimeout(resolve, waitTime);
};
return new Promise(resolver);
}
}
}
test:
let wrapper = mount(MyComponent);
let promise: Promise<void>;
let count = 5;
jest.useFakeTimers();
beforeAll(() => {
promise = wrapper.vm.foo(count, 100);
})
test(`count value decreases at each iteration`, async () => {
while (wrapper.vm.count >= 0) {
const prevCountValue = wrapper.vm.count;
await flushPromises();
jest.runAllTimers();
expect(wrapper.vm.count).toBe(prevCountValue - 1);
}
}
Writing the test in this way breaks due to jest.setTimeout.Error:
Any ideas on what is the correct way to write this test?

Related

Mock, jest and time

I read some tips on how to mock your request/response in Express framework in the blog:
https://codewithhugo.com/express-request-response-mocking/. However, I have no clue how to mock the controller below.
export const healthCheck = async (req, res, next) => {
log("debug", "healthCheck controller called");
const healthcheck = {
uptime: process.uptime(),
message: "Server is running!",
now_timestamp: Date.now()
};
try {
res.send(healthcheck);
} catch (error) {
healthcheck.message = error;
res.status(503).send();
}
};
I am glad to share my efforts below. My suspicion is that I must mock class Date as well.
import {
healthCheck
} from "../healthcheck.js";
const mockRequest = () => {
const req = {}
req.body = jest.fn().mockReturnValue(req)
req.params = jest.fn().mockReturnValue(req)
return req
};
const mockResponse = () => {
const res = {}
res.get = jest.fn().mockReturnValue(res)
res.send = jest.fn().mockReturnValue(res)
res.status = jest.fn().mockReturnValue(res)
res.json = jest.fn().mockReturnValue(res)
return res
};
const mockNext = () => {
return jest.fn()
};
describe("healthcheck", () => {
afterEach(() => {
// restore the spy created with spyOn
jest.restoreAllMocks();
});
it("should call mocked log for invalid from scaler", async () => {
let req = mockRequest();
let res = mockResponse();
let next = mockNext();
await healthCheck(req, res, next);
expect(res.send).toHaveBeenCalledTimes(1)
expect(res.send.mock.calls.length).toBe(1);
});
});

vue method for loop wait for function complete

In this vue component, I have a method containing a for loop, calling another method. The second method does a request to the appserver. I need the first function waiting for the second to continue the for-loop. I've tried several async await options but doesn't understand how to implement it.
methods: {
selectFiles(files) {
this.progressInfos = [];
this.selectedFiles = files;
},
uploadFiles() {
this.message = "";
//var result = 0;
for (let i = 0; i < this.selectedFiles.length; i++) {
console.log(i)
//result = await this.upload(i, this.selectedFiles[i]);
this.upload(i, this.selectedFiles[i]);
}
},
upload(idx, file) {
this.progressInfos[idx] = { percentage: 0, fileName: file.name };
//console.log("FinDocuNum:" + financialDocument.finDocId)
FinancialDocumentDataService.upload(1, file, (event) => {
this.progressInfos[idx].percentage = Math.round(100 * event.loaded / event.total);
}).then((response) => {
let prevMessage = this.message ? this.message + "\n" : "";
this.message = prevMessage + response.status;
return 1;
}).catch(() => {
this.progressInfos[idx].percentage = 0;
this.message = "Could not upload the file:" + file.name;
return 0;
});
}
}
The upload function must be async and return a promise like this:
async upload(file) {
return new Promise((resolve, reject) => {
axios({url: url, data: file, method: 'POST'})
.then(resp => {
resolve(resp)
})
.catch(err => {
reject(err)
})
})
},

jest how can test axios?

No matter how I write, asynchronous problems occur.
test.js:
const auth = require('../methods/auth.js');
describe('test', () => {
test('test', async () => {
expect.assertions(1);
const data = await auth.signin();
return expect(data.success).toBeTruthy();
});
auth.js:
module.exports = {
async signin(data) {
try {
const res = await axios.post('/signin', data);
return res.data;
} catch (error) {
return error.response;
}
},
}
Each execution result is different.
You can test Promises as follows:
test('test awaiting it to resolve', () => {
// Don't await. Note the return; test callback doesn't need to be async
// What I do in my tests as its more readable and the intention is clear
return expect(auth.signin()).resolves.toEqual({success: true});
});
test('test the promises way', () => {
// Not better than above; traditional way; note 'return'
return auth.signin().then(data => { expect(data.success).toBeTruthy() });
});
Detailed notes from jest: https://jestjs.io/docs/asynchronous#promises

Testing a cloudflare worker with HTMLRewriter fails as its undefined

I have a test to test my cloudflare worker that looks like this:
const workerScript = fs.readFileSync(
path.resolve(__dirname, '../pkg-prd/worker.js'),
'utf8'
);
describe('worker unit test', function () {
// this.timeout(60000);
let worker;
beforeEach(() => {
worker = new Cloudworker(workerScript, {
bindings: {
HTMLRewriter
},
});
});
it('tests requests and responses', async () => {
const request = new Cloudworker.Request('https://www.example.com/pathname')
const response = await worker.dispatch(request);
console.log(response);
// const body = await response.json();
expect(response.status).to.eql(200);
// expect(body).to.eql({message: 'Hello mocha!'});
});
});
In my worker I do something like this:
const response = await fetch(BASE_URL, request);
const modifiedResponse = new Response(response.body, response);
// Remove the webflow badge
class ElementHandler {
element(element) {
element.append('<style type="text/css">body .w-webflow-badge {display: none!important}</style>', {html: true})
}
}
console.log(3);
return new HTMLRewriter()
.on('head', new ElementHandler()).transform(modifiedResponse);
Now when i run my test I get this error message:
● worker unit test › tests requests and responses
TypeError: Cannot read property 'transform' of undefined
at evalmachine.<anonymous>:1:1364
at FetchEvent.respondWith (node_modules/#dollarshaveclub/cloudworker/lib/cloudworker.js:39:17)
What seems to be wrong?
HTMLRewriter i created looks like this:
function HTMLRewriter() {
const elementHandler = {};
const on = (selector, handler) => {
if (handler && handler.element) {
if (!elementHandler[selector]) {
elementHandler[selector] = [];
}
elementHandler[selector].push(handler.element.bind(handler));
}
};
const transform = async response => {
const tempResponse = response.clone();
const doc = HTMLParser.parse(await tempResponse.text());
Object.keys(elementHandler).forEach(selector => {
const el = doc.querySelector(selector);
if (el) {
elementHandler[selector].map(callback => {
callback(new _Element(el));
});
}
});
return new Response(doc.toString(), response);
};
return {
on,
transform
};
}
Since HTMLRewriter() is called with new, the function needs to be a constructor. In JavaScript, a constructor function should set properties on this and should not return a value. But, your function is written to return a value.
So, try changing this:
return {
on,
transform
};
To this:
this.on = on;
this.transform = transform;

What's the different between Async.queue and Promise.map?

I tried to stress test my api in ExpressJS and to handler multi request I used Promise.all and then Async.queue with concurrency option.
Promise:
export const myapi = async (args1, args2) => {
console.log('args:', args1, args2);
let testing_queue = [];
testing_queue.push(new Promise(async (resolve, reject) => {
let result = await doAComplexQuery(args1, args2); // SELECT... JOIN...
if (!result || result.length <= 0)
reject(new Error('Cannot find anything!'));
resolve(result);
}
));
return await Bluebird.map(testing_queue, async item => {
return item;
}, {concurrency: 4}); };
Async.queue: (https://www.npmjs.com/package/async)
export const myapi = async (args1, args2) => {
console.log('args:', args1, args2);
let testing_queue = Async.queue(function (task, callback) {
console.log('task', task);
callback();
}, 4);
testing_queue.push(async function () {
let result = await doAComplexQuery(args1, args2); // SELECT... JOIN...
if (!result || result.length <= 0)
throw new Error('Cannot find anything!');
return result;
}
);};
And try to make request as much as possible:
const response = async function () {
return await Axios.post('http://localhost:3000/my-api', {
"args1": "0a0759eb",
"args2": "b9142db8"
}, {}
).then(result => {
return result.data;
}).catch(error => {
console.log(error.message);
});
};
for (var i = 0; i < 10000; i++) {
response();
}
And Run. The #1 way returns many ResourceTimeout or Socket hang up responses. Meanwhile, the #2 returns success response for all requests and runs even faster.
So is the Async.queue better in this case?
I think it could help the speed if you raise the concurrency limit on your promise.map.