Почему время ожидания мокко истекает при использовании с restify и knex?

В настоящее время я использую mocha 2.5.3, supertest 2.0.0, knex 0.11.10, restify 4.1.1 и sqlite3 3.1.4.

У меня есть следующий очень простой сервер восстановления:

const restify = require('restify');
const knex = require('knex')({
  client: 'sqlite3',
  connection: {
    'filename': 'test.db'
  }
});

const app = restify.createServer();

app.get('/', (req, res, next) => {
  knex.select().from('nonexistent_table')
  .then((rows) => {
    return res.json(rows);
  })
  .catch((err) => {
    return res.send('error');
  });
});
module.exports = app;

Приведенный ниже тест приведет к тайм-ауту теста в 2000 мс, а не к сбою:

const assert = require('assert');
const supertest = require('supertest');
const app = require('./app');

describe('GET /', function () {

  it('should not timeout', function (done) {
    supertest(app)
    .get('/')
    .end(function(err, res) {
      assert(false);
      done();
    });
  });
});

Если вызов knex выполнен, а не отклонен, тест завершается правильно и не истечет время ожидания. Тайм-аут появляется только в том случае, если вызов knex отклонен.

У кого-нибудь есть мысли о том, что может быть причиной тайм-аута вместо правильного сбоя?

РЕДАКТИРОВАТЬ: я отлаживал это, насколько мог, и кажется, что тайм-аут происходит, когда мокко пытается создать трассировку стека.


person Community    schedule 25.08.2016    source источник
comment
См. мой ответ здесь: поскольку утверждение выдает ошибку, done никогда не вызывается и ошибка никогда не ловится.   -  person robertklep    schedule 25.08.2016
comment
@robertklep спасибо, но я не уверен, что это правильный ответ по двум причинам. Во-первых, если knex разрешается, тест обычно не проходит. Так как я делаю прямо assert(false) в тесте, то режим отказа вообще не должен зависеть от ответа от restify сервера или результата от knex, но как-то так! Во-вторых, если я напишу мокко-тест, который не выполняет асинхронный http-вызов, а просто выдает ошибку, тест законно провалится, а не истечет время ожидания, хотя я никогда не вызываю done(). Это наводит меня на мысль, что генерация ошибок/неудачных утверждений — это нормальный способ, при котором тесты мокко терпят неудачу.   -  person    schedule 25.08.2016


Ответы (2)


supertest использует superagent за кулисами, а superagent поддерживает промисы. (Ищите .then здесь.) Таким образом, вы можете использовать .then вместо .end и просто вернуть обещание вместо используя done:

  it('should not timeout', function () {
      return supertest(app)
          .get('/')
          .then(function(res) {
              assert(false);
          });
  });

Когда я использую приведенный выше код с остальной частью вашего кода в вопросе, я получаю правильный отказ.

Что касается того, почему использование done не сработало, мне непонятно. Возможно, supertest или superagent проглатывает исключения, вызванные обратным вызовом, переданным .end(). Если исключения проглатываются, Mocha не может их обнаружить. Затем вам нужно будет самостоятельно перехватить исключение, вызванное ошибочным утверждением, и передать их в done. Я предпочитаю использовать промисы.

person Louis    schedule 25.08.2016
comment
Я предполагаю, что обратный вызов end в случае сбоя вызывается из внутри .catch() в обработчике маршрута, что проглотит ошибку утверждения и предотвратит вызов done . - person robertklep; 25.08.2016
comment
Я согласен, что обещания могут быть правильным направлением для этого. Но я начинаю думать, что это может быть ошибка в узле, поскольку, если я вызываю исключение внутри обратного вызова .end(), но knex не вызывается на стороне сервера, тест обычно не проходит. Это говорит мне, что суперагент не глотает исключения. Здесь происходит что-то еще, и я думаю, что это связано с генерацией трассировки стека мокко. Я обновлю свой вопрос своими выводами по этому поводу. - person ; 25.08.2016
comment
Другая теория заключается в том, что, поскольку catch не отправляет ответ об ошибке, некоторые внутренние обещания superagent могут быть разрешены, поэтому последующая ошибка утверждения больше не может их отклонить. - person robertklep; 25.08.2016
comment
@robertklep Я думаю, вы можете что-то здесь понять. Я попытался заменить restify на экспресс, и он работал нормально, что говорит мне о том, что есть что-то в том, как restify взаимодействует с суперагентом, что приводит к зависанию исключения в маршруте .catch(). Возможно, это ошибка в restify. - person ; 25.08.2016
comment
@harrymonster да, я как раз собирался опубликовать то же самое, Express работает, как и ожидалось =D - person robertklep; 25.08.2016

попробуйте изменить первую строку на: bluebird.resolve(knex.select().from('nonexistent_table'))

также вам нужно требовать «голубую птицу» сверху. Это решит проблему и даст вам некоторый контекст об ошибке

Я думаю, что проблема с выбором: вы забыли аргумент

person kharandziuk    schedule 25.08.2016
comment
Только что попробовал оба этих возможных решения, и они не решили проблему. То есть я пробовал knex.select('*').from('nonexistent_table'), а также пробовал bluebird.resolve(knex.select('*')from('nonexistent_table')). - person ; 25.08.2016