guest-checkout-strategy.e2e-spec.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { CreateCustomerInput, SetCustomerForOrderResult } from '@vendure/common/lib/generated-shop-types';
  2. import {
  3. ChannelService,
  4. Customer,
  5. CustomerService,
  6. ErrorResultUnion,
  7. GuestCheckoutError,
  8. GuestCheckoutStrategy,
  9. Injector,
  10. Order,
  11. RequestContext,
  12. TransactionalConnection,
  13. } from '@vendure/core';
  14. import {
  15. createErrorResultGuard,
  16. createTestEnvironment,
  17. ErrorResultGuard,
  18. SimpleGraphQLClient,
  19. } from '@vendure/testing';
  20. import path from 'path';
  21. import { IsNull } from 'typeorm';
  22. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  23. import { initialData } from '../../../e2e-common/e2e-initial-data';
  24. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  25. import { AlreadyLoggedInError } from '../src/common/error/generated-graphql-shop-errors';
  26. import { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
  27. import { ResultOf } from './graphql/graphql-admin';
  28. import { FragmentOf } from './graphql/graphql-shop';
  29. import { getCustomerListDocument } from './graphql/shared-definitions';
  30. import {
  31. activeOrderCustomerDocument,
  32. addItemToOrderDocument,
  33. setCustomerDocument,
  34. } from './graphql/shop-definitions';
  35. class TestGuestCheckoutStrategy implements GuestCheckoutStrategy {
  36. static allowGuestCheckout = true;
  37. static allowGuestCheckoutForRegisteredCustomers = true;
  38. static createNewCustomerOnEmailAddressConflict = false;
  39. private customerService: CustomerService;
  40. private connection: TransactionalConnection;
  41. private channelService: ChannelService;
  42. init(injector: Injector) {
  43. this.customerService = injector.get(CustomerService);
  44. this.connection = injector.get(TransactionalConnection);
  45. this.channelService = injector.get(ChannelService);
  46. }
  47. async setCustomerForOrder(
  48. ctx: RequestContext,
  49. order: Order,
  50. input: CreateCustomerInput,
  51. ): Promise<ErrorResultUnion<SetCustomerForOrderResult, Customer>> {
  52. if (TestGuestCheckoutStrategy.allowGuestCheckout === false) {
  53. return new GuestCheckoutError({ errorDetail: 'Guest orders are disabled' });
  54. }
  55. if (ctx.activeUserId) {
  56. return new AlreadyLoggedInError();
  57. }
  58. if (TestGuestCheckoutStrategy.createNewCustomerOnEmailAddressConflict === true) {
  59. const existing = await this.connection.getRepository(ctx, Customer).findOne({
  60. relations: ['channels'],
  61. where: {
  62. emailAddress: input.emailAddress,
  63. deletedAt: IsNull(),
  64. },
  65. });
  66. if (existing) {
  67. const newCustomer = await this.connection
  68. .getRepository(ctx, Customer)
  69. .save(new Customer(input));
  70. await this.channelService.assignToCurrentChannel(newCustomer, ctx);
  71. return newCustomer;
  72. }
  73. }
  74. const errorOnExistingUser = !TestGuestCheckoutStrategy.allowGuestCheckoutForRegisteredCustomers;
  75. const customer = await this.customerService.createOrUpdate(ctx, input, errorOnExistingUser);
  76. return customer;
  77. }
  78. }
  79. describe('Order taxes', () => {
  80. const { server, adminClient, shopClient } = createTestEnvironment({
  81. ...testConfig(),
  82. orderOptions: {
  83. guestCheckoutStrategy: new TestGuestCheckoutStrategy(),
  84. },
  85. paymentOptions: {
  86. paymentMethodHandlers: [testSuccessfulPaymentMethod],
  87. },
  88. });
  89. let customers: ResultOf<typeof getCustomerListDocument>['customers']['items'];
  90. const orderResultGuard: ErrorResultGuard<FragmentOf<typeof activeOrderCustomerDocument>> =
  91. createErrorResultGuard(input => !!input.lines);
  92. beforeAll(async () => {
  93. await server.init({
  94. initialData: {
  95. ...initialData,
  96. paymentMethods: [
  97. {
  98. name: testSuccessfulPaymentMethod.code,
  99. handler: { code: testSuccessfulPaymentMethod.code, arguments: [] },
  100. },
  101. ],
  102. },
  103. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  104. customerCount: 2,
  105. });
  106. await adminClient.asSuperAdmin();
  107. const result = await adminClient.query(getCustomerListDocument);
  108. customers = result.customers.items;
  109. }, TEST_SETUP_TIMEOUT_MS);
  110. afterAll(async () => {
  111. await server.destroy();
  112. });
  113. it('with guest checkout disabled', async () => {
  114. TestGuestCheckoutStrategy.allowGuestCheckout = false;
  115. await shopClient.asAnonymousUser();
  116. await addItemToOrder(shopClient);
  117. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  118. input: {
  119. emailAddress: 'guest@test.com',
  120. firstName: 'Guest',
  121. lastName: 'User',
  122. },
  123. });
  124. orderResultGuard.assertErrorResult(setCustomerForOrder);
  125. expect(setCustomerForOrder.errorCode).toBe('GUEST_CHECKOUT_ERROR');
  126. expect((setCustomerForOrder as any).errorDetail).toBe('Guest orders are disabled');
  127. });
  128. it('with guest checkout enabled', async () => {
  129. TestGuestCheckoutStrategy.allowGuestCheckout = true;
  130. await shopClient.asAnonymousUser();
  131. await addItemToOrder(shopClient);
  132. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  133. input: {
  134. emailAddress: 'guest@test.com',
  135. firstName: 'Guest',
  136. lastName: 'User',
  137. },
  138. });
  139. orderResultGuard.assertSuccess(setCustomerForOrder);
  140. expect(setCustomerForOrder.customer?.emailAddress).toBe('guest@test.com');
  141. });
  142. it('with guest checkout for registered customers disabled', async () => {
  143. TestGuestCheckoutStrategy.allowGuestCheckoutForRegisteredCustomers = false;
  144. await shopClient.asAnonymousUser();
  145. await addItemToOrder(shopClient);
  146. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  147. input: {
  148. emailAddress: customers[0].emailAddress,
  149. firstName: customers[0].firstName,
  150. lastName: customers[0].lastName,
  151. },
  152. });
  153. orderResultGuard.assertErrorResult(setCustomerForOrder);
  154. expect(setCustomerForOrder.errorCode).toBe('EMAIL_ADDRESS_CONFLICT_ERROR');
  155. });
  156. it('with guest checkout for registered customers enabled', async () => {
  157. TestGuestCheckoutStrategy.allowGuestCheckoutForRegisteredCustomers = true;
  158. await shopClient.asAnonymousUser();
  159. await addItemToOrder(shopClient);
  160. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  161. input: {
  162. emailAddress: customers[0].emailAddress,
  163. firstName: customers[0].firstName,
  164. lastName: customers[0].lastName,
  165. },
  166. });
  167. orderResultGuard.assertSuccess(setCustomerForOrder);
  168. expect(setCustomerForOrder.customer?.emailAddress).toBe(customers[0].emailAddress);
  169. expect(setCustomerForOrder.customer?.id).toBe(customers[0].id);
  170. });
  171. it('create new customer on email address conflict', async () => {
  172. TestGuestCheckoutStrategy.createNewCustomerOnEmailAddressConflict = true;
  173. await shopClient.asAnonymousUser();
  174. await addItemToOrder(shopClient);
  175. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  176. input: {
  177. emailAddress: customers[0].emailAddress,
  178. firstName: customers[0].firstName,
  179. lastName: customers[0].lastName,
  180. },
  181. });
  182. orderResultGuard.assertSuccess(setCustomerForOrder);
  183. expect(setCustomerForOrder.customer?.emailAddress).toBe(customers[0].emailAddress);
  184. expect(setCustomerForOrder.customer?.id).not.toBe(customers[0].id);
  185. });
  186. it('when already logged in', async () => {
  187. await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
  188. await addItemToOrder(shopClient);
  189. const { setCustomerForOrder } = await shopClient.query(setCustomerDocument, {
  190. input: {
  191. emailAddress: customers[0].emailAddress,
  192. firstName: customers[0].firstName,
  193. lastName: customers[0].lastName,
  194. },
  195. });
  196. orderResultGuard.assertErrorResult(setCustomerForOrder);
  197. expect(setCustomerForOrder.errorCode).toBe('ALREADY_LOGGED_IN_ERROR');
  198. });
  199. });
  200. async function addItemToOrder(shopClient: SimpleGraphQLClient) {
  201. await shopClient.query(addItemToOrderDocument, {
  202. productVariantId: 'T_1',
  203. quantity: 1,
  204. });
  205. }