UnhandledPromiseRejectionWarning во время тестирования с мокко-чай с использованием chai-http - PullRequest
0 голосов
/ 11 сентября 2018

Создавая свое первое экспресс-приложение, я пытаюсь написать тест для конечной точки API и использую структуру данных в качестве заполнителя для базы данных, но продолжаю получать сообщение об ошибке в консоли, как показано на рисунке, хотя тест и проходит'

console output

  import chai from 'chai';
import { app } from '../app';
import http from 'chai-http';

let expect = chai.expect;
  
  //test I am having problems with
  it('should get a single todo at "/api/v1/todos/:id" with GET/id', () => {
    return chai
      .request(app)
      .post('/api/v1/todos')
      .send({ title: 'Breakfast', description: 'Breakfast alone' })
      .then(resPost => {
        expect(resPost).to.have.status(201);
        chai
          .request(app)
          .get('/api/v1/todos/2')
          .then(res => {
            expect(res).to.have.status(200);
            expect(res).to.be.json;
            expect(res.body).to.be.an('object');
            expect(res.body)
              .to.have.property('success')
              .eql('true');
            expect(res.body)
              .to.have.property('message')
              .equal('todo retrieved successfully');
            expect(res.body.todo).to.be.an('object');
            expect(res.body.todo)
              .to.have.property('id')
              .equal(1);
            expect(res.body.todo)
              .to.have.property('title')
              .equal('Breakfast');
            expect(res.body.todo)
              .to.have.property('description')
              .equal('Breakfast alone');
          });
      });
  });



//api endpoints
//import and define express framework
import express from 'express';

import todoController from '../todoControllers/todo';

//create router handler
const router = express.Router();

router.get('/api/v1/todos', todoController.getAllTodos);
router.get('api/v1/todos/:id', todoController.getTodo);
router.post('/api/v1/todos', todoController.createTodo);
router.put('/api/v1/todos/:id', todoController.updateTodo);
router.delete('/api/v1/todos/:id', todoController.deleteTodo);

export default router;

//controllers for api endpoints
import db from '../db/db';

class todosController {
  getAllTodos(req, res) {
    return res.status(200).send({
      success: 'true',
      message: 'todos retrieved successfully',
      todos: db
    });
  }

  getTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    db.map(todo => {
      if (todo.id === id) {
        return res.status(200).send({
          success: 'true',
          message: 'todo retrieved successfully',
          todo
        });
      }
    });
    return res.status(400).send({
      success: 'false',
      message: 'todo does not exist'
    });
  }

  createTodo(req, res) {
    if (!req.body.title) {
      return res.status(400).send({
        success: 'false',
        message: 'title is required'
      });
    } else if (!req.body.description) {
      return res.status(400).send({
        success: 'false',
        message: 'description is required'
      });
    }

    const todo = {
      id: db.length + 1,
      title: req.body.title,
      description: req.body.description
    };

    db.push(todo);
    return res.status(201).send({
      success: 'true',
      message: 'todo added successfully',
      todo
    });
  }

  updateTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    let todoFound;
    let itemIndex;
    db.map((todo, index) => {
      if (todo.id === id) {
        todoFound = todo;
        itemIndex = index;
      }
    });

    if (!todoFound) {
      return res.status(404).send({
        success: 'true',
        message: 'todo not found'
      });
    }

    if (!req.body.title) {
      return res.status(400).send({
        success: 'false',
        message: 'title is required'
      });
    } else if (!req.body.description) {
      return res.status(400).send({
        success: 'false',
        message: 'description is required'
      });
    }

    const editedTodo = {
      // @ts-ignore
      id: todoFound.id,
      // @ts-ignore
      title: req.body.title || todoFound.title,
      // @ts-ignore
      description: req.body.description || todoFound.description
    };

    db.splice(itemIndex, 1, editedTodo);

    return res.status(200).send({
      success: 'true',
      message: 'todo updated successfully',
      editedTodo
    });
  }

  deleteTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    let todoFound;
    let itemIndex;
    db.map((todo, index) => {
      if (todo.id === id) {
        todoFound = todo;
        itemIndex = index;
      }
    });

    if (!todoFound) {
      return res.status(404).send({
        success: 'true',
        message: 'todo not found'
      });
    }

    db.splice(itemIndex, 1);

    return res.status(200).send({
      success: 'true',
      message: 'todo deleted successfully'
    });
  }
}

const todoController = new todosController();
export default todoController;

//place-holder database in the form of datasctructures


const todos = [
  {
    id: 1,
    title: 'lunch',
    description: 'Go for lunch by 2pm'
  }
];

//Creating module from data structure and exposing it to be used by parts of the server
export default todos;

//tests written so far including the initial snippet
import chai from 'chai';
import { app } from '../app';
import http from 'chai-http';
import db from '../db/db';

let expect = chai.expect;


chai.use(http);

describe('Test all todo endpoints at "/api/v1/todos and "/api/v1/todo/:id" with (GET, POST, GET/id, PUT)', () => {
  before(() => {});
  after(() => {});

  //GET all todos
  it('should get all todos at "/ap1/v1/todos" with GET', () => {
    return chai
      .request(app)
      .get('/api/v1/todos')
      .then(res => {
        expect(res).to.have.status(200);
        expect(res).to.be.json;
        expect(res.body).to.be.an('object');
        expect(res.body)
          .to.have.property('success')
          .eql('true');
        expect(res.body)
          .to.have.property('message')
          .eql('todos retrieved successfully');
        expect(res.body.todos).to.be.an('array');
        expect(
          res.body.todos[Math.floor(Math.random() * res.body.todos.length)]
        ).to.have.property('id' && 'title' && 'description');
      });
  });

  //POST a todo
  it('should add a todo at "/api/v1/todos" with POST', () => {
    return chai
      .request(app)
      .post('/api/v1/todos')
      .send({ title: 'Dinner', description: 'Dinner with bae' })
      .then(res => {
        expect(res).to.have.status(201);
        expect(res).to.be.json;
        expect(res.body).to.be.an('object');
        expect(res.body)
          .to.have.property('success')
          .eql('true');
        expect(res.body)
          .to.have.property('message')
          .equal('todo added successfully');
        expect(res.body.todo).to.be.an('object');
        expect(res.body.todo)
          .to.have.property('id')
          .equal(db.length);
        expect(res.body.todo)
          .to.have.property('title')
          .equal('Dinner');
        expect(res.body.todo)
          .to.have.property('description')
          .equal('Dinner with bae');
      });
  });

  //corrected test still giving an 'AssertionError'
  it('should get a single todo at "/api/v1/todos/:id" with GET/id', () => {
    return chai
      .request(app)
      .post('/api/v1/todos')
      .send({ title: 'Breakfast', description: 'Breakfast alone' })
      .then(resPost => {
        expect(resPost).to.have.status(201);
        return chai
          .request(app)
          .get('/api/v1/todos/2')
          .then(res => {
            expect(res).to.have.status(200);
            expect(res).to.be.json;
            expect(res.body).to.be.an('object');
            expect(res.body)
              .to.have.property('success')
              .eql('true');
            expect(res.body)
              .to.have.property('message')
              .equal('todo retrieved successfully');
            expect(res.body.todo).to.be.an('object');
            expect(res.body.todo)
              .to.have.property('id')
              .equal(1);
            expect(res.body.todo)
              .to.have.property('title')
              .equal('Breakfast');
            expect(res.body.todo)
              .to.have.property('description')
              .equal('Breakfast alone');
          });
      });
  });
});

Может кто-нибудь объяснить, почему?PS: я обновил вопрос, чтобы показать мои конечные точки API, тесты и заполнитель для базы данных, мне, по сути, нужны советы о том, как обрабатывать запросы и идентификаторы.

1 Ответ

0 голосов
/ 11 сентября 2018

У вас есть две проблемы:

Ваш тест не проходит, несмотря на полученную ошибку подтверждения

Это потому, что в строке 14 вы пропускаете return. Поскольку функция, которую вы регистрируете в строке 12, ничего не возвращает, обещание разрешается. В результате обещание, которое вы возвращаете в строке 8, также разрешается, и ваш тест не проходит, хотя и должен.

Поскольку вы не возвращаете отклоненное обещание, ошибка не распространяется. Вот почему вы получаете сообщение об ошибке.

Сама ошибка утверждения

Вы создаете ресурс и затем запрашиваете этот ресурс, предполагая, что его идентификатор равен 2. Вы получаете ответ 404, что означает, что либо ресурс вообще не был создан, либо он имеет другой идентификатор.

При создании ресурса вы каким-то образом назначаете ему идентификатор (похоже, вы просто используете счетчик для этого, но я не могу сказать наверняка, не увидев вашу реализацию). Ответ POST должен предоставить некоторую информацию об этом идентификаторе. В идеале, он отправляет идентификатор в качестве заголовка Location, но часто полный созданный ресурс отправляется как тело ответа. Поэтому перед выполнением запроса GET необходимо извлечь идентификатор из ответа POST.

...