Skip to content

Commit

Permalink
Add support for yaml config file (#105)
Browse files Browse the repository at this point in the history
* Add support for yaml config file

* add documentation
  • Loading branch information
jsumners authored Oct 11, 2024
1 parent 285613e commit 2d06c47
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 2 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ Here are the available reporters:
* `dot`: outputs the test results in a compact format, where each passing test is represented by a ., and each failing test is represented by a X.
* `junit`: outputs test results in a jUnit XML format

## Config File Support

A limited set of options may be specified via a configuration file. The
configuration file is expected to be in the process's working directory, and
named either `.borp.yaml` or `.borp.yml`; it may also be specified by
defining the environment variable `BORP_CONF_FILE` and setting it to the
full path to some yaml file.

The current supported options are:

+ `files` (string[]): An array of test files to include. Globs are supported.
+ `reporters` (string[]): An array of reporters to use. May be relative path
strings, or module name strings.

### Example

```yaml
files:
- 'test/one.test.js'
- 'test/foo/*.test.js'

reporters:
- './test/lib/my-reporter.js'
- spec
- '@reporters/silent'
```
## License
MIT
6 changes: 6 additions & 0 deletions borp.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ import { checkCoverages } from 'c8/lib/commands/check-coverage.js'
import os from 'node:os'
import { execa } from 'execa'
import { pathToFileURL } from 'node:url'
import loadConfig from './lib/conf.js'

/* c8 ignore next 4 */
process.on('unhandledRejection', (err) => {
console.error(err)
process.exit(1)
})

const foundConfig = await loadConfig()
if (foundConfig.length > 0) {
Array.prototype.push.apply(process.argv, foundConfig)
}

const args = parseArgs({
args: process.argv.slice(2),
options: {
Expand Down
3 changes: 3 additions & 0 deletions fixtures/conf/glob-files.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
files:
- 'test1/*.test.js'
- 'test2/**/*.test.js'
2 changes: 2 additions & 0 deletions fixtures/conf/relative-reporter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
reporters:
- './reporter.js'
3 changes: 3 additions & 0 deletions fixtures/conf/reporters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
reporters:
- spec
- '@reporters/silent'
80 changes: 80 additions & 0 deletions lib/conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { cwd } from 'node:process'
import { open, readFile } from 'node:fs/promises'
import { join } from 'node:path'
import YAML from 'yaml'

async function readYamlFile () {
let target
let fd
if (process.env.BORP_CONF_FILE) {
target = process.env.BORP_CONF_FILE
try {
fd = await open(target, 'r')
} catch {
return
}
} else {
const CWD = cwd()
try {
target = join(CWD, '.borp.yaml')
fd = await open(target, 'r')
} catch {
target = join(CWD, '.borp.yml')
try {
fd = await open(target, 'r')
} catch {
// Neither file is available. If we had an application logger that writes
// to stderr, we'd log an error message. But, as it is, we will just
// assume that all errors are "file does not exist.""
return
}
}
}

let fileData
try {
fileData = await readFile(fd, { encoding: 'utf8' })
} catch {
// Same thing as noted above. Skip it.
return
} finally {
await fd.close()
}

return fileData
}

async function loadConfig () {
const result = []
const fileData = await readYamlFile()
if (typeof fileData !== 'string') {
return result
}

let options
try {
options = YAML.parse(fileData)
} catch {
// We just don't care.
return result
}

if (options.reporters) {
for (const reporter of options.reporters) {
result.push('--reporter')
result.push(reporter)
}
}

// Append files AFTER all other supported config keys. The runner expects
// them as positional parameters.
if (options.files) {
for (const file of options.files) {
result.push(file)
}
}

return result
}

export default loadConfig
15 changes: 14 additions & 1 deletion package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"c8": "^10.0.0",
"execa": "^9.3.0",
"find-up": "^7.0.0",
"glob": "^10.3.10"
"glob": "^10.3.10",
"yaml": "^2.5.1"
}
}
45 changes: 45 additions & 0 deletions test/config.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test } from 'node:test'
import { execa } from 'execa'
import { join } from 'desm'
import { strictEqual } from 'node:assert'
import path from 'node:path'

const borp = join(import.meta.url, '..', 'borp.js')
const confFilesDir = join(import.meta.url, '..', 'fixtures', 'conf')

test('reporter from node_modules', async () => {
const cwd = join(import.meta.url, '..', 'fixtures', 'ts-esm')
const { stdout } = await execa('node', [borp], {
cwd,
env: {
BORP_CONF_FILE: path.join(confFilesDir, 'reporters.yaml')
}
})

strictEqual(stdout.indexOf('tests 2') >= 0, true)
})

test('reporter from relative path', async () => {
const cwd = join(import.meta.url, '..', 'fixtures', 'relative-reporter')
const { stdout } = await execa('node', [borp], {
cwd,
env: {
BORP_CONF_FILE: path.join(confFilesDir, 'relative-reporter.yaml')
}
})

strictEqual(/passed:.+add\.test\.js/.test(stdout), true)
strictEqual(/passed:.+add2\.test\.js/.test(stdout), true)
})

test('interprets globs for files', async () => {
const cwd = join(import.meta.url, '..', 'fixtures', 'files-glob')
const { stdout } = await execa('node', [borp], {
cwd,
env: {
BORP_CONF_FILE: path.join(confFilesDir, 'glob-files.yaml')
}
})

strictEqual(stdout.indexOf('tests 2') >= 0, true)
})

0 comments on commit 2d06c47

Please sign in to comment.