Skip to content

Commit

Permalink
feat: add test command
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Apr 17, 2023
1 parent 867c0bf commit ca12275
Show file tree
Hide file tree
Showing 4 changed files with 694 additions and 10 deletions.
189 changes: 189 additions & 0 deletions commands/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* @adonisjs/core
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import type { CommandOptions } from '../types/ace.js'
import { BaseCommand, flags, args } from '../modules/ace/main.js'
import { detectAssetsBundler, importAssembler, importTypeScript } from '../src/internal_helpers.js'

/**
* Test command is used to run tests with optional file watcher. Under the
* hood, we run "bin/test.js" file.
*/
export default class Test extends BaseCommand {
static commandName = 'test'
static description = 'Run tests along with the file watcher to re-run tests on file change'

static options: CommandOptions = {
allowUnknownFlags: true,
staysAlive: true,
}

@args.spread({
description: 'Mention suite names to run tests for selected suites',
required: false,
})
declare suites?: string[]

@flags.array({ description: 'Filter tests by the filename' })
declare files?: string[]

@flags.array({ description: 'Filter tests by tags' })
declare tags?: string[]

@flags.array({ description: 'Run tests that does not have mentioned tags' })
declare ignoreTags?: string[]

@flags.array({ description: 'Filter tests by parent group title' })
declare groups?: string[]

@flags.array({ description: 'Filter tests by test title' })
declare tests?: string[]

@flags.boolean({ description: 'Watch filesystem and re-run tests on file change' })
declare watch?: boolean

@flags.boolean({ description: 'Use polling to detect filesystem changes' })
declare poll?: boolean

@flags.boolean({
description: 'Clear the terminal for new logs after file change',
showNegatedVariantInHelp: true,
default: true,
})
declare clear?: boolean

@flags.boolean({
description: 'Start assets bundler dev server.',
showNegatedVariantInHelp: true,
default: true,
})
declare assets?: boolean

@flags.array({
description: 'Define CLI arguments to pass to the assets bundler',
})
declare assetsArgs?: string[]

/**
* Log a development dependency is missing
*/
#logMissingDevelopmentDependency(dependency: string) {
this.logger.error(
[
`Cannot find package "${dependency}"`,
'',
`The "${dependency}" package is a development dependency and therefore you should run tests with development dependencies installed.`,
'',
'If you are run tests inside a CI, make sure the NODE_ENV is set to "development"',
].join('\n')
)
}

/**
* Runs tests
*/
async run() {
console.log(this.app.rcFile.tests)
const assembler = await importAssembler(this.app)
if (!assembler) {
this.#logMissingDevelopmentDependency('@adonisjs/assembler')
this.exitCode = 1
return
}

const assetsBundler = await detectAssetsBundler(this.app)

const testRunner = new assembler.TestRunner(this.app.appRoot, {
clearScreen: this.clear === false ? false : true,
nodeArgs: this.parsed.nodeArgs,
scriptArgs: this.parsed.unknownFlags
.map((flag) => {
const value = this.parsed.flags[flag]

/**
* Not mentioning value when value is "true"
*/
if (value === true) {
return [`--${flag}`] as string[]
}

/**
* Repeating flag multiple times when value is an array
*/
if (Array.isArray(value)) {
return value.map((v) => [`--${flag}`, v]) as string[][]
}

return [`--${flag}`, value] as string[]
})
.flat(2),
assets: assetsBundler
? {
serve: this.assets === false ? false : true,
driver: assetsBundler.name,
cmd: assetsBundler.devServerCommand,
args: this.assetsArgs || [],
}
: {
serve: false,
},
filters: {
suites: this.suites,
files: this.files,
groups: this.groups,
tags: this.tags,
ignoreTags: this.ignoreTags,
tests: this.tests,
},
suites: this.app.rcFile.tests.suites.map((suite) => {
return {
name: suite.name,
files: Array.isArray(suite.files) ? suite.files : [suite.files],
}
}),
metaFiles: this.app.rcFile.metaFiles,
})

/**
* Share command logger with assembler, so that CLI flags like --no-ansi has
* similar impact for assembler logs as well.
*/
testRunner.setLogger(this.logger)

/**
* Exit command when the test runner is closed
*/
testRunner.onClose((exitCode) => {
this.exitCode = exitCode
})

/**
* Exit command when the dev server crashes
*/
testRunner.onError(() => {
this.exitCode = 1
})

/**
* Start the test runner in watch mode
*/
if (this.watch) {
const ts = await importTypeScript(this.app)
if (!ts) {
this.#logMissingDevelopmentDependency('typescript')
this.exitCode = 1
return
}

await testRunner.runAndWatch(ts, { poll: this.poll || false })
} else {
await testRunner.run()
}
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
},
"scripts": {
"pretest": "npm run lint",
"test": "cross-env NODE_DEBUG=adonisjs:core c8 npm run vscode:test",
"test": "cross-env NODE_DEBUG=adonisjs:core c8 npm run quick:test",
"clean": "del-cli build",
"copy:templates": "copyfiles \"stubs/**/**/*.stub\" build",
"precompile": "npm run lint",
Expand All @@ -101,7 +101,7 @@
"lint": "eslint . --ext=.ts",
"format": "prettier --write .",
"sync-labels": "github-label-sync --labels .github/labels.json adonisjs/core",
"vscode:test": "node --loader=ts-node/esm --experimental-import-meta-resolve bin/test.ts",
"quick:test": "node --loader=ts-node/esm --experimental-import-meta-resolve bin/test.ts",
"index:commands": "node --loader=ts-node/esm toolkit/main.js index build/commands"
},
"keywords": [
Expand Down
16 changes: 8 additions & 8 deletions tests/commands/serve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ test.group('Serve command', () => {
await ace.app.init()
ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
await command.exec()
await sleep(100)

Expand All @@ -50,7 +50,7 @@ test.group('Serve command', () => {
await ace.app.init()
ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
await command.exec()

await sleep(100)
Expand All @@ -76,7 +76,7 @@ test.group('Serve command', () => {
await ace.app.init()
ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
command.watch = true
await command.exec()

Expand All @@ -97,7 +97,7 @@ test.group('Serve command', () => {
await ace.app.init()
ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
command.watch = true
await command.exec()

Expand Down Expand Up @@ -130,7 +130,7 @@ test.group('Serve command', () => {
await ace.app.init()
ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
command.watch = true
await command.exec()

Expand Down Expand Up @@ -171,7 +171,7 @@ test.group('Serve command', () => {

ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
await command.exec()
await sleep(100)

Expand Down Expand Up @@ -211,7 +211,7 @@ test.group('Serve command', () => {

ace.ui.switchMode('raw')

const command = await ace.create(Serve, [])
const command = await ace.create(Serve, ['--no-clear'])
await command.exec()
await sleep(100)

Expand Down Expand Up @@ -249,7 +249,7 @@ test.group('Serve command', () => {

ace.ui.switchMode('raw')

const command = await ace.create(Serve, ['--no-assets'])
const command = await ace.create(Serve, ['--no-assets', '--no-clear'])
await command.exec()
await sleep(100)

Expand Down

0 comments on commit ca12275

Please sign in to comment.