在测试开始之前解决承诺

时间:2020-07-01 12:51:26

标签: node.js promise mocha nedb

解决方案

Converting the promises into the promise factory解决了测试运行之前出现的日志问题。我的promise.all无法解决,因为I just assumed的NeDB数据库初始化函数遵循没有properly going through the documentation的回调模式。再次查看文档后,我了解到不是。从promise工厂中删除回调即可解决此问题。

问题

我有一个承诺链,其中Promise(如果已解决)将返回Promise.allPromise.all接受3个承诺。这是我的代码:

lib.init = (dir) => {
  // check if the .data directory exists
  return new Promise((resolve, reject) => {
    if(dir) lib.baseDir = path.join(__dirname, '../', dir)
    console.log('DATA LIBRARY INITIALIZATION: working directory - ', lib.baseDir)
    fs.stat(lib.baseDir, (error, stats) => {
      if(!error){
        console.log('DATA LIBRARY INITIALIZATION: successfully retrieved file stats.')
        if(!stats.isDirectory()) {
          console.log('DATA LIBRARY INITIALIZATION: the base directory does not exist. Creating base directory now.')
          fs.mkdir(lib.baseDir, (err) => {
            if(!err) {
              console.log('DATA LIBRARY INITIALIZATION: base directory created successfully.')
              resolve()
            } else reject('Could not create the data directory.')
          })
        } else resolve()
      } else {
        console.log('DATA LIBRARY INITIALIZATION: could not retrieve file stats. Creating base directory now.')
        fs.mkdir(lib.baseDir, (err) => {
          if(!err) {
            console.log('DATA LIBRARY INITIALIZATION: base directory created successfully.')
            resolve()
          } else reject('Could not create the data directory.')
        })
      }
    })
  }).then(() => {
    console.log('DATA LIBRARY INITIALIZATION: initializing databases.')
    return Promise.all([loadComponents, loadShows, loadScreens])
  })
}

以下是作为参数传递的三个承诺:

const loadShows = new Promise((resolve, reject) => {
  // for saving profiles (set of screens designed/configured for different shows)
  console.log('DATA LIBRARY INITIALIZATION: initializing SHOWS collection.')
  lib.shows = new Datastore({ filename: path.join(lib.baseDir, 'shows.db'), autoload: true }, error => {
    if(!error) {
      console.log('DATA LIBRARY INITIALIZATION: successfully initialized SHOWS collection.')
      resolve()
    } else reject(`Could not load shows. Error: ${error.message}`)
  })
})

const loadScreens = new Promise((resolve, reject) => {
  // for saving screen settings (list of component settings)
  console.log('DATA LIBRARY INITIALIZATION: initializing SCREENS collection.')
  lib.screens = new Datastore({ filename: path.join(lib.baseDir, 'screens.db'), autoload: true }, error => {
    if(!error) {
      console.log('DATA LIBRARY INITIALIZATION: successfully initialized SCREENS collection.')
      resolve()
    } else reject(`Could not load screens. Error: ${error.message}`)
  })
})

const loadComponents = new Promise((resolve, reject) => {
  // for saving components (default settings for each component)
  console.log('DATA LIBRARY INITIALIZATION: initializing COMPONENTS collection.')
  lib.components = new Datastore({ filename: path.join(lib.baseDir, 'components.db'), autoload: true }, error => {
    if(!error) {
      console.log('DATA LIBRARY INITIALIZATION: successfully initialized COMPONENTS collection.')
      resolve()
    } else reject(`Could not load components. Error: ${error.message}`)
  })
})

这是我的测试文件:

let chai = require('chai')
let chaiAsPromised = require('chai-as-promised')
chai.use(chaiAsPromised).should()

let _data = require('../lib/data')

describe('data library', () => {
  describe('#init', () => {
    it('should be able to initialize the collections without error', () => {
      return _data.init('testData').should.be.fulfilled
    })
  })

  after(function () {
    // runs once after the last test in this block
    // delete the testData directory and its contents
    return _data.cleanup()
  });
})

这是我运行mocha时获得的日志:

yarn workspace v1.22.4
yarn run v1.22.4
$ mocha
DATA LIBRARY INITIALIZATION: initializing SHOWS collection.
DATA LIBRARY INITIALIZATION: initializing SCREENS collection.
DATA LIBRARY INITIALIZATION: initializing COMPONENTS collection.


  data library
    #init
DATA LIBRARY INITIALIZATION: working directory -  /home/nm/projects/nightmoves/local-data/testData
DATA LIBRARY INITIALIZATION: could not retrieve file stats. Creating base directory now.
DATA LIBRARY INITIALIZATION: base directory created successfully.
DATA LIBRARY INITIALIZATION: initializing databases.
      1) should be able to initialize the collections without error
DATA LIBRARY CLEANUP: removing everything in -  /home/nm/projects/nightmoves/local-data/testData
DATA LIBRARY INITIALIZATION: cleanup successful.


  0 passing (2s)
  1 failing

  1) data library
       #init
         should be able to initialize the collections without error:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/nm/projects/nightmoves/local-data/test/data.js)
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

我没有得到的是为什么我什至在Mocha运行测试之前就看到Promises中的日志通过了promise.all。

1 个答案:

答案 0 :(得分:1)

TLDR。

  1. Node.js执行您加载/需要的模块的所有语句。
  2. 不仅在有人对其结果感兴趣时,也会立即执行承诺。

第二段代码为:

return (
  <form
    onSubmit={(e) => {
      e.preventDefault(e.target.value);
      addTask();
    }}
  >
    <input
      className="input-group-prepend"
      value={task}
      placeholder="Enter your Task"
      onChange={(e) => setTask(e.target.value)}
    />
    <DatePicker
      // No `minDate` prop here anymore!
      className="input-group-prepend"
      placeholderText="Enter task date"
      selected={selectedDate}
      onChange={(date) => setSelectedDate(date)}
      dateFormat="MMMM d, yyyy"
    />
    <br />
    <input className="btn btn-primary" type="submit" value="Submit" />
  </form>
);

仅创建这些承诺,并在程序开始时立即执行(或至少在对模块进行const loadShows = new Promise((resolve, reject) => { } const loadXXX = ... require编辑时执行)。

然后执行mocha和其他代码,并最终调用import,它等待init,并且在这个时间点上,如果它们快速完成,则可能已实现。

要解决此问题,请将功能更改为“承诺工厂”:

Promise.all(...your promises)

然后像这样使用它们:

const loadShows = () => new Promise((resolve, reject) => {

}
const loadXXX = () => ...

或在您的return Promise.all([loadShows(), ...]) 方法中将其声明移至.then处理程序。仅当您到达此代码位置时,它们才会实例化并执行。

相关问题