Время теста Mocha истекает при использовании промисов и пропуска кода, почему?

Я пытаюсь запустить этот тест уже 2 дня и не могу понять, что с ним не так:

/*eslint-env mocha */
// var expect = require('chai').expect;
var chai = require('chai');
var chaiAsPromised = require("chai-as-promised");
var expect = chai.expect;
var Promise = require('bluebird');
var Archive = require('../lib/archive');
var path = require('path');
var fs = Promise.promisifyAll(require('fs-extra'));
var globAsync = Promise.promisify(require('glob'));
var tar = require('tar-fs');
var zlib = Promise.promisifyAll(require('zlib'));

chai.use(chaiAsPromised);

describe('Archive', function() {
  var pkg;
  var archive_location;
  var subject;

  beforeEach(function() {
    pkg = {
      name: 'test_0790feebb1',
      recipient_name: 'Test',
      files: {
        letter: '../documents/letters/test/letter.tex',
        resume: '../documents/cover/cover.tex'
      },
      compiled_files: {
        package: '../documents/letters/test/test.pdf'
      }
    };
    archive_location = path.resolve('archives/test_0790feebb1.tar.gz'); 

    subject = new Archive(pkg);
  });

  after(function() {
    return globAsync('archives/test*')
      .each(function(filename) {
        return fs.removeAsync(filename);
      });
  });

  describe('#make', function() {
    it('has the correct directory structure', function() {
      // debugger;
      var tmp_extract_path = path.resolve('test/.tmp');
      var tarPromise = function(data) {
        console.log('tarP'); // never run
        return new Promise(function(reject, resolve) {
          data
            .pipe(zlib.Unzip())
            .pipe(tar.extract(tmp_extract_path))
            .on('error', reject)
            .on('end', resolve);
        });
      };

      var verifyDir = function() {
        console.log('verD'); // never run
        return Promise.all([
            'code',
            'pdf',
            'code/repo',
            'code/documents',
            'code/documents/letters',
            'code/documents/letters/test',
            'code/documents/letters/shared',
            'code/documents/cover',
            'code/documents/letters'
        ].map(function(subpath) {
          return fs.statAsync(path.resolve(tmp_extract_path, subpath));
        }));
      };

      return fs.createReadStreamAsync(archive_location)
        .then(function(data) { return tarPromise(data); })
        .then(function() { return verifyDir(); })
        .then(function(files) {
          console.log(files); // never run
          return expect(true).to.be.true;
        })
        .catch(function(e) { console.log(e); });
    });
  });
});

Различные console.log даже не выполняются, и в конечном итоге время теста истекает без каких-либо ошибок или трассировки стека.

Я понятия не имею, что я делаю неправильно, и обещания причиняют боль моему мозгу сейчас. Когда я запускаю код с помощью инспектора узлов и раскомментирую точку останова, я вижу, что значение this._runnable._trace равно "done() called multiple times". Я понятия не имею, является ли это реальной ошибкой и почему она не выдает исключение, если это ошибка. Я также не могу объяснить, почему это вообще происходит, поскольку я больше не использую обратные вызовы done() с промисами и что мой тест начинается с function(), а не function(done), как асинхронный тест.

Есть идеи?


person springloaded    schedule 30.09.2015    source источник
comment
Я вижу две проблемы: функция tarPromise возвращает undefined, а не обещание, и verifyDir не вызывается в цепочке, а просто передается дальше. Кроме того, добавление блока catch в цепочку обещаний может помочь определить проблему...   -  person mido    schedule 01.10.2015
comment
Мой плохой, я сделал опечатки, когда форматировал код для SO. Я отредактировал вопрос, чтобы исправить ошибки. Я также добавил блок catch, но он никогда ничего не печатает, когда я запускаю код.   -  person springloaded    schedule 01.10.2015
comment
возможно эта проблема?   -  person mido    schedule 01.10.2015
comment
@ mido22 Да, это была проблема. Я не знал об этом. Спасибо   -  person springloaded    schedule 02.10.2015


Ответы (1)


Ваша проблема в том, что fs.createReadStream является синхронным и возвращает ReadableStream, который считывает данные в память порциями. PromisifyAll преобразует обратные вызовы асинхронных функций в обещания, а не синхронные функции в асинхронные.

Вероятно, вы хотите использовать fs.readFileAsync:

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var path = require('path')
var archive_location = path.resolve('example.zip');
var assert = require('assert');

describe('This', function(){
    it('should work', function(){
       return fs.readFileAsync(archive_location).
           then(function(data) {
                assert.notEqual(data.length, data.length);
                return data;
           }).
           catch(console.log);
    });
});

У меня есть утверждение, установленное на ошибочное утверждение, чтобы продемонстрировать, что это действительно попадает в цепочку обещаний.

person Jim Schubert    schedule 01.10.2015
comment
Спасибо, основываясь на вашем ответе, я переместил fs.createReadStream в tarPromise, и это решило проблему. Я ожидал, что createReadStreamAsync передаст поток следующему методу then(), но это было не так. Ваше решение работает, если вы используете буферы, я хотел придерживаться потоков, потому что мой tar.extract работает с потоками. - person springloaded; 02.10.2015
comment
Если вы когда-нибудь снова столкнетесь с этой проблемой, вы можете обернуть буфер потоком. см. stackoverflow.com/a/16044400/151445. буфер памяти, но он украшает буферы, используемые вашим tar.extract. Если ваша библиотека является общедоступной, было бы неплохо показать ее пользователям. - person Jim Schubert; 02.10.2015