From 7992fe5b634a36c38dfa61a4a0d11150ff87ecaa Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 1 Nov 2022 15:28:14 +0000 Subject: [PATCH] Tools: Setup test framework for CLI app --- .eslintignore | 12 ++ .gitignore | 12 ++ packages/app-cli/app/app.js | 44 +--- packages/app-cli/app/base-command.js | 190 +++++++++--------- packages/app-cli/app/base-command.ts | 95 +++++++++ packages/app-cli/app/command-apidoc.js | 2 +- packages/app-cli/app/command-attach.js | 2 +- packages/app-cli/app/command-batch.js | 2 +- packages/app-cli/app/command-cat.js | 2 +- packages/app-cli/app/command-config.js | 2 +- packages/app-cli/app/command-cp.js | 2 +- packages/app-cli/app/command-done.test.ts | 27 +++ packages/app-cli/app/command-dump.js | 2 +- packages/app-cli/app/command-e2ee.ts | 2 +- packages/app-cli/app/command-edit.js | 2 +- packages/app-cli/app/command-exit.js | 2 +- .../app-cli/app/command-export-sync-status.js | 2 +- packages/app-cli/app/command-export.js | 2 +- packages/app-cli/app/command-geoloc.js | 2 +- packages/app-cli/app/command-help.js | 2 +- packages/app-cli/app/command-import.js | 2 +- packages/app-cli/app/command-ls.js | 2 +- packages/app-cli/app/command-mkbook.js | 2 +- packages/app-cli/app/command-mknote.js | 2 +- packages/app-cli/app/command-mktodo.js | 2 +- packages/app-cli/app/command-mv.js | 2 +- packages/app-cli/app/command-ren.js | 2 +- packages/app-cli/app/command-rmbook.js | 2 +- packages/app-cli/app/command-rmnote.js | 2 +- packages/app-cli/app/command-search.js | 2 +- packages/app-cli/app/command-server.js | 2 +- packages/app-cli/app/command-set.js | 2 +- packages/app-cli/app/command-settingschema.ts | 2 +- packages/app-cli/app/command-status.js | 2 +- packages/app-cli/app/command-sync.ts | 2 +- packages/app-cli/app/command-tag.js | 2 +- packages/app-cli/app/command-testing.ts | 2 +- packages/app-cli/app/command-todo.js | 2 +- packages/app-cli/app/command-undone.js | 2 +- packages/app-cli/app/command-use.js | 2 +- packages/app-cli/app/command-version.js | 2 +- packages/app-cli/app/setupCommand.ts | 39 ++++ packages/app-cli/app/utils/testUtils.ts | 17 ++ packages/app-cli/jest.config.js | 1 + 44 files changed, 339 insertions(+), 168 deletions(-) create mode 100644 packages/app-cli/app/base-command.ts create mode 100644 packages/app-cli/app/command-done.test.ts create mode 100644 packages/app-cli/app/setupCommand.ts create mode 100644 packages/app-cli/app/utils/testUtils.ts diff --git a/.eslintignore b/.eslintignore index 8b2f6e2c0..91c39553c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -78,6 +78,12 @@ readme/ packages/app-cli/app/LinkSelector.d.ts packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js.map +packages/app-cli/app/base-command.d.ts +packages/app-cli/app/base-command.js +packages/app-cli/app/base-command.js.map +packages/app-cli/app/command-done.test.d.ts +packages/app-cli/app/command-done.test.js +packages/app-cli/app/command-done.test.js.map packages/app-cli/app/command-e2ee.d.ts packages/app-cli/app/command-e2ee.js packages/app-cli/app/command-e2ee.js.map @@ -93,6 +99,12 @@ packages/app-cli/app/command-testing.js.map packages/app-cli/app/services/plugins/PluginRunner.d.ts packages/app-cli/app/services/plugins/PluginRunner.js packages/app-cli/app/services/plugins/PluginRunner.js.map +packages/app-cli/app/setupCommand.d.ts +packages/app-cli/app/setupCommand.js +packages/app-cli/app/setupCommand.js.map +packages/app-cli/app/utils/testUtils.d.ts +packages/app-cli/app/utils/testUtils.js +packages/app-cli/app/utils/testUtils.js.map packages/app-cli/tests/HtmlToMd.d.ts packages/app-cli/tests/HtmlToMd.js packages/app-cli/tests/HtmlToMd.js.map diff --git a/.gitignore b/.gitignore index f2b576562..e5bb6c40a 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,12 @@ docs/**/*.mustache packages/app-cli/app/LinkSelector.d.ts packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js.map +packages/app-cli/app/base-command.d.ts +packages/app-cli/app/base-command.js +packages/app-cli/app/base-command.js.map +packages/app-cli/app/command-done.test.d.ts +packages/app-cli/app/command-done.test.js +packages/app-cli/app/command-done.test.js.map packages/app-cli/app/command-e2ee.d.ts packages/app-cli/app/command-e2ee.js packages/app-cli/app/command-e2ee.js.map @@ -81,6 +87,12 @@ packages/app-cli/app/command-testing.js.map packages/app-cli/app/services/plugins/PluginRunner.d.ts packages/app-cli/app/services/plugins/PluginRunner.js packages/app-cli/app/services/plugins/PluginRunner.js.map +packages/app-cli/app/setupCommand.d.ts +packages/app-cli/app/setupCommand.js +packages/app-cli/app/setupCommand.js.map +packages/app-cli/app/utils/testUtils.d.ts +packages/app-cli/app/utils/testUtils.js +packages/app-cli/app/utils/testUtils.js.map packages/app-cli/tests/HtmlToMd.d.ts packages/app-cli/tests/HtmlToMd.js packages/app-cli/tests/HtmlToMd.js.map diff --git a/packages/app-cli/app/app.js b/packages/app-cli/app/app.js index 6f6824fcf..8fd887764 100644 --- a/packages/app-cli/app/app.js +++ b/packages/app-cli/app/app.js @@ -16,6 +16,7 @@ const { cliUtils } = require('./cli-utils.js'); const Cache = require('@joplin/lib/Cache'); const RevisionService = require('@joplin/lib/services/RevisionService').default; const shim = require('@joplin/lib/shim').default; +const setupCommand = require('./setupCommand').default; class Application extends BaseApplication { constructor() { @@ -114,46 +115,12 @@ class Application extends BaseApplication { return []; } - stdout(text) { - return this.gui().stdout(text); + setupCommand(cmd) { + return setupCommand(cmd, t => this.stdout(t), () => this.store(), () => this.gui()); } - setupCommand(cmd) { - cmd.setStdout(text => { - return this.stdout(text); - }); - - cmd.setDispatcher(action => { - if (this.store()) { - return this.store().dispatch(action); - } else { - return () => {}; - } - }); - - cmd.setPrompt(async (message, options) => { - if (!options) options = {}; - if (!options.type) options.type = 'boolean'; - if (!options.booleanAnswerDefault) options.booleanAnswerDefault = 'y'; - if (!options.answers) options.answers = options.booleanAnswerDefault === 'y' ? [_('Y'), _('n')] : [_('N'), _('y')]; - - if (options.type === 'boolean') { - message += ` (${options.answers.join('/')})`; - } - - let answer = await this.gui().prompt('', `${message} `, options); - - if (options.type === 'boolean') { - if (answer === null) return false; // Pressed ESCAPE - if (!answer) answer = options.answers[0]; - const positiveIndex = options.booleanAnswerDefault === 'y' ? 0 : 1; - return answer.toLowerCase() === options.answers[positiveIndex].toLowerCase(); - } else { - return answer; - } - }); - - return cmd; + stdout(text) { + return this.gui().stdout(text); } async exit(code = 0) { @@ -180,6 +147,7 @@ class Application extends BaseApplication { if (!this.allCommandsLoaded_) { fs.readdirSync(__dirname).forEach(path => { if (path.indexOf('command-') !== 0) return; + if (path.endsWith('.test.js')) return; const ext = fileExtension(path); if (ext !== 'js') return; diff --git a/packages/app-cli/app/base-command.js b/packages/app-cli/app/base-command.js index 63cf4f1c1..682ae33a9 100644 --- a/packages/app-cli/app/base-command.js +++ b/packages/app-cli/app/base-command.js @@ -1,97 +1,97 @@ -const { _ } = require('@joplin/lib/locale'); -const { reg } = require('@joplin/lib/registry.js'); - +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const locale_1 = require("@joplin/lib/locale"); +const registry_js_1 = require("@joplin/lib/registry.js"); class BaseCommand { - constructor() { - this.stdout_ = null; - this.prompt_ = null; - } - - usage() { - throw new Error('Usage not defined'); - } - - encryptionCheck(item) { - if (item && item.encryption_applied) throw new Error(_('Cannot change encrypted item')); - } - - description() { - throw new Error('Description not defined'); - } - - async action() { - throw new Error('Action not defined'); - } - - compatibleUis() { - return ['cli', 'gui']; - } - - supportsUi(ui) { - return this.compatibleUis().indexOf(ui) >= 0; - } - - options() { - return []; - } - - hidden() { - return false; - } - - enabled() { - return true; - } - - cancellable() { - return false; - } - - async cancel() {} - - name() { - const r = this.usage().split(' '); - return r[0]; - } - - setDispatcher(fn) { - this.dispatcher_ = fn; - } - - dispatch(action) { - if (!this.dispatcher_) throw new Error('Dispatcher not defined'); - return this.dispatcher_(action); - } - - setStdout(fn) { - this.stdout_ = fn; - } - - stdout(text) { - if (this.stdout_) this.stdout_(text); - } - - setPrompt(fn) { - this.prompt_ = fn; - } - - async prompt(message, options = null) { - if (!this.prompt_) throw new Error('Prompt is undefined'); - return await this.prompt_(message, options); - } - - metadata() { - return { - name: this.name(), - usage: this.usage(), - options: this.options(), - hidden: this.hidden(), - }; - } - - logger() { - return reg.logger(); - } + constructor() { + this.stdout_ = null; + this.prompt_ = null; + } + usage() { + throw new Error('Usage not defined'); + } + encryptionCheck(item) { + if (item && item.encryption_applied) + throw new Error((0, locale_1._)('Cannot change encrypted item')); + } + description() { + throw new Error('Description not defined'); + } + action(_args) { + return __awaiter(this, void 0, void 0, function* () { + throw new Error('Action not defined'); + }); + } + compatibleUis() { + return ['cli', 'gui']; + } + supportsUi(ui) { + return this.compatibleUis().indexOf(ui) >= 0; + } + options() { + return []; + } + hidden() { + return false; + } + enabled() { + return true; + } + cancellable() { + return false; + } + cancel() { + return __awaiter(this, void 0, void 0, function* () { }); + } + name() { + const r = this.usage().split(' '); + return r[0]; + } + setDispatcher(fn) { + this.dispatcher_ = fn; + } + dispatch(action) { + if (!this.dispatcher_) + throw new Error('Dispatcher not defined'); + return this.dispatcher_(action); + } + setStdout(fn) { + this.stdout_ = fn; + } + stdout(text) { + if (this.stdout_) + this.stdout_(text); + } + setPrompt(fn) { + this.prompt_ = fn; + } + prompt(message, options = null) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.prompt_) + throw new Error('Prompt is undefined'); + return yield this.prompt_(message, options); + }); + } + metadata() { + return { + name: this.name(), + usage: this.usage(), + options: this.options(), + hidden: this.hidden(), + }; + } + logger() { + return registry_js_1.reg.logger(); + } } - -module.exports = { BaseCommand }; +exports.default = BaseCommand; +//# sourceMappingURL=base-command.js.map \ No newline at end of file diff --git a/packages/app-cli/app/base-command.ts b/packages/app-cli/app/base-command.ts new file mode 100644 index 000000000..076473a82 --- /dev/null +++ b/packages/app-cli/app/base-command.ts @@ -0,0 +1,95 @@ +import { _ } from '@joplin/lib/locale'; +import { reg } from '@joplin/lib/registry.js'; + +export default class BaseCommand { + + protected stdout_: any = null; + protected prompt_: any = null; + protected dispatcher_: any; + + usage(): string { + throw new Error('Usage not defined'); + } + + encryptionCheck(item: any) { + if (item && item.encryption_applied) throw new Error(_('Cannot change encrypted item')); + } + + description() { + throw new Error('Description not defined'); + } + + async action(_args: any) { + throw new Error('Action not defined'); + } + + compatibleUis() { + return ['cli', 'gui']; + } + + supportsUi(ui: string) { + return this.compatibleUis().indexOf(ui) >= 0; + } + + options(): any[] { + return []; + } + + hidden() { + return false; + } + + enabled() { + return true; + } + + cancellable() { + return false; + } + + async cancel() {} + + name() { + const r = this.usage().split(' '); + return r[0]; + } + + setDispatcher(fn: Function) { + this.dispatcher_ = fn; + } + + dispatch(action: any) { + if (!this.dispatcher_) throw new Error('Dispatcher not defined'); + return this.dispatcher_(action); + } + + setStdout(fn: Function) { + this.stdout_ = fn; + } + + stdout(text: string) { + if (this.stdout_) this.stdout_(text); + } + + setPrompt(fn: Function) { + this.prompt_ = fn; + } + + async prompt(message: string, options: any = null) { + if (!this.prompt_) throw new Error('Prompt is undefined'); + return await this.prompt_(message, options); + } + + metadata() { + return { + name: this.name(), + usage: this.usage(), + options: this.options(), + hidden: this.hidden(), + }; + } + + logger() { + return reg.logger(); + } +} diff --git a/packages/app-cli/app/command-apidoc.js b/packages/app-cli/app/command-apidoc.js index 9565c6181..1e802e235 100644 --- a/packages/app-cli/app/command-apidoc.js +++ b/packages/app-cli/app/command-apidoc.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const BaseItem = require('@joplin/lib/models/BaseItem').default; const BaseModel = require('@joplin/lib/BaseModel').default; const { toTitleCase } = require('@joplin/lib/string-utils.js'); diff --git a/packages/app-cli/app/command-attach.js b/packages/app-cli/app/command-attach.js index 8cc621305..1ab4e4d4c 100644 --- a/packages/app-cli/app/command-attach.js +++ b/packages/app-cli/app/command-attach.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-batch.js b/packages/app-cli/app/command-batch.js index 715e84887..dc445382e 100644 --- a/packages/app-cli/app/command-batch.js +++ b/packages/app-cli/app/command-batch.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _ } = require('@joplin/lib/locale'); class Command extends BaseCommand { diff --git a/packages/app-cli/app/command-cat.js b/packages/app-cli/app/command-cat.js index fb86fec07..5fd84b742 100644 --- a/packages/app-cli/app/command-cat.js +++ b/packages/app-cli/app/command-cat.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-config.js b/packages/app-cli/app/command-config.js index 50b626d6f..d37426d12 100644 --- a/packages/app-cli/app/command-config.js +++ b/packages/app-cli/app/command-config.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _, setLocale } = require('@joplin/lib/locale'); const { app } = require('./app.js'); const fs = require('fs-extra'); diff --git a/packages/app-cli/app/command-cp.js b/packages/app-cli/app/command-cp.js index d687bca91..02658a67e 100644 --- a/packages/app-cli/app/command-cp.js +++ b/packages/app-cli/app/command-cp.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-done.test.ts b/packages/app-cli/app/command-done.test.ts new file mode 100644 index 000000000..f9e6ec8ca --- /dev/null +++ b/packages/app-cli/app/command-done.test.ts @@ -0,0 +1,27 @@ +import Note from '@joplin/lib/models/Note'; +import { NoteEntity } from '@joplin/lib/services/database/types'; +import { setupDatabaseAndSynchronizer, switchClient } from '@joplin/lib/testing/test-utils'; +import { setupCommandForTesting, setupApplication } from './utils/testUtils'; +const Command = require('./command-done'); + +describe('command-done', () => { + + beforeEach(async () => { + await setupDatabaseAndSynchronizer(1); + await switchClient(1); + await setupApplication(); + }); + + it('should make a note as "done"', async () => { + const note = await Note.save({ title: 'hello', is_todo: 1, todo_completed: 0 }); + + const command = setupCommandForTesting(Command); + + const now = Date.now(); + await command.action({ note: note.id }); + + const checkNote: NoteEntity = await Note.load(note.id); + expect(checkNote.todo_completed).toBeGreaterThanOrEqual(now); + }); + +}); diff --git a/packages/app-cli/app/command-dump.js b/packages/app-cli/app/command-dump.js index f166226e2..844661003 100644 --- a/packages/app-cli/app/command-dump.js +++ b/packages/app-cli/app/command-dump.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const Folder = require('@joplin/lib/models/Folder').default; const Note = require('@joplin/lib/models/Note').default; const Tag = require('@joplin/lib/models/Tag').default; diff --git a/packages/app-cli/app/command-e2ee.ts b/packages/app-cli/app/command-e2ee.ts index 9bbf4669b..84a8d90af 100644 --- a/packages/app-cli/app/command-e2ee.ts +++ b/packages/app-cli/app/command-e2ee.ts @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; import { _ } from '@joplin/lib/locale'; import EncryptionService from '@joplin/lib/services/e2ee/EncryptionService'; import DecryptionWorker from '@joplin/lib/services/DecryptionWorker'; diff --git a/packages/app-cli/app/command-edit.js b/packages/app-cli/app/command-edit.js index bbb57e66a..4eca9b9e1 100644 --- a/packages/app-cli/app/command-edit.js +++ b/packages/app-cli/app/command-edit.js @@ -1,5 +1,5 @@ const fs = require('fs-extra'); -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { splitCommandString } = require('@joplin/lib/string-utils.js'); const uuid = require('@joplin/lib/uuid').default; const { app } = require('./app.js'); diff --git a/packages/app-cli/app/command-exit.js b/packages/app-cli/app/command-exit.js index 8c7d2ebda..4ba43d399 100644 --- a/packages/app-cli/app/command-exit.js +++ b/packages/app-cli/app/command-exit.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); diff --git a/packages/app-cli/app/command-export-sync-status.js b/packages/app-cli/app/command-export-sync-status.js index dde09fb67..b14353e96 100644 --- a/packages/app-cli/app/command-export-sync-status.js +++ b/packages/app-cli/app/command-export-sync-status.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const Setting = require('@joplin/lib/models/Setting').default; const ReportService = require('@joplin/lib/services/ReportService').default; diff --git a/packages/app-cli/app/command-export.js b/packages/app-cli/app/command-export.js index 16fc37f3f..588faaf5d 100644 --- a/packages/app-cli/app/command-export.js +++ b/packages/app-cli/app/command-export.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const InteropService = require('@joplin/lib/services/interop/InteropService').default; const BaseModel = require('@joplin/lib/BaseModel').default; const { app } = require('./app.js'); diff --git a/packages/app-cli/app/command-geoloc.js b/packages/app-cli/app/command-geoloc.js index e504ea701..390af96a4 100644 --- a/packages/app-cli/app/command-geoloc.js +++ b/packages/app-cli/app/command-geoloc.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-help.js b/packages/app-cli/app/command-help.js index 258b7321d..eebb816b1 100644 --- a/packages/app-cli/app/command-help.js +++ b/packages/app-cli/app/command-help.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { renderCommandHelp } = require('./help-utils.js'); const { _ } = require('@joplin/lib/locale'); diff --git a/packages/app-cli/app/command-import.js b/packages/app-cli/app/command-import.js index 77913e249..d2cbe770c 100644 --- a/packages/app-cli/app/command-import.js +++ b/packages/app-cli/app/command-import.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const InteropService = require('@joplin/lib/services/interop/InteropService').default; const BaseModel = require('@joplin/lib/BaseModel').default; const { cliUtils } = require('./cli-utils.js'); diff --git a/packages/app-cli/app/command-ls.js b/packages/app-cli/app/command-ls.js index e7687c21d..3d6c96108 100644 --- a/packages/app-cli/app/command-ls.js +++ b/packages/app-cli/app/command-ls.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-mkbook.js b/packages/app-cli/app/command-mkbook.js index 5a472e50e..9dbdaff01 100644 --- a/packages/app-cli/app/command-mkbook.js +++ b/packages/app-cli/app/command-mkbook.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Folder = require('@joplin/lib/models/Folder').default; diff --git a/packages/app-cli/app/command-mknote.js b/packages/app-cli/app/command-mknote.js index 6dabb5348..3b2a82289 100644 --- a/packages/app-cli/app/command-mknote.js +++ b/packages/app-cli/app/command-mknote.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Note = require('@joplin/lib/models/Note').default; diff --git a/packages/app-cli/app/command-mktodo.js b/packages/app-cli/app/command-mktodo.js index 37bf42f13..986d260d0 100644 --- a/packages/app-cli/app/command-mktodo.js +++ b/packages/app-cli/app/command-mktodo.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Note = require('@joplin/lib/models/Note').default; diff --git a/packages/app-cli/app/command-mv.js b/packages/app-cli/app/command-mv.js index 5237a7316..999033eb9 100644 --- a/packages/app-cli/app/command-mv.js +++ b/packages/app-cli/app/command-mv.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-ren.js b/packages/app-cli/app/command-ren.js index 72f3a02be..0b2b7683f 100644 --- a/packages/app-cli/app/command-ren.js +++ b/packages/app-cli/app/command-ren.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-rmbook.js b/packages/app-cli/app/command-rmbook.js index 7dd65c866..77b4594f7 100644 --- a/packages/app-cli/app/command-rmbook.js +++ b/packages/app-cli/app/command-rmbook.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Folder = require('@joplin/lib/models/Folder').default; diff --git a/packages/app-cli/app/command-rmnote.js b/packages/app-cli/app/command-rmnote.js index cfa422708..bba706241 100644 --- a/packages/app-cli/app/command-rmnote.js +++ b/packages/app-cli/app/command-rmnote.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Note = require('@joplin/lib/models/Note').default; diff --git a/packages/app-cli/app/command-search.js b/packages/app-cli/app/command-search.js index 1efca2cfc..b4b0c19fa 100644 --- a/packages/app-cli/app/command-search.js +++ b/packages/app-cli/app/command-search.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; const Folder = require('@joplin/lib/models/Folder').default; diff --git a/packages/app-cli/app/command-server.js b/packages/app-cli/app/command-server.js index 34e1e3dc2..b75b21285 100644 --- a/packages/app-cli/app/command-server.js +++ b/packages/app-cli/app/command-server.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _ } = require('@joplin/lib/locale'); const Setting = require('@joplin/lib/models/Setting').default; const Logger = require('@joplin/lib/Logger').default; diff --git a/packages/app-cli/app/command-set.js b/packages/app-cli/app/command-set.js index 17ad9eaa8..2c5494de7 100644 --- a/packages/app-cli/app/command-set.js +++ b/packages/app-cli/app/command-set.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-settingschema.ts b/packages/app-cli/app/command-settingschema.ts index 3a3b28a91..65aa46578 100644 --- a/packages/app-cli/app/command-settingschema.ts +++ b/packages/app-cli/app/command-settingschema.ts @@ -2,7 +2,7 @@ import Setting, { SettingStorage } from '@joplin/lib/models/Setting'; import { SettingItemType } from '@joplin/lib/services/plugins/api/types'; import shim from '@joplin/lib/shim'; -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; function settingTypeToSchemaType(type: SettingItemType): string { const map: Record = { diff --git a/packages/app-cli/app/command-status.js b/packages/app-cli/app/command-status.js index 6ee4f9854..877307dce 100644 --- a/packages/app-cli/app/command-status.js +++ b/packages/app-cli/app/command-status.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const Setting = require('@joplin/lib/models/Setting').default; const { _ } = require('@joplin/lib/locale'); diff --git a/packages/app-cli/app/command-sync.ts b/packages/app-cli/app/command-sync.ts index 123f6066c..b4e85755b 100644 --- a/packages/app-cli/app/command-sync.ts +++ b/packages/app-cli/app/command-sync.ts @@ -6,7 +6,7 @@ import ResourceFetcher from '@joplin/lib/services/ResourceFetcher'; import Synchronizer from '@joplin/lib/Synchronizer'; import { masterKeysWithoutPassword } from '@joplin/lib/services/e2ee/utils'; import { appTypeToLockType } from '@joplin/lib/services/synchronizer/LockHandler'; -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js'); const { reg } = require('@joplin/lib/registry.js'); diff --git a/packages/app-cli/app/command-tag.js b/packages/app-cli/app/command-tag.js index bd49f50a6..76513ad46 100644 --- a/packages/app-cli/app/command-tag.js +++ b/packages/app-cli/app/command-tag.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const Tag = require('@joplin/lib/models/Tag').default; diff --git a/packages/app-cli/app/command-testing.ts b/packages/app-cli/app/command-testing.ts index f137a92f9..e83cdf772 100644 --- a/packages/app-cli/app/command-testing.ts +++ b/packages/app-cli/app/command-testing.ts @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; import { reg } from '@joplin/lib/registry'; import Note from '@joplin/lib/models/Note'; import uuid from '@joplin/lib/uuid'; diff --git a/packages/app-cli/app/command-todo.js b/packages/app-cli/app/command-todo.js index 90a810396..18e7d32c1 100644 --- a/packages/app-cli/app/command-todo.js +++ b/packages/app-cli/app/command-todo.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-undone.js b/packages/app-cli/app/command-undone.js index aa28cdd67..0b8bff4f6 100644 --- a/packages/app-cli/app/command-undone.js +++ b/packages/app-cli/app/command-undone.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _ } = require('@joplin/lib/locale'); const CommandDone = require('./command-done.js'); diff --git a/packages/app-cli/app/command-use.js b/packages/app-cli/app/command-use.js index 9a699aa7b..ea8bf8fbe 100644 --- a/packages/app-cli/app/command-use.js +++ b/packages/app-cli/app/command-use.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { app } = require('./app.js'); const { _ } = require('@joplin/lib/locale'); const BaseModel = require('@joplin/lib/BaseModel').default; diff --git a/packages/app-cli/app/command-version.js b/packages/app-cli/app/command-version.js index 5a2c7ec68..66f304698 100644 --- a/packages/app-cli/app/command-version.js +++ b/packages/app-cli/app/command-version.js @@ -1,4 +1,4 @@ -const { BaseCommand } = require('./base-command.js'); +const BaseCommand = require('./base-command').default; const { _ } = require('@joplin/lib/locale'); const versionInfo = require('@joplin/lib/versionInfo').default; diff --git a/packages/app-cli/app/setupCommand.ts b/packages/app-cli/app/setupCommand.ts new file mode 100644 index 000000000..ceda917af --- /dev/null +++ b/packages/app-cli/app/setupCommand.ts @@ -0,0 +1,39 @@ +import { _ } from '@joplin/lib/locale'; + +export default (cmd: any, stdout: Function, store: Function, gui: Function) => { + cmd.setStdout((text: string) => { + return stdout(text); + }); + + cmd.setDispatcher((action: any) => { + if (store()) { + return store().dispatch(action); + } else { + return () => {}; + } + }); + + cmd.setPrompt(async (message: string, options: any) => { + if (!options) options = {}; + if (!options.type) options.type = 'boolean'; + if (!options.booleanAnswerDefault) options.booleanAnswerDefault = 'y'; + if (!options.answers) options.answers = options.booleanAnswerDefault === 'y' ? [_('Y'), _('n')] : [_('N'), _('y')]; + + if (options.type === 'boolean') { + message += ` (${options.answers.join('/')})`; + } + + let answer = await gui().prompt('', `${message} `, options); + + if (options.type === 'boolean') { + if (answer === null) return false; // Pressed ESCAPE + if (!answer) answer = options.answers[0]; + const positiveIndex = options.booleanAnswerDefault === 'y' ? 0 : 1; + return answer.toLowerCase() === options.answers[positiveIndex].toLowerCase(); + } else { + return answer; + } + }); + + return cmd; +}; diff --git a/packages/app-cli/app/utils/testUtils.ts b/packages/app-cli/app/utils/testUtils.ts new file mode 100644 index 000000000..19b84f31c --- /dev/null +++ b/packages/app-cli/app/utils/testUtils.ts @@ -0,0 +1,17 @@ +const { app } = require('../app'); +import Folder from '@joplin/lib/models/Folder'; +import BaseCommand from '../base-command'; +import setupCommand from '../setupCommand'; + +export const setupCommandForTesting = (CommandClass: any, stdout: Function = null): BaseCommand => { + const command = new CommandClass(); + setupCommand(command, stdout, null, null); + return command; +}; + +export const setupApplication = async () => { + // We create a notebook and set it as default since most commands require + // such notebook. + await Folder.save({ title: 'default' }); + await app().refreshCurrentFolder(); +}; diff --git a/packages/app-cli/jest.config.js b/packages/app-cli/jest.config.js index a817c3197..3c51753a5 100644 --- a/packages/app-cli/jest.config.js +++ b/packages/app-cli/jest.config.js @@ -27,6 +27,7 @@ module.exports = { testMatch: [ '**/tests/**/*.js', + '**/*.test.js', ], testPathIgnorePatterns: [