From dbc1d3176d1ba996740cdaf86b3c3c8992fe2060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Mon, 30 May 2022 20:36:45 -0300 Subject: [PATCH 1/7] feat(commands): add test and make:test commands --- package.json | 2 +- src/Commands/Make/Test.js | 68 +++++++++++++++++++++++++ src/Commands/Test.js | 75 ++++++++++++++++++++++++++++ src/Helpers/ArtisanLoader.js | 1 + templates/__name__Test.js.ejs | 7 +++ tests/Unit/Commands/Make/TestTest.js | 65 ++++++++++++++++++++++++ 6 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/Commands/Make/Test.js create mode 100644 src/Commands/Test.js create mode 100644 templates/__name__Test.js.ejs create mode 100644 tests/Unit/Commands/Make/TestTest.js diff --git a/package.json b/package.json index bf26215..eeb76ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/artisan", - "version": "1.1.9", + "version": "1.2.0", "description": "The Athenna CLI application. Built on top of commander.", "license": "MIT", "author": "João Lenon ", diff --git a/src/Commands/Make/Test.js b/src/Commands/Make/Test.js new file mode 100644 index 0000000..5fd6256 --- /dev/null +++ b/src/Commands/Make/Test.js @@ -0,0 +1,68 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Path } from '@secjs/utils' +import { Artisan, Command } from '#src/index' +import { TemplateHelper } from '#src/Helpers/TemplateHelper' + +export class MakeTest extends Command { + /** + * The name and signature of the console command. + */ + signature = 'make:test ' + + /** + * The console command description. + */ + description = 'Make a new test file.' + + /** + * Set additional flags in the commander instance. + * This method is executed when registering your command. + * + * @param {import('commander').Command} commander + * @return {import('commander').Command} + */ + addFlags(commander) { + return commander + .option('-u, --unit', 'Create the test inside unit folder.', false) + .option('--no-lint', 'Do not run eslint in the facade.', true) + } + + /** + * Execute the console command. + * + * @param {string} name + * @param {any} options + * @return {Promise} + */ + async handle(name, options) { + const resource = 'Test' + let subPath = Path.tests('E2E') + + if (options.unit) { + subPath = Path.tests('Unit') + } + + this.simpleLog( + `[ MAKING ${resource.toUpperCase()} ]\n`, + 'rmNewLineStart', + 'bold', + 'green', + ) + + const file = await TemplateHelper.getResourceFile(name, resource, subPath) + + this.success(`${resource} ({yellow} "${file.name}") successfully created.`) + + if (options.lint) { + await Artisan.call(`eslint:fix ${file.path} --resource ${resource}`) + } + } +} diff --git a/src/Commands/Test.js b/src/Commands/Test.js new file mode 100644 index 0000000..2c6f377 --- /dev/null +++ b/src/Commands/Test.js @@ -0,0 +1,75 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Path } from '@secjs/utils' + +import { Command } from '#src/index' +import { parse } from 'node:path' +import nodemon from 'nodemon' +import { pathToFileURL } from 'node:url' + +export class Test extends Command { + /** + * The name and signature of the console command. + */ + signature = 'test' + + /** + * The console command description. + */ + description = 'Run the tests of Athenna application.' + + /** + * Set additional flags in the commander instance. + * This method is executed when registering your command. + * + * @param {import('commander').Command} commander + * @return {import('commander').Command} + */ + addFlags(commander) { + return commander + .option('--c8-args', 'Arguments for c8 cli if needed.', '') + .option('--japa-args', 'Arguments for japa cli if needed.', '') + .option('--coverage', 'Coverage the code lines using c8 library.', false) + .option('--debug', 'Enable debug mode to see more logs.', false) + .option('--unit', 'Run unit tests.', false) + .option('--e2e', 'Run e2e tests.', false) + } + + /** + * Execute the console command. + * + * @params {any} options + * @return {Promise} + */ + async handle(options) { + process.env.BOOT_LOGS = 'false' + let command = '' + + if (options.coverage) { + command = command.concat(`${Path.bin('c8')} ${options.c8Args} `) + } + + if (options.debug) { + command = command.concat(`${Path.bin('cross-env')} DEBUG=api:* && `) + } + + command = command.concat(`node ${Path.tests('main.js')} `) + + if (options.unit) { + command = command.concat('Unit ') + } + + if (options.e2e) { + command = command.concat('E2E ') + } + + await this.execCommand(command) + } +} diff --git a/src/Helpers/ArtisanLoader.js b/src/Helpers/ArtisanLoader.js index fbaecd4..eae55d5 100644 --- a/src/Helpers/ArtisanLoader.js +++ b/src/Helpers/ArtisanLoader.js @@ -23,6 +23,7 @@ export class ArtisanLoader { import('#src/Commands/List'), import('#src/Commands/Serve'), import('#src/Commands/Eslint/Fix'), + import('#src/Commands/Make/Test'), import('#src/Commands/Make/Facade'), import('#src/Commands/Make/Service'), import('#src/Commands/Make/Command'), diff --git a/templates/__name__Test.js.ejs b/templates/__name__Test.js.ejs new file mode 100644 index 0000000..5ac63d7 --- /dev/null +++ b/templates/__name__Test.js.ejs @@ -0,0 +1,7 @@ +import { test } from '@japa/runner' + +test.group('<%= namePascal %>Test', () => { + test('should be able to run tests', async ({ assert }) => { + assert.equal(2 + 2, 4) + }) +}) diff --git a/tests/Unit/Commands/Make/TestTest.js b/tests/Unit/Commands/Make/TestTest.js new file mode 100644 index 0000000..519ca1f --- /dev/null +++ b/tests/Unit/Commands/Make/TestTest.js @@ -0,0 +1,65 @@ +/** + * @athenna/artisan + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { test } from '@japa/runner' +import { Config, File, Folder, Path } from '@secjs/utils' + +import { Artisan } from '#src/index' +import { Kernel } from '#tests/Stubs/app/Console/Kernel' +import { ArtisanProvider } from '#src/Providers/ArtisanProvider' +import { LoggerProvider } from '@athenna/logger/providers/LoggerProvider' + +test.group('MakeTestTest', group => { + group.each.setup(async () => { + await new Folder(Path.stubs('app')).copy(Path.app()) + await new Folder(Path.stubs('config')).copy(Path.config()) + + await new Config().safeLoad(Path.config('app.js')) + await new Config().safeLoad(Path.config('logging.js')) + + new LoggerProvider().register() + new ArtisanProvider().register() + + const kernel = new Kernel() + + await kernel.registerErrorHandler() + await kernel.registerCommands() + }) + + group.each.teardown(async () => { + await Folder.safeRemove(Path.app()) + await Folder.safeRemove(Path.config()) + await Folder.safeRemove(Path.providers()) + }) + + test('should be able to create a test file', async ({ assert }) => { + await Artisan.call('make:test FeatureTest') + + const path = Path.tests('E2E/FeatureTest.js') + + assert.isTrue(await File.exists(path)) + + await File.safeRemove(path) + }).timeout(60000) + + test('should be able to create a unit test file', async ({ assert }) => { + await Artisan.call('make:test --unit UnitTest') + + const path = Path.tests('Unit/UnitTest.js') + + assert.isTrue(await File.exists(path)) + + await File.safeRemove(path) + }).timeout(60000) + + test('should throw an error when the file already exists', async ({ assert }) => { + await Artisan.call('make:test TestTest') + await Artisan.call('make:test TestTest') + }).timeout(60000) +}) From ed981efc8be9c43487a8e6e408c9d5e04744844c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Mon, 30 May 2022 20:36:59 -0300 Subject: [PATCH 2/7] feat(commands): add test and make:test commands --- src/Commands/Test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Commands/Test.js b/src/Commands/Test.js index 2c6f377..a768777 100644 --- a/src/Commands/Test.js +++ b/src/Commands/Test.js @@ -10,9 +10,6 @@ import { Path } from '@secjs/utils' import { Command } from '#src/index' -import { parse } from 'node:path' -import nodemon from 'nodemon' -import { pathToFileURL } from 'node:url' export class Test extends Command { /** From d0e14fa97523f8afb29d385837d5087104027bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Fri, 10 Jun 2022 11:48:30 -0300 Subject: [PATCH 3/7] feat(commands): add c8/japa arguments to test command --- src/Commands/Test.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Commands/Test.js b/src/Commands/Test.js index a768777..74c4822 100644 --- a/src/Commands/Test.js +++ b/src/Commands/Test.js @@ -31,8 +31,8 @@ export class Test extends Command { */ addFlags(commander) { return commander - .option('--c8-args', 'Arguments for c8 cli if needed.', '') - .option('--japa-args', 'Arguments for japa cli if needed.', '') + .option('--c8-args', 'Arguments for c8 cli if needed.', null) + .option('--japa-args', 'Arguments for japa cli if needed.', null) .option('--coverage', 'Coverage the code lines using c8 library.', false) .option('--debug', 'Enable debug mode to see more logs.', false) .option('--unit', 'Run unit tests.', false) @@ -50,7 +50,11 @@ export class Test extends Command { let command = '' if (options.coverage) { - command = command.concat(`${Path.bin('c8')} ${options.c8Args} `) + command = command.concat(`${Path.bin('c8')} `) + + if (options.c8Args) { + command = command.concat(options.c8Args, ' ') + } } if (options.debug) { @@ -67,6 +71,10 @@ export class Test extends Command { command = command.concat('E2E ') } + if (options.japaArgs) { + command = command.concat(options.japaArgs, ' ') + } + await this.execCommand(command) } } From 1d06e0d25a0441e32a739549493fe1ebd2bede12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Sat, 11 Jun 2022 11:15:03 -0300 Subject: [PATCH 4/7] feat(commands): add run test command to artisan loader --- src/Helpers/ArtisanLoader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Helpers/ArtisanLoader.js b/src/Helpers/ArtisanLoader.js index eae55d5..b8b5ffa 100644 --- a/src/Helpers/ArtisanLoader.js +++ b/src/Helpers/ArtisanLoader.js @@ -20,6 +20,7 @@ export class ArtisanLoader { */ static loadConsole() { return [ + import('#src/Commands/Test'), import('#src/Commands/List'), import('#src/Commands/Serve'), import('#src/Commands/Eslint/Fix'), From b5b08f090237810b59c01d31e77c262d89d5a7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Sat, 11 Jun 2022 11:47:58 -0300 Subject: [PATCH 5/7] refactor(artisan): make artisan return commander instance on call method --- src/index.d.ts | 4 ++-- src/index.js | 4 ++-- tests/E2E/Test.js | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 tests/E2E/Test.js diff --git a/src/index.d.ts b/src/index.d.ts index ffe5b1f..713c67b 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -274,9 +274,9 @@ export class ArtisanImpl { * Call any command from Artisan. * * @param {string} command - * @return Promise + * @return Promise */ - call(command: string): Promise + call(command: string): Promise /** * List all commands with description. diff --git a/src/index.js b/src/index.js index f3c546c..ec7d2b8 100644 --- a/src/index.js +++ b/src/index.js @@ -72,10 +72,10 @@ export class ArtisanImpl { * Call any command from Artisan. * * @param {string} command - * @return Promise + * @return Promise */ async call(command) { - await this.#commander.parseAsync([ + return this.#commander.parseAsync([ 'node', // This will be ignored by commander 'artisan', // This will be ignored by commander ...command.split(' '), diff --git a/tests/E2E/Test.js b/tests/E2E/Test.js new file mode 100644 index 0000000..c648d9c --- /dev/null +++ b/tests/E2E/Test.js @@ -0,0 +1,7 @@ +import { test } from '@japa/runner' + +test.group('Test', () => { + test('should be able to run tests', async ({ assert }) => { + assert.equal(2 + 2, 4) + }) +}) From 8be61399fe2f64650644296475c4639e6ec5e57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Sat, 11 Jun 2022 11:53:15 -0300 Subject: [PATCH 6/7] fix(test): safe remove E2E testing folder --- tests/E2E/Test.js | 7 ------- tests/Unit/Commands/Make/TestTest.js | 4 +++- 2 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 tests/E2E/Test.js diff --git a/tests/E2E/Test.js b/tests/E2E/Test.js deleted file mode 100644 index c648d9c..0000000 --- a/tests/E2E/Test.js +++ /dev/null @@ -1,7 +0,0 @@ -import { test } from '@japa/runner' - -test.group('Test', () => { - test('should be able to run tests', async ({ assert }) => { - assert.equal(2 + 2, 4) - }) -}) diff --git a/tests/Unit/Commands/Make/TestTest.js b/tests/Unit/Commands/Make/TestTest.js index 519ca1f..3172831 100644 --- a/tests/Unit/Commands/Make/TestTest.js +++ b/tests/Unit/Commands/Make/TestTest.js @@ -45,7 +45,7 @@ test.group('MakeTestTest', group => { assert.isTrue(await File.exists(path)) - await File.safeRemove(path) + await Folder.safeRemove(Path.tests('E2E')) }).timeout(60000) test('should be able to create a unit test file', async ({ assert }) => { @@ -61,5 +61,7 @@ test.group('MakeTestTest', group => { test('should throw an error when the file already exists', async ({ assert }) => { await Artisan.call('make:test TestTest') await Artisan.call('make:test TestTest') + + await Folder.safeRemove(Path.tests('E2E')) }).timeout(60000) }) From 067811b7e6a84c54c93364b6f92fe3fe1ed00adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lenon?= Date: Fri, 17 Jun 2022 22:57:58 -0300 Subject: [PATCH 7/7] feat(commander): add setCommander method in Artisan --- src/index.d.ts | 7 +++++++ src/index.js | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/index.d.ts b/src/index.d.ts index 713c67b..d07a583 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -305,6 +305,13 @@ export class ArtisanImpl { */ getCommander(): Commander + /** + * Set the commander instance of Artisan. + * + * @return {import('commander').Command} + */ + setCommander(commander: Commander): void + /** * Register the command inside commander instance. * diff --git a/src/index.js b/src/index.js index ec7d2b8..4764f5e 100644 --- a/src/index.js +++ b/src/index.js @@ -146,6 +146,16 @@ export class ArtisanImpl { return this.#commander } + /** + * Set the commander instance of Artisan. + * + * @param {import('commander').Command} commander + * @return {void} + */ + setCommander(commander) { + this.#commander = commander + } + /** * Register the command inside commander instance. *