node.js - Making sequential mongoose queries in a for loop inside a mocha test -


i trying use mocha test driver api application.

i have json of user names song names, trying feed api endpoint.

json:

{   "description": "hold lists each user heard before",   "userids":{     "a": ["m2","m6"],     "b": ["m4","m9"],     "c": ["m8","m7"],     "d": ["m2","m6","m7"],     "e": ["m11"]   } } 

let's user , song schema _id name. want after parsing json file, convert "a" user_id, doing mongoose lookup of "a" name, let's id=0. convert each of "m2" song_id name let's id=1, , call request, http://localhost:3001/listen/0/1

here have far mocha test:

test.js:

it('adds songs users listen to', function(done){     var parsedlistenjson = require('../listen.json')["userids"];     //console.log(parsedlistenjson);     (var username in parsedlistenjson) {       if (parsedlistenjson.hasownproperty(username)) {         var songs = parsedlistenjson[username];         var currentuser;         //console.log(username + " -> " + songs);         var userquery = user.findone({'name': username})         userquery.then(function(user){             //console.log("user_id: " + user["_id"]);             currentuser = user;           });          (var i=0; i<songs.length; i++)         {           //console.log(songs[i]);           var songquery = song.findone({'name': songs[i]})             songquery.then(function(song){                 console.log("user_id: " + currentuser["_id"]);                 console.log("song_id: " + song["_id"]);                 // need ensure have both user_id , song_id                  api_request = "http://localhost:3001/listen/" + currentuser["_id"] + "/" + song["_id"];                 console.log(api_request);                 // listen/user_id/song_id                 //.post('http://localhost:3001/listen/0/1')                 request                     .post(api_request)                     .end(function(err, res){                       expect(res.status).to.equal(200);                     });                });         }       }     }     done();   }) 

questions:

1) need make sure have both user_id , song_id before make api cal. right now, each of user.findone , song.findone query has own clauses. passing user_id through currentuser variable block of song query. since query asynchronous, don't think proper. how can structure code proceed api call when both block have executed.

2) when run code is, first user gets executed, , not rest, ie. print out is: user_id: 0 song_id: 1 http://localhost:3001/listen/0/1 user_id: 0 song_id: 5 http://localhost:3001/listen/0/5

3) api endpoint works postman, , in simpler mocha test below. doesn't seem work in original code.

var request = require('superagent'); var expect = require('expect.js'); var user = require('../models/user'); var song = require('../models/song'); var mongoose = require('mongoose'); mongoose.connect('localhost/testsongrecommender'); ... it('adds songs', function(){     request         .post('http://localhost:3001/listen/0/2')         .end(function(res){           expect(res.status).to.equal(200);         });   }); 

update:

the async.foreach approach works. here's final snippet:

updated test.js

var request = require('superagent'); var expect = require('expect.js'); var async = require('async'); var user = require('../models/user'); var song = require('../models/song'); var mongoose = require('mongoose'); mongoose.connect('localhost/test');  describe('song recommendations', function(){ it('adds songs users listen to', function(done){     var parsedlistenjson = require('../listen.json')["userids"];     //console.log(parsedlistenjson);     async.foreach(object.keys(parsedlistenjson), function forallusers(username, callback) {         var songs = parsedlistenjson[username];         //var currentuser;         //console.log(username + " -> " + songs);         var userquery = user.findone({'name': username})         userquery.then(function(user){             //console.log("user_id: " + user["_id"]);             //console.log(songs);             //currentuser = user;             async.foreach(songs, function runsongquery(songname, smallback) {               //console.log(songname);               var songquery = song.findone({'name': songname})               songquery.then(function(song){                 //console.log("user_id: " + user["_id"]);                 //console.log("song_id: " + song["_id"]);                 // need ensure have both user_id , song_id                 api_request = "http://localhost:3001/listen/" + user["_id"] + "/" + song["_id"];                 console.log(api_request);                 // listen/user_id/song_id                 //.post('http://localhost:3001/listen/0/1')                 request                     .post(api_request)                     .end(function(err, res){                       expect(res.status).to.equal(200);                       smallback()                     });                });             }, function allsongs(err) {               callback();             })           });     }, function allusernames(err) {       done()     })   }) }); 

1&2) you're going want use async package npm. can command npm install async --save in main folder , var async = require('async') in code.

you'll have replace each loop async.foreach. async.foreach takes array , 2 functions arguments. calls first function on each item in array , second function once callbacks have returned.

the way you're doing it, loops isn't going work. time asynchronous things return, loop has iterated past them (non-blocking io, remember) , variables no longer set correctly.

you need things set call done once code has run.

it end looking if written properly:

it('adds songs users listen to', function(done){     var parsedlistenjson = require('../listen.json')["userids"];     //console.log(parsedlistenjson);     async.foreach(parsedlistenjson, function forallusers(username, callback) {         var songs = parsedlistenjson[username];         //console.log(username + " -> " + songs);         var userquery = user.findone({'name': username})         userquery.then(function(user){             //console.log("user_id: " + user["_id"]);             var currentuser = user;             async.foreach(songs, function runsongquery(songname, smallback) {               var songquery = song.findone({'name': songname})               songquery.then(function(song){                 console.log("user_id: " + currentuser["_id"]);                 console.log("song_id: " + song["_id"]);                 // need ensure have both user_id , song_id                  api_request = "http://localhost:3001/listen/" + currentuser["_id"] + "/" + song["_id"];                 console.log(api_request);                 // listen/user_id/song_id                 //.post('http://localhost:3001/listen/0/1')                 request                     .post(api_request)                     .end(function(res){                       expect(res.status).to.equal(200);                       smallback()                     });                });             }, function allran(err) {               callback();             })           });     }, function allusernames(err) {       done()     })    }) 

3) you're going want use testing framework testing api. recommend supertest. once have supertest, require app , supertest:

var request = require('supertest'); var app = require('./testapp.js'); 

use in tests like:

request(app)   .post(api_request)   .end(function(res){        expect(res.status).to.equal(200);        smallback()   }); 

Comments

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -