Skip to content

Commit 2e4daa1

Browse files
committed
feat: add support to configure tests via command
1 parent 769bac8 commit 2e4daa1

File tree

5 files changed

+257
-17
lines changed

5 files changed

+257
-17
lines changed

commands/Invoke.ts

Lines changed: 117 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,31 @@
88
*/
99

1010
import { join } from 'path'
11+
import { tasks, files, logger } from '@adonisjs/sink'
1112
import { BaseCommand, args } from '@adonisjs/core/build/standalone'
13+
1214
import { Manifest } from '../src/Manifest'
1315

1416
/**
1517
* Configure a package
1618
*/
1719
export default class Configure extends BaseCommand {
1820
public static commandName = 'configure'
19-
public static description = 'Configure a given AdonisJS package'
21+
public static description = 'Configure one or more AdonisJS packages'
2022
public static aliases = ['invoke']
2123

2224
/**
2325
* Use yarn when building for production to install dependencies
2426
*/
25-
@args.string({
26-
description: 'Name of the package you want to configure',
27+
@args.spread({
28+
description: 'Name of the package(s) you want to configure',
2729
})
28-
public name: string
30+
public packages: string[]
2931

3032
/**
3133
* Configure encore
3234
*/
3335
private async configureEncore() {
34-
const { files, logger } = await import('@adonisjs/sink')
35-
3636
/**
3737
* Create the webpack config file
3838
*/
@@ -55,6 +55,9 @@ export default class Configure extends BaseCommand {
5555
logger.action('create').succeeded('resources/js/app.js')
5656
}
5757

58+
/**
59+
* Install Encore
60+
*/
5861
const pkgFile = new files.PackageJsonFile(this.application.appRoot)
5962
pkgFile.install('@symfony/webpack-encore')
6063

@@ -70,23 +73,120 @@ export default class Configure extends BaseCommand {
7073
}
7174

7275
/**
73-
* Invoked automatically by ace
76+
* Configure tests
7477
*/
75-
public async run() {
76-
if (this.name === 'encore') {
77-
await this.configureEncore()
78-
return
78+
private async configureTests() {
79+
/**
80+
* Create "test.ts" file
81+
*/
82+
const testsEntryPointFile = new files.MustacheFile(
83+
this.application.appRoot,
84+
'test.ts',
85+
join(__dirname, '..', 'templates/test-entrypoint.txt')
86+
)
87+
if (!testsEntryPointFile.exists()) {
88+
testsEntryPointFile.apply({}).commit()
89+
logger.action('create').succeeded('test.ts')
90+
}
91+
92+
/**
93+
* Create "tests/bootstrap.ts" file
94+
*/
95+
const testsBootstrapFile = new files.MustacheFile(
96+
this.application.appRoot,
97+
'tests/bootstrap.ts',
98+
join(__dirname, '..', 'templates/tests/bootstrap.txt')
99+
)
100+
if (!testsBootstrapFile.exists()) {
101+
testsBootstrapFile.apply({}).commit()
102+
logger.action('create').succeeded('tests/bootstrap.ts')
79103
}
80104

81-
const { tasks } = await import('@adonisjs/sink')
105+
/**
106+
* Create "tests/functional/hello-world.spec.ts" file
107+
*/
108+
const helloWorldTestFile = new files.MustacheFile(
109+
this.application.appRoot,
110+
'tests/functional/hello-world.spec.ts',
111+
join(__dirname, '..', 'templates/tests/functional/hello-world.spec.txt')
112+
)
113+
if (!helloWorldTestFile.exists()) {
114+
helloWorldTestFile.apply({}).commit()
115+
logger.action('create').succeeded('tests/functional/hello-world.spec.ts')
116+
}
82117

83-
await new tasks.Instructions(
84-
this.name,
118+
/**
119+
* Create "contracts/tests.ts" file
120+
*/
121+
const testsContractsFile = new files.MustacheFile(
85122
this.application.appRoot,
86-
this.application,
87-
true
88-
).execute()
123+
'contracts/tests.ts',
124+
join(__dirname, '..', 'templates/tests-contract.txt')
125+
)
126+
if (!testsContractsFile.exists()) {
127+
testsContractsFile.apply({}).commit()
128+
logger.action('create').succeeded('contracts/tests.ts')
129+
}
130+
131+
/**
132+
* Update AdonisRc file with test suites
133+
*/
134+
const rcFile = new files.AdonisRcFile(this.application.appRoot)
135+
rcFile.set('tests', {
136+
suites: [
137+
{
138+
name: 'functional',
139+
files: ['tests/functional/**/*.spec(.ts|.js)'],
140+
timeout: 60 * 1000,
141+
},
142+
],
143+
})
89144

145+
rcFile.commit()
146+
logger.action('update').succeeded('.adonisrc.json')
147+
148+
/**
149+
* Install required dependencies
150+
*/
151+
const pkgFile = new files.PackageJsonFile(this.application.appRoot)
152+
pkgFile.install('@japa/runner')
153+
pkgFile.install('@japa/preset-adonis')
154+
155+
const spinner = logger.await(logger.colors.gray('installing @japa/runner, @japa/preset-adonis'))
156+
157+
try {
158+
await pkgFile.commitAsync()
159+
spinner.update('Installed')
160+
} catch (error) {
161+
spinner.update('Unable to install packages')
162+
logger.fatal(error)
163+
}
164+
}
165+
166+
/**
167+
* Configure a give package
168+
*/
169+
private async configurePackage(name: string) {
170+
if (name === 'encore') {
171+
await this.configureEncore()
172+
return
173+
}
174+
175+
if (name === 'tests') {
176+
await this.configureTests()
177+
return
178+
}
179+
180+
await new tasks.Instructions(name, this.application.appRoot, this.application, true).execute()
90181
await new Manifest(this.application.appRoot, this.logger).generate()
91182
}
183+
184+
/**
185+
* Invoked automatically by ace
186+
*/
187+
public async run() {
188+
for (let name of this.packages) {
189+
await this.configurePackage(name)
190+
}
191+
}
92192
}

templates/test-entrypoint.txt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
|--------------------------------------------------------------------------
3+
| Tests
4+
|--------------------------------------------------------------------------
5+
|
6+
| The contents in this file boots the AdonisJS application and configures
7+
| the Japa tests runner.
8+
|
9+
| For the most part you will never edit this file. The configuration
10+
| for the tests can be controlled via ".adonisrc.json" and
11+
| "tests/bootstrap.ts" files.
12+
|
13+
*/
14+
15+
process.env.NODE_ENV = 'testing'
16+
17+
import 'reflect-metadata'
18+
import sourceMapSupport from 'source-map-support'
19+
import { Ignitor } from '@adonisjs/core/build/standalone'
20+
import { configure, processCliArgs, run, RunnerHooksHandler } from '@japa/runner'
21+
22+
sourceMapSupport.install({ handleUncaughtExceptions: false })
23+
24+
const kernel = new Ignitor(__dirname).kernel('test')
25+
26+
kernel
27+
.boot()
28+
.then(() => import('./tests/bootstrap'))
29+
.then(({ runnerHooks, ...config }) => {
30+
const app: RunnerHooksHandler[] = [() => kernel.start()]
31+
32+
configure({
33+
...kernel.application.rcFile.tests,
34+
...processCliArgs(process.argv.slice(2)),
35+
...config,
36+
...{
37+
importer: (filePath) => import(filePath),
38+
setup: app.concat(runnerHooks.setup),
39+
teardown: runnerHooks.teardown,
40+
},
41+
cwd: kernel.application.appRoot
42+
})
43+
44+
run()
45+
})

templates/tests-contract.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Contract source: https://github.com/adonisjs/core/blob/master/templates/contracts/tests.txt
3+
*
4+
* Feel free to let us know via PR, if you find something broken in this contract
5+
* file.
6+
*/
7+
8+
import '@japa/runner'
9+
10+
declare module '@japa/runner' {
11+
interface TestContext {
12+
// Extend context
13+
}
14+
15+
interface Test<DataSet> {
16+
// Extend test
17+
}
18+
}

templates/tests/bootstrap.txt

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* File source: https://bit.ly/3BUZKtR
3+
*
4+
* Feel free to let us know via PR, if you find something broken in this contract
5+
* file.
6+
*/
7+
8+
import type { Config } from '@japa/runner'
9+
import TestUtils from '@ioc:Adonis/Core/TestUtils'
10+
import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis'
11+
12+
/*
13+
|--------------------------------------------------------------------------
14+
| Japa Plugins
15+
|--------------------------------------------------------------------------
16+
|
17+
| Japa plugins allows you to add additional features to Japa. By default
18+
| we register the assertion plugin.
19+
|
20+
| Feel free to remove existing plugins or add more.
21+
|
22+
*/
23+
export const plugins: Config['plugins'] = [assert(), runFailedTests(), apiClient()]
24+
25+
/*
26+
|--------------------------------------------------------------------------
27+
| Japa Reporters
28+
|--------------------------------------------------------------------------
29+
|
30+
| Japa reporters displays/saves the progress of tests as they are executed.
31+
| By default, we register the spec reporter to show a detailed report
32+
| of tests on the terminal.
33+
|
34+
*/
35+
export const reporters: Config['reporters'] = [specReporter()]
36+
37+
/*
38+
|--------------------------------------------------------------------------
39+
| Runner hooks
40+
|--------------------------------------------------------------------------
41+
|
42+
| Runner hooks are executed after booting the AdonisJS app and
43+
| before the test files are imported.
44+
|
45+
| You can perform actions like starting the HTTP server or running migrations
46+
| within the runner hooks
47+
|
48+
*/
49+
export const runnerHooks: Required<Pick<Config, 'setup' | 'teardown'>> = {
50+
setup: [() => TestUtils.ace().loadCommands()],
51+
teardown: [],
52+
}
53+
54+
/*
55+
|--------------------------------------------------------------------------
56+
| Configure individual suites
57+
|--------------------------------------------------------------------------
58+
|
59+
| The configureSuite method gets called for every test suite registered
60+
| within ".adonisrc.json" file.
61+
|
62+
| You can use this method to configure suites. For example: Only start
63+
| the HTTP server when it is a functional suite.
64+
*/
65+
export const configureSuite: Config['configureSuite'] = (suite) => {
66+
if (suite.name === 'functional') {
67+
suite.setup(() => TestUtils.httpServer().start())
68+
}
69+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '@japa/runner'
2+
3+
test('display welcome page', async ({ client }) => {
4+
const response = await client.get('/')
5+
6+
response.assertStatus(200)
7+
response.assertTextIncludes('<h1 class="title"> It Works! </h1>')
8+
})

0 commit comments

Comments
 (0)