1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

Chore: Cli: Fix CLI app integration tests (#13089)

This commit is contained in:
Henry Heino
2025-09-13 06:17:40 -07:00
committed by GitHub
parent 38b368e997
commit 99ba854ee1
4 changed files with 92 additions and 26 deletions

View File

@@ -96,6 +96,7 @@ packages/onenote-converter/pkg/onenote_converter.js
packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js packages/app-cli/app/app.js
packages/app-cli/app/base-command.js packages/app-cli/app/base-command.js
packages/app-cli/app/cli-integration-tests.js
packages/app-cli/app/command-apidoc.js packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js packages/app-cli/app/command-batch.js

1
.gitignore vendored
View File

@@ -69,6 +69,7 @@ docs/**/*.mustache
packages/app-cli/app/LinkSelector.js packages/app-cli/app/LinkSelector.js
packages/app-cli/app/app.js packages/app-cli/app/app.js
packages/app-cli/app/base-command.js packages/app-cli/app/base-command.js
packages/app-cli/app/cli-integration-tests.js
packages/app-cli/app/command-apidoc.js packages/app-cli/app/command-apidoc.js
packages/app-cli/app/command-attach.js packages/app-cli/app/command-attach.js
packages/app-cli/app/command-batch.js packages/app-cli/app/command-batch.js

View File

@@ -2,33 +2,44 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
const fs = require('fs-extra'); import * as fs from 'fs-extra';
const Logger = require('@joplin/utils/Logger').default; import Logger, { TargetType } from '@joplin/utils/Logger';
const { dirname } = require('@joplin/lib/path-utils'); import { dirname } from '@joplin/lib/path-utils';
const { DatabaseDriverNode } = require('@joplin/lib/database-driver-node.js'); const { DatabaseDriverNode } = require('@joplin/lib/database-driver-node.js');
const JoplinDatabase = require('@joplin/lib/JoplinDatabase').default; import JoplinDatabase from '@joplin/lib/JoplinDatabase';
const BaseModel = require('@joplin/lib/BaseModel').default; import BaseModel from '@joplin/lib/BaseModel';
const Folder = require('@joplin/lib/models/Folder').default; import Folder from '@joplin/lib/models/Folder';
const Note = require('@joplin/lib/models/Note').default; import Note from '@joplin/lib/models/Note';
const Setting = require('@joplin/lib/models/Setting').default; import Setting from '@joplin/lib/models/Setting';
const { sprintf } = require('sprintf-js'); const { sprintf } = require('sprintf-js');
const exec = require('child_process').exec; const exec = require('child_process').exec;
const nodeSqlite = require('sqlite3');
const { loadKeychainServiceAndSettings } = require('@joplin/lib/services/SettingUtils');
const { default: shimInitCli } = require('./utils/shimInitCli');
const baseDir = `${dirname(__dirname)}/tests/cli-integration`; const baseDir = `${dirname(__dirname)}/tests/cli-integration`;
const joplinAppPath = `${__dirname}/main.js`; const joplinAppPath = `${__dirname}/main.js`;
shimInitCli({ nodeSqlite, appVersion: () => require('../package.json').version, keytar: null });
require('@joplin/lib/testing/test-utils');
const logger = new Logger(); const logger = new Logger();
logger.addTarget('console'); logger.addTarget(TargetType.Console);
logger.setLevel(Logger.LEVEL_ERROR); logger.setLevel(Logger.LEVEL_ERROR);
const dbLogger = new Logger(); const dbLogger = new Logger();
dbLogger.addTarget('console'); dbLogger.addTarget(TargetType.Console);
dbLogger.setLevel(Logger.LEVEL_INFO); dbLogger.setLevel(Logger.LEVEL_INFO);
const db = new JoplinDatabase(new DatabaseDriverNode()); const db = new JoplinDatabase(new DatabaseDriverNode());
db.setLogger(dbLogger); db.setLogger(dbLogger);
function createClient(id) { interface Client {
id: number;
profileDir: string;
}
function createClient(id: number): Client {
return { return {
id: id, id: id,
profileDir: `${baseDir}/client${id}`, profileDir: `${baseDir}/client${id}`,
@@ -37,13 +48,13 @@ function createClient(id) {
const client = createClient(1); const client = createClient(1);
function execCommand(client, command) { function execCommand(client: Client, command: string) {
const exePath = `node ${joplinAppPath}`; const exePath = `node ${joplinAppPath}`;
const cmd = `${exePath} --update-geolocation-disabled --env dev --profile ${client.profileDir} ${command}`; const cmd = `${exePath} --update-geolocation-disabled --env dev --profile ${client.profileDir} ${command}`;
logger.info(`${client.id}: ${command}`); logger.info(`${client.id}: ${command}`);
return new Promise((resolve, reject) => { return new Promise<string>((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => { exec(cmd, (error: string, stdout: string, stderr: string) => {
if (error) { if (error) {
logger.error(stderr); logger.error(stderr);
reject(error); reject(error);
@@ -54,17 +65,17 @@ function execCommand(client, command) {
}); });
} }
function assertTrue(v) { function assertTrue(v: unknown) {
if (!v) throw new Error(sprintf('Expected "true", got "%s"."', v)); if (!v) throw new Error(sprintf('Expected "true", got "%s"."', v));
process.stdout.write('.'); process.stdout.write('.');
} }
function assertFalse(v) { function assertFalse(v: unknown) {
if (v) throw new Error(sprintf('Expected "false", got "%s"."', v)); if (v) throw new Error(sprintf('Expected "false", got "%s"."', v));
process.stdout.write('.'); process.stdout.write('.');
} }
function assertEquals(expected, real) { function assertEquals(expected: unknown, real: unknown) {
if (expected !== real) throw new Error(sprintf('Expecting "%s", got "%s"', expected, real)); if (expected !== real) throw new Error(sprintf('Expecting "%s", got "%s"', expected, real));
process.stdout.write('.'); process.stdout.write('.');
} }
@@ -73,7 +84,7 @@ async function clearDatabase() {
await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']); await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']);
} }
const testUnits = {}; const testUnits: Record<string, ()=> Promise<void>> = {};
testUnits.testFolders = async () => { testUnits.testFolders = async () => {
await execCommand(client, 'mkbook nb1'); await execCommand(client, 'mkbook nb1');
@@ -85,10 +96,16 @@ testUnits.testFolders = async () => {
await execCommand(client, 'mkbook nb1'); await execCommand(client, 'mkbook nb1');
folders = await Folder.all(); folders = await Folder.all();
assertEquals(1, folders.length); assertEquals(2, folders.length);
assertEquals('nb1', folders[0].title); assertEquals('nb1', folders[0].title);
assertEquals('nb1', folders[1].title);
await execCommand(client, 'rm -r -f nb1'); await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all();
assertEquals(1, folders.length);
await execCommand(client, 'rmbook -p -f nb1');
folders = await Folder.all(); folders = await Folder.all();
assertEquals(0, folders.length); assertEquals(0, folders.length);
@@ -102,7 +119,7 @@ testUnits.testNotes = async () => {
assertEquals(1, notes.length); assertEquals(1, notes.length);
assertEquals('n1', notes[0].title); assertEquals('n1', notes[0].title);
await execCommand(client, 'rm -f n1'); await execCommand(client, 'rmnote -p -f n1');
notes = await Note.all(); notes = await Note.all();
assertEquals(0, notes.length); assertEquals(0, notes.length);
@@ -112,12 +129,19 @@ testUnits.testNotes = async () => {
notes = await Note.all(); notes = await Note.all();
assertEquals(2, notes.length); assertEquals(2, notes.length);
await execCommand(client, 'rm -f \'blabla*\''); // Should fail to delete a non-existent note
let failed = false;
try {
await execCommand(client, 'rmnote -f \'blabla*\'');
} catch (error) {
failed = true;
}
assertEquals(failed, true);
notes = await Note.all(); notes = await Note.all();
assertEquals(2, notes.length); assertEquals(2, notes.length);
await execCommand(client, 'rm -f \'n*\''); await execCommand(client, 'rmnote -f -p \'n*\'');
notes = await Note.all(); notes = await Note.all();
assertEquals(0, notes.length); assertEquals(0, notes.length);
@@ -140,10 +164,12 @@ testUnits.testCat = async () => {
testUnits.testConfig = async () => { testUnits.testConfig = async () => {
await execCommand(client, 'config editor vim'); await execCommand(client, 'config editor vim');
await Setting.reset();
await Setting.load(); await Setting.load();
assertEquals('vim', Setting.value('editor')); assertEquals('vim', Setting.value('editor'));
await execCommand(client, 'config editor subl'); await execCommand(client, 'config editor subl');
await Setting.reset();
await Setting.load(); await Setting.load();
assertEquals('subl', Setting.value('editor')); assertEquals('subl', Setting.value('editor'));
@@ -201,15 +227,47 @@ testUnits.testMv = async () => {
await execCommand(client, 'mknote note2'); await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3'); await execCommand(client, 'mknote note3');
await execCommand(client, 'mknote blabla'); await execCommand(client, 'mknote blabla');
await execCommand(client, 'mv \'note*\' nb2');
notes1 = await Note.previews(f1.id); notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id); notes2 = await Note.previews(f2.id);
assertEquals(4, notes1.length);
assertEquals(1, notes2.length);
await execCommand(client, 'mv \'note*\' nb2');
notes2 = await Note.previews(f2.id);
notes1 = await Note.previews(f1.id);
assertEquals(1, notes1.length); assertEquals(1, notes1.length);
assertEquals(4, notes2.length); assertEquals(4, notes2.length);
}; };
testUnits.testUse = async () => {
await execCommand(client, 'mkbook nb1');
await execCommand(client, 'mkbook nb2');
await execCommand(client, 'mknote n1');
await execCommand(client, 'mknote n2');
const f1 = await Folder.loadByTitle('nb1');
const f2 = await Folder.loadByTitle('nb2');
let notes1 = await Note.previews(f1.id);
let notes2 = await Note.previews(f2.id);
assertEquals(0, notes1.length);
assertEquals(2, notes2.length);
await execCommand(client, 'use nb1');
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
assertEquals(2, notes1.length);
assertEquals(2, notes2.length);
};
async function main() { async function main() {
await fs.remove(baseDir); await fs.remove(baseDir);
@@ -217,7 +275,9 @@ async function main() {
await db.open({ name: `${client.profileDir}/database.sqlite` }); await db.open({ name: `${client.profileDir}/database.sqlite` });
BaseModel.setDb(db); BaseModel.setDb(db);
await Setting.load(); Setting.setConstant('rootProfileDir', client.profileDir);
Setting.setConstant('profileDir', client.profileDir);
await loadKeychainServiceAndSettings([]);
let onlyThisTest = 'testMv'; let onlyThisTest = 'testMv';
onlyThisTest = ''; onlyThisTest = '';
@@ -234,7 +294,7 @@ async function main() {
} }
} }
main(process.argv).catch(error => { main().catch(error => {
console.info(''); console.info('');
logger.error(error); logger.error(error);
}); });

View File

@@ -891,6 +891,10 @@ export default class BaseApplication {
if (!currentFolder) currentFolder = await Folder.defaultFolder(); if (!currentFolder) currentFolder = await Folder.defaultFolder();
Setting.setValue('activeFolderId', currentFolder ? currentFolder.id : ''); Setting.setValue('activeFolderId', currentFolder ? currentFolder.id : '');
if (currentFolder && !this.hasGui()) {
this.currentFolder_ = currentFolder;
}
await setupAutoDeletion(); await setupAutoDeletion();
await MigrationService.instance().run(); await MigrationService.instance().run();