Skip to content

Commit 018da9d

Browse files
authored
feat: add make:suite command (#48)
1 parent f7a3069 commit 018da9d

File tree

2 files changed

+250
-0
lines changed

2 files changed

+250
-0
lines changed

commands/Make/Suite.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) AdonisJS
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { BaseCommand, args, flags } from '@adonisjs/core/build/standalone'
11+
import { files, logger } from '@adonisjs/sink'
12+
import globParent from 'glob-parent'
13+
import { join } from 'path'
14+
15+
/**
16+
* Create a new test suite
17+
*/
18+
export default class CreateSuite extends BaseCommand {
19+
public static commandName = 'make:suite'
20+
public static description = 'Create a new test suite'
21+
22+
/**
23+
* Name of the test suite to be created
24+
*/
25+
@args.string({ description: 'Name of the test suite' })
26+
public suite: string
27+
28+
/**
29+
* Glob pattern for the test suite, or only location to the test suite
30+
*/
31+
@args.string({ description: 'Path to the test suite directory', required: false })
32+
public location: string = ''
33+
34+
/**
35+
* Should add a sample test file
36+
*/
37+
@flags.boolean({ description: 'Add a sample test file' })
38+
public withExampleTest: boolean = true
39+
40+
/**
41+
* Get the destination path for the sample test file
42+
*/
43+
private getExampleTestDestinationPath() {
44+
return globParent(this.location) + '/test.spec.ts'
45+
}
46+
47+
/**
48+
* Generate suite glob pattern based on `location` argument
49+
*/
50+
private generateSuiteGlobPattern() {
51+
if (!this.location) {
52+
this.location = `tests/${this.suite}`
53+
}
54+
55+
if (!['*', '.js', '.ts'].find((keyword) => this.location.includes(keyword))) {
56+
this.location = `${this.location}/**/*.spec(.ts|.js)`
57+
}
58+
}
59+
60+
/**
61+
* Check if the suite name is already defined in RcFile
62+
*/
63+
private checkIfSuiteExists(rcFile: files.AdonisRcFile) {
64+
const existingSuites = rcFile.get('tests.suites') || []
65+
const existingSuitesNames = existingSuites.map((suite) => suite.name)
66+
67+
return existingSuitesNames.includes(this.suite)
68+
}
69+
70+
/**
71+
* Add the new test suite to the AdonisRC File and save it
72+
*/
73+
private async addSuiteToRcFile() {
74+
const rcFile = new files.AdonisRcFile(this.application.appRoot)
75+
const existingSuites = rcFile.get('tests.suites') || []
76+
77+
if (this.checkIfSuiteExists(rcFile)) {
78+
return logger.action('update').skipped(`Suite ${this.suite} already exists`)
79+
}
80+
81+
rcFile.set('tests.suites', [
82+
...existingSuites,
83+
{
84+
name: this.suite,
85+
files: [this.location],
86+
timeout: 60 * 1000,
87+
},
88+
])
89+
90+
rcFile.commit()
91+
logger.action('update').succeeded('.adonisrc.json')
92+
}
93+
94+
/**
95+
* Add a sample test file to the new suite folder
96+
*/
97+
private createSampleTestFile() {
98+
const path = this.getExampleTestDestinationPath()
99+
const testFile = new files.MustacheFile(
100+
this.application.appRoot,
101+
path,
102+
join(__dirname, '../..', 'templates/test.txt')
103+
)
104+
105+
if (!testFile.exists()) {
106+
testFile.apply({}).commit()
107+
logger.action('create').succeeded(path)
108+
}
109+
}
110+
111+
public async run() {
112+
this.generateSuiteGlobPattern()
113+
114+
await this.addSuiteToRcFile()
115+
116+
if (this.withExampleTest) {
117+
this.createSampleTestFile()
118+
}
119+
}
120+
}

test/make-suite.spec.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* @adonisjs/assembler
3+
*
4+
* (c) AdonisJS
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
import { test } from '@japa/runner'
11+
import { join } from 'path'
12+
import { Kernel } from '@adonisjs/ace'
13+
import { Filesystem } from '@poppinss/dev-utils'
14+
import { Application } from '@adonisjs/application'
15+
import { files } from '@adonisjs/sink'
16+
import CreateSuite from '../commands/Make/Suite'
17+
18+
const fs = new Filesystem(join(__dirname, '__app'))
19+
20+
test.group('Make Suite', (group) => {
21+
group.each.teardown(async () => {
22+
await fs.cleanup()
23+
})
24+
25+
test('Should add suite to RcFile and create sample test', async ({ assert }) => {
26+
await fs.ensureRoot()
27+
const app = new Application(fs.basePath, 'test', {})
28+
const suiteName = 'my-super-suite'
29+
const createSuite = new CreateSuite(app, new Kernel(app).mockConsoleOutput())
30+
31+
createSuite.suite = suiteName
32+
await createSuite.run()
33+
34+
const sampleTestExist = fs.fsExtra.pathExistsSync(
35+
join(fs.basePath, `tests/${suiteName}/test.spec.ts`)
36+
)
37+
assert.isTrue(sampleTestExist)
38+
39+
const rcFile = new files.AdonisRcFile(fs.basePath)
40+
assert.deepEqual(rcFile.get('tests.suites'), [
41+
{
42+
name: suiteName,
43+
files: [`tests/${suiteName}/**/*.spec(.ts|.js)`],
44+
timeout: 60000,
45+
},
46+
])
47+
})
48+
49+
test("Shouldn't add suite to RcFile if it already exists", async ({ assert }) => {
50+
await fs.ensureRoot()
51+
const app = new Application(fs.basePath, 'test', {})
52+
const suiteName = 'my-super-suite'
53+
const createSuite = new CreateSuite(app, new Kernel(app).mockConsoleOutput())
54+
55+
createSuite.suite = suiteName
56+
await createSuite.run()
57+
await createSuite.run()
58+
await createSuite.run()
59+
60+
const rcFile = new files.AdonisRcFile(fs.basePath)
61+
assert.deepEqual(rcFile.get('tests.suites'), [
62+
{
63+
name: suiteName,
64+
files: [`tests/${suiteName}/**/*.spec(.ts|.js)`],
65+
timeout: 60000,
66+
},
67+
])
68+
})
69+
70+
test("Shouldn't add a sample file if specified", async ({ assert }) => {
71+
await fs.ensureRoot()
72+
const app = new Application(fs.basePath, 'test', {})
73+
74+
const suiteName = 'my-super-suite'
75+
const createSuite = new CreateSuite(app, new Kernel(app).mockConsoleOutput())
76+
77+
createSuite.suite = suiteName
78+
createSuite.withExampleTest = false
79+
await createSuite.run()
80+
81+
const sampleTestExist = fs.fsExtra.pathExistsSync(
82+
join(fs.basePath, `tests/${suiteName}/test.spec.ts`)
83+
)
84+
85+
assert.isFalse(sampleTestExist)
86+
})
87+
88+
test('Custom location - {location}')
89+
.with([
90+
{ location: 'tests/unit/**.spec.ts', filePath: 'tests/unit/test.spec.ts' },
91+
{ location: 'tests/a/**/*.spec.ts', filePath: 'tests/a/test.spec.ts' },
92+
{
93+
location: 'tests/a/b/c/**.spec.ts',
94+
filePath: 'tests/a/b/c/test.spec.ts',
95+
},
96+
{
97+
location: 'tests/my-tests',
98+
globPattern: 'tests/my-tests/**/*.spec(.ts|.js)',
99+
filePath: 'tests/my-tests/test.spec.ts',
100+
},
101+
{
102+
location: '',
103+
globPattern: 'tests/my-super-suite/**/*.spec(.ts|.js)',
104+
filePath: 'tests/my-super-suite/test.spec.ts',
105+
},
106+
])
107+
.run(async ({ assert }, { location, filePath, globPattern }) => {
108+
await fs.ensureRoot()
109+
const app = new Application(fs.basePath, 'test', {})
110+
const suiteName = 'my-super-suite'
111+
const createSuite = new CreateSuite(app, new Kernel(app).mockConsoleOutput())
112+
113+
createSuite.suite = suiteName
114+
createSuite.location = location
115+
116+
await createSuite.run()
117+
118+
const sampleTestExist = fs.fsExtra.pathExistsSync(join(fs.basePath, filePath))
119+
assert.isTrue(sampleTestExist)
120+
121+
const rcFile = new files.AdonisRcFile(fs.basePath)
122+
assert.deepEqual(rcFile.get('tests.suites'), [
123+
{
124+
name: suiteName,
125+
files: [globPattern || location],
126+
timeout: 60000,
127+
},
128+
])
129+
})
130+
})

0 commit comments

Comments
 (0)