more note etapi tests

This commit is contained in:
zadam 2023-10-30 23:51:53 +01:00
parent 8690228d98
commit 695c9d5cf3
5 changed files with 128 additions and 11 deletions

View File

@ -109,7 +109,9 @@ module.exports = {
// src\public\app\services\utils.js // src\public\app\services\utils.js
logInfo: true, logInfo: true,
__non_webpack_require__: true, __non_webpack_require__: true,
// describe: true,
it: true,
expect: true
}, },
parserOptions: { parserOptions: {
ecmaVersion: 'latest', ecmaVersion: 'latest',

View File

@ -1,4 +1,6 @@
const {describeEtapi, postEtapi, getEtapi, getEtapiContent} = require("../support/etapi"); const {describeEtapi, postEtapi, getEtapi, getEtapiContent, patchEtapi, putEtapi, putEtapiContent} = require("../support/etapi");
const crypto = require('crypto');
const {deleteEtapi, getEtapiResponse} = require("../support/etapi.js");
describeEtapi("notes", () => { describeEtapi("notes", () => {
it("create", async () => { it("create", async () => {
@ -17,11 +19,84 @@ describeEtapi("notes", () => {
const rNote = await getEtapi(`notes/${note.noteId}`); const rNote = await getEtapi(`notes/${note.noteId}`);
expect(rNote.title).toEqual("Hello World!"); expect(rNote.title).toEqual("Hello World!");
const rContent = await getEtapiContent(`notes/${note.noteId}/content`); const rContent = await (await getEtapiContent(`notes/${note.noteId}/content`)).text();
expect(rContent).toEqual("Content"); expect(rContent).toEqual("Content");
const rBranch = await getEtapi(`branches/${branch.branchId}`); const rBranch = await getEtapi(`branches/${branch.branchId}`);
expect(rBranch.parentNoteId).toEqual("root"); expect(rBranch.parentNoteId).toEqual("root");
expect(rBranch.prefix).toEqual("Custom prefix"); expect(rBranch.prefix).toEqual("Custom prefix");
}); });
it("patch", async () => {
const {note} = await postEtapi('create-note', {
parentNoteId: 'root',
type: 'text',
title: 'Hello World!',
content: 'Content'
});
await patchEtapi(`notes/${note.noteId}`, {
title: 'new title',
type: 'code',
mime: 'text/apl',
dateCreated: '2000-01-01 12:34:56.999+0200',
utcDateCreated: '2000-01-01 10:34:56.999Z',
});
const rNote = await getEtapi(`notes/${note.noteId}`);
expect(rNote.title).toEqual("new title");
expect(rNote.type).toEqual("code");
expect(rNote.mime).toEqual("text/apl");
expect(rNote.dateCreated).toEqual("2000-01-01 12:34:56.999+0200");
expect(rNote.utcDateCreated).toEqual("2000-01-01 10:34:56.999Z");
});
it("update content", async () => {
const {note} = await postEtapi('create-note', {
parentNoteId: 'root',
type: 'text',
title: 'Hello World!',
content: 'Content'
});
await putEtapiContent(`notes/${note.noteId}/content`, "new content");
const rContent = await (await getEtapiContent(`notes/${note.noteId}/content`)).text();
expect(rContent).toEqual("new content");
});
it("create / update binary content", async () => {
const {note} = await postEtapi('create-note', {
parentNoteId: 'root',
type: 'file',
title: 'Hello World!',
content: 'ZZZ'
});
const updatedContent = crypto.randomBytes(16);
await putEtapiContent(`notes/${note.noteId}/content`, updatedContent);
const rContent = await (await getEtapiContent(`notes/${note.noteId}/content`)).arrayBuffer();
expect(Buffer.from(new Uint8Array(rContent))).toEqual(updatedContent);
});
it("delete note", async () => {
const {note} = await postEtapi('create-note', {
parentNoteId: 'root',
type: 'text',
title: 'Hello World!',
content: 'Content'
});
await deleteEtapi(`notes/${note.noteId}`);
const resp = await getEtapiResponse(`notes/${note.noteId}`);
expect(resp.status).toEqual(404);
const error = await resp.json();
expect(error.status).toEqual(404);
expect(error.code).toEqual("NOTE_NOT_FOUND");
expect(error.message).toEqual(`Note '${note.noteId}' not found.`);
});
}); });

View File

@ -51,13 +51,17 @@ function describeEtapi(description, specDefinitions) {
}); });
} }
async function getEtapi(url) { async function getEtapiResponse(url) {
const response = await fetch(`${HOST}/etapi/${url}`, { return await fetch(`${HOST}/etapi/${url}`, {
method: 'GET', method: 'GET',
headers: { headers: {
Authorization: getEtapiAuthorizationHeader() Authorization: getEtapiAuthorizationHeader()
} }
}); });
}
async function getEtapi(url) {
const response = await getEtapiResponse(url);
return await processEtapiResponse(response); return await processEtapiResponse(response);
} }
@ -68,7 +72,10 @@ async function getEtapiContent(url) {
Authorization: getEtapiAuthorizationHeader() Authorization: getEtapiAuthorizationHeader()
} }
}); });
return await response.text();
checkStatus(response);
return response;
} }
async function postEtapi(url, data = {}) { async function postEtapi(url, data = {}) {
@ -95,6 +102,31 @@ async function putEtapi(url, data = {}) {
return await processEtapiResponse(response); return await processEtapiResponse(response);
} }
async function putEtapiContent(url, data) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'PUT',
headers: {
"Content-Type": "application/octet-stream",
Authorization: getEtapiAuthorizationHeader()
},
body: data
});
checkStatus(response);
}
async function patchEtapi(url, data = {}) {
const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'PATCH',
headers: {
"Content-Type": "application/json",
Authorization: getEtapiAuthorizationHeader()
},
body: JSON.stringify(data)
});
return await processEtapiResponse(response);
}
async function deleteEtapi(url) { async function deleteEtapi(url) {
const response = await fetch(`${HOST}/etapi/${url}`, { const response = await fetch(`${HOST}/etapi/${url}`, {
method: 'DELETE', method: 'DELETE',
@ -106,20 +138,29 @@ async function deleteEtapi(url) {
} }
async function processEtapiResponse(response) { async function processEtapiResponse(response) {
const json = await response.json(); const text = await response.text();
if (response.status < 200 || response.status >= 300) { if (response.status < 200 || response.status >= 300) {
throw new Error("ETAPI error: " + JSON.stringify(json)); throw new Error(`ETAPI error ${response.status}: ` + text);
} }
return json; return text?.trim() ? JSON.parse(text) : null;
}
function checkStatus(response) {
if (response.status < 200 || response.status >= 300) {
throw new Error(`ETAPI error ${response.status}`);
}
} }
module.exports = { module.exports = {
describeEtapi, describeEtapi,
getEtapi, getEtapi,
getEtapiResponse,
getEtapiContent, getEtapiContent,
postEtapi, postEtapi,
putEtapi, putEtapi,
putEtapiContent,
patchEtapi,
deleteEtapi deleteEtapi
}; };

View File

@ -15,7 +15,7 @@ function register(app) {
// catch 404 and forward to error handler // catch 404 and forward to error handler
app.use((req, res, next) => { app.use((req, res, next) => {
const err = new Error(`Router not found for request ${req.url}`); const err = new Error(`Router not found for request ${req.method} ${req.url}`);
err.status = 404; err.status = 404;
next(err); next(err);
}); });

View File

@ -412,7 +412,6 @@ function checkImageAttachments(note, content) {
}; };
} }
function findImageLinks(content, foundLinks) { function findImageLinks(content, foundLinks) {
const re = /src="[^"]*api\/images\/([a-zA-Z0-9_]+)\//g; const re = /src="[^"]*api\/images\/([a-zA-Z0-9_]+)\//g;
let match; let match;