运行-序列同步任务永远不会完成
run-sequence synchronous task never completes
我几乎肯定是以错误的方式解决这个问题,所以首先提出我的高级要求。
我正在使用 angular2-seed 并希望 运行 Protractor 使用 Xvfb 在无头模式下进行测试。我不想一直使用 Xvfb 服务器 运行ning(这是一个构建服务器)所以我想启动一个 Xvfb 服务,让 Protractor 做这件事,然后 "gracefully"关闭 Xvfb。单独来看,这些任务运行良好,但是在将它们添加到 gulp 构建设置时我遇到了困难。
这是 gulp 文件中的任务:
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
有人可以给我 straight/push 正确的方向吗??
您需要向 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);
});
});
感谢 angular2-seed 团队的 Ludovic!
错误在于没有从包装器 class 中调用 runProtractor 函数,即
export = runProtractor()
。一旦注意到这一点,我就可以去除不必要的包装函数以及 promiseFromChildProcess,它们会分散注意力。
最后的任务只是一个匿名函数,它接受 gulp 回调 "done" 退出时调用:
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();
}
});
}
我几乎肯定是以错误的方式解决这个问题,所以首先提出我的高级要求。
我正在使用 angular2-seed 并希望 运行 Protractor 使用 Xvfb 在无头模式下进行测试。我不想一直使用 Xvfb 服务器 运行ning(这是一个构建服务器)所以我想启动一个 Xvfb 服务,让 Protractor 做这件事,然后 "gracefully"关闭 Xvfb。单独来看,这些任务运行良好,但是在将它们添加到 gulp 构建设置时我遇到了困难。
这是 gulp 文件中的任务:
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
有人可以给我 straight/push 正确的方向吗??
您需要向 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);
});
});
感谢 angular2-seed 团队的 Ludovic!
错误在于没有从包装器 class 中调用 runProtractor 函数,即
export = runProtractor()
。一旦注意到这一点,我就可以去除不必要的包装函数以及 promiseFromChildProcess,它们会分散注意力。
最后的任务只是一个匿名函数,它接受 gulp 回调 "done" 退出时调用:
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();
}
});
}