mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	etapi test infrastructure plus a basic note creation test
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -11,5 +11,6 @@ cert.crt | |||||||
| server-package.json | server-package.json | ||||||
| .idea/httpRequests/ | .idea/httpRequests/ | ||||||
| data/ | data/ | ||||||
|  | data-test/ | ||||||
| tmp/ | tmp/ | ||||||
| .eslintcache | .eslintcache | ||||||
							
								
								
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "version": "0.61.8-beta", |   "version": "0.61.10-beta", | ||||||
|   "lockfileVersion": 2, |   "lockfileVersion": 2, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "trilium", |       "name": "trilium", | ||||||
|       "version": "0.61.8-beta", |       "version": "0.61.10-beta", | ||||||
|       "hasInstallScript": true, |       "hasInstallScript": true, | ||||||
|       "license": "AGPL-3.0-only", |       "license": "AGPL-3.0-only", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @@ -68,6 +68,7 @@ | |||||||
|         "stream-throttle": "0.1.3", |         "stream-throttle": "0.1.3", | ||||||
|         "striptags": "3.2.0", |         "striptags": "3.2.0", | ||||||
|         "tmp": "0.2.1", |         "tmp": "0.2.1", | ||||||
|  |         "tree-kill": "^1.2.2", | ||||||
|         "turndown": "7.1.2", |         "turndown": "7.1.2", | ||||||
|         "unescape": "1.0.1", |         "unescape": "1.0.1", | ||||||
|         "ws": "8.14.2", |         "ws": "8.14.2", | ||||||
| @@ -12630,6 +12631,14 @@ | |||||||
|         "node": ">=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": { |     "node_modules/trim-repeated": { | ||||||
|       "version": "1.0.0", |       "version": "1.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", | ||||||
| @@ -23061,6 +23070,11 @@ | |||||||
|         "punycode": "^2.3.0" |         "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": { |     "trim-repeated": { | ||||||
|       "version": "1.0.0", |       "version": "1.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", | ||||||
|   | |||||||
| @@ -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": "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 .", |     "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 .", |     "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-server": "rm -rf ./node_modules/better-sqlite3 && npm install", | ||||||
|     "switch-electron": "./node_modules/.bin/electron-rebuild", |     "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-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-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", |     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", | ||||||
|     "webpack": "webpack -c webpack.config.js", |     "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-es6": "node -r esm spec-es6/attribute_parser.spec.js ", | ||||||
|     "test": "npm run test-jasmine && npm run test-es6", |     "test": "npm run test-jasmine && npm run test-es6", | ||||||
|     "postinstall": "rimraf ./node_modules/canvas", |     "postinstall": "rimraf ./node_modules/canvas", | ||||||
| @@ -91,6 +92,7 @@ | |||||||
|     "stream-throttle": "0.1.3", |     "stream-throttle": "0.1.3", | ||||||
|     "striptags": "3.2.0", |     "striptags": "3.2.0", | ||||||
|     "tmp": "0.2.1", |     "tmp": "0.2.1", | ||||||
|  |     "tree-kill": "^1.2.2", | ||||||
|     "turndown": "7.1.2", |     "turndown": "7.1.2", | ||||||
|     "unescape": "1.0.1", |     "unescape": "1.0.1", | ||||||
|     "ws": "8.14.2", |     "ws": "8.14.2", | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								spec/etapi/notes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								spec/etapi/notes.js
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										125
									
								
								spec/support/etapi.js
									
									
									
									
									
										Normal 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 | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user