entity-serialization.e2e-spec.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import { LanguageCode } from '@vendure/common/lib/generated-types';
  2. import {
  3. Channel,
  4. ChannelService,
  5. discountOnItemWithFacets,
  6. hasFacetValues,
  7. Order,
  8. OrderLine,
  9. OrderService,
  10. ProductVariant,
  11. ProductVariantService,
  12. Promotion,
  13. PromotionService,
  14. RequestContextService,
  15. ShippingLine,
  16. ShippingMethod,
  17. ShippingMethodService,
  18. TransactionalConnection,
  19. } from '@vendure/core';
  20. import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing';
  21. import { fail } from 'assert';
  22. import path from 'path';
  23. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  24. import { initialData } from '../../../e2e-common/e2e-initial-data';
  25. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  26. import { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
  27. import { FragmentOf } from './graphql/graphql-shop';
  28. import { createPromotionDocument } from './graphql/shared-definitions';
  29. import {
  30. activeOrderCustomerDocument,
  31. addItemToOrderDocument,
  32. addPaymentDocument,
  33. orderWithAddressesFragmentDocument,
  34. setShippingMethodDocument,
  35. testOrderFragment,
  36. testOrderWithPaymentsFragment,
  37. transitionToStateDocument,
  38. updatedOrderFragment,
  39. } from './graphql/shop-definitions';
  40. /**
  41. * This suite tests to make sure entities can be serialized. It focuses on those
  42. * entities that contain methods and/or properties which potentially reference
  43. * non-serializable objects.
  44. *
  45. * See https://github.com/vendure-ecommerce/vendure/issues/3277
  46. */
  47. describe('Entity serialization', () => {
  48. type OrderSuccessResult =
  49. | FragmentOf<typeof updatedOrderFragment>
  50. | FragmentOf<typeof testOrderFragment>
  51. | FragmentOf<typeof testOrderWithPaymentsFragment>
  52. | FragmentOf<typeof activeOrderCustomerDocument>
  53. | FragmentOf<typeof orderWithAddressesFragmentDocument>;
  54. const orderResultGuard: ErrorResultGuard<OrderSuccessResult> = createErrorResultGuard(
  55. input => !!input.lines,
  56. );
  57. const { server, adminClient, shopClient } = createTestEnvironment({
  58. ...testConfig(),
  59. paymentOptions: {
  60. paymentMethodHandlers: [testSuccessfulPaymentMethod],
  61. },
  62. });
  63. beforeAll(async () => {
  64. await server.init({
  65. initialData: {
  66. ...initialData,
  67. paymentMethods: [
  68. {
  69. name: testSuccessfulPaymentMethod.code,
  70. handler: { code: testSuccessfulPaymentMethod.code, arguments: [] },
  71. },
  72. ],
  73. },
  74. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  75. customerCount: 1,
  76. });
  77. await adminClient.asSuperAdmin();
  78. }, TEST_SETUP_TIMEOUT_MS);
  79. afterAll(async () => {
  80. await server.destroy();
  81. });
  82. it('serialize ShippingMethod', async () => {
  83. const ctx = await createCtx();
  84. const result = await server.app.get(ShippingMethodService).findAll(ctx);
  85. expect(result.items.length).toBeGreaterThan(0);
  86. const shippingMethod = result.items[0];
  87. expect(shippingMethod instanceof ShippingMethod).toBe(true);
  88. assertCanBeSerialized(shippingMethod);
  89. const json = JSON.stringify(shippingMethod);
  90. const parsed = JSON.parse(json);
  91. expect(parsed.createdAt).toBe(shippingMethod.createdAt.toISOString());
  92. });
  93. it('serialize Channel', async () => {
  94. const result = await server.app.get(ChannelService).getDefaultChannel();
  95. expect(result instanceof Channel).toBe(true);
  96. assertCanBeSerialized(result);
  97. });
  98. it('serialize Order', async () => {
  99. await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test');
  100. await shopClient.query(addItemToOrderDocument, {
  101. productVariantId: 'T_1',
  102. quantity: 1,
  103. });
  104. await shopClient.query(setShippingMethodDocument, {
  105. // @ts-expect-error - old test passes string, schema expects array
  106. id: 'T_1',
  107. });
  108. const result = await shopClient.query(transitionToStateDocument, { state: 'ArrangingPayment' });
  109. const { addPaymentToOrder } = await shopClient.query(addPaymentDocument, {
  110. input: {
  111. method: testSuccessfulPaymentMethod.code,
  112. metadata: {
  113. foo: 'bar',
  114. },
  115. },
  116. });
  117. orderResultGuard.assertSuccess(addPaymentToOrder);
  118. const ctx = await createCtx();
  119. const order = await server.app.get(OrderService).findOneByCode(ctx, addPaymentToOrder.code);
  120. expect(order).not.toBeNull();
  121. expect(order instanceof Order).toBe(true);
  122. assertCanBeSerialized(order);
  123. });
  124. it('serialize OrderLine', async () => {
  125. const ctx = await createCtx();
  126. const orderLine = await server.app.get(TransactionalConnection).getEntityOrThrow(ctx, OrderLine, 1);
  127. expect(orderLine instanceof OrderLine).toBe(true);
  128. assertCanBeSerialized(orderLine);
  129. });
  130. it('serialize ProductVariant', async () => {
  131. const ctx = await createCtx();
  132. const productVariant = await server.app.get(ProductVariantService).findOne(ctx, 1);
  133. expect(productVariant instanceof ProductVariant).toBe(true);
  134. assertCanBeSerialized(productVariant);
  135. });
  136. it('serialize Promotion', async () => {
  137. await adminClient.query(createPromotionDocument, {
  138. input: {
  139. enabled: true,
  140. // @ts-expect-error - old test uses Date, schema expects string
  141. startsAt: new Date('2019-10-30T00:00:00.000Z'),
  142. // @ts-expect-error - old test uses Date, schema expects string
  143. endsAt: new Date('2019-12-01T00:00:00.000Z'),
  144. translations: [
  145. {
  146. languageCode: LanguageCode.en,
  147. name: 'test promotion',
  148. description: 'a test promotion',
  149. },
  150. ],
  151. conditions: [
  152. {
  153. code: hasFacetValues.code,
  154. arguments: [
  155. { name: 'minimum', value: '2' },
  156. { name: 'facets', value: `["T_1"]` },
  157. ],
  158. },
  159. ],
  160. actions: [
  161. {
  162. code: discountOnItemWithFacets.code,
  163. arguments: [
  164. { name: 'discount', value: '50' },
  165. { name: 'facets', value: `["T_1"]` },
  166. ],
  167. },
  168. ],
  169. },
  170. });
  171. const ctx = await createCtx();
  172. const promotion = await server.app.get(PromotionService).findOne(ctx, 1);
  173. expect(promotion instanceof Promotion).toBe(true);
  174. assertCanBeSerialized(promotion);
  175. });
  176. it('serialize ShippingLine', async () => {
  177. const ctx = await createCtx();
  178. const shippingLine = await server.app
  179. .get(TransactionalConnection)
  180. .getEntityOrThrow(ctx, ShippingLine, 1);
  181. expect(shippingLine instanceof ShippingLine).toBe(true);
  182. assertCanBeSerialized(shippingLine);
  183. });
  184. it('serialize Order with nested ShippingMethod', async () => {
  185. const ctx = await createCtx();
  186. const order = await server.app
  187. .get(OrderService)
  188. .findOne(ctx, 1, ['lines', 'surcharges', 'shippingLines.shippingMethod']);
  189. expect(order).not.toBeNull();
  190. expect(order instanceof Order).toBe(true);
  191. assertCanBeSerialized(order);
  192. });
  193. function assertCanBeSerialized(entity: any) {
  194. try {
  195. const json = JSON.stringify(entity);
  196. } catch (e: any) {
  197. fail(`Could not serialize entity: ${e.message as string}`);
  198. }
  199. }
  200. async function createCtx() {
  201. return server.app.get(RequestContextService).create({
  202. apiType: 'admin',
  203. });
  204. }
  205. });