Reputation: 4685
I'm trying to simplify my test scaffolding for an Express backend. Rather than call a single record insert routine a number of times, which seems to have sync issues when checking the result, I want to perform the db inserts one after the other, using the array.
Here's what I have so far... but I seem to be screwing about the async await somehow. The tests fail as I get 0 body lengths and maybe one insertion. Any ideas where I'm going wrong?
async function asyncForEach (array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
};
}
async function insertTemplates(myTemplatesArray) {
const client = new Client(dbConfig);
client.connect();
await asyncForEach(
myTemplatesArray,
async (myTemplate) => {
let { name, status, version } = myTemplate;
await client.query(
SQL`INSERT INTO templates (name, status, version )
VALUES (${name}, ${status}, ${version})`)
.catch( err => console.error(err) );
});
client.end();
}
function randomTemplate() {
const template = {
name: faker.internet.userName(),
status: faker.hacker.phrase(),
version: String(faker.random.number())
};
return template;
}
function clean_db(){
const client = new Client(dbConfig);
client.connect();
client.query(
`TRUNCATE TABLE "templates";
ALTER SEQUENCE "templates_id_seq" RESTART WITH 1;`)
.catch( err => { console.error(err); } )
.then( () => client.end() );
}
describe('When there are 1 or more records in the table', () => {
const templ1 = randomTemplate();
const templ2 = randomTemplate();
const templ3 = randomTemplate();
beforeEach(async () => {
await clean_db();
await insertTemplates([templ1,templ2,templ3]);
});
afterEach(async () => {
await clean_db();
});
test('It should respond with a 200 status', async done => {
const response = await template(app).get('/templates');
expect(response.status).toBe(200);
done();
});
test('It should respond with an JSON array of records', async done => {
const response = await template(app).get('/templates');
expect(response.body.length).toBe(3);
done();
});
test('It should respond with the correct records', async done => {
templ1.id = 1;
templ2.id = 2;
templ3.id = 3;
const response = await template(app).get('/templates');
expect(response.body).toStrictEqual([templ1,templ2,templ3]);
done();
});
});
});
Upvotes: 2
Views: 140
Reputation: 30695
I believe the reason your test isn't working as expected is that you're breaking the promise chain in clean_db().. and perhaps a few other functions. This is very easy to do this when working with promises!
I'd suggest making sure clean_db returns a promise, e.g. like so:
function clean_db(){
const client = new Client(dbConfig);
client.connect();
// return promise to keep chain intact.
return client.query(
`TRUNCATE TABLE "templates";
ALTER SEQUENCE "templates_id_seq" RESTART WITH 1;`)
.catch( err => { console.error(err); } )
.then( () => client.end() );
}
I'm presuming that client.end() returns something.. this should cause clean_db() to return a promise so the await call will actually await.
I'd do the same for insertTemplates, e.g. return the result of client.end().
async function insertTemplates(myTemplatesArray) {
const client = new Client(dbConfig);
client.connect();
await asyncForEach(
myTemplatesArray,
async (myTemplate) => {
let { name, status, version } = myTemplate;
// Return promise to calling proc.
return client.query(
SQL`INSERT INTO templates (name, status, version )
VALUES (${name}, ${status}, ${version})`)
.catch( err => console.error(err) );
});
return client.end();
}
Also, make sure that the callback you pass to asyncForEach returns a promise.. I'm not sure if it does.
Upvotes: 1