customer.e2e-spec.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. import { omit } from '@vendure/common/lib/omit';
  2. import gql from 'graphql-tag';
  3. import path from 'path';
  4. import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
  5. import { CUSTOMER_FRAGMENT } from './graphql/fragments';
  6. import {
  7. CreateAddress,
  8. DeleteCustomer,
  9. DeleteCustomerAddress,
  10. DeletionResult,
  11. GetCustomer,
  12. GetCustomerList,
  13. GetCustomerOrders,
  14. UpdateAddress,
  15. UpdateCustomer,
  16. } from './graphql/generated-e2e-admin-types';
  17. import { AddItemToOrder } from './graphql/generated-e2e-shop-types';
  18. import { GET_CUSTOMER, GET_CUSTOMER_LIST } from './graphql/shared-definitions';
  19. import { ADD_ITEM_TO_ORDER } from './graphql/shop-definitions';
  20. import { TestAdminClient, TestShopClient } from './test-client';
  21. import { TestServer } from './test-server';
  22. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  23. // tslint:disable:no-non-null-assertion
  24. describe('Customer resolver', () => {
  25. const adminClient = new TestAdminClient();
  26. const shopClient = new TestShopClient();
  27. const server = new TestServer();
  28. let firstCustomer: GetCustomerList.Items;
  29. let secondCustomer: GetCustomerList.Items;
  30. let thirdCustomer: GetCustomerList.Items;
  31. beforeAll(async () => {
  32. const token = await server.init({
  33. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  34. customerCount: 5,
  35. });
  36. await adminClient.init();
  37. }, TEST_SETUP_TIMEOUT_MS);
  38. afterAll(async () => {
  39. await server.destroy();
  40. });
  41. it('customers list', async () => {
  42. const result = await adminClient.query<GetCustomerList.Query, GetCustomerList.Variables>(
  43. GET_CUSTOMER_LIST,
  44. );
  45. expect(result.customers.items.length).toBe(5);
  46. expect(result.customers.totalItems).toBe(5);
  47. firstCustomer = result.customers.items[0];
  48. secondCustomer = result.customers.items[1];
  49. thirdCustomer = result.customers.items[2];
  50. });
  51. describe('addresses', () => {
  52. let firstCustomerAddressIds: string[] = [];
  53. let firstCustomerThirdAddressId: string;
  54. it(
  55. 'createCustomerAddress throws on invalid countryCode',
  56. assertThrowsWithMessage(
  57. () =>
  58. adminClient.query<CreateAddress.Mutation, CreateAddress.Variables>(CREATE_ADDRESS, {
  59. id: firstCustomer.id,
  60. input: {
  61. streetLine1: 'streetLine1',
  62. countryCode: 'INVALID',
  63. },
  64. }),
  65. `The countryCode "INVALID" was not recognized`,
  66. ),
  67. );
  68. it('createCustomerAddress creates a new address', async () => {
  69. const result = await adminClient.query<CreateAddress.Mutation, CreateAddress.Variables>(
  70. CREATE_ADDRESS,
  71. {
  72. id: firstCustomer.id,
  73. input: {
  74. fullName: 'fullName',
  75. company: 'company',
  76. streetLine1: 'streetLine1',
  77. streetLine2: 'streetLine2',
  78. city: 'city',
  79. province: 'province',
  80. postalCode: 'postalCode',
  81. countryCode: 'GB',
  82. phoneNumber: 'phoneNumber',
  83. defaultShippingAddress: false,
  84. defaultBillingAddress: false,
  85. },
  86. },
  87. );
  88. expect(omit(result.createCustomerAddress, ['id'])).toEqual({
  89. fullName: 'fullName',
  90. company: 'company',
  91. streetLine1: 'streetLine1',
  92. streetLine2: 'streetLine2',
  93. city: 'city',
  94. province: 'province',
  95. postalCode: 'postalCode',
  96. country: {
  97. code: 'GB',
  98. name: 'United Kingdom',
  99. },
  100. phoneNumber: 'phoneNumber',
  101. defaultShippingAddress: false,
  102. defaultBillingAddress: false,
  103. });
  104. });
  105. it('customer query returns addresses', async () => {
  106. const result = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  107. id: firstCustomer.id,
  108. });
  109. expect(result.customer!.addresses!.length).toBe(2);
  110. firstCustomerAddressIds = result.customer!.addresses!.map(a => a.id);
  111. });
  112. it('updateCustomerAddress updates the country', async () => {
  113. const result = await adminClient.query<UpdateAddress.Mutation, UpdateAddress.Variables>(
  114. UPDATE_ADDRESS,
  115. {
  116. input: {
  117. id: firstCustomerAddressIds[0],
  118. countryCode: 'AT',
  119. },
  120. },
  121. );
  122. expect(result.updateCustomerAddress.country).toEqual({
  123. code: 'AT',
  124. name: 'Austria',
  125. });
  126. });
  127. it('updateCustomerAddress allows only a single default address', async () => {
  128. // set the first customer's second address to be default
  129. const result1 = await adminClient.query<UpdateAddress.Mutation, UpdateAddress.Variables>(
  130. UPDATE_ADDRESS,
  131. {
  132. input: {
  133. id: firstCustomerAddressIds[1],
  134. defaultShippingAddress: true,
  135. defaultBillingAddress: true,
  136. },
  137. },
  138. );
  139. expect(result1.updateCustomerAddress.defaultShippingAddress).toBe(true);
  140. expect(result1.updateCustomerAddress.defaultBillingAddress).toBe(true);
  141. // assert the first customer's first address is not default
  142. const result2 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  143. id: firstCustomer.id,
  144. });
  145. expect(result2.customer!.addresses![0].defaultShippingAddress).toBe(false);
  146. expect(result2.customer!.addresses![0].defaultBillingAddress).toBe(false);
  147. // set the first customer's first address to be default
  148. const result3 = await adminClient.query<UpdateAddress.Mutation, UpdateAddress.Variables>(
  149. UPDATE_ADDRESS,
  150. {
  151. input: {
  152. id: firstCustomerAddressIds[0],
  153. defaultShippingAddress: true,
  154. defaultBillingAddress: true,
  155. },
  156. },
  157. );
  158. expect(result3.updateCustomerAddress.defaultShippingAddress).toBe(true);
  159. expect(result3.updateCustomerAddress.defaultBillingAddress).toBe(true);
  160. // assert the first customer's second address is not default
  161. const result4 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  162. id: firstCustomer.id,
  163. });
  164. expect(result4.customer!.addresses![1].defaultShippingAddress).toBe(false);
  165. expect(result4.customer!.addresses![1].defaultBillingAddress).toBe(false);
  166. // get the second customer's address id
  167. const result5 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  168. id: secondCustomer.id,
  169. });
  170. const secondCustomerAddressId = result5.customer!.addresses![0].id;
  171. // set the second customer's address to be default
  172. const result6 = await adminClient.query<UpdateAddress.Mutation, UpdateAddress.Variables>(
  173. UPDATE_ADDRESS,
  174. {
  175. input: {
  176. id: secondCustomerAddressId,
  177. defaultShippingAddress: true,
  178. defaultBillingAddress: true,
  179. },
  180. },
  181. );
  182. expect(result6.updateCustomerAddress.defaultShippingAddress).toBe(true);
  183. expect(result6.updateCustomerAddress.defaultBillingAddress).toBe(true);
  184. // assets the first customer's address defaults are unchanged
  185. const result7 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  186. id: firstCustomer.id,
  187. });
  188. expect(result7.customer!.addresses![0].defaultShippingAddress).toBe(true);
  189. expect(result7.customer!.addresses![0].defaultBillingAddress).toBe(true);
  190. expect(result7.customer!.addresses![1].defaultShippingAddress).toBe(false);
  191. expect(result7.customer!.addresses![1].defaultBillingAddress).toBe(false);
  192. });
  193. it('createCustomerAddress with true defaults unsets existing defaults', async () => {
  194. const result1 = await adminClient.query<CreateAddress.Mutation, CreateAddress.Variables>(
  195. CREATE_ADDRESS,
  196. {
  197. id: firstCustomer.id,
  198. input: {
  199. streetLine1: 'new default streetline',
  200. countryCode: 'GB',
  201. defaultShippingAddress: true,
  202. defaultBillingAddress: true,
  203. },
  204. },
  205. );
  206. expect(omit(result1.createCustomerAddress, ['id'])).toEqual({
  207. fullName: '',
  208. company: '',
  209. streetLine1: 'new default streetline',
  210. streetLine2: '',
  211. city: '',
  212. province: '',
  213. postalCode: '',
  214. country: {
  215. code: 'GB',
  216. name: 'United Kingdom',
  217. },
  218. phoneNumber: '',
  219. defaultShippingAddress: true,
  220. defaultBillingAddress: true,
  221. });
  222. const result2 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  223. id: firstCustomer.id,
  224. });
  225. expect(result2.customer!.addresses![0].defaultShippingAddress).toBe(false);
  226. expect(result2.customer!.addresses![0].defaultBillingAddress).toBe(false);
  227. expect(result2.customer!.addresses![1].defaultShippingAddress).toBe(false);
  228. expect(result2.customer!.addresses![1].defaultBillingAddress).toBe(false);
  229. expect(result2.customer!.addresses![2].defaultShippingAddress).toBe(true);
  230. expect(result2.customer!.addresses![2].defaultBillingAddress).toBe(true);
  231. firstCustomerThirdAddressId = result2.customer!.addresses![2].id;
  232. });
  233. it('deleteCustomerAddress on default address resets defaults', async () => {
  234. const result = await adminClient.query<
  235. DeleteCustomerAddress.Mutation,
  236. DeleteCustomerAddress.Variables
  237. >(
  238. gql`
  239. mutation DeleteCustomerAddress($id: ID!) {
  240. deleteCustomerAddress(id: $id)
  241. }
  242. `,
  243. { id: firstCustomerThirdAddressId },
  244. );
  245. expect(result.deleteCustomerAddress).toBe(true);
  246. const result2 = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  247. id: firstCustomer.id,
  248. });
  249. expect(result2.customer!.addresses!.length).toBe(2);
  250. expect(result2.customer!.addresses![0].defaultShippingAddress).toBe(true);
  251. expect(result2.customer!.addresses![0].defaultBillingAddress).toBe(true);
  252. expect(result2.customer!.addresses![1].defaultShippingAddress).toBe(false);
  253. expect(result2.customer!.addresses![1].defaultBillingAddress).toBe(false);
  254. });
  255. });
  256. describe('orders', () => {
  257. it(`lists that user\'s orders`, async () => {
  258. // log in as first customer
  259. await shopClient.asUserWithCredentials(firstCustomer.emailAddress, 'test');
  260. // add an item to the order to create an order
  261. const { addItemToOrder } = await shopClient.query<
  262. AddItemToOrder.Mutation,
  263. AddItemToOrder.Variables
  264. >(ADD_ITEM_TO_ORDER, {
  265. productVariantId: 'T_1',
  266. quantity: 1,
  267. });
  268. const { customer } = await adminClient.query<
  269. GetCustomerOrders.Query,
  270. GetCustomerOrders.Variables
  271. >(GET_CUSTOMER_ORDERS, { id: firstCustomer.id });
  272. expect(customer!.orders.totalItems).toBe(1);
  273. expect(customer!.orders.items[0].id).toBe(addItemToOrder!.id);
  274. });
  275. });
  276. describe('deletion', () => {
  277. it('deletes a customer', async () => {
  278. const result = await adminClient.query<DeleteCustomer.Mutation, DeleteCustomer.Variables>(DELETE_CUSTOMER, { id: thirdCustomer.id });
  279. expect(result.deleteCustomer).toEqual({ result: DeletionResult.DELETED });
  280. });
  281. it('cannot get a deleted customer', async () => {
  282. const result = await adminClient.query<GetCustomer.Query, GetCustomer.Variables>(GET_CUSTOMER, {
  283. id: thirdCustomer.id,
  284. });
  285. expect(result.customer).toBe(null);
  286. });
  287. it('deleted customer omitted from list', async () => {
  288. const result = await adminClient.query<GetCustomerList.Query, GetCustomerList.Variables>(
  289. GET_CUSTOMER_LIST,
  290. );
  291. expect(result.customers.items.map(c => c.id).includes(thirdCustomer.id)).toBe(false);
  292. });
  293. it(
  294. 'updateCustomer throws for deleted customer',
  295. assertThrowsWithMessage(
  296. () =>
  297. adminClient.query<UpdateCustomer.Mutation, UpdateCustomer.Variables>(UPDATE_CUSTOMER, {
  298. input: {
  299. id: thirdCustomer.id,
  300. firstName: 'updated',
  301. },
  302. }),
  303. `No Customer with the id '3' could be found`,
  304. ),
  305. );
  306. it(
  307. 'createCustomerAddress throws for deleted customer',
  308. assertThrowsWithMessage(
  309. () =>
  310. adminClient.query<CreateAddress.Mutation, CreateAddress.Variables>(CREATE_ADDRESS, {
  311. id: thirdCustomer.id,
  312. input: {
  313. streetLine1: 'test',
  314. countryCode: 'GB',
  315. },
  316. }),
  317. `No Customer with the id '3' could be found`,
  318. ),
  319. );
  320. });
  321. });
  322. const CREATE_ADDRESS = gql`
  323. mutation CreateAddress($id: ID!, $input: CreateAddressInput!) {
  324. createCustomerAddress(customerId: $id, input: $input) {
  325. id
  326. fullName
  327. company
  328. streetLine1
  329. streetLine2
  330. city
  331. province
  332. postalCode
  333. country {
  334. code
  335. name
  336. }
  337. phoneNumber
  338. defaultShippingAddress
  339. defaultBillingAddress
  340. }
  341. }
  342. `;
  343. const UPDATE_ADDRESS = gql`
  344. mutation UpdateAddress($input: UpdateAddressInput!) {
  345. updateCustomerAddress(input: $input) {
  346. id
  347. defaultShippingAddress
  348. defaultBillingAddress
  349. country {
  350. code
  351. name
  352. }
  353. }
  354. }
  355. `;
  356. const GET_CUSTOMER_ORDERS = gql`
  357. query GetCustomerOrders($id: ID!) {
  358. customer(id: $id) {
  359. orders {
  360. items {
  361. id
  362. }
  363. totalItems
  364. }
  365. }
  366. }
  367. `;
  368. export const UPDATE_CUSTOMER = gql`
  369. mutation UpdateCustomer($input: UpdateCustomerInput!) {
  370. updateCustomer(input: $input) {
  371. ...Customer
  372. }
  373. }
  374. ${CUSTOMER_FRAGMENT}
  375. `;
  376. const DELETE_CUSTOMER = gql`
  377. mutation DeleteCustomer($id: ID!) {
  378. deleteCustomer(id: $id) {
  379. result
  380. }
  381. }
  382. `;