etapi test infrastructure plus a basic note creation test

This commit is contained in:
zadam 2023-10-29 23:24:11 +01:00
parent 690caf7da1
commit 8690228d98
5 changed files with 173 additions and 4 deletions

3
.gitignore vendored
View file

@ -11,5 +11,6 @@ cert.crt
server-package.json
.idea/httpRequests/
data/
data-test/
tmp/
.eslintcache
.eslintcache

18
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "trilium",
"version": "0.61.8-beta",
"version": "0.61.10-beta",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "trilium",
"version": "0.61.8-beta",
"version": "0.61.10-beta",
"hasInstallScript": true,
"license": "AGPL-3.0-only",
"dependencies": {
@ -68,6 +68,7 @@
"stream-throttle": "0.1.3",
"striptags": "3.2.0",
"tmp": "0.2.1",
"tree-kill": "^1.2.2",
"turndown": "7.1.2",
"unescape": "1.0.1",
"ws": "8.14.2",
@ -12630,6 +12631,14 @@
"node": ">=14"
}
},
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"bin": {
"tree-kill": "cli.js"
}
},
"node_modules/trim-repeated": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
@ -23061,6 +23070,11 @@
"punycode": "^2.3.0"
}
},
"tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="
},
"trim-repeated": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",

View file

@ -19,13 +19,14 @@
"start-electron": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .",
"start-electron-no-dir": "cross-env TRILIUM_SAFE_MODE=1 TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 electron --inspect=5858 .",
"qstart-electron": "rm -r ./node_modules/better-sqlite3/bin ; mkdir -p ./node_modules/better-sqlite3/build ; cp ./bin/better-sqlite3/linux-desktop-better_sqlite3.node ./node_modules/better-sqlite3/build/better_sqlite3.node && TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .",
"start-test-server": "rm -rf ./data-test; cross-env TRILIUM_SAFE_MODE=1 TRILIUM_DATA_DIR=./data-test TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev TRILIUM_PORT=9999 node ./src/www",
"switch-server": "rm -rf ./node_modules/better-sqlite3 && npm install",
"switch-electron": "./node_modules/.bin/electron-rebuild",
"build-backend-docs": "rm -rf ./docs/backend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/becca/entities/*.js src/services/backend_script_api.js src/services/sql.js",
"build-frontend-docs": "rm -rf ./docs/frontend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js",
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
"webpack": "webpack -c webpack.config.js",
"test-jasmine": "jasmine",
"test-jasmine": "TRILIUM_DATA_DIR=~/trilium/data-test jasmine",
"test-es6": "node -r esm spec-es6/attribute_parser.spec.js ",
"test": "npm run test-jasmine && npm run test-es6",
"postinstall": "rimraf ./node_modules/canvas",
@ -91,6 +92,7 @@
"stream-throttle": "0.1.3",
"striptags": "3.2.0",
"tmp": "0.2.1",
"tree-kill": "^1.2.2",
"turndown": "7.1.2",
"unescape": "1.0.1",
"ws": "8.14.2",

27
spec/etapi/notes.js Normal file
View file

@ -0,0 +1,27 @@
const {describeEtapi, postEtapi, getEtapi, getEtapiContent} = require("../support/etapi");
describeEtapi("notes", () => {
it("create", async () => {
const {note, branch} = await postEtapi('create-note', {
parentNoteId: 'root',
type: 'text',
title: 'Hello World!',
content: 'Content',
prefix: 'Custom prefix'
});
expect(note.title).toEqual("Hello World!");
expect(branch.parentNoteId).toEqual("root");
expect(branch.prefix).toEqual("Custom prefix");
const rNote = await getEtapi(`notes/${note.noteId}`);
expect(rNote.title).toEqual("Hello World!");
const rContent = await getEtapiContent(`notes/${note.noteId}/content`);
expect(rContent).toEqual("Content");
const rBranch = await getEtapi(`branches/${branch.branchId}`);
expect(rBranch.parentNoteId).toEqual("root");
expect(rBranch.prefix).toEqual("Custom prefix");
});
});

125
spec/support/etapi.js Normal file
View file

@ -0,0 +1,125 @@
const {spawn} = require("child_process");
const kill = require('tree-kill');
let etapiAuthToken;
const getEtapiAuthorizationHeader = () => "Basic " + Buffer.from(`etapi:${etapiAuthToken}`).toString('base64');
const PORT = '9999';
const HOST = 'http://localhost:' + PORT;
function describeEtapi(description, specDefinitions) {
describe(description, () => {
let appProcess;
beforeAll(async () => {
appProcess = spawn('npm', ['run', 'start-test-server']);
await new Promise(res => {
appProcess.stdout.on('data', data => {
console.log("Trilium: " + data.toString().trim());
if (data.toString().includes('Listening on port')) {
res();
}
});
});
await fetch(HOST + '/api/setup/new-document', { method: 'POST' });
const formData = new URLSearchParams();
formData.append('password1', '1234');
formData.append('password2', '1234');
await fetch(HOST + '/set-password', { method: 'POST', body: formData });
etapiAuthToken = (await (await fetch(HOST + '/etapi/auth/login', {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ password: '1234' })
})).json()).authToken;
});
afterAll(() => {
console.log("Attempting to kill the Trilium process as part of the cleanup...");
kill(appProcess.pid, 'SIGKILL', () => { console.log("Trilium process killed.") });
});
specDefinitions();
});
}
async function getEtapi(url) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'GET',
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
return await processEtapiResponse(response);
}
async function getEtapiContent(url) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'GET',
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
return await response.text();
}
async function postEtapi(url, data = {}) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'POST',
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function putEtapi(url, data = {}) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function deleteEtapi(url) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'DELETE',
headers: {
Authorization: getEtapiAuthorizationHeader()
}
});
return await processEtapiResponse(response);
}
async function processEtapiResponse(response) {
const json = await response.json();
if (response.status < 200 || response.status >= 300) {
throw new Error("ETAPI error: " + JSON.stringify(json));
}
return json;
}
module.exports = {
describeEtapi,
getEtapi,
getEtapiContent,
postEtapi,
putEtapi,
deleteEtapi
};