customer.e2e-spec.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. import { OnModuleInit } from '@nestjs/common';
  2. import { HistoryEntryType } from '@vendure/common/lib/generated-types';
  3. import { omit } from '@vendure/common/lib/omit';
  4. import { pick } from '@vendure/common/lib/pick';
  5. import {
  6. AccountRegistrationEvent,
  7. EventBus,
  8. EventBusModule,
  9. mergeConfig,
  10. VendurePlugin,
  11. } from '@vendure/core';
  12. import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing';
  13. import gql from 'graphql-tag';
  14. import path from 'path';
  15. import { initialData } from '../../../e2e-common/e2e-initial-data';
  16. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  17. import { CUSTOMER_FRAGMENT } from './graphql/fragments';
  18. import { DeletionResult, ErrorCode } from './graphql/generated-e2e-admin-types';
  19. import * as Codegen from './graphql/generated-e2e-admin-types';
  20. import {
  21. AddItemToOrderMutation,
  22. AddItemToOrderMutationVariables,
  23. UpdatedOrderFragment,
  24. } from './graphql/generated-e2e-shop-types';
  25. import {
  26. CREATE_ADDRESS,
  27. CREATE_CUSTOMER,
  28. DELETE_CUSTOMER,
  29. DELETE_CUSTOMER_NOTE,
  30. GET_CUSTOMER,
  31. GET_CUSTOMER_HISTORY,
  32. GET_CUSTOMER_LIST,
  33. ME,
  34. UPDATE_ADDRESS,
  35. UPDATE_CUSTOMER,
  36. UPDATE_CUSTOMER_NOTE,
  37. } from './graphql/shared-definitions';
  38. import { ADD_ITEM_TO_ORDER } from './graphql/shop-definitions';
  39. import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
  40. // tslint:disable:no-non-null-assertion
  41. let sendEmailFn: jest.Mock;
  42. /**
  43. * This mock plugin simulates an EmailPlugin which would send emails
  44. * on the registration & password reset events.
  45. */
  46. @VendurePlugin({
  47. imports: [EventBusModule],
  48. })
  49. class TestEmailPlugin implements OnModuleInit {
  50. constructor(private eventBus: EventBus) {}
  51. onModuleInit() {
  52. this.eventBus.ofType(AccountRegistrationEvent).subscribe(event => {
  53. sendEmailFn(event);
  54. });
  55. }
  56. }
  57. type CustomerListItem = Codegen.GetCustomerListQuery['customers']['items'][number];
  58. describe('Customer resolver', () => {
  59. const { server, adminClient, shopClient } = createTestEnvironment(
  60. mergeConfig(testConfig(), { plugins: [TestEmailPlugin] }),
  61. );
  62. let firstCustomer: CustomerListItem;
  63. let secondCustomer: CustomerListItem;
  64. let thirdCustomer: CustomerListItem;
  65. const customerErrorGuard: ErrorResultGuard<Codegen.CustomerFragment> = createErrorResultGuard(
  66. input => !!input.emailAddress,
  67. );
  68. beforeAll(async () => {
  69. await server.init({
  70. initialData,
  71. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  72. customerCount: 5,
  73. });
  74. await adminClient.asSuperAdmin();
  75. }, TEST_SETUP_TIMEOUT_MS);
  76. afterAll(async () => {
  77. await server.destroy();
  78. });
  79. it('customers list', async () => {
  80. const result = await adminClient.query<
  81. Codegen.GetCustomerListQuery,
  82. Codegen.GetCustomerListQueryVariables
  83. >(GET_CUSTOMER_LIST);
  84. expect(result.customers.items.length).toBe(5);
  85. expect(result.customers.totalItems).toBe(5);
  86. firstCustomer = result.customers.items[0];
  87. secondCustomer = result.customers.items[1];
  88. thirdCustomer = result.customers.items[2];
  89. });
  90. it('customers list filter by postalCode', async () => {
  91. const result = await adminClient.query<
  92. Codegen.GetCustomerListQuery,
  93. Codegen.GetCustomerListQueryVariables
  94. >(GET_CUSTOMER_LIST, {
  95. options: {
  96. filter: {
  97. postalCode: {
  98. eq: 'NU9 0PW',
  99. },
  100. },
  101. },
  102. });
  103. expect(result.customers.items.length).toBe(1);
  104. expect(result.customers.items[0].emailAddress).toBe('eliezer56@yahoo.com');
  105. });
  106. it('customer resolver resolves User', async () => {
  107. const { customer } = await adminClient.query<
  108. Codegen.GetCustomerWithUserQuery,
  109. Codegen.GetCustomerWithUserQueryVariables
  110. >(GET_CUSTOMER_WITH_USER, {
  111. id: firstCustomer.id,
  112. });
  113. expect(customer!.user).toEqual({
  114. id: 'T_2',
  115. identifier: firstCustomer.emailAddress,
  116. verified: true,
  117. });
  118. });
  119. describe('addresses', () => {
  120. let firstCustomerAddressIds: string[] = [];
  121. let firstCustomerThirdAddressId: string;
  122. it(
  123. 'createCustomerAddress throws on invalid countryCode',
  124. assertThrowsWithMessage(
  125. () =>
  126. adminClient.query<Codegen.CreateAddressMutation, Codegen.CreateAddressMutationVariables>(
  127. CREATE_ADDRESS,
  128. {
  129. id: firstCustomer.id,
  130. input: {
  131. streetLine1: 'streetLine1',
  132. countryCode: 'INVALID',
  133. },
  134. },
  135. ),
  136. `The countryCode "INVALID" was not recognized`,
  137. ),
  138. );
  139. it('createCustomerAddress creates a new address', async () => {
  140. const result = await adminClient.query<
  141. Codegen.CreateAddressMutation,
  142. Codegen.CreateAddressMutationVariables
  143. >(CREATE_ADDRESS, {
  144. id: firstCustomer.id,
  145. input: {
  146. fullName: 'fullName',
  147. company: 'company',
  148. streetLine1: 'streetLine1',
  149. streetLine2: 'streetLine2',
  150. city: 'city',
  151. province: 'province',
  152. postalCode: 'postalCode',
  153. countryCode: 'GB',
  154. phoneNumber: 'phoneNumber',
  155. defaultShippingAddress: false,
  156. defaultBillingAddress: false,
  157. },
  158. });
  159. expect(omit(result.createCustomerAddress, ['id'])).toEqual({
  160. fullName: 'fullName',
  161. company: 'company',
  162. streetLine1: 'streetLine1',
  163. streetLine2: 'streetLine2',
  164. city: 'city',
  165. province: 'province',
  166. postalCode: 'postalCode',
  167. country: {
  168. code: 'GB',
  169. name: 'United Kingdom',
  170. },
  171. phoneNumber: 'phoneNumber',
  172. defaultShippingAddress: false,
  173. defaultBillingAddress: false,
  174. });
  175. });
  176. it('customer query returns addresses', async () => {
  177. const result = await adminClient.query<
  178. Codegen.GetCustomerQuery,
  179. Codegen.GetCustomerQueryVariables
  180. >(GET_CUSTOMER, {
  181. id: firstCustomer.id,
  182. });
  183. expect(result.customer!.addresses!.length).toBe(2);
  184. firstCustomerAddressIds = result.customer!.addresses!.map(a => a.id).sort();
  185. });
  186. it('updateCustomerAddress updates the country', async () => {
  187. const result = await adminClient.query<
  188. Codegen.UpdateAddressMutation,
  189. Codegen.UpdateAddressMutationVariables
  190. >(UPDATE_ADDRESS, {
  191. input: {
  192. id: firstCustomerAddressIds[0],
  193. countryCode: 'AT',
  194. },
  195. });
  196. expect(result.updateCustomerAddress.country).toEqual({
  197. code: 'AT',
  198. name: 'Austria',
  199. });
  200. });
  201. it('updateCustomerAddress allows only a single default address', async () => {
  202. // set the first customer's second address to be default
  203. const result1 = await adminClient.query<
  204. Codegen.UpdateAddressMutation,
  205. Codegen.UpdateAddressMutationVariables
  206. >(UPDATE_ADDRESS, {
  207. input: {
  208. id: firstCustomerAddressIds[1],
  209. defaultShippingAddress: true,
  210. defaultBillingAddress: true,
  211. },
  212. });
  213. expect(result1.updateCustomerAddress.defaultShippingAddress).toBe(true);
  214. expect(result1.updateCustomerAddress.defaultBillingAddress).toBe(true);
  215. // assert the first customer's other addresse is not default
  216. const result2 = await adminClient.query<
  217. Codegen.GetCustomerQuery,
  218. Codegen.GetCustomerQueryVariables
  219. >(GET_CUSTOMER, {
  220. id: firstCustomer.id,
  221. });
  222. const otherAddress = result2.customer!.addresses!.filter(
  223. a => a.id !== firstCustomerAddressIds[1],
  224. )[0]!;
  225. expect(otherAddress.defaultShippingAddress).toBe(false);
  226. expect(otherAddress.defaultBillingAddress).toBe(false);
  227. // set the first customer's first address to be default
  228. const result3 = await adminClient.query<
  229. Codegen.UpdateAddressMutation,
  230. Codegen.UpdateAddressMutationVariables
  231. >(UPDATE_ADDRESS, {
  232. input: {
  233. id: firstCustomerAddressIds[0],
  234. defaultShippingAddress: true,
  235. defaultBillingAddress: true,
  236. },
  237. });
  238. expect(result3.updateCustomerAddress.defaultShippingAddress).toBe(true);
  239. expect(result3.updateCustomerAddress.defaultBillingAddress).toBe(true);
  240. // assert the first customer's second address is not default
  241. const result4 = await adminClient.query<
  242. Codegen.GetCustomerQuery,
  243. Codegen.GetCustomerQueryVariables
  244. >(GET_CUSTOMER, {
  245. id: firstCustomer.id,
  246. });
  247. const otherAddress2 = result4.customer!.addresses!.filter(
  248. a => a.id !== firstCustomerAddressIds[0],
  249. )[0]!;
  250. expect(otherAddress2.defaultShippingAddress).toBe(false);
  251. expect(otherAddress2.defaultBillingAddress).toBe(false);
  252. // get the second customer's address id
  253. const result5 = await adminClient.query<
  254. Codegen.GetCustomerQuery,
  255. Codegen.GetCustomerQueryVariables
  256. >(GET_CUSTOMER, {
  257. id: secondCustomer.id,
  258. });
  259. const secondCustomerAddressId = result5.customer!.addresses![0].id;
  260. // set the second customer's address to be default
  261. const result6 = await adminClient.query<
  262. Codegen.UpdateAddressMutation,
  263. Codegen.UpdateAddressMutationVariables
  264. >(UPDATE_ADDRESS, {
  265. input: {
  266. id: secondCustomerAddressId,
  267. defaultShippingAddress: true,
  268. defaultBillingAddress: true,
  269. },
  270. });
  271. expect(result6.updateCustomerAddress.defaultShippingAddress).toBe(true);
  272. expect(result6.updateCustomerAddress.defaultBillingAddress).toBe(true);
  273. // assets the first customer's address defaults are unchanged
  274. const result7 = await adminClient.query<
  275. Codegen.GetCustomerQuery,
  276. Codegen.GetCustomerQueryVariables
  277. >(GET_CUSTOMER, {
  278. id: firstCustomer.id,
  279. });
  280. expect(result7.customer!.addresses![0].defaultShippingAddress).toBe(true);
  281. expect(result7.customer!.addresses![0].defaultBillingAddress).toBe(true);
  282. expect(result7.customer!.addresses![1].defaultShippingAddress).toBe(false);
  283. expect(result7.customer!.addresses![1].defaultBillingAddress).toBe(false);
  284. });
  285. it('createCustomerAddress with true defaults unsets existing defaults', async () => {
  286. const { createCustomerAddress } = await adminClient.query<
  287. Codegen.CreateAddressMutation,
  288. Codegen.CreateAddressMutationVariables
  289. >(CREATE_ADDRESS, {
  290. id: firstCustomer.id,
  291. input: {
  292. streetLine1: 'new default streetline',
  293. countryCode: 'GB',
  294. defaultShippingAddress: true,
  295. defaultBillingAddress: true,
  296. },
  297. });
  298. expect(omit(createCustomerAddress, ['id'])).toEqual({
  299. fullName: '',
  300. company: '',
  301. streetLine1: 'new default streetline',
  302. streetLine2: '',
  303. city: '',
  304. province: '',
  305. postalCode: '',
  306. country: {
  307. code: 'GB',
  308. name: 'United Kingdom',
  309. },
  310. phoneNumber: '',
  311. defaultShippingAddress: true,
  312. defaultBillingAddress: true,
  313. });
  314. const { customer } = await adminClient.query<
  315. Codegen.GetCustomerQuery,
  316. Codegen.GetCustomerQueryVariables
  317. >(GET_CUSTOMER, {
  318. id: firstCustomer.id,
  319. });
  320. for (const address of customer!.addresses!) {
  321. const shouldBeDefault = address.id === createCustomerAddress.id;
  322. expect(address.defaultShippingAddress).toEqual(shouldBeDefault);
  323. expect(address.defaultBillingAddress).toEqual(shouldBeDefault);
  324. }
  325. firstCustomerThirdAddressId = createCustomerAddress.id;
  326. });
  327. it('deleteCustomerAddress on default address resets defaults', async () => {
  328. const { deleteCustomerAddress } = await adminClient.query<
  329. Codegen.DeleteCustomerAddressMutation,
  330. Codegen.DeleteCustomerAddressMutationVariables
  331. >(
  332. gql`
  333. mutation DeleteCustomerAddress($id: ID!) {
  334. deleteCustomerAddress(id: $id) {
  335. success
  336. }
  337. }
  338. `,
  339. { id: firstCustomerThirdAddressId },
  340. );
  341. expect(deleteCustomerAddress.success).toBe(true);
  342. const { customer } = await adminClient.query<
  343. Codegen.GetCustomerQuery,
  344. Codegen.GetCustomerQueryVariables
  345. >(GET_CUSTOMER, {
  346. id: firstCustomer.id,
  347. });
  348. expect(customer!.addresses!.length).toBe(2);
  349. const defaultAddress = customer!.addresses!.filter(
  350. a => a.defaultBillingAddress && a.defaultShippingAddress,
  351. );
  352. const otherAddress = customer!.addresses!.filter(
  353. a => !a.defaultBillingAddress && !a.defaultShippingAddress,
  354. );
  355. expect(defaultAddress.length).toBe(1);
  356. expect(otherAddress.length).toBe(1);
  357. });
  358. });
  359. describe('orders', () => {
  360. const orderResultGuard: ErrorResultGuard<UpdatedOrderFragment> = createErrorResultGuard(
  361. input => !!input.lines,
  362. );
  363. it(`lists that user\'s orders`, async () => {
  364. // log in as first customer
  365. await shopClient.asUserWithCredentials(firstCustomer.emailAddress, 'test');
  366. // add an item to the order to create an order
  367. const { addItemToOrder } = await shopClient.query<
  368. AddItemToOrderMutation,
  369. AddItemToOrderMutationVariables
  370. >(ADD_ITEM_TO_ORDER, {
  371. productVariantId: 'T_1',
  372. quantity: 1,
  373. });
  374. orderResultGuard.assertSuccess(addItemToOrder);
  375. const { customer } = await adminClient.query<
  376. Codegen.GetCustomerOrdersQuery,
  377. Codegen.GetCustomerOrdersQueryVariables
  378. >(GET_CUSTOMER_ORDERS, { id: firstCustomer.id });
  379. expect(customer!.orders.totalItems).toBe(1);
  380. expect(customer!.orders.items[0].id).toBe(addItemToOrder!.id);
  381. });
  382. });
  383. describe('creation', () => {
  384. it('triggers verification event if no password supplied', async () => {
  385. sendEmailFn = jest.fn();
  386. const { createCustomer } = await adminClient.query<
  387. Codegen.CreateCustomerMutation,
  388. Codegen.CreateCustomerMutationVariables
  389. >(CREATE_CUSTOMER, {
  390. input: {
  391. emailAddress: 'test1@test.com',
  392. firstName: 'New',
  393. lastName: 'Customer',
  394. },
  395. });
  396. customerErrorGuard.assertSuccess(createCustomer);
  397. expect(createCustomer.user!.verified).toBe(false);
  398. expect(sendEmailFn).toHaveBeenCalledTimes(1);
  399. expect(sendEmailFn.mock.calls[0][0] instanceof AccountRegistrationEvent).toBe(true);
  400. expect(sendEmailFn.mock.calls[0][0].user.identifier).toBe('test1@test.com');
  401. });
  402. it('creates a verified Customer', async () => {
  403. sendEmailFn = jest.fn();
  404. const { createCustomer } = await adminClient.query<
  405. Codegen.CreateCustomerMutation,
  406. Codegen.CreateCustomerMutationVariables
  407. >(CREATE_CUSTOMER, {
  408. input: {
  409. emailAddress: 'test2@test.com',
  410. firstName: 'New',
  411. lastName: 'Customer',
  412. },
  413. password: 'test',
  414. });
  415. customerErrorGuard.assertSuccess(createCustomer);
  416. expect(createCustomer.user!.verified).toBe(true);
  417. expect(sendEmailFn).toHaveBeenCalledTimes(0);
  418. });
  419. it('return error result when using an existing, non-deleted emailAddress', async () => {
  420. const { createCustomer } = await adminClient.query<
  421. Codegen.CreateCustomerMutation,
  422. Codegen.CreateCustomerMutationVariables
  423. >(CREATE_CUSTOMER, {
  424. input: {
  425. emailAddress: 'test2@test.com',
  426. firstName: 'New',
  427. lastName: 'Customer',
  428. },
  429. password: 'test',
  430. });
  431. customerErrorGuard.assertErrorResult(createCustomer);
  432. expect(createCustomer.message).toBe('The email address is not available.');
  433. expect(createCustomer.errorCode).toBe(ErrorCode.EMAIL_ADDRESS_CONFLICT_ERROR);
  434. });
  435. });
  436. describe('update', () => {
  437. it('returns error result when emailAddress not available', async () => {
  438. const { updateCustomer } = await adminClient.query<
  439. Codegen.UpdateCustomerMutation,
  440. Codegen.UpdateCustomerMutationVariables
  441. >(UPDATE_CUSTOMER, {
  442. input: {
  443. id: thirdCustomer.id,
  444. emailAddress: firstCustomer.emailAddress,
  445. },
  446. });
  447. customerErrorGuard.assertErrorResult(updateCustomer);
  448. expect(updateCustomer.message).toBe('The email address is not available.');
  449. expect(updateCustomer.errorCode).toBe(ErrorCode.EMAIL_ADDRESS_CONFLICT_ERROR);
  450. });
  451. it('succeeds when emailAddress is available', async () => {
  452. const { updateCustomer } = await adminClient.query<
  453. Codegen.UpdateCustomerMutation,
  454. Codegen.UpdateCustomerMutationVariables
  455. >(UPDATE_CUSTOMER, {
  456. input: {
  457. id: thirdCustomer.id,
  458. emailAddress: 'unique-email@test.com',
  459. },
  460. });
  461. customerErrorGuard.assertSuccess(updateCustomer);
  462. expect(updateCustomer.emailAddress).toBe('unique-email@test.com');
  463. });
  464. // https://github.com/vendure-ecommerce/vendure/issues/1071
  465. it('updates the associated User email address', async () => {
  466. await shopClient.asUserWithCredentials('unique-email@test.com', 'test');
  467. const { me } = await shopClient.query<Codegen.MeQuery>(ME);
  468. expect(me?.identifier).toBe('unique-email@test.com');
  469. });
  470. });
  471. describe('deletion', () => {
  472. it('deletes a customer', async () => {
  473. const result = await adminClient.query<
  474. Codegen.DeleteCustomerMutation,
  475. Codegen.DeleteCustomerMutationVariables
  476. >(DELETE_CUSTOMER, { id: thirdCustomer.id });
  477. expect(result.deleteCustomer).toEqual({ result: DeletionResult.DELETED });
  478. });
  479. it('cannot get a deleted customer', async () => {
  480. const result = await adminClient.query<
  481. Codegen.GetCustomerQuery,
  482. Codegen.GetCustomerQueryVariables
  483. >(GET_CUSTOMER, {
  484. id: thirdCustomer.id,
  485. });
  486. expect(result.customer).toBe(null);
  487. });
  488. it('deleted customer omitted from list', async () => {
  489. const result = await adminClient.query<
  490. Codegen.GetCustomerListQuery,
  491. Codegen.GetCustomerListQueryVariables
  492. >(GET_CUSTOMER_LIST);
  493. expect(result.customers.items.map(c => c.id).includes(thirdCustomer.id)).toBe(false);
  494. });
  495. it(
  496. 'updateCustomer throws for deleted customer',
  497. assertThrowsWithMessage(
  498. () =>
  499. adminClient.query<
  500. Codegen.UpdateCustomerMutation,
  501. Codegen.UpdateCustomerMutationVariables
  502. >(UPDATE_CUSTOMER, {
  503. input: {
  504. id: thirdCustomer.id,
  505. firstName: 'updated',
  506. },
  507. }),
  508. `No Customer with the id '3' could be found`,
  509. ),
  510. );
  511. it(
  512. 'createCustomerAddress throws for deleted customer',
  513. assertThrowsWithMessage(
  514. () =>
  515. adminClient.query<Codegen.CreateAddressMutation, Codegen.CreateAddressMutationVariables>(
  516. CREATE_ADDRESS,
  517. {
  518. id: thirdCustomer.id,
  519. input: {
  520. streetLine1: 'test',
  521. countryCode: 'GB',
  522. },
  523. },
  524. ),
  525. `No Customer with the id '3' could be found`,
  526. ),
  527. );
  528. it('new Customer can be created with same emailAddress as a deleted Customer', async () => {
  529. const { createCustomer } = await adminClient.query<
  530. Codegen.CreateCustomerMutation,
  531. Codegen.CreateCustomerMutationVariables
  532. >(CREATE_CUSTOMER, {
  533. input: {
  534. emailAddress: thirdCustomer.emailAddress,
  535. firstName: 'Reusing Email',
  536. lastName: 'Customer',
  537. },
  538. });
  539. customerErrorGuard.assertSuccess(createCustomer);
  540. expect(createCustomer.emailAddress).toBe(thirdCustomer.emailAddress);
  541. expect(createCustomer.firstName).toBe('Reusing Email');
  542. expect(createCustomer.user?.identifier).toBe(thirdCustomer.emailAddress);
  543. });
  544. });
  545. describe('customer notes', () => {
  546. let noteId: string;
  547. it('addNoteToCustomer', async () => {
  548. const { addNoteToCustomer } = await adminClient.query<
  549. Codegen.AddNoteToCustomerMutation,
  550. Codegen.AddNoteToCustomerMutationVariables
  551. >(ADD_NOTE_TO_CUSTOMER, {
  552. input: {
  553. id: firstCustomer.id,
  554. isPublic: false,
  555. note: 'Test note',
  556. },
  557. });
  558. const { customer } = await adminClient.query<
  559. Codegen.GetCustomerHistoryQuery,
  560. Codegen.GetCustomerHistoryQueryVariables
  561. >(GET_CUSTOMER_HISTORY, {
  562. id: firstCustomer.id,
  563. options: {
  564. filter: {
  565. type: {
  566. eq: HistoryEntryType.CUSTOMER_NOTE,
  567. },
  568. },
  569. },
  570. });
  571. expect(customer?.history.items.map(pick(['type', 'data']))).toEqual([
  572. {
  573. type: HistoryEntryType.CUSTOMER_NOTE,
  574. data: {
  575. note: 'Test note',
  576. },
  577. },
  578. ]);
  579. noteId = customer?.history.items[0].id!;
  580. });
  581. it('update note', async () => {
  582. const { updateCustomerNote } = await adminClient.query<
  583. Codegen.UpdateCustomerNoteMutation,
  584. Codegen.UpdateCustomerNoteMutationVariables
  585. >(UPDATE_CUSTOMER_NOTE, {
  586. input: {
  587. noteId,
  588. note: 'An updated note',
  589. },
  590. });
  591. expect(updateCustomerNote.data).toEqual({
  592. note: 'An updated note',
  593. });
  594. });
  595. it('delete note', async () => {
  596. const { customer: before } = await adminClient.query<
  597. Codegen.GetCustomerHistoryQuery,
  598. Codegen.GetCustomerHistoryQueryVariables
  599. >(GET_CUSTOMER_HISTORY, { id: firstCustomer.id });
  600. const historyCount = before?.history.totalItems!;
  601. const { deleteCustomerNote } = await adminClient.query<
  602. Codegen.DeleteCustomerNoteMutation,
  603. Codegen.DeleteCustomerNoteMutationVariables
  604. >(DELETE_CUSTOMER_NOTE, {
  605. id: noteId,
  606. });
  607. expect(deleteCustomerNote.result).toBe(DeletionResult.DELETED);
  608. const { customer: after } = await adminClient.query<
  609. Codegen.GetCustomerHistoryQuery,
  610. Codegen.GetCustomerHistoryQueryVariables
  611. >(GET_CUSTOMER_HISTORY, { id: firstCustomer.id });
  612. expect(after?.history.totalItems).toBe(historyCount - 1);
  613. });
  614. });
  615. });
  616. const GET_CUSTOMER_WITH_USER = gql`
  617. query GetCustomerWithUser($id: ID!) {
  618. customer(id: $id) {
  619. id
  620. user {
  621. id
  622. identifier
  623. verified
  624. }
  625. }
  626. }
  627. `;
  628. const GET_CUSTOMER_ORDERS = gql`
  629. query GetCustomerOrders($id: ID!) {
  630. customer(id: $id) {
  631. orders {
  632. items {
  633. id
  634. }
  635. totalItems
  636. }
  637. }
  638. }
  639. `;
  640. const ADD_NOTE_TO_CUSTOMER = gql`
  641. mutation AddNoteToCustomer($input: AddNoteToCustomerInput!) {
  642. addNoteToCustomer(input: $input) {
  643. ...Customer
  644. }
  645. }
  646. ${CUSTOMER_FRAGMENT}
  647. `;