customer.e2e-spec.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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 address 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. const firstCustomerFirstAddress = result7.customer!.addresses!.find(
  281. a => a.id === firstCustomerAddressIds[0],
  282. )!;
  283. const firstCustomerSecondAddress = result7.customer!.addresses!.find(
  284. a => a.id === firstCustomerAddressIds[1],
  285. )!;
  286. expect(firstCustomerFirstAddress.defaultShippingAddress).toBe(true);
  287. expect(firstCustomerFirstAddress.defaultBillingAddress).toBe(true);
  288. expect(firstCustomerSecondAddress.defaultShippingAddress).toBe(false);
  289. expect(firstCustomerSecondAddress.defaultBillingAddress).toBe(false);
  290. });
  291. it('createCustomerAddress with true defaults unsets existing defaults', async () => {
  292. const { createCustomerAddress } = await adminClient.query<
  293. Codegen.CreateAddressMutation,
  294. Codegen.CreateAddressMutationVariables
  295. >(CREATE_ADDRESS, {
  296. id: firstCustomer.id,
  297. input: {
  298. streetLine1: 'new default streetline',
  299. countryCode: 'GB',
  300. defaultShippingAddress: true,
  301. defaultBillingAddress: true,
  302. },
  303. });
  304. expect(omit(createCustomerAddress, ['id'])).toEqual({
  305. fullName: '',
  306. company: '',
  307. streetLine1: 'new default streetline',
  308. streetLine2: '',
  309. city: '',
  310. province: '',
  311. postalCode: '',
  312. country: {
  313. code: 'GB',
  314. name: 'United Kingdom',
  315. },
  316. phoneNumber: '',
  317. defaultShippingAddress: true,
  318. defaultBillingAddress: true,
  319. });
  320. const { customer } = await adminClient.query<
  321. Codegen.GetCustomerQuery,
  322. Codegen.GetCustomerQueryVariables
  323. >(GET_CUSTOMER, {
  324. id: firstCustomer.id,
  325. });
  326. for (const address of customer!.addresses!) {
  327. const shouldBeDefault = address.id === createCustomerAddress.id;
  328. expect(address.defaultShippingAddress).toEqual(shouldBeDefault);
  329. expect(address.defaultBillingAddress).toEqual(shouldBeDefault);
  330. }
  331. firstCustomerThirdAddressId = createCustomerAddress.id;
  332. });
  333. it('deleteCustomerAddress on default address resets defaults', async () => {
  334. const { deleteCustomerAddress } = await adminClient.query<
  335. Codegen.DeleteCustomerAddressMutation,
  336. Codegen.DeleteCustomerAddressMutationVariables
  337. >(
  338. gql`
  339. mutation DeleteCustomerAddress($id: ID!) {
  340. deleteCustomerAddress(id: $id) {
  341. success
  342. }
  343. }
  344. `,
  345. { id: firstCustomerThirdAddressId },
  346. );
  347. expect(deleteCustomerAddress.success).toBe(true);
  348. const { customer } = await adminClient.query<
  349. Codegen.GetCustomerQuery,
  350. Codegen.GetCustomerQueryVariables
  351. >(GET_CUSTOMER, {
  352. id: firstCustomer.id,
  353. });
  354. expect(customer!.addresses!.length).toBe(2);
  355. const defaultAddress = customer!.addresses!.filter(
  356. a => a.defaultBillingAddress && a.defaultShippingAddress,
  357. );
  358. const otherAddress = customer!.addresses!.filter(
  359. a => !a.defaultBillingAddress && !a.defaultShippingAddress,
  360. );
  361. expect(defaultAddress.length).toBe(1);
  362. expect(otherAddress.length).toBe(1);
  363. });
  364. });
  365. describe('orders', () => {
  366. const orderResultGuard: ErrorResultGuard<UpdatedOrderFragment> = createErrorResultGuard(
  367. input => !!input.lines,
  368. );
  369. it(`lists that user\'s orders`, async () => {
  370. // log in as first customer
  371. await shopClient.asUserWithCredentials(firstCustomer.emailAddress, 'test');
  372. // add an item to the order to create an order
  373. const { addItemToOrder } = await shopClient.query<
  374. AddItemToOrderMutation,
  375. AddItemToOrderMutationVariables
  376. >(ADD_ITEM_TO_ORDER, {
  377. productVariantId: 'T_1',
  378. quantity: 1,
  379. });
  380. orderResultGuard.assertSuccess(addItemToOrder);
  381. const { customer } = await adminClient.query<
  382. Codegen.GetCustomerOrdersQuery,
  383. Codegen.GetCustomerOrdersQueryVariables
  384. >(GET_CUSTOMER_ORDERS, { id: firstCustomer.id });
  385. expect(customer!.orders.totalItems).toBe(1);
  386. expect(customer!.orders.items[0].id).toBe(addItemToOrder!.id);
  387. });
  388. });
  389. describe('creation', () => {
  390. it('triggers verification event if no password supplied', async () => {
  391. sendEmailFn = jest.fn();
  392. const { createCustomer } = await adminClient.query<
  393. Codegen.CreateCustomerMutation,
  394. Codegen.CreateCustomerMutationVariables
  395. >(CREATE_CUSTOMER, {
  396. input: {
  397. emailAddress: 'test1@test.com',
  398. firstName: 'New',
  399. lastName: 'Customer',
  400. },
  401. });
  402. customerErrorGuard.assertSuccess(createCustomer);
  403. expect(createCustomer.user!.verified).toBe(false);
  404. expect(sendEmailFn).toHaveBeenCalledTimes(1);
  405. expect(sendEmailFn.mock.calls[0][0] instanceof AccountRegistrationEvent).toBe(true);
  406. expect(sendEmailFn.mock.calls[0][0].user.identifier).toBe('test1@test.com');
  407. });
  408. it('creates a verified Customer', async () => {
  409. sendEmailFn = jest.fn();
  410. const { createCustomer } = await adminClient.query<
  411. Codegen.CreateCustomerMutation,
  412. Codegen.CreateCustomerMutationVariables
  413. >(CREATE_CUSTOMER, {
  414. input: {
  415. emailAddress: 'test2@test.com',
  416. firstName: 'New',
  417. lastName: 'Customer',
  418. },
  419. password: 'test',
  420. });
  421. customerErrorGuard.assertSuccess(createCustomer);
  422. expect(createCustomer.user!.verified).toBe(true);
  423. expect(sendEmailFn).toHaveBeenCalledTimes(0);
  424. });
  425. it('return error result when using an existing, non-deleted emailAddress', async () => {
  426. const { createCustomer } = await adminClient.query<
  427. Codegen.CreateCustomerMutation,
  428. Codegen.CreateCustomerMutationVariables
  429. >(CREATE_CUSTOMER, {
  430. input: {
  431. emailAddress: 'test2@test.com',
  432. firstName: 'New',
  433. lastName: 'Customer',
  434. },
  435. password: 'test',
  436. });
  437. customerErrorGuard.assertErrorResult(createCustomer);
  438. expect(createCustomer.message).toBe('The email address is not available.');
  439. expect(createCustomer.errorCode).toBe(ErrorCode.EMAIL_ADDRESS_CONFLICT_ERROR);
  440. });
  441. });
  442. describe('update', () => {
  443. it('returns error result when emailAddress not available', async () => {
  444. const { updateCustomer } = await adminClient.query<
  445. Codegen.UpdateCustomerMutation,
  446. Codegen.UpdateCustomerMutationVariables
  447. >(UPDATE_CUSTOMER, {
  448. input: {
  449. id: thirdCustomer.id,
  450. emailAddress: firstCustomer.emailAddress,
  451. },
  452. });
  453. customerErrorGuard.assertErrorResult(updateCustomer);
  454. expect(updateCustomer.message).toBe('The email address is not available.');
  455. expect(updateCustomer.errorCode).toBe(ErrorCode.EMAIL_ADDRESS_CONFLICT_ERROR);
  456. });
  457. it('succeeds when emailAddress is available', async () => {
  458. const { updateCustomer } = await adminClient.query<
  459. Codegen.UpdateCustomerMutation,
  460. Codegen.UpdateCustomerMutationVariables
  461. >(UPDATE_CUSTOMER, {
  462. input: {
  463. id: thirdCustomer.id,
  464. emailAddress: 'unique-email@test.com',
  465. },
  466. });
  467. customerErrorGuard.assertSuccess(updateCustomer);
  468. expect(updateCustomer.emailAddress).toBe('unique-email@test.com');
  469. });
  470. // https://github.com/vendure-ecommerce/vendure/issues/1071
  471. it('updates the associated User email address', async () => {
  472. await shopClient.asUserWithCredentials('unique-email@test.com', 'test');
  473. const { me } = await shopClient.query<Codegen.MeQuery>(ME);
  474. expect(me?.identifier).toBe('unique-email@test.com');
  475. });
  476. });
  477. describe('deletion', () => {
  478. it('deletes a customer', async () => {
  479. const result = await adminClient.query<
  480. Codegen.DeleteCustomerMutation,
  481. Codegen.DeleteCustomerMutationVariables
  482. >(DELETE_CUSTOMER, { id: thirdCustomer.id });
  483. expect(result.deleteCustomer).toEqual({ result: DeletionResult.DELETED });
  484. });
  485. it('cannot get a deleted customer', async () => {
  486. const result = await adminClient.query<
  487. Codegen.GetCustomerQuery,
  488. Codegen.GetCustomerQueryVariables
  489. >(GET_CUSTOMER, {
  490. id: thirdCustomer.id,
  491. });
  492. expect(result.customer).toBe(null);
  493. });
  494. it('deleted customer omitted from list', async () => {
  495. const result = await adminClient.query<
  496. Codegen.GetCustomerListQuery,
  497. Codegen.GetCustomerListQueryVariables
  498. >(GET_CUSTOMER_LIST);
  499. expect(result.customers.items.map(c => c.id).includes(thirdCustomer.id)).toBe(false);
  500. });
  501. it(
  502. 'updateCustomer throws for deleted customer',
  503. assertThrowsWithMessage(
  504. () =>
  505. adminClient.query<
  506. Codegen.UpdateCustomerMutation,
  507. Codegen.UpdateCustomerMutationVariables
  508. >(UPDATE_CUSTOMER, {
  509. input: {
  510. id: thirdCustomer.id,
  511. firstName: 'updated',
  512. },
  513. }),
  514. `No Customer with the id '3' could be found`,
  515. ),
  516. );
  517. it(
  518. 'createCustomerAddress throws for deleted customer',
  519. assertThrowsWithMessage(
  520. () =>
  521. adminClient.query<Codegen.CreateAddressMutation, Codegen.CreateAddressMutationVariables>(
  522. CREATE_ADDRESS,
  523. {
  524. id: thirdCustomer.id,
  525. input: {
  526. streetLine1: 'test',
  527. countryCode: 'GB',
  528. },
  529. },
  530. ),
  531. `No Customer with the id '3' could be found`,
  532. ),
  533. );
  534. it('new Customer can be created with same emailAddress as a deleted Customer', async () => {
  535. const { createCustomer } = await adminClient.query<
  536. Codegen.CreateCustomerMutation,
  537. Codegen.CreateCustomerMutationVariables
  538. >(CREATE_CUSTOMER, {
  539. input: {
  540. emailAddress: thirdCustomer.emailAddress,
  541. firstName: 'Reusing Email',
  542. lastName: 'Customer',
  543. },
  544. });
  545. customerErrorGuard.assertSuccess(createCustomer);
  546. expect(createCustomer.emailAddress).toBe(thirdCustomer.emailAddress);
  547. expect(createCustomer.firstName).toBe('Reusing Email');
  548. expect(createCustomer.user?.identifier).toBe(thirdCustomer.emailAddress);
  549. });
  550. });
  551. describe('customer notes', () => {
  552. let noteId: string;
  553. it('addNoteToCustomer', async () => {
  554. const { addNoteToCustomer } = await adminClient.query<
  555. Codegen.AddNoteToCustomerMutation,
  556. Codegen.AddNoteToCustomerMutationVariables
  557. >(ADD_NOTE_TO_CUSTOMER, {
  558. input: {
  559. id: firstCustomer.id,
  560. isPublic: false,
  561. note: 'Test note',
  562. },
  563. });
  564. const { customer } = await adminClient.query<
  565. Codegen.GetCustomerHistoryQuery,
  566. Codegen.GetCustomerHistoryQueryVariables
  567. >(GET_CUSTOMER_HISTORY, {
  568. id: firstCustomer.id,
  569. options: {
  570. filter: {
  571. type: {
  572. eq: HistoryEntryType.CUSTOMER_NOTE,
  573. },
  574. },
  575. },
  576. });
  577. expect(customer?.history.items.map(pick(['type', 'data']))).toEqual([
  578. {
  579. type: HistoryEntryType.CUSTOMER_NOTE,
  580. data: {
  581. note: 'Test note',
  582. },
  583. },
  584. ]);
  585. noteId = customer?.history.items[0].id!;
  586. });
  587. it('update note', async () => {
  588. const { updateCustomerNote } = await adminClient.query<
  589. Codegen.UpdateCustomerNoteMutation,
  590. Codegen.UpdateCustomerNoteMutationVariables
  591. >(UPDATE_CUSTOMER_NOTE, {
  592. input: {
  593. noteId,
  594. note: 'An updated note',
  595. },
  596. });
  597. expect(updateCustomerNote.data).toEqual({
  598. note: 'An updated note',
  599. });
  600. });
  601. it('delete note', async () => {
  602. const { customer: before } = await adminClient.query<
  603. Codegen.GetCustomerHistoryQuery,
  604. Codegen.GetCustomerHistoryQueryVariables
  605. >(GET_CUSTOMER_HISTORY, { id: firstCustomer.id });
  606. const historyCount = before?.history.totalItems!;
  607. const { deleteCustomerNote } = await adminClient.query<
  608. Codegen.DeleteCustomerNoteMutation,
  609. Codegen.DeleteCustomerNoteMutationVariables
  610. >(DELETE_CUSTOMER_NOTE, {
  611. id: noteId,
  612. });
  613. expect(deleteCustomerNote.result).toBe(DeletionResult.DELETED);
  614. const { customer: after } = await adminClient.query<
  615. Codegen.GetCustomerHistoryQuery,
  616. Codegen.GetCustomerHistoryQueryVariables
  617. >(GET_CUSTOMER_HISTORY, { id: firstCustomer.id });
  618. expect(after?.history.totalItems).toBe(historyCount - 1);
  619. });
  620. });
  621. });
  622. const GET_CUSTOMER_WITH_USER = gql`
  623. query GetCustomerWithUser($id: ID!) {
  624. customer(id: $id) {
  625. id
  626. user {
  627. id
  628. identifier
  629. verified
  630. }
  631. }
  632. }
  633. `;
  634. const GET_CUSTOMER_ORDERS = gql`
  635. query GetCustomerOrders($id: ID!) {
  636. customer(id: $id) {
  637. orders {
  638. items {
  639. id
  640. }
  641. totalItems
  642. }
  643. }
  644. }
  645. `;
  646. const ADD_NOTE_TO_CUSTOMER = gql`
  647. mutation AddNoteToCustomer($input: AddNoteToCustomerInput!) {
  648. addNoteToCustomer(input: $input) {
  649. ...Customer
  650. }
  651. }
  652. ${CUSTOMER_FRAGMENT}
  653. `;