Issue Tracker PUT and Delete failing

Tell us what’s happening:
Quality Assurance Projects - Issue Tracker is failing put and delete requests, when manually testing the app works fine and all functional tests pass.
Under both functions i have commented the request bodys i’m getting from freecodecamp tests and the responses i’m sending.

Your code so far
server.js

'use strict';

const express     = require('express');
const bodyParser  = require('body-parser');
const expect      = require('chai').expect;
const cors        = require('cors');
require('dotenv').config();

const apiRoutes         = require('./routes/api.js');
const fccTestingRoutes  = require('./routes/fcctesting.js');
const runner            = require('./test-runner');

let app = express();

app.use('/public', express.static(process.cwd() + '/public'));

app.use(cors({origin: '*'})); //For FCC testing purposes only

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

//-------------------------------------
// prevent MIME sniffing
app.use((req, res, next) => {
  req.header('X-Content-Type-Options', 'nosniff');
  next();
});

// connect to database
const MongoClient = require('mongodb').MongoClient;
const MongoServer = require('mongodb').Server;
async function connectDB(callback) {
  const URI = process.env.DB;
  const client = new MongoClient(URI, {useNewUrlParser: true, useUnifiedTopology: true});

  try{
    await client.connect();
    await callback(client);
  } catch(e) {
    //console.error(e);
    throw new Error('Unable to Connect to Database');
  }
}

// routing
connectDB(async function(client) {
  const dataBase = await client.db('database');

  //Sample front-end
  app.route('/:project/')
    .get(function (req, res) {
      res.sendFile(process.cwd() + '/views/issue.html');
    }
  );

  //Index page (static HTML)
  app.route('/')
    .get(function (req, res) {
      res.sendFile(process.cwd() + '/views/index.html');
    }
  );

  //For FCC testing purposes
  fccTestingRoutes(app);

  //Routing for API 
  apiRoutes(app, dataBase);

  //404 Not Found Middleware
  app.use(function(req, res, next) {
    res.status(404).type('text').send('NOT FOUND');
  });

}).catch((e) => {
  app.route('/')
    .get(function (req, res) {
      res.status(500).type('text').send('INTERNAL SERVER ERROR');
    }
  );
});

//-------------------------------------

//Start our server and tests!
app.listen(process.env.PORT || 3000, function () {
  console.log("Listening on port " + process.env.PORT);
  if(process.env.NODE_ENV==='test') {
    console.log('Running Tests...');
    setTimeout(function () {
      try {
        runner.run();
      } catch(e) {
        let error = e;
          console.log('Tests are not valid:');
          console.log('error: '+error);
      }
    }, 3500);
  }
});

module.exports = app; //for testing

api.js

/*
*
*
*       Complete the API routing below
*
*
*/

'use strict';
const ObjectID = require('mongodb').ObjectID;

module.exports = function (app, dataBase) {

  app.route('/api/issues/:project')
  
    .get(function (req, res){
      // get issue
      let projectCollection = dataBase.collection(req.params.project);
      // TODO: implement filters
      let query = {};
      if(req.query._id) {query._id = new ObjectID(req.query._id);}
      if(req.query.issue_title) {query.issue_title = req.query.issue_title;}
      if(req.query.issue_text) {query.issue_text = req.query.issue_text;}
      if(req.query.created_on) {query.created_on = new Date(req.query.created_on);}
      if(req.query.updated_on) {query.updated_on = new Date(req.query.updated_on);}
      if(req.query.created_by) {query.created_by = req.query.created_by;}
      if(req.query.assigned_to) {query.assigned_to = req.query.assigned_to;}
      if(req.query.open) {query.open = req.query.open;}
      if(req.query.status_text) {query.status_text = req.query.status_text;}
      projectCollection
        .find(query)
        .toArray()
        .then(result => {
          return res.status(200).json(result);
        })
        .catch(error => {
          return res.status(200).json({error: error});
        });
      //
    })

    .post(function (req, res){
      // create issue
      if(!req.body.issue_title || !req.body.issue_text || !req.body.created_by) {
        return res.status(200).json({error: 'required field(s) missing'})
      }
      let projectCollection = dataBase.collection(req.params.project);
      projectCollection
        .insertOne({
          issue_title: req.body.issue_title,
          issue_text: req.body.issue_text,
          created_on: new Date(),
          updated_on: new Date(),
          created_by: req.body.created_by,
          assigned_to: req.body.assigned_to ? req.body.assigned_to : '',
          open: req.body.open ? req.body.open : true,
          status_text: req.body.status_text ? req.body.status_text : ''
        })
        .then(result => {
          projectCollection
            .findOne({_id: result.insertedId})
            .then(doc => {
              return res.status(200).json(doc);
            })
            .catch(error => {
              return res.status(200).json({error: error});
            });
          //
        })
        .catch(error => {
          return res.status(200).json({error: error});
        });
      //
    })
    
    .put(function (req, res){
      console.log('UPDATE: req.body is: ');
      console.log(req.body);
      // update issue
      if(!req.body._id) {
        console.log('UPDATE: missing _id');
        return res.status(200).json({error: 'missing _id'});
      }
      if(req.body._id == '') {
        console.log('UPDATE: missing _id');
        return res.status(200).json({error: 'missing _id'});
      }
      if(!req.body.issue_title && !req.body.issue_text && !req.body.created_on && !req.body.updated_on && !req.body.created_by && !req.body.assigned_to && !req.body.open && !req.body.status_text) {
        console.log('UPDATE: no update field(s) sent');
        return res.status(200).json({error: 'no update field(s) sent', _id: req.body._id});
      }
      let objID;
      try{
        objID = new ObjectID(req.body._id);
      } catch(e) {
        console.log('UPDATE: could not update');
        return res.status(200).json({error: 'could not update', _id: req.body._id});
      }
      let query = {_id: new ObjectID(req.body._id)};
      if(req.body.issue_title) {query.issue_title = req.body.issue_title;}
      if(req.body.issue_text) {query.issue_text = req.body.issue_text;}
      if(req.body.created_on) {query.created_on = new Date(req.body.created_on);}
      query.updated_on = new Date();
      if(req.body.created_by) {query.created_by = req.body.created_by;}
      if(req.body.assigned_to) {query.assigned_to = req.body.assigned_to;}
      if(req.body.open) {query.open = false;}
      if(req.body.status_text) {query.status_text = req.body.status_text;}
      let projectCollection = dataBase.collection(req.params.project);
      projectCollection
        .findOneAndUpdate({
            _id: objID
          }, {
            $set: query
          }, {
            upsert: true,
            returnOriginal: false
          })
        .then(result => {
          if(!result.value) {
            console.log('UPDATE: could not update');
            return res.status(200).json({error: 'could not update', _id: req.body._id});
          } else {
            console.log('UPDATED');
            return res.status(200).json({result: "successfully updated", _id: result.value._id});
          }
        })
        .catch(error => {
          console.log('UPDATE: could not update');
          return res.status(200).json({error: 'could not update', _id: req.body._id});
        });
      //
    })
    /*
    req.body: { _id: '5fc27f391d7b2403937ef1a0', issue_text: 'New Issue Text' }
    RESPONSE: res.status(200).json({result: "successfully updated", _id: result.value._id});

    req.body: {}
    RESPONSE: res.status(200).json({error: 'missing _id'});

    req.body: { _id: '5f665eb46e296f6b9b6a504d' }
    RESPONSE: res.status(200).json({error: 'no update field(s) sent', _id: req.body._id});

    req.body: { _id: '5f665eb46e296f6b9b6a504d', issue_text: 'New Issue Text' }
    RESPONSE: res.status(200).json({result: "successfully updated", _id: result.value._id});
    */
    
    .delete(function (req, res){
      try{
        console.log('DELETED: req.body is: ');
        console.log(req.body);
      } catch(e) {
        console.log('DELETED: req.body is UNDEFINED');
      }
      // delete issue
      if(!req.body._id) {
        console.log('DELETED: missing _id');
        return res.status(200).json({error: 'missing _id'});
      }
      let objID;
      try{
        objID = new ObjectID(req.body._id);
      } catch(e) {
        console.log('DELETED: could not delete');
        return res.status(200).json({error: 'could not delete', _id: req.body._id});
      }
      // TODO: filters
      let query = {_id: new ObjectID(req.body._id)};
      if(req.body.issue_title) {query.issue_title = req.body.issue_title;}
      if(req.body.issue_text) {query.issue_text = req.body.issue_text;}
      if(req.body.created_on) {query.created_on = new Date(req.body.created_on);}
      if(req.body.updated_on) {query.updated_on = new Date(req.body.updated_on);}
      if(req.body.created_by) {query.created_by = req.body.created_by;}
      if(req.body.assigned_to) {query.assigned_to = req.body.assigned_to;}
      if(req.body.open) {query.open = req.body.open;}
      if(req.body.status_text) {query.status_text = req.body.status_text;}
      let projectCollection = dataBase.collection(req.params.project);
      projectCollection
        .findOneAndDelete(query, {sort: {_id: -1} } )
        .then(result => {
          if(!result.value) {
            console.log('DELETED: could not delete');
            return res.status(200).json({error: 'could not delete', _id: req.body._id});
          } else {
            console.log('DELETED');
            return res.status(200).json({result: 'successfully deleted', _id: req.body._id});
          }
        })
        .catch(error => {
          console.log('DELETED: could not delete');
          return res.status(200).json({error: 'could not delete', _id: req.body._id});
        });
      //
    });
    /*
    req.body: { _id: '5fc27532eb23b8023f4ae282' }
    RESPONSE: res.status(200).json({result: 'successfully deleted', _id: req.body._id});

    req.body: {}
    RESPONSE: res.status(200).json({error: 'missing _id'});

    req.body: { _id: '5f665eb46e296f6b9b6a504d', issue_text: 'New Issue Text' }
    RESPONSE: res.status(200).json({result: 'successfully deleted', _id: req.body._id});
    */
    
};

2_functional-tests.js

/*
*
*
*       FILL IN EACH FUNCTIONAL TEST BELOW COMPLETELY
*       -----[Keep the tests in the same order!]-----
*       (if additional are added, keep them at the very end!)
*/

const chaiHttp = require('chai-http');
const chai = require('chai');
const assert = chai.assert;
const server = require('../server');

chai.use(chaiHttp);

suite('Functional Tests', function() {
  let id;
  
  suite('POST /api/issues/{project}', function() {
    
    test('Every field filled in', function(done) {
      chai.request(server)
      .post('/api/issues/test')
      .send({
        issue_title: 'Title',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in',
        assigned_to: 'Chai and Mocha',
        status_text: 'In QA'
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.issue_title, 'Title');
        assert.equal(res.body.issue_text, 'text');
        assert.equal(res.body.created_by, 'Functional Test - Every field filled in');
        assert.equal(res.body.assigned_to, 'Chai and Mocha');
        assert.equal(res.body.status_text, 'In QA');
        id = res.body._id; // for testing put updates
        done();
      });
    });
    
    test('Required fields filled in, Optional Fields Blank', function(done) {
      chai.request(server)
      .post('/api/issues/test')
      .send({
        issue_title: 'Title',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in'
        //assigned_to: 'Chai and Mocha',
        //status_text: 'In QA'
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.issue_title, 'Title');
        assert.equal(res.body.issue_text, 'text');
        assert.equal(res.body.created_by, 'Functional Test - Every field filled in');
        done();
      });
    });
    
    test('Missing required fields => { error: "required field(s) missing" }', function(done) {
      chai.request(server)
      .post('/api/issues/test')
      .send({
        issue_title: 'Title',
        issue_text: 'text',
        created_by: ''
        //assigned_to: 'Chai and Mocha',
        //status_text: 'In QA'
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'required field(s) missing');
        done();
      });
    });
    
  });

  suite('GET /api/issues/{project}', function() {
    
    test('No filter', function(done) {
      chai.request(server)
      .get('/api/issues/test')
      .query({})
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.isArray(res.body);
        assert.property(res.body[0], 'issue_title');
        assert.property(res.body[0], 'issue_text');
        assert.property(res.body[0], 'created_on');
        assert.property(res.body[0], 'updated_on');
        assert.property(res.body[0], 'created_by');
        assert.property(res.body[0], 'assigned_to');
        assert.property(res.body[0], 'open');
        assert.property(res.body[0], 'status_text');
        assert.property(res.body[0], '_id');
        done();
      });
    });
    
    test('One filter', function(done) {
      chai.request(server)
      .get('/api/issues/test')
      .query({issue_title: 'Title'})
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.isArray(res.body);
        for(let i in res.body) {
          assert.equal(res.body[i].issue_title, 'Title');
        }
        done();
      });
    });
    
    test('Multiple filters (test for multiple fields you know will be in the db for a return)', function(done) {
      chai.request(server)
      .get('/api/issues/test')
      .query({
        issue_title: 'Title',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in',
        assigned_to: 'Chai and Mocha',
        status_text: 'In QA'
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.isArray(res.body);
        for(let i in res.body) {
          assert.equal(res.body[i].issue_title, 'Title');
          assert.equal(res.body[i].issue_text, 'text');
          assert.equal(res.body[i].created_by, 'Functional Test - Every field filled in');
          assert.equal(res.body[i].assigned_to, 'Chai and Mocha');
          assert.equal(res.body[i].status_text, 'In QA');
        }
        done();
      });
    });
    
  });
  
  suite('PUT /api/issues/{project}', function() {
          
    test('One field to update => {result: "successfully updated", _id: _id}', function(done) {
      chai.request(server)
      .put('/api/issues/test')
      .send({
        _id: id,
        issue_title: 'Title Change'
        //issue_text: 'text',
        //created_by: 'Functional Test - Every field filled in',
        //assigned_to: 'Chai and Mocha',
        //status_text: 'In QA'
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.result, 'successfully updated');
        assert.equal(res.body._id, id);
        done();
      });
    });
    
    test('Multiple fields to update => {result: "successfully updated", _id: _id}', function(done) {
      chai.request(server)
      .put('/api/issues/test')
      .send({
        _id: id,
        issue_title: 'Title Change',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in',
        assigned_to: 'Chai and Mocha',
        status_text: 'In QA',
        open: true
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.result, 'successfully updated');
        assert.equal(res.body._id, id);
        done();
      });
    });

    test('No _id submitted => { error: "missing _id" }', function(done) {
      chai.request(server)
      .put('/api/issues/test')
      .send({
        //_id: id,
        issue_title: 'Title Change',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in',
        assigned_to: 'Chai and Mocha',
        status_text: 'In QA',
        open: true
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'missing _id');
        done();
      });
    });

    test('No fields to update => { error: "no update field(s) sent", _id: _id }', function(done) {
      chai.request(server)
      .put('/api/issues/test')
      .send({
        _id: id
        //issue_title: 'Title Change',
        //issue_text: 'text',
        //created_by: 'Functional Test - Every field filled in',
        //assigned_to: 'Chai and Mocha',
        //status_text: 'In QA',
        //open: true
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'no update field(s) sent');
        assert.equal(res.body._id, id);
        done();
      });
    });

    test('Invalid _id => { error: "missing _id" }', function(done) {
      chai.request(server)
      .put('/api/issues/test')
      .send({
        _id: '',
        issue_title: 'Title Change',
        issue_text: 'text',
        created_by: 'Functional Test - Every field filled in',
        assigned_to: 'Chai and Mocha',
        status_text: 'In QA',
        open: true
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'missing _id');
        done();
      });
    });
    
  });
   
  
  suite('DELETE /api/issues/{project}', function() {

    test('Valid _id', function(done) {
      chai.request(server)
      .delete('/api/issues/test')
      .send({
        _id: id
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.result, 'successfully deleted');
        assert.equal(res.body._id, id);
        done();
      });
    });

    test('Invalid _id => { error: "could not delete", "_id": _id }', function(done) {
      const badId = "5f665eb46e296f6b9b6a504d";
      chai.request(server)
      .delete('/api/issues/test')
      .send({
        _id: badId
      })
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'could not delete');
        assert.equal(res.body._id, badId);
        done();
      });
    });
    
    test('No _id => { error: "missing _id" }', function(done) {
      chai.request(server)
      .delete('/api/issues/test')
      .send({})
      .end(function(err, res){
        assert.equal(res.status, 200);
        assert.equal(res.body.error, 'missing _id');
        done();
      });
    });

  });

});

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36.

Challenge: Issue Tracker

Link to the challenge:

1 Like

Managed to figure out the problem.
On the PUT route i was using findOneAndUpdate() with the option {upsert: true}, this caused the problem because instead of being unable to find the issue and return {error: ‘could not update’, ‘_id’: req.body._id}, it would just create a new issue and return {result: “successfully updated”, _id: result.value._id}.
Once i fixed the PUT route the DELETE route also passed the test.

Hello @fijosilo can you please help me out here:

https://repl.it/join/twkruvvb-kennethbit

I don’t see what is missing and I have been reading on this problem but can’t pass the delete test.