etapi.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. const {spawn} = require("child_process");
  2. const kill = require('tree-kill');
  3. let etapiAuthToken;
  4. const getEtapiAuthorizationHeader = () => "Basic " + Buffer.from(`etapi:${etapiAuthToken}`).toString('base64');
  5. const PORT = '9999';
  6. const HOST = 'http://localhost:' + PORT;
  7. function describeEtapi(description, specDefinitions) {
  8. describe(description, () => {
  9. let appProcess;
  10. beforeAll(async () => {
  11. appProcess = spawn('npm', ['run', 'start-test-server']);
  12. await new Promise(res => {
  13. appProcess.stdout.on('data', data => {
  14. console.log("Trilium: " + data.toString().trim());
  15. if (data.toString().includes('Listening on port')) {
  16. res();
  17. }
  18. });
  19. });
  20. await fetch(HOST + '/api/setup/new-document', { method: 'POST' });
  21. const formData = new URLSearchParams();
  22. formData.append('password1', '1234');
  23. formData.append('password2', '1234');
  24. await fetch(HOST + '/set-password', { method: 'POST', body: formData });
  25. etapiAuthToken = (await (await fetch(HOST + '/etapi/auth/login', {
  26. method: 'POST',
  27. headers: {
  28. "Content-Type": "application/json",
  29. },
  30. body: JSON.stringify({ password: '1234' })
  31. })).json()).authToken;
  32. });
  33. afterAll(() => {
  34. console.log("Attempting to kill the Trilium process as part of the cleanup...");
  35. kill(appProcess.pid, 'SIGKILL', () => { console.log("Trilium process killed.") });
  36. });
  37. specDefinitions();
  38. });
  39. }
  40. async function getEtapiResponse(url) {
  41. return await fetch(`${HOST}/etapi/${url}`, {
  42. method: 'GET',
  43. headers: {
  44. Authorization: getEtapiAuthorizationHeader()
  45. }
  46. });
  47. }
  48. async function getEtapi(url) {
  49. const response = await getEtapiResponse(url);
  50. return await processEtapiResponse(response);
  51. }
  52. async function getEtapiContent(url) {
  53. const response = await fetch(`${HOST}/etapi/${url}`, {
  54. method: 'GET',
  55. headers: {
  56. Authorization: getEtapiAuthorizationHeader()
  57. }
  58. });
  59. checkStatus(response);
  60. return response;
  61. }
  62. async function postEtapi(url, data = {}) {
  63. const response = await fetch(`${HOST}/etapi/${url}`, {
  64. method: 'POST',
  65. headers: {
  66. "Content-Type": "application/json",
  67. Authorization: getEtapiAuthorizationHeader()
  68. },
  69. body: JSON.stringify(data)
  70. });
  71. return await processEtapiResponse(response);
  72. }
  73. async function postEtapiContent(url, data) {
  74. const response = await fetch(`${HOST}/etapi/${url}`, {
  75. method: 'POST',
  76. headers: {
  77. "Content-Type": "application/octet-stream",
  78. Authorization: getEtapiAuthorizationHeader()
  79. },
  80. body: data
  81. });
  82. checkStatus(response);
  83. return response;
  84. }
  85. async function putEtapi(url, data = {}) {
  86. const response = await fetch(`${HOST}/etapi/${url}`, {
  87. method: 'PUT',
  88. headers: {
  89. "Content-Type": "application/json",
  90. Authorization: getEtapiAuthorizationHeader()
  91. },
  92. body: JSON.stringify(data)
  93. });
  94. return await processEtapiResponse(response);
  95. }
  96. async function putEtapiContent(url, data) {
  97. const response = await fetch(`${HOST}/etapi/${url}`, {
  98. method: 'PUT',
  99. headers: {
  100. "Content-Type": "application/octet-stream",
  101. Authorization: getEtapiAuthorizationHeader()
  102. },
  103. body: data
  104. });
  105. checkStatus(response);
  106. return response;
  107. }
  108. async function patchEtapi(url, data = {}) {
  109. const response = await fetch(`${HOST}/etapi/${url}`, {
  110. method: 'PATCH',
  111. headers: {
  112. "Content-Type": "application/json",
  113. Authorization: getEtapiAuthorizationHeader()
  114. },
  115. body: JSON.stringify(data)
  116. });
  117. return await processEtapiResponse(response);
  118. }
  119. async function deleteEtapi(url) {
  120. const response = await fetch(`${HOST}/etapi/${url}`, {
  121. method: 'DELETE',
  122. headers: {
  123. Authorization: getEtapiAuthorizationHeader()
  124. }
  125. });
  126. return await processEtapiResponse(response);
  127. }
  128. async function processEtapiResponse(response) {
  129. const text = await response.text();
  130. if (response.status < 200 || response.status >= 300) {
  131. throw new Error(`ETAPI error ${response.status}: ` + text);
  132. }
  133. return text?.trim() ? JSON.parse(text) : null;
  134. }
  135. function checkStatus(response) {
  136. if (response.status < 200 || response.status >= 300) {
  137. throw new Error(`ETAPI error ${response.status}`);
  138. }
  139. }
  140. module.exports = {
  141. describeEtapi,
  142. getEtapi,
  143. getEtapiResponse,
  144. getEtapiContent,
  145. postEtapi,
  146. postEtapiContent,
  147. putEtapi,
  148. putEtapiContent,
  149. patchEtapi,
  150. deleteEtapi
  151. };