【问题标题】:run-sequence synchronous task never completes运行序列同步任务永远不会完成
【发布时间】:2016-04-12 23:15:44
【问题描述】:

我几乎肯定会以错误的方式解决这个问题,所以首先提出我的高级要求。

我正在使用angular2-seed 并希望使用 Xvfb 在无头模式下运行 Protractor 测试。我不想让 Xvfb 服务器一直运行(这是一个构建服务器),所以我想启动一个 Xvfb 服务,让 Protractor 完成它,然后“优雅地”关闭 Xvfb。单独来看,这些任务运行良好,但是在将它们添加到 gulp 构建设置时我遇到了困难。

这是 gulpfile 中的任务:

gulp.task('e2e.headless', (done: any) =>
  runSequence('start.xvfb',
              'protractor',
              'stop.xvfb',
              done));

任务本身是通过单独的打字稿任务文件加载的,即:

import {runProtractor} from '../../utils';

export = runProtractor

这是我的(最新)实用程序文件本身。

protractor.ts

import * as util from 'gulp-util';
import {normalize, join} from 'path';
import {ChildProcess} from 'child_process';

function reportError(message: string) {
  console.error(require('chalk').white.bgRed.bold(message));
  process.exit(1);
}

function promiseFromChildProcess(child: ChildProcess) {
  return new Promise(function (resolve: () => void, reject: () => void) {
    child.on('close', (code: any) => {
      util.log('Exited with code: ', code);
      resolve();
    });
    child.stdout.on('data', (data: any) => {
      util.log(`stdout: ${data}`);
    });

    child.stderr.on('data', (data: any) => {
      util.log(`stderr: ${data}`);
      reject();
    });
  });
}

export function runProtractor(): (done: () => void) => void {
  return done => {
    const root = normalize(join(__dirname, '..', '..', '..'));
    const exec = require('child_process').exec;

    // Our Xvfb instance is running on :99
    // TODO: Pass this in instead of hard-coding
    process.env.DISPLAY=':99';
    util.log('cwd:', root);

    let child = exec('protractor', { cwd: root, env: process.env},
      function (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) {
        if (error !== null) {
          reportError('Protractor error: ' + error + stderr);
        }
      });
    promiseFromChildProcess(child).then(() => done());
  };
}

xvfb_tools.ts

import * as util from 'gulp-util';

const exec = require('child_process').exec;

function reportError(message: string) {
  console.error(require('chalk').white.bgRed.bold(message));
  process.exit(1);
}

export function stopXvfb() {
    return exec('pkill -c -n Xvfb',
        function (error: NodeJS.ErrnoException, stdout: NodeBuffer, stderr: NodeBuffer) {
            if (error !== null) {
                reportError('Failed to kill Xvfb.  Not really sure why...');
            } else if (stdout.toString() === '0') {
                reportError('No known Xvfb instance.  Is it running?');
            } else {
                util.log('Xvfb terminated');
            }
        });
}

export function startXvfb() {
    return exec('Xvfb :99 -ac -screen 0 1600x1200x24',
        function (error: NodeJS.ErrnoException, stdout: NodeBuffer, stderr: NodeBuffer) {
            if (error !== null && error.code !== null) {
                reportError('Xvfb failed to start.  Err: ' + error.code + ', ' + error + ', ' + stderr);
            }
        });
}

我觉得我可能会在我的exec child_process 中创建一个承诺,但是早期的代码交互并没有这样做,所以...... 请注意,应该在显示根目录的runProtractor() 中输出的调试日志永远不会被调用,所以我很确定这里存在异步问题。这是任务的输出:

[00:47:49] Starting 'e2e.headless'...
[00:47:49] Starting 'start.xvfb'...
[00:47:49] Finished 'start.xvfb' after 12 ms
[00:47:49] Starting 'protractor'...
[00:47:49] Finished 'protractor' after 5.74 ms
[00:47:49] Starting 'stop.xvfb'...
[00:47:49] Finished 'stop.xvfb' after 11 ms
[00:47:49] Finished 'e2e.headless' after 38 ms
[00:47:49] Xvfb terminated

有人可以帮我直/推我到正确的方向吗??

【问题讨论】:

    标签: node.js typescript gulp run-sequence


    【解决方案1】:

    感谢 angular2-seed 团队的 Ludovic!

    错误在于没有从包装类调用 runProtractor 函数,即 export = runProtractor()。一旦注意到这一点,我就可以去掉不必要的包装函数以及 promiseFromChildProcess,它们会分散注意力。

    最后的任务只是一个匿名函数,它接受退出时调用的 gulp 回调“完成”:

    function reportError(message: string) {
      console.error(require('chalk').white.bgRed.bold(message));
      process.exit(1);
    }
    
    export = (done: any) => {
        const root = normalize(join(__dirname, '..', '..', '..'));
        const exec = require('child_process').exec;
    
        process.env.DISPLAY=':99';
        util.log('cwd:', root);
    
        exec('protractor', { cwd: root, env: process.env},
          function (error: Error, stdout: NodeBuffer, stderr: NodeBuffer) {
            if (error !== null) {
              reportError('Protractor error: ' + error + stderr);
            } else {
              done();
            }
          });
    }
    

    【讨论】:

      【解决方案2】:

      你需要在你的 gulp 任务中添加一个回调函数,并在你所有的 runSequence 任务完成后调用 cb(回调)函数。

      gulp.task('e2e.headless', (cb) =>
      runSequence('start.xvfb',
          'protractor',
          'stop.xvfb',
           (err) => {
              if (err) {
                  console.log(err.message);
              } else {
                  console.log("Build finished successfully");
              }
              cb(err);
          });
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-09
        • 1970-01-01
        • 1970-01-01
        • 2021-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-05
        相关资源
        最近更新 更多