customer.e2e-spec.ts 28 KB

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