apps.resolver.test.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import { DataSource } from 'typeorm';
  2. import { setupConnection, teardownConnection } from '../../../test/connection';
  3. import fs from 'fs-extra';
  4. import { gcall } from '../../../test/gcall';
  5. import App from '../app.entity';
  6. import { getAppQuery, InstalledAppsQuery, listAppInfosQuery } from '../../../test/queries';
  7. import { createApp } from './apps.factory';
  8. import { AppInfo, AppStatusEnum, ListAppsResonse } from '../apps.types';
  9. import { createUser } from '../../auth/__tests__/user.factory';
  10. import User from '../../auth/user.entity';
  11. import { installAppMutation } from '../../../test/mutations';
  12. jest.mock('fs');
  13. jest.mock('child_process');
  14. jest.mock('internal-ip');
  15. jest.mock('tcp-port-used');
  16. type TApp = App & {
  17. info: AppInfo;
  18. };
  19. let db: DataSource | null = null;
  20. const TEST_SUITE = 'appsresolver';
  21. beforeAll(async () => {
  22. db = await setupConnection(TEST_SUITE);
  23. });
  24. afterAll(async () => {
  25. await db?.destroy();
  26. await teardownConnection(TEST_SUITE);
  27. });
  28. beforeEach(async () => {
  29. jest.resetModules();
  30. jest.resetAllMocks();
  31. jest.restoreAllMocks();
  32. await App.clear();
  33. await User.clear();
  34. });
  35. describe('ListAppsInfos', () => {
  36. let app1: AppInfo;
  37. beforeEach(async () => {
  38. const { MockFiles, appInfo } = await createApp({});
  39. app1 = appInfo;
  40. // @ts-ignore
  41. fs.__createMockFiles(MockFiles);
  42. });
  43. it('Can list apps', async () => {
  44. const { data } = await gcall<{ listAppsInfo: ListAppsResonse }>({ source: listAppInfosQuery });
  45. expect(data?.listAppsInfo.apps.length).toBe(1);
  46. expect(data?.listAppsInfo.total).toBe(1);
  47. const app = data?.listAppsInfo.apps[0];
  48. expect(app?.id).toBe(app1.id);
  49. expect(app?.author).toBe(app1.author);
  50. expect(app?.name).toBe(app1.name);
  51. expect(app?.available).toBe(app1.available);
  52. });
  53. });
  54. describe('GetApp', () => {
  55. let app1: AppInfo;
  56. let app2: AppInfo;
  57. beforeEach(async () => {
  58. const app1create = await createApp({});
  59. const app2create = await createApp({ installed: true });
  60. app1 = app1create.appInfo;
  61. app2 = app2create.appInfo;
  62. // @ts-ignore
  63. fs.__createMockFiles(Object.assign(app1create.MockFiles, app2create.MockFiles));
  64. });
  65. it('Can get app', async () => {
  66. const { data } = await gcall<{ getApp: TApp }>({
  67. source: getAppQuery,
  68. variableValues: { id: app1.id },
  69. });
  70. expect(data?.getApp.info.id).toBe(app1.id);
  71. expect(data?.getApp.status).toBe(AppStatusEnum.MISSING.toUpperCase());
  72. const { data: data2 } = await gcall<{ getApp: TApp }>({
  73. source: getAppQuery,
  74. variableValues: { id: app2.id },
  75. });
  76. expect(data2?.getApp.info.id).toBe(app2.id);
  77. });
  78. it("Should return an error if app doesn't exist", async () => {
  79. const { data, errors } = await gcall<{ getApp: TApp }>({
  80. source: getAppQuery,
  81. variableValues: { id: 'not-existing' },
  82. });
  83. expect(errors?.[0].message).toBe('Error loading app not-existing');
  84. expect(data?.getApp).toBeUndefined();
  85. });
  86. });
  87. describe('InstalledApps', () => {
  88. let app1: AppInfo;
  89. beforeEach(async () => {
  90. const app1create = await createApp({ installed: true });
  91. app1 = app1create.appInfo;
  92. // @ts-ignore
  93. fs.__createMockFiles(app1create.MockFiles);
  94. });
  95. it('Can list installed apps', async () => {
  96. const user = await createUser();
  97. const { data } = await gcall<{ installedApps: TApp[] }>({ source: InstalledAppsQuery, userId: user.id });
  98. expect(data?.installedApps.length).toBe(1);
  99. const app = data?.installedApps[0];
  100. expect(app?.id).toBe(app1.id);
  101. expect(app?.info.author).toBe(app1.author);
  102. expect(app?.info.name).toBe(app1.name);
  103. });
  104. it("Should return an error if user doesn't exist", async () => {
  105. const { data, errors } = await gcall<{ installedApps: TApp[] }>({
  106. source: InstalledAppsQuery,
  107. userId: 1,
  108. });
  109. expect(errors?.[0].message).toBe('Access denied! You need to be authorized to perform this action!');
  110. expect(data?.installedApps).toBeUndefined();
  111. });
  112. it('Should throw an error if no userId is provided', async () => {
  113. const { data, errors } = await gcall<{ installedApps: TApp[] }>({
  114. source: InstalledAppsQuery,
  115. });
  116. expect(errors?.[0].message).toBe('Access denied! You need to be authorized to perform this action!');
  117. expect(data?.installedApps).toBeUndefined();
  118. });
  119. });
  120. describe('InstallApp', () => {
  121. let app1: AppInfo;
  122. beforeEach(async () => {
  123. const app1create = await createApp({});
  124. app1 = app1create.appInfo;
  125. // @ts-ignore
  126. fs.__createMockFiles(app1create.MockFiles);
  127. });
  128. it('Can install app', async () => {
  129. const user = await createUser();
  130. const { data } = await gcall<{ installApp: TApp }>({
  131. source: installAppMutation,
  132. userId: user.id,
  133. variableValues: { input: { id: app1.id, form: { TEST_FIELD: 'hello' } } },
  134. });
  135. expect(data?.installApp.info.id).toBe(app1.id);
  136. expect(data?.installApp.status).toBe(AppStatusEnum.RUNNING.toUpperCase());
  137. });
  138. it("Should return an error if app doesn't exist", async () => {
  139. const user = await createUser();
  140. const { data, errors } = await gcall<{ installApp: TApp }>({
  141. source: installAppMutation,
  142. userId: user.id,
  143. variableValues: { input: { id: 'not-existing', form: { TEST_FIELD: 'hello' } } },
  144. });
  145. expect(errors?.[0].message).toBe('App not-existing not found');
  146. expect(data?.installApp).toBeUndefined();
  147. });
  148. it("Should throw an error if user doesn't exist", async () => {
  149. const { data, errors } = await gcall<{ installApp: TApp }>({
  150. source: installAppMutation,
  151. variableValues: { input: { id: app1.id, form: { TEST_FIELD: 'hello' } } },
  152. });
  153. expect(errors?.[0].message).toBe('Access denied! You need to be authorized to perform this action!');
  154. expect(data?.installApp).toBeUndefined();
  155. });
  156. it('Should throw an error if no userId is provided', async () => {
  157. const { data, errors } = await gcall<{ installApp: TApp }>({
  158. source: installAppMutation,
  159. variableValues: { input: { id: app1.id, form: { TEST_FIELD: 'hello' } } },
  160. });
  161. expect(errors?.[0].message).toBe('Access denied! You need to be authorized to perform this action!');
  162. expect(data?.installApp).toBeUndefined();
  163. });
  164. it('Should throw an error if a required field is missing in form', async () => {
  165. const user = await createUser();
  166. const { data, errors } = await gcall<{ installApp: TApp }>({
  167. source: installAppMutation,
  168. userId: user.id,
  169. variableValues: { input: { id: app1.id, form: {} } },
  170. });
  171. expect(errors?.[0].message).toBe(`Variable ${app1.form_fields?.[0].env_variable} is required`);
  172. expect(data?.installApp).toBeUndefined();
  173. });
  174. it('Should throw an error if the requirements are not met', async () => {
  175. const { appInfo, MockFiles } = await createApp({ requiredPort: 400 });
  176. // @ts-ignore
  177. fs.__createMockFiles(MockFiles);
  178. const user = await createUser();
  179. const { data, errors } = await gcall<{ installApp: TApp }>({
  180. source: installAppMutation,
  181. userId: user.id,
  182. variableValues: { input: { id: appInfo.id, form: { TEST_FIELD: 'hello' } } },
  183. });
  184. expect(errors?.[0].message).toBe(`App ${appInfo.id} requirements not met`);
  185. expect(data?.installApp).toBeUndefined();
  186. });
  187. });