administrator.e2e-spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. import { SUPER_ADMIN_USER_IDENTIFIER } from '@vendure/common/lib/shared-constants';
  2. import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing';
  3. import { fail } from 'assert';
  4. import gql from 'graphql-tag';
  5. import path from 'path';
  6. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  7. import { initialData } from '../../../e2e-common/e2e-initial-data';
  8. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  9. import { ADMINISTRATOR_FRAGMENT } from './graphql/fragments';
  10. import * as Codegen from './graphql/generated-e2e-admin-types';
  11. import {
  12. AdministratorFragment,
  13. AttemptLoginDocument,
  14. CurrentUser,
  15. DeletionResult,
  16. } from './graphql/generated-e2e-admin-types';
  17. import { CREATE_ADMINISTRATOR, UPDATE_ADMINISTRATOR } from './graphql/shared-definitions';
  18. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  19. describe('Administrator resolver', () => {
  20. const { server, adminClient } = createTestEnvironment(testConfig());
  21. let createdAdmin: AdministratorFragment;
  22. beforeAll(async () => {
  23. await server.init({
  24. initialData,
  25. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  26. customerCount: 1,
  27. });
  28. await adminClient.asSuperAdmin();
  29. }, TEST_SETUP_TIMEOUT_MS);
  30. afterAll(async () => {
  31. await server.destroy();
  32. });
  33. it('administrators', async () => {
  34. const result = await adminClient.query<
  35. Codegen.GetAdministratorsQuery,
  36. Codegen.GetAdministratorsQueryVariables
  37. >(GET_ADMINISTRATORS);
  38. expect(result.administrators.items.length).toBe(1);
  39. expect(result.administrators.totalItems).toBe(1);
  40. });
  41. it('createAdministrator', async () => {
  42. const result = await adminClient.query<
  43. Codegen.CreateAdministratorMutation,
  44. Codegen.CreateAdministratorMutationVariables
  45. >(CREATE_ADMINISTRATOR, {
  46. input: {
  47. emailAddress: 'test@test.com',
  48. firstName: 'First',
  49. lastName: 'Last',
  50. password: 'password',
  51. roleIds: ['1'],
  52. },
  53. });
  54. createdAdmin = result.createAdministrator;
  55. expect(createdAdmin).toMatchSnapshot();
  56. });
  57. it('administrator', async () => {
  58. const result = await adminClient.query<
  59. Codegen.GetAdministratorQuery,
  60. Codegen.GetAdministratorQueryVariables
  61. >(GET_ADMINISTRATOR, {
  62. id: createdAdmin.id,
  63. });
  64. expect(result.administrator).toEqual(createdAdmin);
  65. });
  66. it('updateAdministrator', async () => {
  67. const result = await adminClient.query<
  68. Codegen.UpdateAdministratorMutation,
  69. Codegen.UpdateAdministratorMutationVariables
  70. >(UPDATE_ADMINISTRATOR, {
  71. input: {
  72. id: createdAdmin.id,
  73. emailAddress: 'new-email',
  74. firstName: 'new first',
  75. lastName: 'new last',
  76. password: 'new password',
  77. roleIds: ['2'],
  78. },
  79. });
  80. expect(result.updateAdministrator).toMatchSnapshot();
  81. });
  82. it('updateAdministrator works with partial input', async () => {
  83. const result = await adminClient.query<
  84. Codegen.UpdateAdministratorMutation,
  85. Codegen.UpdateAdministratorMutationVariables
  86. >(UPDATE_ADMINISTRATOR, {
  87. input: {
  88. id: createdAdmin.id,
  89. emailAddress: 'newest-email',
  90. },
  91. });
  92. expect(result.updateAdministrator.emailAddress).toBe('newest-email');
  93. expect(result.updateAdministrator.firstName).toBe('new first');
  94. expect(result.updateAdministrator.lastName).toBe('new last');
  95. });
  96. it(
  97. 'updateAdministrator throws with invalid roleId',
  98. assertThrowsWithMessage(
  99. () =>
  100. adminClient.query<
  101. Codegen.UpdateAdministratorMutation,
  102. Codegen.UpdateAdministratorMutationVariables
  103. >(UPDATE_ADMINISTRATOR, {
  104. input: {
  105. id: createdAdmin.id,
  106. emailAddress: 'new-email',
  107. firstName: 'new first',
  108. lastName: 'new last',
  109. password: 'new password',
  110. roleIds: ['999'],
  111. },
  112. }),
  113. 'No Role with the id "999" could be found',
  114. ),
  115. );
  116. it('deleteAdministrator', async () => {
  117. const { administrators: before } = await adminClient.query<
  118. Codegen.GetAdministratorsQuery,
  119. Codegen.GetAdministratorsQueryVariables
  120. >(GET_ADMINISTRATORS);
  121. expect(before.totalItems).toBe(2);
  122. const { deleteAdministrator } = await adminClient.query<
  123. Codegen.DeleteAdministratorMutation,
  124. Codegen.DeleteAdministratorMutationVariables
  125. >(DELETE_ADMINISTRATOR, {
  126. id: createdAdmin.id,
  127. });
  128. expect(deleteAdministrator.result).toBe(DeletionResult.DELETED);
  129. const { administrators: after } = await adminClient.query<
  130. Codegen.GetAdministratorsQuery,
  131. Codegen.GetAdministratorsQueryVariables
  132. >(GET_ADMINISTRATORS);
  133. expect(after.totalItems).toBe(1);
  134. });
  135. it('cannot delete sole SuperAdmin', async () => {
  136. const { administrators: before } = await adminClient.query<
  137. Codegen.GetAdministratorsQuery,
  138. Codegen.GetAdministratorsQueryVariables
  139. >(GET_ADMINISTRATORS);
  140. expect(before.totalItems).toBe(1);
  141. expect(before.items[0].emailAddress).toBe('superadmin');
  142. try {
  143. const { deleteAdministrator } = await adminClient.query<
  144. Codegen.DeleteAdministratorMutation,
  145. Codegen.DeleteAdministratorMutationVariables
  146. >(DELETE_ADMINISTRATOR, {
  147. id: before.items[0].id,
  148. });
  149. fail('Should have thrown');
  150. } catch (e: any) {
  151. expect(e.message).toBe('The sole SuperAdmin cannot be deleted');
  152. }
  153. const { administrators: after } = await adminClient.query<
  154. Codegen.GetAdministratorsQuery,
  155. Codegen.GetAdministratorsQueryVariables
  156. >(GET_ADMINISTRATORS);
  157. expect(after.totalItems).toBe(1);
  158. });
  159. it(
  160. 'cannot remove SuperAdmin role from sole SuperAdmin',
  161. assertThrowsWithMessage(async () => {
  162. const result = await adminClient.query<
  163. Codegen.UpdateAdministratorMutation,
  164. Codegen.UpdateAdministratorMutationVariables
  165. >(UPDATE_ADMINISTRATOR, {
  166. input: {
  167. id: 'T_1',
  168. roleIds: [],
  169. },
  170. });
  171. }, 'Cannot remove the SuperAdmin role from the sole SuperAdmin'),
  172. );
  173. it('cannot query a deleted Administrator', async () => {
  174. const { administrator } = await adminClient.query<
  175. Codegen.GetAdministratorQuery,
  176. Codegen.GetAdministratorQueryVariables
  177. >(GET_ADMINISTRATOR, {
  178. id: createdAdmin.id,
  179. });
  180. expect(administrator).toBeNull();
  181. });
  182. it('activeAdministrator', async () => {
  183. await adminClient.asAnonymousUser();
  184. const { activeAdministrator: result1 } = await adminClient.query<Codegen.ActiveAdministratorQuery>(
  185. GET_ACTIVE_ADMINISTRATOR,
  186. );
  187. expect(result1).toBeNull();
  188. await adminClient.asSuperAdmin();
  189. const { activeAdministrator: result2 } = await adminClient.query<Codegen.ActiveAdministratorQuery>(
  190. GET_ACTIVE_ADMINISTRATOR,
  191. );
  192. expect(result2?.emailAddress).toBe(SUPER_ADMIN_USER_IDENTIFIER);
  193. });
  194. it('updateActiveAdministrator', async () => {
  195. const { updateActiveAdministrator } = await adminClient.query<
  196. Codegen.UpdateActiveAdministratorMutation,
  197. Codegen.UpdateActiveAdministratorMutationVariables
  198. >(UPDATE_ACTIVE_ADMINISTRATOR, {
  199. input: {
  200. firstName: 'Thomas',
  201. lastName: 'Anderson',
  202. emailAddress: 'neo@metacortex.com',
  203. },
  204. });
  205. expect(updateActiveAdministrator.firstName).toBe('Thomas');
  206. expect(updateActiveAdministrator.lastName).toBe('Anderson');
  207. const { activeAdministrator } = await adminClient.query<Codegen.ActiveAdministratorQuery>(
  208. GET_ACTIVE_ADMINISTRATOR,
  209. );
  210. expect(activeAdministrator?.firstName).toBe('Thomas');
  211. expect(activeAdministrator?.user.identifier).toBe('neo@metacortex.com');
  212. });
  213. it('supports case-sensitive admin identifiers', async () => {
  214. const loginResultGuard: ErrorResultGuard<CurrentUser> = createErrorResultGuard(
  215. input => !!input.identifier,
  216. );
  217. const { createAdministrator } = await adminClient.query<
  218. Codegen.CreateAdministratorMutation,
  219. Codegen.CreateAdministratorMutationVariables
  220. >(CREATE_ADMINISTRATOR, {
  221. input: {
  222. emailAddress: 'NewAdmin',
  223. firstName: 'New',
  224. lastName: 'Admin',
  225. password: 'password',
  226. roleIds: ['1'],
  227. },
  228. });
  229. const { login } = await adminClient.query(AttemptLoginDocument, {
  230. username: 'NewAdmin',
  231. password: 'password',
  232. });
  233. loginResultGuard.assertSuccess(login);
  234. expect(login.identifier).toBe('NewAdmin');
  235. });
  236. });
  237. export const GET_ADMINISTRATORS = gql`
  238. query GetAdministrators($options: AdministratorListOptions) {
  239. administrators(options: $options) {
  240. items {
  241. ...Administrator
  242. }
  243. totalItems
  244. }
  245. }
  246. ${ADMINISTRATOR_FRAGMENT}
  247. `;
  248. export const GET_ADMINISTRATOR = gql`
  249. query GetAdministrator($id: ID!) {
  250. administrator(id: $id) {
  251. ...Administrator
  252. }
  253. }
  254. ${ADMINISTRATOR_FRAGMENT}
  255. `;
  256. export const GET_ACTIVE_ADMINISTRATOR = gql`
  257. query ActiveAdministrator {
  258. activeAdministrator {
  259. ...Administrator
  260. }
  261. }
  262. ${ADMINISTRATOR_FRAGMENT}
  263. `;
  264. export const UPDATE_ACTIVE_ADMINISTRATOR = gql`
  265. mutation UpdateActiveAdministrator($input: UpdateActiveAdministratorInput!) {
  266. updateActiveAdministrator(input: $input) {
  267. ...Administrator
  268. }
  269. }
  270. ${ADMINISTRATOR_FRAGMENT}
  271. `;
  272. export const DELETE_ADMINISTRATOR = gql`
  273. mutation DeleteAdministrator($id: ID!) {
  274. deleteAdministrator(id: $id) {
  275. message
  276. result
  277. }
  278. }
  279. `;