mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
Refactored Gulp tasks to exist within a tasks folder
This commit is contained in:
@@ -1,125 +0,0 @@
|
|||||||
import { exec } from 'child_process';
|
|
||||||
import psTree from 'ps-tree';
|
|
||||||
import gulp from 'gulp';
|
|
||||||
import net from 'net';
|
|
||||||
import Q from 'q';
|
|
||||||
|
|
||||||
const TEST_SERVER_PORT = 3001
|
|
||||||
const TEST_DB = 'habitrpg_test'
|
|
||||||
|
|
||||||
const TEST_DB_URI = `mongodb://localhost/${TEST_DB}`
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a helper function that allows us to kill background tasks, such as
|
|
||||||
* the Selenium webdriver. We need to recurse through any child processes they
|
|
||||||
* have spun up, or gulp will hang after task completion.
|
|
||||||
*/
|
|
||||||
let kill = (proc) => {
|
|
||||||
((pid) => {
|
|
||||||
psTree(pid, (_, pids) => {
|
|
||||||
if(pids.length) {
|
|
||||||
pids.forEach(kill); return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
exec(/^win/.test(process.platform)
|
|
||||||
? `taskkill /PID ${pid} /T /F`
|
|
||||||
: `kill -9 ${pid}`)
|
|
||||||
}
|
|
||||||
catch(e) { console.log(e) }
|
|
||||||
});
|
|
||||||
}(proc.PID || proc.pid));
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Another helper function, returns a promise that will resolve when a response
|
|
||||||
* is received on the specified port. Accepts a second argument indicating the
|
|
||||||
* maximum seconds to wait before failing.
|
|
||||||
*/
|
|
||||||
let awaitPort = (port, max = 60) => {
|
|
||||||
let socket, timeout, interval;
|
|
||||||
let deferred = Q.defer();
|
|
||||||
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
clearInterval(interval);
|
|
||||||
deferred.reject(`Timed out after ${max} seconds`);
|
|
||||||
}, max * 1000);
|
|
||||||
|
|
||||||
interval = setInterval(() => {
|
|
||||||
socket = net.connect({port: port}, () => {
|
|
||||||
clearInterval(interval);
|
|
||||||
clearTimeout(timeout);
|
|
||||||
socket.destroy();
|
|
||||||
deferred.resolve();
|
|
||||||
}).on('error', () => { socket.destroy });
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return deferred.promise
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* And another helper function to add "noisy" listeners (pipe child process
|
|
||||||
* stdout and stderr to the parent.
|
|
||||||
*/
|
|
||||||
let listen = (child) => {
|
|
||||||
child.stdout.on('data', (data) => { process.stdout.write(data) });
|
|
||||||
child.stderr.on('data', (data) => { process.stderr.write(data) });
|
|
||||||
};
|
|
||||||
|
|
||||||
gulp.task('test:common', (cb) => {
|
|
||||||
listen(exec('NODE_ENV=testing ./node_modules/.bin/mocha test/common', cb));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:api', (cb) => {
|
|
||||||
listen(exec('NODE_ENV=testing ./node_modules/.bin/mocha test/api', cb));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:karma', (cb) => {
|
|
||||||
listen(exec('NODE_ENV=testing ./node_modules/.bin/grunt karma:continuous', cb));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:prepare:build', (cb) => {
|
|
||||||
exec('grunt build:test', cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:prepare:mongo', (cb) => {
|
|
||||||
exec(`mongo "${TEST_DB}" --eval "db.dropDatabase()"`, cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:prepare', [
|
|
||||||
'test:prepare:build',
|
|
||||||
'test:prepare:webdriver',
|
|
||||||
'test:prepare:mongo'
|
|
||||||
]);
|
|
||||||
|
|
||||||
gulp.task('test:prepare:webdriver', (cb) => {
|
|
||||||
exec('./node_modules/protractor/bin/webdriver-manager update', cb);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test:e2e', ['test:prepare'], (cb) => {
|
|
||||||
let support = [
|
|
||||||
'Xvfb :99 -screen 0 1024x768x24 -extension RANDR',
|
|
||||||
`NODE_DB_URI="${TEST_DB_URI}" PORT="${TEST_SERVER_PORT}" node ./website/src/server.js`,
|
|
||||||
'./node_modules/protractor/bin/webdriver-manager start',
|
|
||||||
].map(exec);
|
|
||||||
|
|
||||||
awaitPort(3001)
|
|
||||||
.then(awaitPort.bind(null, 4444))
|
|
||||||
.then(() => {
|
|
||||||
listen(
|
|
||||||
exec('DISPLAY=:99 NODE_ENV=testing ./node_modules/protractor/bin/protractor protractor.conf.js', () => {
|
|
||||||
support.forEach(kill);
|
|
||||||
cb();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('test', [
|
|
||||||
'test:common',
|
|
||||||
'test:api',
|
|
||||||
'test:karma',
|
|
||||||
'test:e2e'
|
|
||||||
]);
|
|
||||||
|
|
||||||
gulp.task('default', ['test']);
|
|
||||||
11
gulpfile.js
Normal file
11
gulpfile.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Note: You probably don't need to edit this file. Instead, add your gulp
|
||||||
|
* tasks with the ./tasks directory, where tasks are grouped by their
|
||||||
|
* particular purpose. If you feel like your task doesn't fit within the
|
||||||
|
* existing files, feel free to create a "gulp-thing.js" file within that
|
||||||
|
* directory, and it will automatically be included.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require('babel/register');
|
||||||
|
require('glob').sync('./tasks/gulp-*').forEach(require);
|
||||||
|
require('gulp').task('default', ['test']);
|
||||||
79
tasks/gulp-tests.js
Normal file
79
tasks/gulp-tests.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { pipe, awaitPort, kill } from './taskHelper';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import gulp from 'gulp';
|
||||||
|
import Q from 'q';
|
||||||
|
|
||||||
|
const TEST_SERVER_PORT = 3001
|
||||||
|
const TEST_DB = 'habitrpg_test'
|
||||||
|
|
||||||
|
const TEST_DB_URI = `mongodb://localhost/${TEST_DB}`
|
||||||
|
|
||||||
|
let testBin = (string) => {
|
||||||
|
return `NODE_ENV=testing ./node_modules/.bin/${string}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
gulp.task('test:prepare:mongo', (cb) => {
|
||||||
|
exec(`mongo "${TEST_DB}" --eval "db.dropDatabase()"`, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test:prepare:build', (cb) => {
|
||||||
|
exec(testBin('grunt build:test'), cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test:prepare:webdriver', (cb) => {
|
||||||
|
exec('./node_modules/protractor/bin/webdriver-manager update', cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test:prepare', [
|
||||||
|
'test:prepare:build',
|
||||||
|
'test:prepare:mongo',
|
||||||
|
'test:prepare:webdriver'
|
||||||
|
]);
|
||||||
|
|
||||||
|
gulp.task('test:common', ['test:prepare'], (cb) => {
|
||||||
|
let runner = exec(
|
||||||
|
testBin('mocha test/common'), cb
|
||||||
|
);
|
||||||
|
pipe(runner);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('test:api', ['test:prepare'], (cb) => {
|
||||||
|
let runner = exec(
|
||||||
|
testBin('mocha test/api'), cb
|
||||||
|
);
|
||||||
|
pipe(runner);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test:karma', ['test:prepare'], (cb) => {
|
||||||
|
let runner = exec(
|
||||||
|
testBin('grunt karma:continuous'), cb
|
||||||
|
);
|
||||||
|
pipe(runner);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test:e2e', ['test:prepare'], (cb) => {
|
||||||
|
let support = [
|
||||||
|
'Xvfb :99 -screen 0 1024x768x24 -extension RANDR',
|
||||||
|
`NODE_DB_URI="${TEST_DB_URI}" PORT="${TEST_SERVER_PORT}" node ./website/src/server.js`,
|
||||||
|
'./node_modules/protractor/bin/webdriver-manager start',
|
||||||
|
].map(exec);
|
||||||
|
|
||||||
|
Q.all([
|
||||||
|
awaitPort(3001),
|
||||||
|
awaitPort(4444)
|
||||||
|
]).then(() => {
|
||||||
|
exec('DISPLAY=:99 NODE_ENV=testing ./node_modules/protractor/bin/protractor protractor.conf.js', () => {
|
||||||
|
support.forEach(kill);
|
||||||
|
cb();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('test', [
|
||||||
|
'test:prepare',
|
||||||
|
'test:common',
|
||||||
|
'test:karma',
|
||||||
|
'test:api',
|
||||||
|
'test:e2e'
|
||||||
|
]);
|
||||||
60
tasks/taskHelper.js
Normal file
60
tasks/taskHelper.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { exec } from 'child_process';
|
||||||
|
import psTree from 'ps-tree';
|
||||||
|
import net from 'net';
|
||||||
|
import Q from 'q';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kill a child process and any sub-children that process may have spawned.
|
||||||
|
* This is necessary to ensure that Gulp will terminate when it has completed
|
||||||
|
* its tasks.
|
||||||
|
*/
|
||||||
|
export function kill(proc) {
|
||||||
|
((pid) => {
|
||||||
|
psTree(pid, (_, pids) => {
|
||||||
|
if(pids.length) {
|
||||||
|
pids.forEach(kill); return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
exec(/^win/.test(process.platform)
|
||||||
|
? `taskkill /PID ${pid} /T /F`
|
||||||
|
: `kill -9 ${pid}`)
|
||||||
|
}
|
||||||
|
catch(e) { console.log(e) }
|
||||||
|
});
|
||||||
|
}(proc.PID || proc.pid));
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a promise that will execute when Node is able to connect on a
|
||||||
|
* specific port. For example, this can be used to halt tasks until Selenium
|
||||||
|
* has fully spun up. Optionally provide a maximum number of seconds to wait
|
||||||
|
* before failing.
|
||||||
|
*/
|
||||||
|
export function awaitPort(port, max=60) {
|
||||||
|
let socket, timeout, interval;
|
||||||
|
let deferred = Q.defer();
|
||||||
|
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
deferred.reject(`Timed out after ${max} seconds`);
|
||||||
|
}, max * 1000);
|
||||||
|
|
||||||
|
interval = setInterval(() => {
|
||||||
|
socket = net.connect({port: port}, () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
clearTimeout(timeout);
|
||||||
|
socket.destroy();
|
||||||
|
deferred.resolve();
|
||||||
|
}).on('error', () => { socket.destroy });
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return deferred.promise
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pipe the child's stdin and stderr to the parent process.
|
||||||
|
*/
|
||||||
|
export function pipe(child) {
|
||||||
|
child.stdout.on('data', (data) => { process.stdout.write(data) });
|
||||||
|
child.stderr.on('data', (data) => { process.stderr.write(data) });
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user