X-Press 68 pass 2 Fail PUT / DELETE Errors

Hi everyone!

I am at the end of this X-Press Course

X-Press

I have run my tests and 68 out of 70 tests passed except 2 —

Here is the Terminal Results of (npm test)

DBP Post@DESKTOP-BP7QPD2 MINGW64 /z/Coding/X-Press/capstone-project-1-x-press-publishing
$ npm test

> x-press-publishing@1.0.0 test Z:\Coding\X-Press\capstone-project-1-x-press-publishing
> mocha



Listening on PORT: 8081
  Artist Table
    √ should exist
    √ should have name, date_of_birth, biography, and is_currently_employed columns with appropriate data types
    √ should have a required name column
    √ should have a required date_of_birth column
    √ should have a required biography column
    √ is_currently_employed should default to 1

  Series Table
    √ should exist
    √ should have id, name, and description columns with appropriate data types
    √ should have a required name column
    √ should have a required description column

  Issue Table
    √ should exist
    √ should have id, name, issue_number, publication_date, artist_id, and series_id columns with appropriate data types
    √ should have a required name column
    √ should have a required name column
    √ should have a required issue_number column
    √ should have a required publication_date column
    √ should have a required artist_id column
    √ should have a required series_id column

  GET /api/artists
GET /api/artists 200 2.375 ms - 242
    √ should return all currently-employed artists
GET /api/artists 200 0.508 ms - 242
    √ should return a status code of 200

  GET /api/artists/:id
GET /api/artists/2 200 0.734 ms - 127
    √ should return the artist with the given ID
GET /api/artists/2 200 0.413 ms - 127
    √ should return a 200 status code for valid IDs
GET /api/artists/999 404 0.320 ms - 9
    √ should return a 404 status code for invalid IDs

  POST /api/artists
POST /api/artists/ 201 4.044 ms - 127
    √ should create a valid artist
POST /api/artists/ 201 3.389 ms - 127
    √ should return a 201 status code after artist creation
POST /api/artists/ 201 2.835 ms - 127
    √ should return the newly-created artist after artist creation
POST /api/artists/ 201 2.906 ms - 127
    √ should set new artists as currently-employed by default
POST /api/artists/ 400 0.146 ms - 11
    √ should return a 400 status code for invalid artists

  PUT /api/artists/:id
PUT /api/artists/1 200 2.930 ms - 135
    √ should update the artist with the given ID
PUT /api/artists/1 200 3.542 ms - 135
    √ should return a 200 status code after artist update
PUT /api/artists/1 200 3.197 ms - 135
    √ should return the updated artist after artist update
PUT /api/artists/1 400 0.405 ms - 11
    √ should return a 400 status code for invalid artist updates

  DELETE /api/artists/:id
DELETE /api/artists/1 200 2.930 ms - 122
    √ should set the artist with the given ID as not currently-employed
DELETE /api/artists/1 200 2.823 ms - 122
    √ should return a 200 status code after artist delete
DELETE /api/artists/1 200 2.751 ms - 122
    √ should return the deleted artist after artist delete

  GET /api/series
GET /api/series 200 0.477 ms - 192
    √ should return all series
GET /api/series 200 0.422 ms - 192
    √ should return a status code of 200

  GET /api/series/:id
GET /api/series/2 200 0.530 ms - 70
    √ should return the series with the given ID
GET /api/series/2 200 0.315 ms - 70
    √ should return a 200 status code for valid IDs
GET /api/series/999 404 0.293 ms - 9
    √ should return a 404 status code for invalid IDs

  POST /api/series
POST /api/series/ 201 2.838 ms - 71
    √ should create a valid series
POST /api/series/ 201 2.679 ms - 71
    √ should return a 201 status code after series creation
POST /api/series/ 201 3.008 ms - 71
    √ should return the newly-created series after series creation
POST /api/series/ 400 0.138 ms - 11
    √ should return a 400 status code for invalid series

  PUT /api/series/:id
PUT /api/series/1 200 3.269 ms - 79
    √ should update the series with the given ID
PUT /api/series/1 200 2.901 ms - 79
    √ should return a 200 status code after series update
PUT /api/series/1 200 3.062 ms - 79
    √ should return the updated series after series update
PUT /api/series/1 400 0.406 ms - 11
    √ should return a 400 status code for invalid series updates

  DELETE /api/series/:id
DELETE /api/series/1 204 2.926 ms - -
    √ should remove the series with the specified ID from the database if that series has no related issues
DELETE /api/series/1 204 2.833 ms - -
    √ should return a 204 status code after series delete
DELETE /api/series/2 400 0.609 ms - 11
    √ should not delete series with existing related issues
DELETE /api/series/2 400 0.572 ms - 11
    √ should return a 400 status code if deleted series has existing related issues

  GET /api/series/:seriesId/issues
GET /api/series/2/issues 200 0.781 ms - 246
    √ should return all issues of an existing series
GET /api/series/1/issues 200 0.426 ms - 13
    √ should return an empty array for existing series with no issues
GET /api/series/2/issues 200 0.397 ms - 246
    √ should return a status code of 200 for valid series
GET /api/series/999/issues 404 0.220 ms - 9
    √ should return a status code of 404 for invalid series

  POST /api/series/:seriesId/issues
POST /api/series/2/issues 201 3.047 ms - 119
    √ should create a valid issue
POST /api/series/2/issues 201 4.048 ms - 119
    √ should return a 201 status code after issue creation
POST /api/series/2/issues 201 3.142 ms - 119
    √ should return the newly-created issue after issue creation
POST /api/series/2/issues 400 0.704 ms - 11
    √ should return a 400 status code for invalid issues
POST /api/series/2/issues 400 1.267 ms - 11
    √ should return a 400 status code if an artist with the issue's artist ID doesn't exist

  PUT /api/series/:seriesId/issues/:issueId
PUT /api/series/2/issues/1 200 3.413 ms - 123
    √ should update the issue with the given ID
PUT /api/series/2/issues/1 200 3.244 ms - 123
    √ should return a 200 status code after issue update
PUT /api/series/2/issues/1 200 3.266 ms - 123
    √ should return the updated issue after issue update
PUT /api/series/2/issues/999 400 0.652 ms - 11
    1) should return a 404 status code for invalid issue IDs
PUT /api/series/2/issues/1 400 0.590 ms - 11
    √ should return a 400 status code for invalid issue updates
PUT /api/series/2/issues/1 400 0.651 ms - 11
    √ should return a 400 status code if an artist with the updated artist ID doesn't exist

  DELETE /api/series/:seriesId/issues/:issueId
DELETE /api/series/2/issues/1 204 3.337 ms - -
    √ should remove the issue with the specified ID from the database
DELETE /api/series/2/issues/1 204 2.943 ms - -
    √ should return a 204 status code after issue delete
DELETE /api/series/2/issues/999 204 0.676 ms - -
    2) should return a 404 status code for invalid issue IDs


  68 passing (859ms)
  2 failing

  1) PUT /api/series/:seriesId/issues/:issueId should return a 404 status code for invalid issue IDs:
     Error: expected 404 "Not Found", got 400 "Bad Request"
      at Test._assertStatus (node_modules\supertest\lib\test.js:268:12)
      at Test._assertFunction (node_modules\supertest\lib\test.js:283:11)
      at Test.assert (node_modules\supertest\lib\test.js:173:18)
      at Server.localAssert (node_modules\supertest\lib\test.js:131:12)
      at emitCloseNT (net.js:1659:8)
      at processTicksAndRejections (internal/process/task_queues.js:79:21)

  2) DELETE /api/series/:seriesId/issues/:issueId should return a 404 status code for invalid issue IDs:
     Error: expected 404 "Not Found", got 204 "No Content"
      at Test._assertStatus (node_modules\supertest\lib\test.js:268:12)
      at Test._assertFunction (node_modules\supertest\lib\test.js:283:11)
      at Test.assert (node_modules\supertest\lib\test.js:173:18)
      at Server.localAssert (node_modules\supertest\lib\test.js:131:12)
      at emitCloseNT (net.js:1659:8)
      at processTicksAndRejections (internal/process/task_queues.js:79:21)



npm ERR! Test failed.  See above for more details.

Here is my code below:

server.js

const bodyParser = require('body-parser');
const cors = require('cors');
const errorhandler = require('errorhandler');
const express = require('express');
const morgan = require('morgan');
const apiRouter = require('./api/api');

const app = express();
const PORT = process.env.PORT || 4000;

app.use(bodyParser.json());
app.use(cors());
app.use(morgan('dev'));

app.use('/api', apiRouter);

app.use(errorhandler());

app.listen(PORT, () => {
    console.log(`Listening on PORT: ${PORT}`);
});

module.exports = app;

api.js

const express = require('express');
const apiRouter = express.Router();
const artistsRouter = require('./artists.js');
const seriesRouter = require('./series.js');

apiRouter.use('/artists', artistsRouter);
apiRouter.use('/series', seriesRouter);

module.exports = apiRouter;

migration.js

const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./database.sqlite');
//Create Artist Table
 db.serialize(function() {
     db.run('CREATE TABLE IF NOT EXISTS `Artist` ( ' + 
        '`id` INTEGER NOT NULL, ' +
        '`name` TEXT NOT NULL, ' +
        '`date_of_birth` TEXT NOT NULL, ' +
        '`biography` TEXT NOT NULL, ' +
        '`is_currently_employed` INTEGER NOT NULL DEFAULT 1, ' +
        'PRIMARY KEY(`id`) )' );

//Create Series Table
        db.run('CREATE TABLE IF NOT EXISTS `Series` ( ' +
        '`id` INTEGER NOT NULL, ' +
        '`name` TEXT NOT NULL, ' +
        '`description` TEXT NOT NULL, ' +
        'PRIMARY KEY(`id`) )');

//Create Issue's Table 45
        db.run('CREATE TABLE IF NOT EXISTS `Issue` ( ' +
        '`id` INTEGER NOT NULL,' +
        '`name` TEXT NOT NULL, ' +
        '`issue_number` INTEGER NOT NULL,' +
        '`publication_date` TEXT NOT NULL,' +
        '`artist_id` INTEGER NOT NULL,' +
        '`series_id` INTEGER NOT NULL,' +
        'PRIMARY KEY(`id`), ' +
        'FOREIGN KEY(`artist_id`) REFERENCES `Artist`(`id`), ' +
        'FOREIGN KEY(`series_id`) REFERENCES `Series`(`id`) )');
 });

artists.js

const express = require('express');
const artistsRouter = express.Router();

const sqlite3 = require('sqlite3');
const db = new sqlite3.Database(process.env.TEST_DATABASE || './database.sqlite');

// app.param()
artistsRouter.param('artistId', (req, res, next, artistId) => {
    const sql = 'SELECT * FROM Artist WHERE Artist.id = $artistId';
    const values = {$artistId: artistId};
    db.get(sql, values, (error, artist) => {
        if (error) {
            next(error);
        } else if (artist) {
            req.artist = artist;
            next();
        } else {
            res.sendStatus(404);
        }
    });
})


// artists currently employed?
artistsRouter.get('/', (req, res, next) => {
    db.all('SELECT * FROM Artist WHERE Artist.is_currently_employed = 1', (err, artists) => {
        if (err) {
            next(err);
          } else {
            res.status(200).json({artists: artists});
          }
    });
});
// GET -- this reads the relevant path and displays it
artistsRouter.get('/:artistId', (req, res, next) => {
    res.status(200).json({artist: req.artist});
})
// POST -- Creating a new field for the Artist table status (201)(created)
artistsRouter.post('/', (req, res, next) => {
    const name = req.body.artist.name;
    const dateOfBirth = req.body.artist.dateOfBirth;
    const biography = req.body.artist.biography;
    const isCurrentlyEmployed = req.body.artist.isCurrentlyEmployed === 0 ? 0 : 1;
    if (!name || !dateOfBirth || !biography) {
        return res.sendStatus(400);
    }

    const sql = 'INSERT INTO Artist (name, date_of_birth, biography, is_currently_employed) VALUES ($name, $dateOfBirth, $biography, $isCurrentlyEmployed)';
    const values = {
        $name: name,
        $dateOfBirth: dateOfBirth,
        $biography: biography,
        $isCurrentlyEmployed: isCurrentlyEmployed
    };

    db.run(sql, values, function(error) {
        if (error) {
            next(error);
        } else {
            db.get(`SELECT * FROM Artist WHERE Artist.id = ${this.lastID}`,
            (error, artist) => {
                res.status(201).json({artist: artist});
            });
        }
    })
});
// PUT -- Update/Replace artist table by artistId -- updates the relavant artists fields -- after if ! (not) required fields send back status of (400) NOT FOUND - This way we know the selected artist has been removed??
artistsRouter.put('/:artistId', (req, res, next) => {
    const name = req.body.artist.name;
    const dateOfBirth = req.body.artist.dateOfBirth;
    const biography = req.body.artist.biography;
    const isCurrentlyEmployed = req.body.artist.isCurrentlyEmployed === 0 ? 0 : 1;
    if (!name || !dateOfBirth || !biography) {
        return res.sendStatus(400);
    }
const sql = 'UPDATE Artist SET name = $name, date_of_birth = $dateOfBirth, biography = $biography, is_currently_employed = $isCurrentlyEmployed WHERE Artist.id = $artistId';
const values = {
    $name: name,
    $dateOfBirth: dateOfBirth,
    $biography: biography,
    $isCurrentlyEmployed: isCurrentlyEmployed,
    $artistId: req.params.artistId
};
 
db.run(sql, values, (error) => {
    if (error) {
        next(error);
    }else {
        db.get(`SELECT * FROM Artist WHERE Artist.id = ${req.params.artistId}`,
        
        (error, artist) => {
            res.status(200).json({artist: artist});
        });
    }
  }); 
});
// delete artist by id logic
artistsRouter.delete('/:artistId', (req, res, next) => {
    const sql = 'UPDATE Artist SET is_currently_employed = 0 WHERE Artist.id = $artistId';
    const values = {$artistId: req.params.artistId};
//db.run() sql, values & error // if/else --- error / else -- grabs and deletes artist by id requested with req.params.artistId -- sends back a status of (200).json for artist requested..
    db.run(sql, values, (error) => {
        if (error) {
            next(error);
        } else {
            db.get(`SELECT * FROM Artist WHERE Artist.id = ${req.params.artistId}`,
            (error, artist) => {
                res.status(200).json({artist: artist});
            });
        }
    });
});

module.exports = artistsRouter;

issues.js

const express = require('express');
const issuesRouter = express.Router({mergeParams: true});

const sqlite3 = require('sqlite3');
const db = new sqlite3.Database(process.env.TEST_DATABASE || './database.sqlite');

issuesRouter.param('issuesId', (req, res, next, userId) => {
  const sql = 'SELECT* FROM Issue WHERE Issue.id = $issueId';
  const values = {$issueId: issueId};
  db.get(sql, values, (error, issue) => {
    if (error) {
      next(error);
    } else if (issue) {
      next();
    } else {
      res.sendStatus(404);
    }
  })
})

issuesRouter.get('/', (req, res, next) => {
    const sql = 'SELECT * FROM Issue WHERE Issue.series_id = $seriesId';
    const values = { $seriesId: req.params.seriesId};
    db.all(sql, values, (error, issues) => {
      if (error) {
        next(error);
      } else {
        res.status(200).json({issues: issues});
      }
    });
  });
//49
  issuesRouter.post('/', (req, res, next) => {
    const name = req.body.issue.name,
          issueNumber = req.body.issue.issueNumber,
          publicationDate = req.body.issue.publicationDate,
          artistId = req.body.issue.artistId;
    const artistSql = 'SELECT * FROM Artist WHERE Artist.id = $artistId';
    const artistValues = {$artistId: artistId};
    db.get(artistSql, artistValues, (error, artist) => {
      if (error) {
        next(error);
      } else {
        if (!name || !issueNumber || !publicationDate || !artist) {
          return res.sendStatus(400);
        }
  
        const sql = 'INSERT INTO Issue (name, issue_number, publication_date, artist_id, series_id)' +
            'VALUES ($name, $issueNumber, $publicationDate, $artistId, $seriesId)';
        const values = {
          $name: name,
          $issueNumber: issueNumber,
          $publicationDate: publicationDate,
          $artistId: artistId,
          $seriesId: req.params.seriesId
        };
  
        db.run(sql, values, function(error) {
          if (error) {
            next(error);
          } else {
            db.get(`SELECT * FROM Issue WHERE Issue.id = ${this.lastID}`,
              (error, issue) => {
                res.status(201).json({issue: issue});
              });
          }
        });
      }
    });
  });

  issuesRouter.put('/:issueId', (req, res, next) => {
    const name = req.body.issue.name,
          issueNumber = req.body.issue.issueNumber,
          publicationDate = req.body.issue.publicationDate,
          artistId = req.body.issue.artistId;
    const artistSql = 'SELECT * FROM Artist WHERE Artist.id = $artistId';
    const artistValues = {$artistId: artistId};
    db.get(artistSql, artistValues, (error, artist) => {
      if (error) {
        next(error);
      } else {
        if (!name || !issueNumber || !publicationDate || !artist) {
          return res.sendStatus(400);
        }
  
        const sql = 'UPDATE Issue SET name = $name, issue_number = $issueNumber, ' +
            'publication_date = $publicationDate, artist_id = $artistId ' +
            'WHERE Issue.id = $issueId';
        const values = {
          $name: name,
          $issueNumber: issueNumber,
          $publicationDate: publicationDate,
          $artistId: artistId,
          $issueId: req.params.issueId
        };
  
        db.run(sql, values, function(error) {
          if (error) {
            next(error);
          } else {
            db.get(`SELECT * FROM Issue WHERE Issue.id = ${req.params.issueId}`,
              (error, issue) => {
                res.status(200).json({issue: issue});
              });
          }
        });
      }
    });
  });

  //52: Delete Request

  issuesRouter.delete('/:issueId', (req, res, next) => {
  const sql = 'DELETE FROM Issue WHERE Issue.id = $issueId';
  const values = {$issueId: req.params.issueId};

  db.run(sql, values, (error) => {
    if (error) {
      next(error);
    } else {
      res.sendStatus(204);
    }
  });
});


module.exports = issuesRouter;

series.js

const express = require('express');
const seriesRouter = express.Router();

const sqlite3 = require('sqlite3');
const db = new sqlite3.Database(process.env.TEST_DATABASE || './database.sqlite');

const issuesRouter = require('./issues.js');

// Step 41
seriesRouter.param('seriesId', (req, res, next, seriesId) => {
    const sql = 'SELECT * FROM Series WHERE Series.id = $seriesId';
    const values = {$seriesId: seriesId};
    db.get(sql, values, (error, series) => {
        if (error) {
            next(error);
        } else if (series) {
            req.series = series;
            next();
        } else {
            res.sendStatus(404);
        }
    });
});

seriesRouter.use('/:seriesId/issues', issuesRouter);

seriesRouter.get('/', (req, res, next) => {
    db.all('SELECT * FROM Series', (err, series) => {
      if (err) {
        next(err);
      } else {
        res.status(200).json({series: series});
      }
    });
  });
// 42
seriesRouter.get('/:seriesId', (req, res, next) => {
    res.status(200).json({series: req.series});
});
//43
seriesRouter.post('/', (req, res, next) => {
    const name = req.body.series.name,
    description = req.body.series.description;
    if (!name || !description) {
        return res.sendStatus(400);
    }
const sql = 'INSERT INTO Series (name, description) VALUES ($name, $description)';
const values = {
    $name: name,
    $description: description
    };
db.run(sql, values, function(error) {
    if (error) {
        next(error);
    } else {
        db.get(`SELECT * FROM Series WHERE Series.id = ${this.lastID}`,
        (error, series) => {
            res.status(201).json({series: series});
            });
        }
    });
});

// 44

seriesRouter.put('/:seriesId', (req, res, next) => {
    const name = req.body.series.name,
          description = req.body.series.description;
    if (!name || !description) {
      return res.sendStatus(400);
    }
  
    const sql = 'UPDATE Series SET name = $name, description = $description ' +
        'WHERE Series.id = $seriesId';
    const values = {
      $name: name,
      $description: description,
      $seriesId: req.params.seriesId
    };
  
    db.run(sql, values, (error) => {
      if (error) {
        next(error);
      } else {
        db.get(`SELECT * FROM Series WHERE Series.id = ${req.params.seriesId}`,
          (error, series) => {
            res.status(200).json({series: series});
          });
      }
    });
  });


seriesRouter.post('/', (req, res, next) => {
    const name = req.body.series.name,
    description = req.body.series.description;
    if (!name || !description) {
        return res.sendStatus(400);
    }
    const sql = 'INSERT INTO Series (name, description) VALUES ($name, $description)';
    const values = {
        $name: name,
        $description: description
    };

    db.run(sql, values, function(error) {
        if (error) {
            next(error);
        } else {
            db.get(`SELECT * FROM Series WHERE Series.id = ${this.lastID}`,
            (error, series) => {
                res.status(201).json({series: series});
            });
        }
    });
});


seriesRouter.delete('/:seriesId', (req, res, next) => {
    const issueSql = 'SELECT * FROM Issue WHERE Issue.series_id = $seriesId';
    const issueValues = {$seriesId: req.params.seriesId};
    db.get(issueSql, issueValues, (error, issue) => {
      if (error) {
        next(error);
      } else if (issue) {
        res.sendStatus(400);
      } else {
        const deleteSql = 'DELETE FROM Series WHERE Series.id = $seriesId';
        const deleteValues = {$seriesId: req.params.seriesId};
  
        db.run(deleteSql, deleteValues, (error) => {
          if (error) {
            next(error);
          } else {
            res.sendStatus(204);
          }
        });
      }
    });
  });

module.exports = seriesRouter;

I have decided to move on with the course in the mean time as I cant waste any more time on this right now! I hope some one can help me with this problem!

Thanks in advance and happy coding!

I’m wondering if your issue is that you have userId as the 4th parameter of the callback function, but you don’t actually use it. You instead use issueId, which isn’t defined in that scope. I’m assuming you got those mixed up. I’m actually stuck in almost the same place except that I have 4 tests failing. It’s frustrating!