Quality Assurance Projects - Issue Tracker

Tell us what’s happening:

Hello, I’m working on the Issue Tracker project. My environment uses Node.js v20.19.3, Express, Chai, Mocha, and MongoDB. I have the following files: server.js (unchanged), /routes/api.js (custom routes), /tests/2_functional-tests.js (functional tests), and .env with NODE_ENV=test. The app runs on Replit. Manual tests work, but FCC automated tests fail: POST/GET/PUT requests return errors like { error: ‘could not create issue’ }. I suspect MongoDB integration or test handling may be the cause.

###Your project link(s)

solution: https://db37e2f4-96f7-42eb-aa5b-d4206ba4d6f8-00-r3zns2u2i1tm.riker.replit.dev

githubLink: GitHub - HernyT22/Conversor-m-trico-imperial

Your browser information:

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

Challenge Information:

Quality Assurance Projects - Issue Tracker

I developed it in Repli Clone from this repository: GitHub - freeCodeCamp/boilerplate-project-issuetracker: A boilerplate for a freeCodeCamp project. Download these dependencies:

npm install

mangodb mongoose

Add the models.js file:

// Models.js
const mongoose = require(‘mongoose’); // ← solo una vez

const { Schema } = mongoose;

const issueSchema = new Schema({
project: { type: String, required: true },
issue_title: { type: String, required: true },
issue_text: { type: String, required: true },
created_by: { type: String, required: true },
assigned_to: { type: String, default: ‘’ },
status_text: { type: String, default: ‘’ },
created_on: { type: Date, default: Date.now },
updated_on: { type: Date, default: Date.now },
open: { type: Boolean, default: true }
});

const Issue = mongoose.model(‘Issue’, issueSchema);

module.exports = Issue; // ← export para CommonJS
db-conection.js file

const mongoose = require(‘mongoose’);
require(‘dotenv’).config(); // opcional en Replit

const uri = process.env.MONGO_URL; // debe coincidir con tu variable de entorno

if (!uri) {
console.error(‘Error: la variable de entorno MONGO_URL no está definida’);
process.exit(1);
}

mongoose.connect(uri)
.then(() => console.log(‘Conectado a MongoDB’))
.catch(err => console.error(‘Error al conectar a MongoDB:’, err));

module.exports = mongoose;

Api.js file

‘use strict’;
const Issue = require(‘../models’); // ajusta la ruta si es necesario

module.exports = function (app) {

app.route(‘/api/issues/:project’)

// GET: obtener issues
.get(async (req, res) => {
  const project = req.params.project;
  const filters = { project, ...req.query };
  try {
    const issues = await Issue.find(filters).exec();
    res.json(issues);
  } catch (err) {
    res.status(500).json({ error: 'could not fetch issues' });
  }
})

// POST: crear issue
.post(async (req, res) => {
  const project = req.params.project;
  const { issue_title, issue_text, created_by, assigned_to, status_text } = req.body;

  if (!issue_title || !issue_text || !created_by) {
    return res.json({ error: 'required field(s) missing' });
  }

  const newIssue = new Issue({
    project,
    issue_title,
    issue_text,
    created_by,
    assigned_to: assigned_to || '',
    status_text: status_text || ''
  });

  try {
    const saved = await newIssue.save();
    res.json(saved);
  } catch (err) {
    res.status(500).json({ error: 'could not create issue' });
  }
})

// PUT: actualizar issue
.put(async (req, res) => {
  const { _id, ...updateFields } = req.body;

  if (!_id) return res.json({ error: 'missing _id' });
  if (Object.keys(updateFields).length === 0) return res.json({ error: 'no update field(s) sent', _id });

  updateFields.updated_on = new Date();

  try {
    const updated = await Issue.findByIdAndUpdate(_id, updateFields, { new: true });
    if (!updated) return res.json({ error: 'could not update', _id });
    res.json({ result: 'successfully updated', _id });
  } catch (err) {
    res.json({ error: 'could not update', _id });
  }
})

// DELETE: eliminar issue
.delete(async (req, res) => {
  const { _id } = req.body;

  if (!_id) return res.json({ error: 'missing _id' });

  try {
    const deleted = await Issue.findByIdAndDelete(_id);
    if (!deleted) return res.json({ error: 'could not delete', _id });
    res.json({ result: 'successfully deleted', _id });
  } catch (err) {
    res.json({ error: 'could not delete', _id });
  }
});

};

The tests in reply are fine, but not in FreeCodeCamp.

Test in FreeCodeCamp

// running tests
11. All 14 functional tests are complete and passing.
// tests completed

Welcome to the forum @hernangguevara.8

Where are your functional tests?

Happy coding

2_funtional-test.js file

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 testIssueId;

const project = ‘test-project’;

// 1. Crear un problema con cada campo
test(‘Create an issue with every field’, function(done) {
chai.request(server)
.post(/api/issues/${project})
.send({
issue_title: ‘Test issue’,
issue_text: ‘Testing all fields’,
created_by: ‘Tester’,
assigned_to: ‘Chai’,
status_text: ‘In QA’
})
.end(function(err, res) {
assert.equal(res.status, 200);
assert.property(res.body, ‘_id’);
assert.equal(res.body.issue_title, ‘Test issue’);
assert.equal(res.body.issue_text, ‘Testing all fields’);
assert.equal(res.body.created_by, ‘Tester’);
assert.equal(res.body.assigned_to, ‘Chai’);
assert.equal(res.body.status_text, ‘In QA’);
assert.property(res.body, ‘created_on’);
assert.property(res.body, ‘updated_on’);
assert.property(res.body, ‘open’);
testIssueId = res.body._id;
done();
});
});

// 2. Crear un problema solo con campos obligatorios
test(‘Create an issue with only required fields’, function(done) {
chai.request(server)
.post(/api/issues/${project})
.send({
issue_title: ‘Required fields issue’,
issue_text: ‘Only required fields’,
created_by: ‘Tester’
})
.end(function(err, res) {
assert.equal(res.status, 200);
assert.equal(res.body.issue_title, ‘Required fields issue’);
assert.equal(res.body.assigned_to, ‘’);
assert.equal(res.body.status_text, ‘’);
done();
});
});

// 3. Crear un problema con campos obligatorios faltantes
test(‘Create an issue with missing required fields’, function(done) {
chai.request(server)
.post(/api/issues/${project})
.send({ issue_title: ‘’, issue_text: ‘Missing title’, created_by: ‘’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘required field(s) missing’ });
done();
});
});

// 4. Ver problemas en un proyecto
test(‘View issues on a project’, function(done) {
chai.request(server)
.get(/api/issues/${project})
.end(function(err, res) {
assert.equal(res.status, 200);
assert.isArray(res.body);
assert.property(res.body[0], ‘issue_title’);
done();
});
});

// 5. Ver problemas en un proyecto con un filtro
test(‘View issues on a project with one filter’, function(done) {
chai.request(server)
.get(/api/issues/${project})
.query({ open: ‘true’ })
.end(function(err, res) {
assert.equal(res.status, 200);
res.body.forEach(issue => assert.isTrue(issue.open));
done();
});
});

// 6. Ver problemas con múltiples filtros
test(‘View issues on a project with multiple filters’, function(done) {
chai.request(server)
.get(/api/issues/${project})
.query({ open: ‘true’, created_by: ‘Tester’ })
.end(function(err, res) {
assert.equal(res.status, 200);
res.body.forEach(issue => {
assert.isTrue(issue.open);
assert.equal(issue.created_by, ‘Tester’);
});
done();
});
});

// 7. Actualizar un campo
test(‘Update one field on an issue’, function(done) {
chai.request(server)
.put(/api/issues/${project})
.send({ _id: testIssueId, issue_text: ‘Updated text’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { result: ‘successfully updated’, _id: testIssueId });
done();
});
});

// 8. Actualizar varios campos
test(‘Update multiple fields on an issue’, function(done) {
chai.request(server)
.put(/api/issues/${project})
.send({ _id: testIssueId, issue_text: ‘Updated text again’, status_text: ‘Done’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { result: ‘successfully updated’, _id: testIssueId });
done();
});
});

// 9. Actualizar sin _id
test(‘Update an issue with missing _id’, function(done) {
chai.request(server)
.put(/api/issues/${project})
.send({ issue_text: ‘No ID’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘missing _id’ });
done();
});
});

// 10. Actualizar sin campos
test(‘Update an issue with no fields to update’, function(done) {
chai.request(server)
.put(/api/issues/${project})
.send({ _id: testIssueId })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘no update field(s) sent’, _id: testIssueId });
done();
});
});

// 11. Actualizar con _id inválido
test(‘Update an issue with invalid _id’, function(done) {
chai.request(server)
.put(/api/issues/${project})
.send({ _id: ‘invalidid’, issue_text: ‘Test’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘could not update’, _id: ‘invalidid’ });
done();
});
});

// 12. Eliminar un issue
test(‘Delete an issue’, function(done) {
chai.request(server)
.delete(/api/issues/${project})
.send({ _id: testIssueId })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { result: ‘successfully deleted’, _id: testIssueId });
done();
});
});

// 13. Eliminar con _id inválido
test(‘Delete an issue with invalid _id’, function(done) {
chai.request(server)
.delete(/api/issues/${project})
.send({ _id: ‘invalidid’ })
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘could not delete’, _id: ‘invalidid’ });
done();
});
});

// 14. Eliminar sin _id
test(‘Delete an issue with missing _id’, function(done) {
chai.request(server)
.delete(/api/issues/${project})
.send({})
.end(function(err, res) {
assert.equal(res.status, 200);
assert.deepEqual(res.body, { error: ‘missing _id’ });
done();
});
});

});

Try running the following in the terminal.

npm run test

Happy coding