customer-channel.e2e-spec.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* eslint-disable @typescript-eslint/no-non-null-assertion */
  2. import { CurrencyCode, LanguageCode } from '@vendure/common/lib/generated-types';
  3. import { createTestEnvironment, E2E_DEFAULT_CHANNEL_TOKEN } from '@vendure/testing';
  4. import path from 'path';
  5. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  6. import { initialData } from '../../../e2e-common/e2e-initial-data';
  7. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  8. import { ResultOf } from './graphql/graphql-admin';
  9. import {
  10. addCustomersToGroupDocument,
  11. createAddressDocument,
  12. createChannelDocument,
  13. createCustomerDocument,
  14. createCustomerGroupDocument,
  15. deleteCustomerDocument,
  16. getCustomerGroupDocument,
  17. getCustomerListDocument,
  18. MeDocument,
  19. removeCustomersFromGroupDocument,
  20. updateAddressDocument,
  21. updateCustomerDocument,
  22. } from './graphql/shared-definitions';
  23. import { deleteAddressDocument, registerAccountDocument } from './graphql/shop-definitions';
  24. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  25. type CustomerListItem = ResultOf<typeof getCustomerListDocument>['customers']['items'][number];
  26. describe('ChannelAware Customers', () => {
  27. const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
  28. const SECOND_CHANNEL_TOKEN = 'second_channel_token';
  29. let firstCustomer: CustomerListItem;
  30. let secondCustomer: CustomerListItem;
  31. let thirdCustomer: CustomerListItem;
  32. const numberOfCustomers = 3;
  33. let customerGroupId: string;
  34. beforeAll(async () => {
  35. await server.init({
  36. initialData,
  37. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  38. customerCount: numberOfCustomers,
  39. });
  40. await adminClient.asSuperAdmin();
  41. const { customers } = await adminClient.query(getCustomerListDocument, {
  42. options: { take: numberOfCustomers },
  43. });
  44. firstCustomer = customers.items[0];
  45. secondCustomer = customers.items[1];
  46. thirdCustomer = customers.items[2];
  47. await adminClient.query(createChannelDocument, {
  48. input: {
  49. code: 'second-channel',
  50. token: SECOND_CHANNEL_TOKEN,
  51. defaultLanguageCode: LanguageCode.en,
  52. currencyCode: CurrencyCode.GBP,
  53. pricesIncludeTax: true,
  54. defaultShippingZoneId: 'T_1',
  55. defaultTaxZoneId: 'T_1',
  56. },
  57. });
  58. const { createCustomerGroup } = await adminClient.query(createCustomerGroupDocument, {
  59. input: {
  60. name: 'TestGroup',
  61. },
  62. });
  63. customerGroupId = createCustomerGroup.id;
  64. }, TEST_SETUP_TIMEOUT_MS);
  65. afterAll(async () => {
  66. await server.destroy();
  67. });
  68. describe('Address manipulation', () => {
  69. it(
  70. 'throws when updating address from customer from other channel',
  71. assertThrowsWithMessage(async () => {
  72. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  73. await adminClient.query(updateAddressDocument, {
  74. input: {
  75. id: 'T_1',
  76. streetLine1: 'Dummy street',
  77. },
  78. });
  79. }, 'No Address with the id "1" could be found'),
  80. );
  81. it(
  82. 'throws when creating address for customer from other channel',
  83. assertThrowsWithMessage(async () => {
  84. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  85. await adminClient.query(createAddressDocument, {
  86. id: firstCustomer.id,
  87. input: {
  88. streetLine1: 'Dummy street',
  89. countryCode: 'BE',
  90. },
  91. });
  92. }, 'No Customer with the id "1" could be found'),
  93. );
  94. it(
  95. 'throws when deleting address from customer from other channel',
  96. assertThrowsWithMessage(async () => {
  97. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  98. await adminClient.query(deleteAddressDocument, {
  99. id: 'T_1',
  100. });
  101. }, 'No Address with the id "1" could be found'),
  102. );
  103. });
  104. describe('Customer manipulation', () => {
  105. it(
  106. 'throws when deleting customer from other channel',
  107. assertThrowsWithMessage(async () => {
  108. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  109. await adminClient.query(deleteCustomerDocument, {
  110. id: firstCustomer.id,
  111. });
  112. }, 'No Customer with the id "1" could be found'),
  113. );
  114. it(
  115. 'throws when updating customer from other channel',
  116. assertThrowsWithMessage(async () => {
  117. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  118. await adminClient.query(updateCustomerDocument, {
  119. input: {
  120. id: firstCustomer.id,
  121. firstName: 'John',
  122. lastName: 'Doe',
  123. },
  124. });
  125. }, 'No Customer with the id "1" could be found'),
  126. );
  127. it('creates customers on current and default channel', async () => {
  128. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  129. await adminClient.query(createCustomerDocument, {
  130. input: {
  131. firstName: 'John',
  132. lastName: 'Doe',
  133. emailAddress: 'john.doe@test.com',
  134. },
  135. });
  136. const customersSecondChannel = await adminClient.query(getCustomerListDocument);
  137. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  138. const customersDefaultChannel = await adminClient.query(getCustomerListDocument);
  139. expect(customersSecondChannel.customers.totalItems).toBe(1);
  140. expect(customersDefaultChannel.customers.totalItems).toBe(numberOfCustomers + 1);
  141. });
  142. it('only shows customers from current channel', async () => {
  143. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  144. const { customers } = await adminClient.query(getCustomerListDocument);
  145. expect(customers.totalItems).toBe(1);
  146. });
  147. it('shows all customers on default channel', async () => {
  148. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  149. const { customers } = await adminClient.query(getCustomerListDocument);
  150. expect(customers.totalItems).toBe(numberOfCustomers + 1);
  151. });
  152. it('brings customer to current channel when creating with existing emailAddress', async () => {
  153. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  154. let customersDefaultChannel = await adminClient.query(getCustomerListDocument);
  155. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  156. let customersSecondChannel = await adminClient.query(getCustomerListDocument);
  157. expect(customersDefaultChannel.customers.items.map(customer => customer.emailAddress)).toContain(
  158. firstCustomer.emailAddress,
  159. );
  160. expect(
  161. customersSecondChannel.customers.items.map(customer => customer.emailAddress),
  162. ).not.toContain(firstCustomer.emailAddress);
  163. await adminClient.query(createCustomerDocument, {
  164. input: {
  165. firstName: firstCustomer.firstName + '_new',
  166. lastName: firstCustomer.lastName + '_new',
  167. emailAddress: firstCustomer.emailAddress,
  168. },
  169. });
  170. customersSecondChannel = await adminClient.query(getCustomerListDocument);
  171. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  172. customersDefaultChannel = await adminClient.query(getCustomerListDocument);
  173. const firstCustomerOnNewChannel = customersSecondChannel.customers.items.find(
  174. customer => customer.emailAddress === firstCustomer.emailAddress,
  175. );
  176. const firstCustomerOnDefaultChannel = customersDefaultChannel.customers.items.find(
  177. customer => customer.emailAddress === firstCustomer.emailAddress,
  178. );
  179. expect(firstCustomerOnNewChannel).not.toBeNull();
  180. expect(firstCustomerOnNewChannel?.emailAddress).toBe(firstCustomer.emailAddress);
  181. expect(firstCustomerOnNewChannel?.firstName).toBe(firstCustomer.firstName + '_new');
  182. expect(firstCustomerOnNewChannel?.lastName).toBe(firstCustomer.lastName + '_new');
  183. expect(firstCustomerOnDefaultChannel).not.toBeNull();
  184. expect(firstCustomerOnDefaultChannel?.emailAddress).toBe(firstCustomer.emailAddress);
  185. expect(firstCustomerOnDefaultChannel?.firstName).toBe(firstCustomer.firstName + '_new');
  186. expect(firstCustomerOnDefaultChannel?.lastName).toBe(firstCustomer.lastName + '_new');
  187. });
  188. });
  189. describe('Shop API', () => {
  190. it('assigns authenticated customers to the channels they visit', async () => {
  191. shopClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  192. await shopClient.asUserWithCredentials(secondCustomer.emailAddress, 'test');
  193. await shopClient.query(MeDocument);
  194. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  195. const { customers } = await adminClient.query(getCustomerListDocument);
  196. expect(customers.totalItems).toBe(3);
  197. expect(customers.items.map(customer => customer.emailAddress)).toContain(
  198. secondCustomer.emailAddress,
  199. );
  200. });
  201. it('assigns newly registered customers to channel', async () => {
  202. shopClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  203. await shopClient.asAnonymousUser();
  204. await shopClient.query(registerAccountDocument, {
  205. input: {
  206. emailAddress: 'john.doe.2@test.com',
  207. },
  208. });
  209. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  210. const { customers } = await adminClient.query(getCustomerListDocument);
  211. expect(customers.totalItems).toBe(4);
  212. expect(customers.items.map(customer => customer.emailAddress)).toContain('john.doe.2@test.com');
  213. });
  214. // https://github.com/vendure-ecommerce/vendure/issues/834
  215. it('handles concurrent assignments to a new channel', async () => {
  216. const THIRD_CHANNEL_TOKEN = 'third_channel_token';
  217. await adminClient.query(createChannelDocument, {
  218. input: {
  219. code: 'third-channel',
  220. token: THIRD_CHANNEL_TOKEN,
  221. defaultLanguageCode: LanguageCode.en,
  222. currencyCode: CurrencyCode.GBP,
  223. pricesIncludeTax: true,
  224. defaultShippingZoneId: 'T_1',
  225. defaultTaxZoneId: 'T_1',
  226. },
  227. });
  228. await shopClient.asUserWithCredentials(secondCustomer.emailAddress, 'test');
  229. shopClient.setChannelToken(THIRD_CHANNEL_TOKEN);
  230. try {
  231. await Promise.all([shopClient.query(MeDocument), shopClient.query(MeDocument)]);
  232. } catch (e: any) {
  233. fail('Threw: ' + (e.message as string));
  234. }
  235. adminClient.setChannelToken(THIRD_CHANNEL_TOKEN);
  236. const { customers } = await adminClient.query(getCustomerListDocument);
  237. expect(customers.totalItems).toBe(1);
  238. expect(customers.items.map(customer => customer.emailAddress)).toContain(
  239. secondCustomer.emailAddress,
  240. );
  241. });
  242. });
  243. describe('Customergroup manipulation', () => {
  244. it('does not add a customer from another channel to customerGroup', async () => {
  245. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  246. await adminClient.query(addCustomersToGroupDocument, {
  247. groupId: customerGroupId,
  248. customerIds: [thirdCustomer.id],
  249. });
  250. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  251. const { customerGroup } = await adminClient.query(getCustomerGroupDocument, {
  252. id: customerGroupId,
  253. });
  254. expect(customerGroup!.customers.totalItems).toBe(0);
  255. });
  256. it('only shows customers from current channel in customerGroup', async () => {
  257. adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
  258. await adminClient.query(addCustomersToGroupDocument, {
  259. groupId: customerGroupId,
  260. customerIds: [secondCustomer.id, thirdCustomer.id],
  261. });
  262. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  263. const { customerGroup } = await adminClient.query(getCustomerGroupDocument, {
  264. id: customerGroupId,
  265. });
  266. expect(customerGroup!.customers.totalItems).toBe(1);
  267. expect(customerGroup!.customers.items.map(customer => customer.id)).toContain(secondCustomer.id);
  268. });
  269. it('throws when deleting customer from other channel from customerGroup', async () => {
  270. adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
  271. await adminClient.query(removeCustomersFromGroupDocument, {
  272. groupId: customerGroupId,
  273. customerIds: [thirdCustomer.id],
  274. });
  275. });
  276. });
  277. });