node.jstestingmocha.jsyeoman

How do I build a mocha test that waits for a process to finish first?


I'm attempting to write a test for my Yeoman generator which calls a command-line utility to generate some files in the folder I'm scaffolding. I've seen various examples of how to set a timeout to wait for a function to finish but am struggling to get it to work locally.

Here's my test:

 describe('Should properly scaffold with config for Spring and wsdl2rest', function () {

    before(function () {
      basicProps.name = 'MyAppMock';
      basicProps.package = 'com.generator.mock';
      basicProps.camelVersion = '2.18.2';
      basicProps.camelDSL = 'spring';
      var wsdlPath = path.join(__dirname, '../test/address.wsdl');
      basicProps.wsdl = wsdlPath;
      basicProps.outdirectory = 'src/main/java';

      return helpers.run(path.join(__dirname, '../app'))
        .inTmpDir(function (dir) {
          var done = this.async(); // `this` is the RunContext object.
          fs.copy(path.join(__dirname, '../templates'), dir, done);
          basicProps.outdirectory = path.join(dir, 'src/main/java');
        })
        .withOptions({ wsdl2rest: true })
        .withPrompts({ name: basicProps.name })
        .withPrompts({ camelVersion: basicProps.camelVersion })
        .withPrompts({ camelDSL: basicProps.camelDSL })
        .withPrompts({ package: basicProps.package })
        .withPrompts({ wsdl: basicProps.wsdl })
        .withPrompts({ outdirectory: basicProps.outdirectory })
        .toPromise();
    });

    it('Should create the basic structure two ways', function () {
      assert.file('pom.xml');
      assert.file('README.md');
      assert.file('src/main/resources/META-INF/spring/camel-context.xml');
      assert.file('src/main/resources/META-INF/spring/camel-context-rest.xml')
    });
  });

The problem is that the command-line executable is finishing AFTER the test to see if the files that it generates are there so I'm getting:

Creating wsdl2rest java output directory
calling: java -jar C:\Users\brianf\Documents\GitHub\generator-camel-project-fork\app\wsdl2rest\target\wsdl2rest-impl-fatjar-0.1.3-SNAPSHOT.jar --wsdl file:///C:/Users/brianf/Documents/GitHub/generator-camel-project-fork/test/address.wsdl --out C:\Users\brianf\AppData\Local\Temp\8d84f15024327cbe792407e1294ab46a5b4a1080\src\main\java --camel-context C:\Users\brianf\AppData\Local\Temp\8d84f15024327cbe792407e1294ab46a5b4a1080\src\main\resources\META-INF\spring\camel-context-rest.xml
      1) Should create the basic structure two ways


  11 passing (411ms)
  1 failing

  1) generator-camel:wsdl2rest
       Should properly scaffold with config for Spring and wsdl2rest
         Should create the basic structure two ways:

      AssertionError [ERR_ASSERTION]: src/main/resources/META-INF/spring/camel-context-rest.xml, no such file or directory
      + expected - actual

      -false
      +true

      at convertArgs.forEach.file (node_modules\yeoman-assert\index.js:56:12)
      at Array.forEach (<anonymous>)
      at Function.assert.file (node_modules\yeoman-assert\index.js:54:26)
      at Context.<anonymous> (test\app.js:206:14)



stdout: Retrieving document at 'file:/C:/Users/brianf/Documents/GitHub/generator-camel-project-fork/test/address.wsdl'.

stderr: log4j:WARN No appenders could be found for logger (org.jboss.fuse.wsdl2rest.impl.WSDLProcessorImpl).

stderr: log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

wsdl2rest generated artifacts successfully

What's the secret to getting this thing to wait? I'm positive I'm missing something obvious, but I'm mostly a Java programmer not JavaScript and struggling a bit with some of the asynchronous aspects of the language.

Thanks in advance!

Update: Though it has been suggested that I use Mocha's asynchronous code options (https://mochajs.org/#asynchronous-code) I am having a difficult time wrestling those concepts into the test I have written and could use some additional help if anybody has tackled this with Yeoman generator testing?


Solution

  • Thanks to @Evan, we found a solution yesterday...

    There are two parts - one was the fact that the method we created to actually call our Java jar wasn't returning a Promise... so we changed it to:

       console.log('calling: ' + cmdString);
    return new Promise((resolve, reject) => {
        const wsdl2rest = exec(cmdString);
        wsdl2rest.stdout.on('data', function (data) {
            console.log(`stdout: ${data}`);
        });
        wsdl2rest.stderr.on('data', function (data) {
            console.log(`stderr: ${data}`);
        });
        wsdl2rest.on('close', function (code) {
            if (code === 0) {
                console.log(`wsdl2rest generated artifacts successfully`);
                resolve()
            } else {
                reject()
                console.log(`stderr: ${code}`);
                console.log(`wsdl2rest did not generate artifacts successfully - please check the log file for details`);
            }
        });    
    })
    

    And we changed the test to be:

    describe('generator-camel:wsdl2rest', function () {
      describe('Should properly scaffold with config for Spring and wsdl2rest', function () {
        it('Should create the basic structure two ways', function () {
          basicProps.name = 'MyAppMock';
          basicProps.package = 'com.generator.mock';
          basicProps.camelVersion = '2.18.2';
          basicProps.camelDSL = 'spring';
          var wsdlPath = path.join(__dirname, '../test/address.wsdl');
          basicProps.wsdl = wsdlPath;
          basicProps.outdirectory = 'src/main/java';
          return helpers.run(path.join(__dirname, '../app'))
            .inTmpDir(function (dir) {
              var done = this.async(); // `this` is the RunContext object.
              fs.copy(path.join(__dirname, '../templates'), dir, done);
              basicProps.outdirectory = path.join(dir, 'src/main/java');
            })
            .withOptions({ wsdl2rest: true })
            .withPrompts({ name: basicProps.name })
            .withPrompts({ camelVersion: basicProps.camelVersion })
            .withPrompts({ camelDSL: basicProps.camelDSL })
            .withPrompts({ package: basicProps.package })
            .withPrompts({ wsdl: basicProps.wsdl })
            .withPrompts({ outdirectory: basicProps.outdirectory })
            .toPromise() 
            .then(() => { 
              assert.file('pom.xml'); 
              assert.file('README.md'); 
              assert.file('src/main/resources/META-INF/spring/camel-context.xml'); 
              assert.file('src/main/resources/META-INF/spring/camel-context-rest.xml')
            });
        });
    });

    With all of this in place, we're able to run toPromise and it waits to do the asserts.

    Thank you for the guidance Evan!