draft-order.e2e-spec.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /* tslint:disable:no-non-null-assertion */
  2. import { DefaultLogger, mergeConfig, orderPercentageDiscount } from '@vendure/core';
  3. import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing';
  4. import gql from 'graphql-tag';
  5. import path from 'path';
  6. import { initialData } from '../../../e2e-common/e2e-initial-data';
  7. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  8. import { singleStageRefundablePaymentMethod } from './fixtures/test-payment-methods';
  9. import { ORDER_WITH_LINES_FRAGMENT } from './graphql/fragments';
  10. import * as Codegen from './graphql/generated-e2e-admin-types';
  11. import { CanceledOrderFragment, OrderWithLinesFragment } from './graphql/generated-e2e-admin-types';
  12. import {
  13. GetActiveCustomerOrdersQuery,
  14. TestOrderFragmentFragment,
  15. UpdatedOrderFragment,
  16. } from './graphql/generated-e2e-shop-types';
  17. import { CREATE_PROMOTION, GET_CUSTOMER_LIST } from './graphql/shared-definitions';
  18. import { GET_ACTIVE_CUSTOMER_ORDERS } from './graphql/shop-definitions';
  19. describe('Draft Orders resolver', () => {
  20. const { server, adminClient, shopClient } = createTestEnvironment(
  21. mergeConfig(testConfig(), {
  22. logger: new DefaultLogger(),
  23. paymentOptions: {
  24. paymentMethodHandlers: [singleStageRefundablePaymentMethod],
  25. },
  26. }),
  27. );
  28. let customers: Codegen.GetCustomerListQuery['customers']['items'];
  29. let draftOrder: OrderWithLinesFragment;
  30. const freeOrderCouponCode = 'FREE';
  31. const orderGuard: ErrorResultGuard<
  32. TestOrderFragmentFragment | CanceledOrderFragment | UpdatedOrderFragment
  33. > = createErrorResultGuard(input => !!input.lines);
  34. beforeAll(async () => {
  35. await server.init({
  36. initialData: {
  37. ...initialData,
  38. paymentMethods: [
  39. {
  40. name: singleStageRefundablePaymentMethod.code,
  41. handler: { code: singleStageRefundablePaymentMethod.code, arguments: [] },
  42. },
  43. ],
  44. },
  45. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  46. customerCount: 3,
  47. });
  48. await adminClient.asSuperAdmin();
  49. // Create a couple of orders to be queried
  50. const result = await adminClient.query<
  51. Codegen.GetCustomerListQuery,
  52. Codegen.GetCustomerListQueryVariables
  53. >(GET_CUSTOMER_LIST, {
  54. options: {
  55. take: 3,
  56. },
  57. });
  58. customers = result.customers.items;
  59. // Create a coupon code promotion
  60. const { createPromotion } = await adminClient.query<
  61. Codegen.CreatePromotionMutation,
  62. Codegen.CreatePromotionMutationVariables
  63. >(CREATE_PROMOTION, {
  64. input: {
  65. name: 'Free Order',
  66. enabled: true,
  67. conditions: [],
  68. couponCode: freeOrderCouponCode,
  69. actions: [
  70. {
  71. code: orderPercentageDiscount.code,
  72. arguments: [{ name: 'discount', value: '100' }],
  73. },
  74. ],
  75. },
  76. });
  77. }, TEST_SETUP_TIMEOUT_MS);
  78. afterAll(async () => {
  79. await server.destroy();
  80. });
  81. it('create draft order', async () => {
  82. const { createDraftOrder } = await adminClient.query<Codegen.CreateDraftOrderMutation>(
  83. CREATE_DRAFT_ORDER,
  84. );
  85. expect(createDraftOrder.state).toBe('Draft');
  86. expect(createDraftOrder.active).toBe(false);
  87. draftOrder = createDraftOrder;
  88. });
  89. it('addItemToDraftOrder', async () => {
  90. const { addItemToDraftOrder } = await adminClient.query<
  91. Codegen.AddItemToDraftOrderMutation,
  92. Codegen.AddItemToDraftOrderMutationVariables
  93. >(ADD_ITEM_TO_DRAFT_ORDER, {
  94. orderId: draftOrder.id,
  95. input: {
  96. productVariantId: 'T_5',
  97. quantity: 2,
  98. },
  99. });
  100. orderGuard.assertSuccess(addItemToDraftOrder);
  101. expect(addItemToDraftOrder.lines.length).toBe(1);
  102. draftOrder = addItemToDraftOrder;
  103. });
  104. it('adjustDraftOrderLine', async () => {
  105. const { adjustDraftOrderLine } = await adminClient.query<
  106. Codegen.AdjustDraftOrderLineMutation,
  107. Codegen.AdjustDraftOrderLineMutationVariables
  108. >(ADJUST_DRAFT_ORDER_LINE, {
  109. orderId: draftOrder.id,
  110. input: {
  111. orderLineId: draftOrder.lines[0]!.id,
  112. quantity: 5,
  113. },
  114. });
  115. orderGuard.assertSuccess(adjustDraftOrderLine);
  116. expect(adjustDraftOrderLine.lines[0].quantity).toBe(5);
  117. });
  118. it('removeDraftOrderLine', async () => {
  119. const { removeDraftOrderLine } = await adminClient.query<
  120. Codegen.RemoveDraftOrderLineMutation,
  121. Codegen.RemoveDraftOrderLineMutationVariables
  122. >(REMOVE_DRAFT_ORDER_LINE, {
  123. orderId: draftOrder.id,
  124. orderLineId: draftOrder.lines[0]!.id,
  125. });
  126. orderGuard.assertSuccess(removeDraftOrderLine);
  127. expect(removeDraftOrderLine.lines.length).toBe(0);
  128. });
  129. it('setCustomerForDraftOrder', async () => {
  130. const { setCustomerForDraftOrder } = await adminClient.query<
  131. Codegen.SetCustomerForDraftOrderMutation,
  132. Codegen.SetCustomerForDraftOrderMutationVariables
  133. >(SET_CUSTOMER_FOR_DRAFT_ORDER, {
  134. orderId: draftOrder.id,
  135. customerId: customers[0].id,
  136. });
  137. orderGuard.assertSuccess(setCustomerForDraftOrder);
  138. expect(setCustomerForDraftOrder.customer?.id).toBe(customers[0].id);
  139. });
  140. it('custom does not see draft orders in history', async () => {
  141. await shopClient.asUserWithCredentials(customers[0].emailAddress, 'test');
  142. const { activeCustomer } = await shopClient.query<GetActiveCustomerOrdersQuery>(
  143. GET_ACTIVE_CUSTOMER_ORDERS,
  144. );
  145. expect(activeCustomer?.orders.totalItems).toBe(0);
  146. expect(activeCustomer?.orders.items.length).toBe(0);
  147. });
  148. it('setDraftOrderShippingAddress', async () => {
  149. const { setDraftOrderShippingAddress } = await adminClient.query<
  150. Codegen.SetDraftOrderShippingAddressMutation,
  151. Codegen.SetDraftOrderShippingAddressMutationVariables
  152. >(SET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER, {
  153. orderId: draftOrder.id,
  154. input: {
  155. streetLine1: 'Shipping Street',
  156. city: 'Wigan',
  157. province: 'Greater Manchester',
  158. postalCode: 'WN1 2DD',
  159. countryCode: 'GB',
  160. },
  161. });
  162. expect(setDraftOrderShippingAddress.shippingAddress).toEqual({
  163. company: null,
  164. fullName: null,
  165. phoneNumber: null,
  166. streetLine2: null,
  167. province: 'Greater Manchester',
  168. city: 'Wigan',
  169. country: 'United Kingdom',
  170. postalCode: 'WN1 2DD',
  171. streetLine1: 'Shipping Street',
  172. });
  173. });
  174. it('setDraftOrderBillingAddress', async () => {
  175. const { setDraftOrderBillingAddress } = await adminClient.query<
  176. Codegen.SetDraftOrderBillingAddressMutation,
  177. Codegen.SetDraftOrderBillingAddressMutationVariables
  178. >(SET_BILLING_ADDRESS_FOR_DRAFT_ORDER, {
  179. orderId: draftOrder.id,
  180. input: {
  181. streetLine1: 'Billing Street',
  182. city: 'Skelmerdale',
  183. province: 'Lancashire',
  184. postalCode: 'WN8 3QW',
  185. countryCode: 'GB',
  186. },
  187. });
  188. expect(setDraftOrderBillingAddress.billingAddress).toEqual({
  189. company: null,
  190. fullName: null,
  191. phoneNumber: null,
  192. streetLine2: null,
  193. province: 'Lancashire',
  194. city: 'Skelmerdale',
  195. country: 'United Kingdom',
  196. postalCode: 'WN8 3QW',
  197. streetLine1: 'Billing Street',
  198. });
  199. });
  200. it('applyCouponCodeToDraftOrder', async () => {
  201. const { addItemToDraftOrder } = await adminClient.query<
  202. Codegen.AddItemToDraftOrderMutation,
  203. Codegen.AddItemToDraftOrderMutationVariables
  204. >(ADD_ITEM_TO_DRAFT_ORDER, {
  205. orderId: draftOrder.id,
  206. input: {
  207. productVariantId: 'T_1',
  208. quantity: 1,
  209. },
  210. });
  211. orderGuard.assertSuccess(addItemToDraftOrder);
  212. expect(addItemToDraftOrder.totalWithTax).toBe(155880);
  213. const { applyCouponCodeToDraftOrder } = await adminClient.query<
  214. Codegen.ApplyCouponCodeToDraftOrderMutation,
  215. Codegen.ApplyCouponCodeToDraftOrderMutationVariables
  216. >(APPLY_COUPON_CODE_TO_DRAFT_ORDER, {
  217. orderId: draftOrder.id,
  218. couponCode: freeOrderCouponCode,
  219. });
  220. orderGuard.assertSuccess(applyCouponCodeToDraftOrder);
  221. expect(applyCouponCodeToDraftOrder.couponCodes).toEqual([freeOrderCouponCode]);
  222. expect(applyCouponCodeToDraftOrder.totalWithTax).toBe(0);
  223. });
  224. it('removeCouponCodeFromDraftOrder', async () => {
  225. const { removeCouponCodeFromDraftOrder } = await adminClient.query<
  226. Codegen.RemoveCouponCodeFromDraftOrderMutation,
  227. Codegen.RemoveCouponCodeFromDraftOrderMutationVariables
  228. >(REMOVE_COUPON_CODE_FROM_DRAFT_ORDER, {
  229. orderId: draftOrder.id,
  230. couponCode: freeOrderCouponCode,
  231. });
  232. expect(removeCouponCodeFromDraftOrder!.couponCodes).toEqual([]);
  233. expect(removeCouponCodeFromDraftOrder!.totalWithTax).toBe(155880);
  234. });
  235. it('eligibleShippingMethodsForDraftOrder', async () => {
  236. const { eligibleShippingMethodsForDraftOrder } = await adminClient.query<
  237. Codegen.DraftOrderEligibleShippingMethodsQuery,
  238. Codegen.DraftOrderEligibleShippingMethodsQueryVariables
  239. >(DRAFT_ORDER_ELIGIBLE_SHIPPING_METHODS, {
  240. orderId: draftOrder.id,
  241. });
  242. expect(eligibleShippingMethodsForDraftOrder).toEqual([
  243. {
  244. code: 'standard-shipping',
  245. description: '',
  246. id: 'T_1',
  247. metadata: null,
  248. name: 'Standard Shipping',
  249. price: 500,
  250. priceWithTax: 500,
  251. },
  252. {
  253. code: 'express-shipping',
  254. description: '',
  255. id: 'T_2',
  256. metadata: null,
  257. name: 'Express Shipping',
  258. price: 1000,
  259. priceWithTax: 1000,
  260. },
  261. ]);
  262. });
  263. it('setDraftOrderShippingMethod', async () => {
  264. const { setDraftOrderShippingMethod } = await adminClient.query<
  265. Codegen.SetDraftOrderShippingMethodMutation,
  266. Codegen.SetDraftOrderShippingMethodMutationVariables
  267. >(SET_DRAFT_ORDER_SHIPPING_METHOD, {
  268. orderId: draftOrder.id,
  269. shippingMethodId: 'T_2',
  270. });
  271. orderGuard.assertSuccess(setDraftOrderShippingMethod);
  272. expect(setDraftOrderShippingMethod.shippingWithTax).toBe(1000);
  273. expect(setDraftOrderShippingMethod.shippingLines.length).toBe(1);
  274. expect(setDraftOrderShippingMethod.shippingLines[0].shippingMethod.id).toBe('T_2');
  275. });
  276. });
  277. export const CREATE_DRAFT_ORDER = gql`
  278. mutation CreateDraftOrder {
  279. createDraftOrder {
  280. ...OrderWithLines
  281. }
  282. }
  283. ${ORDER_WITH_LINES_FRAGMENT}
  284. `;
  285. export const ADD_ITEM_TO_DRAFT_ORDER = gql`
  286. mutation AddItemToDraftOrder($orderId: ID!, $input: AddItemToDraftOrderInput!) {
  287. addItemToDraftOrder(orderId: $orderId, input: $input) {
  288. ...OrderWithLines
  289. ... on ErrorResult {
  290. errorCode
  291. message
  292. }
  293. }
  294. }
  295. ${ORDER_WITH_LINES_FRAGMENT}
  296. `;
  297. export const ADJUST_DRAFT_ORDER_LINE = gql`
  298. mutation AdjustDraftOrderLine($orderId: ID!, $input: AdjustDraftOrderLineInput!) {
  299. adjustDraftOrderLine(orderId: $orderId, input: $input) {
  300. ...OrderWithLines
  301. ... on ErrorResult {
  302. errorCode
  303. message
  304. }
  305. }
  306. }
  307. ${ORDER_WITH_LINES_FRAGMENT}
  308. `;
  309. export const REMOVE_DRAFT_ORDER_LINE = gql`
  310. mutation RemoveDraftOrderLine($orderId: ID!, $orderLineId: ID!) {
  311. removeDraftOrderLine(orderId: $orderId, orderLineId: $orderLineId) {
  312. ...OrderWithLines
  313. ... on ErrorResult {
  314. errorCode
  315. message
  316. }
  317. }
  318. }
  319. ${ORDER_WITH_LINES_FRAGMENT}
  320. `;
  321. export const SET_CUSTOMER_FOR_DRAFT_ORDER = gql`
  322. mutation SetCustomerForDraftOrder($orderId: ID!, $customerId: ID, $input: CreateCustomerInput) {
  323. setCustomerForDraftOrder(orderId: $orderId, customerId: $customerId, input: $input) {
  324. ...OrderWithLines
  325. ... on ErrorResult {
  326. errorCode
  327. message
  328. }
  329. }
  330. }
  331. ${ORDER_WITH_LINES_FRAGMENT}
  332. `;
  333. export const SET_SHIPPING_ADDRESS_FOR_DRAFT_ORDER = gql`
  334. mutation SetDraftOrderShippingAddress($orderId: ID!, $input: CreateAddressInput!) {
  335. setDraftOrderShippingAddress(orderId: $orderId, input: $input) {
  336. ...OrderWithLines
  337. }
  338. }
  339. ${ORDER_WITH_LINES_FRAGMENT}
  340. `;
  341. export const SET_BILLING_ADDRESS_FOR_DRAFT_ORDER = gql`
  342. mutation SetDraftOrderBillingAddress($orderId: ID!, $input: CreateAddressInput!) {
  343. setDraftOrderBillingAddress(orderId: $orderId, input: $input) {
  344. ...OrderWithLines
  345. billingAddress {
  346. ...ShippingAddress
  347. }
  348. }
  349. }
  350. ${ORDER_WITH_LINES_FRAGMENT}
  351. `;
  352. export const APPLY_COUPON_CODE_TO_DRAFT_ORDER = gql`
  353. mutation ApplyCouponCodeToDraftOrder($orderId: ID!, $couponCode: String!) {
  354. applyCouponCodeToDraftOrder(orderId: $orderId, couponCode: $couponCode) {
  355. ...OrderWithLines
  356. ... on Order {
  357. couponCodes
  358. }
  359. ... on ErrorResult {
  360. errorCode
  361. message
  362. }
  363. }
  364. }
  365. ${ORDER_WITH_LINES_FRAGMENT}
  366. `;
  367. export const REMOVE_COUPON_CODE_FROM_DRAFT_ORDER = gql`
  368. mutation RemoveCouponCodeFromDraftOrder($orderId: ID!, $couponCode: String!) {
  369. removeCouponCodeFromDraftOrder(orderId: $orderId, couponCode: $couponCode) {
  370. ...OrderWithLines
  371. ... on Order {
  372. couponCodes
  373. }
  374. }
  375. }
  376. ${ORDER_WITH_LINES_FRAGMENT}
  377. `;
  378. export const DRAFT_ORDER_ELIGIBLE_SHIPPING_METHODS = gql`
  379. query DraftOrderEligibleShippingMethods($orderId: ID!) {
  380. eligibleShippingMethodsForDraftOrder(orderId: $orderId) {
  381. id
  382. name
  383. code
  384. description
  385. price
  386. priceWithTax
  387. metadata
  388. }
  389. }
  390. `;
  391. export const SET_DRAFT_ORDER_SHIPPING_METHOD = gql`
  392. mutation SetDraftOrderShippingMethod($orderId: ID!, $shippingMethodId: ID!) {
  393. setDraftOrderShippingMethod(orderId: $orderId, shippingMethodId: $shippingMethodId) {
  394. ...OrderWithLines
  395. ... on ErrorResult {
  396. errorCode
  397. message
  398. }
  399. }
  400. }
  401. ${ORDER_WITH_LINES_FRAGMENT}
  402. `;