custom-field-permissions.e2e-spec.ts 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import { Permission } from '@vendure/common/lib/generated-types';
  2. import { mergeConfig } from '@vendure/core';
  3. import { createTestEnvironment, SimpleGraphQLClient } from '@vendure/testing';
  4. import { fail } from 'assert';
  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 { ResultOf } from './graphql/graphql-admin';
  10. import {
  11. createAdministratorDocument,
  12. createRoleDocument,
  13. getProductWithCustomFieldsDocument,
  14. getProductWithPublicCustomFieldsDocument,
  15. updateProductDocument,
  16. } from './graphql/shared-definitions';
  17. describe('Custom field permissions', () => {
  18. const { server, adminClient, shopClient } = createTestEnvironment(
  19. mergeConfig(testConfig(), {
  20. customFields: {
  21. Product: [
  22. {
  23. name: 'publicField',
  24. type: 'string',
  25. public: true,
  26. defaultValue: 'publicField Value',
  27. },
  28. {
  29. name: 'authenticatedField',
  30. type: 'string',
  31. defaultValue: 'authenticatedField Value',
  32. public: true,
  33. requiresPermission: Permission.Authenticated,
  34. },
  35. {
  36. name: 'updateProductField',
  37. type: 'string',
  38. defaultValue: 'updateProductField Value',
  39. public: true,
  40. requiresPermission: Permission.UpdateProduct,
  41. },
  42. {
  43. name: 'updateProductOrCustomerField',
  44. type: 'string',
  45. defaultValue: 'updateProductOrCustomerField Value',
  46. public: false,
  47. requiresPermission: [Permission.UpdateProduct, Permission.UpdateCustomer],
  48. },
  49. {
  50. name: 'superadminField',
  51. type: 'string',
  52. defaultValue: 'superadminField Value',
  53. public: false,
  54. requiresPermission: Permission.SuperAdmin,
  55. },
  56. ],
  57. },
  58. }),
  59. );
  60. let readProductUpdateProductAdmin: ResultOf<typeof createAdministratorDocument>['createAdministrator'];
  61. let readProductUpdateCustomerAdmin: ResultOf<typeof createAdministratorDocument>['createAdministrator'];
  62. beforeAll(async () => {
  63. await server.init({
  64. initialData,
  65. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  66. customerCount: 3,
  67. });
  68. await adminClient.asSuperAdmin();
  69. readProductUpdateProductAdmin = await createAdminWithPermissions({
  70. adminClient,
  71. name: 'ReadProductUpdateProduct',
  72. permissions: [Permission.ReadProduct, Permission.UpdateProduct],
  73. });
  74. readProductUpdateCustomerAdmin = await createAdminWithPermissions({
  75. adminClient,
  76. name: 'ReadProductUpdateCustomer',
  77. permissions: [Permission.ReadProduct, Permission.UpdateCustomer],
  78. });
  79. }, TEST_SETUP_TIMEOUT_MS);
  80. afterAll(async () => {
  81. await server.destroy();
  82. });
  83. it('readProductUpdateProductAdmin can read public and updateProduct custom fields', async () => {
  84. await adminClient.asUserWithCredentials(readProductUpdateProductAdmin.emailAddress, 'test');
  85. const { product } = await adminClient.query(getProductWithCustomFieldsDocument, {
  86. id: 'T_1',
  87. });
  88. expect(product.customFields).toEqual({
  89. publicField: 'publicField Value',
  90. authenticatedField: 'authenticatedField Value',
  91. updateProductField: 'updateProductField Value',
  92. updateProductOrCustomerField: 'updateProductOrCustomerField Value',
  93. superadminField: null,
  94. });
  95. });
  96. it('readProductUpdateCustomerAdmin can read public and updateCustomer custom fields', async () => {
  97. await adminClient.asUserWithCredentials(readProductUpdateCustomerAdmin.emailAddress, 'test');
  98. const { product } = await adminClient.query(getProductWithCustomFieldsDocument, {
  99. id: 'T_1',
  100. });
  101. expect(product.customFields).toEqual({
  102. publicField: 'publicField Value',
  103. authenticatedField: 'authenticatedField Value',
  104. updateProductField: null,
  105. updateProductOrCustomerField: 'updateProductOrCustomerField Value',
  106. superadminField: null,
  107. });
  108. });
  109. it('superadmin can read all custom fields', async () => {
  110. await adminClient.asSuperAdmin();
  111. const { product } = await adminClient.query(getProductWithCustomFieldsDocument, {
  112. id: 'T_1',
  113. });
  114. expect(product.customFields).toEqual({
  115. publicField: 'publicField Value',
  116. authenticatedField: 'authenticatedField Value',
  117. updateProductField: 'updateProductField Value',
  118. updateProductOrCustomerField: 'updateProductOrCustomerField Value',
  119. superadminField: 'superadminField Value',
  120. });
  121. });
  122. it('superadmin can update all custom fields', async () => {
  123. await adminClient.asSuperAdmin();
  124. await adminClient.query(updateProductDocument, {
  125. input: {
  126. id: 'T_1',
  127. customFields: {
  128. publicField: 'new publicField Value',
  129. authenticatedField: 'new authenticatedField Value',
  130. updateProductField: 'new updateProductField Value',
  131. updateProductOrCustomerField: 'new updateProductOrCustomerField Value',
  132. superadminField: 'new superadminField Value',
  133. },
  134. },
  135. });
  136. const { product } = await adminClient.query(getProductWithCustomFieldsDocument, {
  137. id: 'T_1',
  138. });
  139. expect(product.customFields).toEqual({
  140. publicField: 'new publicField Value',
  141. authenticatedField: 'new authenticatedField Value',
  142. updateProductField: 'new updateProductField Value',
  143. updateProductOrCustomerField: 'new updateProductOrCustomerField Value',
  144. superadminField: 'new superadminField Value',
  145. });
  146. });
  147. it('readProductUpdateProductAdmin can update updateProduct custom field', async () => {
  148. await adminClient.asUserWithCredentials(readProductUpdateProductAdmin.emailAddress, 'test');
  149. await adminClient.query(updateProductDocument, {
  150. input: {
  151. id: 'T_1',
  152. customFields: {
  153. updateProductField: 'new updateProductField Value 2',
  154. },
  155. },
  156. });
  157. const { product } = await adminClient.query(getProductWithCustomFieldsDocument, {
  158. id: 'T_1',
  159. });
  160. expect(product.customFields.updateProductField).toBe('new updateProductField Value 2');
  161. });
  162. it('readProductUpdateProductAdmin cannot update superadminField', async () => {
  163. await adminClient.asUserWithCredentials(readProductUpdateProductAdmin.emailAddress, 'test');
  164. try {
  165. await adminClient.query(updateProductDocument, {
  166. input: {
  167. id: 'T_1',
  168. customFields: {
  169. superadminField: 'new superadminField Value 2',
  170. },
  171. },
  172. });
  173. fail('Should have thrown');
  174. } catch (e: any) {
  175. expect(e.message).toBe(
  176. 'You do not have the required permissions to update the "superadminField" field',
  177. );
  178. }
  179. });
  180. // This will throw anyway because the user does not have permission to even
  181. // update the Product at all.
  182. it('readProductUpdateCustomerAdmin cannot update updateProductField', async () => {
  183. await adminClient.asUserWithCredentials(readProductUpdateCustomerAdmin.emailAddress, 'test');
  184. try {
  185. await adminClient.query(updateProductDocument, {
  186. input: {
  187. id: 'T_1',
  188. customFields: {
  189. updateProductField: 'new updateProductField Value 2',
  190. },
  191. },
  192. });
  193. fail('Should have thrown');
  194. } catch (e: any) {
  195. expect(e.message).toBe('You are not currently authorized to perform this action');
  196. }
  197. });
  198. describe('Shop API', () => {
  199. it('all public fields are accessible in Shop API regardless of permissions', async () => {
  200. await shopClient.asAnonymousUser();
  201. const { product } = await shopClient.query(getProductWithPublicCustomFieldsDocument, {
  202. id: 'T_1',
  203. });
  204. expect(product.customFields).toEqual({
  205. publicField: 'new publicField Value',
  206. authenticatedField: 'new authenticatedField Value',
  207. updateProductField: 'new updateProductField Value 2',
  208. });
  209. });
  210. });
  211. });
  212. async function createAdminWithPermissions(input: {
  213. adminClient: SimpleGraphQLClient;
  214. name: string;
  215. permissions: Permission[];
  216. }) {
  217. const { adminClient, name, permissions } = input;
  218. const { createRole } = await adminClient.query(createRoleDocument, {
  219. input: {
  220. code: name,
  221. description: name,
  222. permissions,
  223. },
  224. });
  225. const { createAdministrator } = await adminClient.query(createAdministratorDocument, {
  226. input: {
  227. firstName: name,
  228. lastName: 'LastName',
  229. emailAddress: `${name}@test.com`,
  230. roleIds: [createRole.id],
  231. password: 'test',
  232. },
  233. });
  234. return createAdministrator;
  235. }