Skip to content

Commit

Permalink
feat: implement hooks and fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed Jul 11, 2017
1 parent 07d3554 commit e0f716c
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 84 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,26 @@ The `aegir` section in `package.json` was not really useful anymore so it is not

### Pre and Post Hooks

As we are no longer using `gulp` the previous setup using a custom `gulpfile` will not work anymore. To setup hooks around your tests you can use npm script hooks instead. For example
As we are no longer using `gulp` the previous setup using a custom `gulpfile` will not work anymore. To setup hooks around your tests you can use a new configuration option `hooks` in `.aegir.js`.

```json
"scripts": {
"pretest": "node ./test/setup.js",
"posttest": "node ./test/teardown.js",
"test": "aegir test",
"release": "npm run test && aegir release --no-test"
```js
// .aegir.js
module.exports = {
hooks: {
pre (callback) {
console.log('I am called before node and browser tests')
callback()
},
post (callback) {
console.log('I am called after node and browser tests')
callback()
}
}
}
```

You can also specify `hooks.browser` and `hooks.node` if you have a different setup for browser and/or node based tests.

### Renamed binaries

`aegir` is now a single binary with subcommands. While something like `aegir-test` still works, we recommend to switch to the new `aegir test` syntax.
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"test:browser": "./cli.js test --target browser webworker --files test/browser.spec.js",
"test": "npm run test:node && npm run test:browser",
"coverage": "./cli.js coverage --target node",
"watch": "./cli.js tets --target node --watch",
"watch": "./cli.js test --target node --watch",
"release": "./cli.js release --no-build",
"release-minor": "./cli.js release --no-build --type minor",
"release-major": "./cli.js release --no-build --type major"
Expand All @@ -45,6 +45,7 @@
"coveralls": "^2.13.1",
"detect-node": "^2.0.3",
"documentation": "^4.0.0-rc.1",
"es6-promisify": "^5.0.0",
"eslint": "^4.1.1",
"eslint-config-aegir": "^1.0.1",
"execa": "^0.7.0",
Expand All @@ -53,6 +54,7 @@
"gh-pages": "^1.0.0",
"glob": "^7.1.2",
"jest": "^20.0.4",
"joi": "^10.6.0",
"json-loader": "^0.5.4",
"karma": "^1.7.0",
"karma-chrome-launcher": "^2.1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/config/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ module.exports = function (config) {
autoWatch: false,
browsers: browsers,
customLaunchers: launchers,
singleRun: false,
singleRun: true,
concurrency: concurrency,
browserNoActivityTimeout: timeout,
failOnEmptyTestSuite: true
Expand Down
68 changes: 67 additions & 1 deletion src/config/user.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,83 @@
'use strict'

const _ = require('lodash')
const Joi = require('joi')
const promisify = require('es6-promisify')

const utils = require('../utils')

const hookSchema = Joi.object().keys({
pre: Joi.func(),
post: Joi.func()
}).unknown(false)

const envSchema = Joi.object().keys({
browser: hookSchema,
node: hookSchema
}).unknown(false)

const HOOK_ENVS = [
'browser',
'node'
]

const HOOK_STAGES = [
'pre',
'post'
]

function promisifyHooks (hooks) {
Object.keys(hooks).forEach((key) => {
hooks[key] = promisify(hooks[key])
})

return hooks
}

function normalizeHooks (hooks) {
const keys = Object.keys(hooks)

// no hooks provided
if (keys.length === 0) {
return hooks
}

// same hooks for all envs
if (_.every(keys, (k) => _.includes(HOOK_STAGES, k))) {
const v = promisifyHooks(Joi.attempt(hooks, hookSchema))

const res = {}
HOOK_ENVS.forEach((env) => {
res[env] = v
})
return res
}

// regular per env hook specification
if (_.every(keys, (k) => _.includes(HOOK_ENVS, k))) {
const res = Joi.attempt(hooks, envSchema)
keys.forEach((key) => {
res[key] = promisifyHooks(res[key])
})
return res
}

throw new Error(`Found unknown keys in hook definiton: "${keys.join(' ')}"`)
}

function userConfig () {
const config = utils.getUserConfig()

return _.defaultsDeep({}, config, {
const user = _.defaultsDeep({}, config, {
webpack: {},
karma: {},
hooks: {},
entry: 'src/index.js'
})

user.hooks = normalizeHooks(user.hooks)

return user
}

module.exports = userConfig
29 changes: 18 additions & 11 deletions src/test/browser-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,23 @@ function getClient (isWebworker, ctx) {
}

function getConfig (isWebworker, ctx) {
return _.defaultsDeep({}, user().karma, {
const ctxFiles = getPatterns(ctx).map((pattern) => ({
pattern: pattern,
included: !isWebworker
}))

const fixtureFiles = [{
pattern: 'test/fixtures/**/*',
watched: false,
served: true,
included: false
}]
const userKarma = user().karma
const userFiles = userKarma.files || []

return _.defaultsDeep({
files: ctxFiles.concat(fixtureFiles).concat(userFiles)
}, userKarma, {
configFile: CONFIG_FILE,
singleRun: !ctx.watch,
watch: ctx.watch,
Expand All @@ -54,16 +70,7 @@ function getConfig (isWebworker, ctx) {
client: getClient(isWebworker, ctx),
mochaOwnReporter: {
reporter: ctx.verbose ? 'spec' : 'progress'
},
files: getPatterns(ctx).map((pattern) => ({
pattern: pattern,
included: !isWebworker
})).concat([{
pattern: 'test/fixtures/**/*',
watched: false,
served: true,
included: false
}])
}
})
}

Expand Down
20 changes: 16 additions & 4 deletions src/test/browser.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
'use strict'

const Server = require('karma').Server

const getConfig = require('./browser-config')
const utils = require('../utils')

const IS_SAUCE = process.env.SAUCE_USERNAME && process.env.TRAVIS

function testBrowser (isWebworker) {
return (ctx) => new Promise((resolve, reject) => {
const config = getConfig(isWebworker, ctx)

function karma (config) {
return new Promise((resolve, reject) => {
const server = new Server(config, (exitCode) => {
if (exitCode > 0 && !IS_SAUCE) {
reject(new Error('Some tests are failing'))
}

resolve()
})

server.start()
})
}

function testBrowser (isWebworker) {
const postHook = utils.hook('node', 'post')
const preHook = utils.hook('node', 'pre')

return (ctx) => {
return preHook(ctx)
.then(() => karma(getConfig(isWebworker, ctx)))
.then(() => postHook(ctx))
}
}

module.exports = {
default: testBrowser(false),
webworker: testBrowser(true)
Expand Down
3 changes: 3 additions & 0 deletions src/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const _ = require('lodash')
const node = require('./node')
const browser = require('./browser')

const userConfig = require('../config/user')

const TASKS = [{
title: 'Test Node.js',
task: node,
Expand All @@ -22,6 +24,7 @@ const TASKS = [{

module.exports = {
run (opts) {
opts.hooks = userConfig().hooks
return pmap(TASKS, (task) => {
if (!task.enabled(opts)) {
return Promise.resolve()
Expand Down
39 changes: 24 additions & 15 deletions src/test/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const execa = require('execa')
const path = require('path')

const utils = require('../utils')

function testNode (ctx) {
const args = [
'--colors',
Expand Down Expand Up @@ -35,21 +37,28 @@ function testNode (ctx) {
files = ctx.files
}

const res = execa('jest', args.concat(files), {
cwd: process.cwd(),
preferLocal: true,
localDir: path.join(__dirname, '../..')
})
res.stdout.pipe(process.stdout)
res.stderr.pipe(process.stderr)

return res.catch((err) => {
// catch and rethrow custom to avoid double printing failed tests
if (err.code === 1 && err.stderr) {
throw new Error('Tests failed')
} else {
throw err
}
const postHook = utils.hook('node', 'post')
const preHook = utils.hook('node', 'pre')

return preHook(ctx).then(() => {
return execa('jest', args.concat(files), {
cwd: process.cwd(),
preferLocal: true,
localDir: path.join(__dirname, '../..'),
stdin: process.stdin,
stdout: process.stdout,
stderr: process.stderr
}).catch((err) => {
// catch and rethrow custom to avoid double printing failed tests
if (err.code === 1) {
throw new Error('Your tests failed')
} else {
throw err
}
})
}).then(() => {
console.log('post')
postHook(ctx)
})
}

Expand Down
10 changes: 9 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ exports.getUserConfigPath = () => {
exports.getUserConfig = () => {
let conf = {}
try {
conf = require(exports.getUserConfig())
conf = require(exports.getUserConfigPath())
} catch (err) {
}
return conf
Expand Down Expand Up @@ -157,3 +157,11 @@ exports.getPathToDocs = () => {
exports.getPathToDocsFile = () => {
return path.join(exports.getPathToDocs(), 'index.html')
}

exports.hook = (env, key) => (ctx) => {
if (ctx && ctx.hooks && ctx.hooks[env] && ctx.hooks[env][key]) {
return ctx.hooks[env][key]()
}

return Promise.resolve()
}
10 changes: 10 additions & 0 deletions test/config/__snapshots__/user.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
exports[`config - user custom config 1`] = `
Object {
"entry": "src/main.js",
"hooks": Object {
"browser": Object {
"post": [Function],
"pre": [Function],
},
"node": Object {
"post": [Function],
"pre": [Function],
},
},
"karma": Object {},
"webpack": Object {
"devtool": "eval",
Expand Down
19 changes: 18 additions & 1 deletion test/config/user.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ describe('config - user', () => {
webpack: {
devtool: 'eval'
},
entry: 'src/main.js'
entry: 'src/main.js',
hooks: {
pre (cb) {
cb(null, 'pre')
},
post (cb) {
cb(null, 'post')
}
}
}
},
getLibraryName () {
Expand All @@ -43,5 +51,14 @@ describe('config - user', () => {
devtool: 'eval'
})
expect(config).toHaveProperty('entry', 'src/main.js')

expect(config.hooks).toHaveProperty('browser.pre')
expect(config.hooks).toHaveProperty('browser.post')
expect(config.hooks).toHaveProperty('node.pre')
expect(config.hooks).toHaveProperty('node.post')

return config.hooks.browser.pre().then((res) => {
expect(res).toEqual('pre')
})
})
})
5 changes: 5 additions & 0 deletions test/fixtures/.aegir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict'

module.exports = {
config: 'mine'
}
Loading

0 comments on commit e0f716c

Please sign in to comment.