Skip to content

Commit

Permalink
feat: support transpiling configuration files written in arbitrary la…
Browse files Browse the repository at this point in the history
  • Loading branch information
devoto13 committed May 4, 2021
1 parent 138e651 commit 8b42a4a
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 61 deletions.
12 changes: 12 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ function describeStart (yargs) {
describe: 'A path to a file that exports the format function.',
type: 'string'
})
.option('require', {
describe: 'Module to require before loading configuration file. Use to register a transpiler for a configuration file.',
type: 'string'
})
}

function describeRun (yargs) {
Expand Down Expand Up @@ -242,6 +246,10 @@ function describeRun (yargs) {
describe: 'Comma-separated paths to added files. Useful when automatic file watching is disabled.',
type: 'string'
})
.option('require', {
describe: 'Module to require before loading configuration file. Use to register a transpiler for a configuration file.',
type: 'string'
})
}

function describeStop (yargs) {
Expand All @@ -258,6 +266,10 @@ function describeStop (yargs) {
})
.describe('port', '<integer> Port where the server is listening.')
.describe('log-level', '<disable | error | warn | info | debug> Level of logging.')
.option('require', {
describe: 'Module to require before loading configuration file. Use to register a transpiler for a configuration file.',
type: 'string'
})
}

function describeCompletion (yargs) {
Expand Down
77 changes: 44 additions & 33 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,6 @@ const constant = require('./constants')

const _ = require('lodash')

let COFFEE_SCRIPT_AVAILABLE = false
let LIVE_SCRIPT_AVAILABLE = false
let TYPE_SCRIPT_AVAILABLE = false

try {
require('coffeescript').register()
COFFEE_SCRIPT_AVAILABLE = true
} catch (e) {}

// LiveScript is required here to enable config files written in LiveScript.
// It's not directly used in this file.
try {
require('LiveScript')
LIVE_SCRIPT_AVAILABLE = true
} catch (e) {}

try {
require('ts-node')
TYPE_SCRIPT_AVAILABLE = true
} catch (e) {}

class Pattern {
constructor (pattern, served, included, watched, nocache, type, isBinary) {
this.pattern = pattern
Expand Down Expand Up @@ -400,6 +379,7 @@ function parseConfig (configFilePath, cliOptions, parseOptions) {
// The first argument MUST BE an object
logger.setupFromConfig({})
}

function fail () {
log.error(...arguments)
if (throwErrors) {
Expand All @@ -425,24 +405,55 @@ function parseConfig (configFilePath, cliOptions, parseOptions) {

let configModule
if (configFilePath) {
try {
if (path.extname(configFilePath) === '.ts' && TYPE_SCRIPT_AVAILABLE) {
require('ts-node').register()
const extension = path.extname(configFilePath)

if (cliOptions.require != null) {
if (cliOptions.require !== 'none') {
try {
const requirePath = require.resolve(cliOptions.require, { paths: [process.cwd()] })
require(requirePath)
} catch (e) {
return fail('Failed to load a configuration file transpiler:', e)
}
}
} else {
try {
require('coffeescript').register()
} catch (e) {}

try {
require('LiveScript')
} catch (e) {}

if (extension === '.ts') {
try {
require('ts-node').register()
} catch (e) {}
}

if (extension !== '.js') {
log.warn('Starting with the next major version Karma will not load any transpilers for configuration file ' +
`by default. You see this message because the configuration file (${configFilePath}) has an extension ` +
'other than .js and probably requires a transpiler. To suppress this warning, configure a transpiler ' +
'explicitly with e.g. `karma start --require ts-node/register` or `karma start --require none` (if no ' +
'transpiler is needed). See https://karma-runner.github.io/latest/intro/configuration.html for more ' +
'information.')
}
}

try {
configModule = require(configFilePath)
if (typeof configModule === 'object' && typeof configModule.default !== 'undefined') {
configModule = configModule.default
}
} catch (e) {
const extension = path.extname(configFilePath)
if (extension === '.coffee' && !COFFEE_SCRIPT_AVAILABLE) {
log.error('You need to install CoffeeScript.\n npm install coffeescript --save-dev')
} else if (extension === '.ls' && !LIVE_SCRIPT_AVAILABLE) {
log.error('You need to install LiveScript.\n npm install LiveScript --save-dev')
} else if (extension === '.ts' && !TYPE_SCRIPT_AVAILABLE) {
log.error('You need to install TypeScript.\n npm install typescript ts-node --save-dev')
if (extension !== '.js' && cliOptions.require === 'none') {
log.warn(`The configuration file (${configFilePath}) has an extension other than .js, but no transpiler is ` +
'configured. Configure a transpiler with e.g. `karma start --require ts-node/register`. See ' +
'https://karma-runner.github.io/latest/intro/configuration.html for more information.')
}
return fail('Error in config file!\n ' + e.stack || e)

return fail('Error in config file:', e)
}
if (!helper.isFunction(configModule)) {
return fail('Config file must export a function!\n' + CONFIG_SYNTAX_HELP)
Expand All @@ -467,7 +478,7 @@ function parseConfig (configFilePath, cliOptions, parseOptions) {
try {
configModuleReturn = configModule(config)
} catch (e) {
return fail('Error in config file!\n', e)
return fail('Error in config file:', e)
}
function finalizeConfig (config) {
// merge the config from config file and cliOptions (precedence)
Expand Down
62 changes: 62 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,8 @@
"sinon-chai": "^3.5.0",
"supertest": "^4.0.2",
"timer-shim": "^0.3.0",
"ts-node": "^9.1.1",
"typescript": "^4.2.4",
"watchify": "^3.11.1",
"which": "^1.3.1"
},
Expand Down
8 changes: 8 additions & 0 deletions test/e2e/cli.feature
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ Feature: CLI
--no-fail-on-failing-test-suite Do not fail on failing test suite.
--format-error A path to a file that exports the format
function. [string]
--require Module to require before loading
configuration file. Use to register a
transpiler for a configuration file. [string]
"""

Scenario: Run command help
Expand Down Expand Up @@ -173,6 +176,9 @@ Feature: CLI
--added-files Comma-separated paths to added files. Useful
when automatic file watching is disabled.
[string]
--require Module to require before loading configuration
file. Use to register a transpiler for a
configuration file. [string]
"""

Scenario: Stop command help
Expand All @@ -193,6 +199,8 @@ Feature: CLI
--help Print usage and options. [boolean]
--port <integer> Port where the server is listening.
--log-level <disable | error | warn | info | debug> Level of logging.
--require Module to require before loading configuration file. Use to
register a transpiler for a configuration file. [string]
"""

Scenario: Completion command help
Expand Down
89 changes: 89 additions & 0 deletions test/e2e/config.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Feature: Config
In order to use Karma
As a person who wants to write great tests
I want to write Karma config in my favourite language.

Scenario: Transpile TypeScript config
Given a configuration file named "karma.conf.ts" containing:
"""
import { resolve } from 'path';
module.exports = (config: any) => {
config.set({
files: [resolve('basic/plus.js'), resolve('basic/test.js')],
browsers: ['ChromeHeadlessNoSandbox'],
plugins: ['karma-jasmine', 'karma-chrome-launcher'],
singleRun: true,
reporters: ['dots'],
frameworks: ['jasmine'],
colors: false,
logLevel: 'warn',
customLaunchers: {
ChromeHeadlessNoSandbox: { base: 'ChromeHeadless', flags: ['--no-sandbox'] }
}
});
};
"""
When I start Karma with additional arguments: "--require ts-node/register"
Then it passes with:
"""
..
Chrome Headless
"""

Scenario: Local transpiler is resolved relative to the CWD
Given a configuration file named "karma.conf.ts" containing:
"""
import { resolve } from 'path';
module.exports = (config: any) => {
config.set({
files: [resolve('basic/plus.js'), resolve('basic/test.js')],
browsers: ['ChromeHeadlessNoSandbox'],
plugins: ['karma-jasmine', 'karma-chrome-launcher'],
singleRun: true,
reporters: ['dots'],
frameworks: ['jasmine'],
colors: false,
logLevel: 'warn',
customLaunchers: {
ChromeHeadlessNoSandbox: { base: 'ChromeHeadless', flags: ['--no-sandbox'] }
}
});
};
"""
When I start Karma with additional arguments: "--require ./config/register"
Then it passes with:
"""
..
Chrome Headless
"""

Scenario: Warning for deprecated behavior
Given a configuration file named "karma.conf.ts" containing:
"""
import { resolve } from 'path';
module.exports = (config: any) => {
config.set({
files: [resolve('basic/plus.js'), resolve('basic/test.js')],
browsers: ['ChromeHeadlessNoSandbox'],
plugins: ['karma-jasmine', 'karma-chrome-launcher'],
singleRun: true,
reporters: ['dots'],
frameworks: ['jasmine'],
colors: false,
logLevel: 'warn',
customLaunchers: {
ChromeHeadlessNoSandbox: { base: 'ChromeHeadless', flags: ['--no-sandbox'] }
}
});
};
"""
When I start Karma
Then it passes with regexp:
"""
WARN \[config\]:.+Starting with the next major version Karma will not load any transpilers for configuration file by default. You see this message because the configuration file \(.+karma.conf.ts\) has an extension other than .js and probably requires a transpiler. To suppress this warning, configure a transpiler explicitly with e.g. `karma start --require ts-node/register` or `karma start --require none` \(if no transpiler is needed\). See https://karma-runner.github.io/latest/intro/configuration.html for more information.
..
Chrome Headless
"""
Loading

0 comments on commit 8b42a4a

Please sign in to comment.