shipping-method.e2e-spec.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /* tslint:disable:no-non-null-assertion */
  2. import {
  3. defaultShippingCalculator,
  4. defaultShippingEligibilityChecker,
  5. ShippingCalculator,
  6. } from '@vendure/core';
  7. import { createTestEnvironment } from '@vendure/testing';
  8. import gql from 'graphql-tag';
  9. import path from 'path';
  10. import { initialData } from '../../../e2e-common/e2e-initial-data';
  11. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  12. import { manualFulfillmentHandler } from '../src/config/fulfillment/manual-fulfillment-handler';
  13. import { SHIPPING_METHOD_FRAGMENT } from './graphql/fragments';
  14. import {
  15. CreateShippingMethod,
  16. DeleteShippingMethod,
  17. DeletionResult,
  18. GetCalculators,
  19. GetEligibilityCheckers,
  20. GetShippingMethod,
  21. GetShippingMethodList,
  22. LanguageCode,
  23. TestEligibleMethods,
  24. TestShippingMethod,
  25. UpdateShippingMethod,
  26. } from './graphql/generated-e2e-admin-types';
  27. import {
  28. CREATE_SHIPPING_METHOD,
  29. DELETE_SHIPPING_METHOD,
  30. UPDATE_SHIPPING_METHOD,
  31. } from './graphql/shared-definitions';
  32. const TEST_METADATA = {
  33. foo: 'bar',
  34. baz: [1, 2, 3],
  35. };
  36. const calculatorWithMetadata = new ShippingCalculator({
  37. code: 'calculator-with-metadata',
  38. description: [{ languageCode: LanguageCode.en, value: 'Has metadata' }],
  39. args: {},
  40. calculate: () => {
  41. return {
  42. price: 100,
  43. priceIncludesTax: true,
  44. taxRate: 0,
  45. metadata: TEST_METADATA,
  46. };
  47. },
  48. });
  49. describe('ShippingMethod resolver', () => {
  50. const { server, adminClient, shopClient } = createTestEnvironment({
  51. ...testConfig,
  52. shippingOptions: {
  53. shippingEligibilityCheckers: [defaultShippingEligibilityChecker],
  54. shippingCalculators: [defaultShippingCalculator, calculatorWithMetadata],
  55. },
  56. });
  57. beforeAll(async () => {
  58. await server.init({
  59. initialData,
  60. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  61. customerCount: 1,
  62. });
  63. await adminClient.asSuperAdmin();
  64. }, TEST_SETUP_TIMEOUT_MS);
  65. afterAll(async () => {
  66. await server.destroy();
  67. });
  68. it('shippingEligibilityCheckers', async () => {
  69. const { shippingEligibilityCheckers } = await adminClient.query<GetEligibilityCheckers.Query>(
  70. GET_ELIGIBILITY_CHECKERS,
  71. );
  72. expect(shippingEligibilityCheckers).toEqual([
  73. {
  74. args: [
  75. {
  76. description: 'Order is eligible only if its total is greater or equal to this value',
  77. label: 'Minimum order value',
  78. name: 'orderMinimum',
  79. type: 'int',
  80. ui: {
  81. component: 'currency-form-input',
  82. },
  83. },
  84. ],
  85. code: 'default-shipping-eligibility-checker',
  86. description: 'Default Shipping Eligibility Checker',
  87. },
  88. ]);
  89. });
  90. it('shippingCalculators', async () => {
  91. const { shippingCalculators } = await adminClient.query<GetCalculators.Query>(GET_CALCULATORS);
  92. expect(shippingCalculators).toEqual([
  93. {
  94. args: [
  95. {
  96. ui: {
  97. component: 'currency-form-input',
  98. },
  99. description: null,
  100. label: 'Shipping price',
  101. name: 'rate',
  102. type: 'int',
  103. },
  104. {
  105. label: 'Price includes tax',
  106. name: 'includesTax',
  107. type: 'string',
  108. description: null,
  109. ui: {
  110. component: 'select-form-input',
  111. options: [
  112. {
  113. label: [{ languageCode: LanguageCode.en, value: 'Includes tax' }],
  114. value: 'include',
  115. },
  116. {
  117. label: [{ languageCode: LanguageCode.en, value: 'Excludes tax' }],
  118. value: 'exclude',
  119. },
  120. {
  121. label: [
  122. { languageCode: LanguageCode.en, value: 'Auto (based on Channel)' },
  123. ],
  124. value: 'auto',
  125. },
  126. ],
  127. },
  128. },
  129. {
  130. ui: {
  131. component: 'number-form-input',
  132. suffix: '%',
  133. },
  134. description: null,
  135. label: 'Tax rate',
  136. name: 'taxRate',
  137. type: 'int',
  138. },
  139. ],
  140. code: 'default-shipping-calculator',
  141. description: 'Default Flat-Rate Shipping Calculator',
  142. },
  143. {
  144. args: [],
  145. code: 'calculator-with-metadata',
  146. description: 'Has metadata',
  147. },
  148. ]);
  149. });
  150. it('shippingMethods', async () => {
  151. const { shippingMethods } = await adminClient.query<GetShippingMethodList.Query>(
  152. GET_SHIPPING_METHOD_LIST,
  153. );
  154. expect(shippingMethods.totalItems).toEqual(2);
  155. expect(shippingMethods.items[0].code).toBe('standard-shipping');
  156. expect(shippingMethods.items[1].code).toBe('express-shipping');
  157. });
  158. it('shippingMethod', async () => {
  159. const { shippingMethod } = await adminClient.query<
  160. GetShippingMethod.Query,
  161. GetShippingMethod.Variables
  162. >(GET_SHIPPING_METHOD, {
  163. id: 'T_1',
  164. });
  165. expect(shippingMethod!.code).toBe('standard-shipping');
  166. });
  167. it('createShippingMethod', async () => {
  168. const { createShippingMethod } = await adminClient.query<
  169. CreateShippingMethod.Mutation,
  170. CreateShippingMethod.Variables
  171. >(CREATE_SHIPPING_METHOD, {
  172. input: {
  173. code: 'new-method',
  174. fulfillmentHandler: manualFulfillmentHandler.code,
  175. checker: {
  176. code: defaultShippingEligibilityChecker.code,
  177. arguments: [
  178. {
  179. name: 'orderMinimum',
  180. value: '0',
  181. },
  182. ],
  183. },
  184. calculator: {
  185. code: calculatorWithMetadata.code,
  186. arguments: [],
  187. },
  188. translations: [{ languageCode: LanguageCode.en, name: 'new method', description: '' }],
  189. },
  190. });
  191. expect(createShippingMethod).toEqual({
  192. id: 'T_3',
  193. code: 'new-method',
  194. name: 'new method',
  195. description: '',
  196. calculator: {
  197. code: 'calculator-with-metadata',
  198. args: [],
  199. },
  200. checker: {
  201. code: 'default-shipping-eligibility-checker',
  202. args: [
  203. {
  204. name: 'orderMinimum',
  205. value: '0',
  206. },
  207. ],
  208. },
  209. });
  210. });
  211. it('testShippingMethod', async () => {
  212. const { testShippingMethod } = await adminClient.query<
  213. TestShippingMethod.Query,
  214. TestShippingMethod.Variables
  215. >(TEST_SHIPPING_METHOD, {
  216. input: {
  217. calculator: {
  218. code: calculatorWithMetadata.code,
  219. arguments: [],
  220. },
  221. checker: {
  222. code: defaultShippingEligibilityChecker.code,
  223. arguments: [
  224. {
  225. name: 'orderMinimum',
  226. value: '0',
  227. },
  228. ],
  229. },
  230. lines: [{ productVariantId: 'T_1', quantity: 1 }],
  231. shippingAddress: {
  232. streetLine1: '',
  233. countryCode: 'GB',
  234. },
  235. },
  236. });
  237. expect(testShippingMethod).toEqual({
  238. eligible: true,
  239. quote: {
  240. price: 100,
  241. priceWithTax: 100,
  242. metadata: TEST_METADATA,
  243. },
  244. });
  245. });
  246. it('testEligibleShippingMethods', async () => {
  247. const { testEligibleShippingMethods } = await adminClient.query<
  248. TestEligibleMethods.Query,
  249. TestEligibleMethods.Variables
  250. >(TEST_ELIGIBLE_SHIPPING_METHODS, {
  251. input: {
  252. lines: [{ productVariantId: 'T_1', quantity: 1 }],
  253. shippingAddress: {
  254. streetLine1: '',
  255. countryCode: 'GB',
  256. },
  257. },
  258. });
  259. expect(testEligibleShippingMethods).toEqual([
  260. {
  261. id: 'T_3',
  262. name: 'new method',
  263. description: '',
  264. price: 100,
  265. priceWithTax: 100,
  266. metadata: TEST_METADATA,
  267. },
  268. {
  269. id: 'T_1',
  270. name: 'Standard Shipping',
  271. description: '',
  272. price: 500,
  273. priceWithTax: 500,
  274. metadata: null,
  275. },
  276. {
  277. id: 'T_2',
  278. name: 'Express Shipping',
  279. description: '',
  280. price: 1000,
  281. priceWithTax: 1000,
  282. metadata: null,
  283. },
  284. ]);
  285. });
  286. it('updateShippingMethod', async () => {
  287. const { updateShippingMethod } = await adminClient.query<
  288. UpdateShippingMethod.Mutation,
  289. UpdateShippingMethod.Variables
  290. >(UPDATE_SHIPPING_METHOD, {
  291. input: {
  292. id: 'T_3',
  293. translations: [{ languageCode: LanguageCode.en, name: 'changed method', description: '' }],
  294. },
  295. });
  296. expect(updateShippingMethod.name).toBe('changed method');
  297. });
  298. it('deleteShippingMethod', async () => {
  299. const listResult1 = await adminClient.query<GetShippingMethodList.Query>(GET_SHIPPING_METHOD_LIST);
  300. expect(listResult1.shippingMethods.items.map(i => i.id)).toEqual(['T_1', 'T_2', 'T_3']);
  301. const { deleteShippingMethod } = await adminClient.query<
  302. DeleteShippingMethod.Mutation,
  303. DeleteShippingMethod.Variables
  304. >(DELETE_SHIPPING_METHOD, {
  305. id: 'T_3',
  306. });
  307. expect(deleteShippingMethod).toEqual({
  308. result: DeletionResult.DELETED,
  309. message: null,
  310. });
  311. const listResult2 = await adminClient.query<GetShippingMethodList.Query>(GET_SHIPPING_METHOD_LIST);
  312. expect(listResult2.shippingMethods.items.map(i => i.id)).toEqual(['T_1', 'T_2']);
  313. });
  314. });
  315. const GET_SHIPPING_METHOD_LIST = gql`
  316. query GetShippingMethodList {
  317. shippingMethods {
  318. items {
  319. ...ShippingMethod
  320. }
  321. totalItems
  322. }
  323. }
  324. ${SHIPPING_METHOD_FRAGMENT}
  325. `;
  326. const GET_SHIPPING_METHOD = gql`
  327. query GetShippingMethod($id: ID!) {
  328. shippingMethod(id: $id) {
  329. ...ShippingMethod
  330. }
  331. }
  332. ${SHIPPING_METHOD_FRAGMENT}
  333. `;
  334. const GET_ELIGIBILITY_CHECKERS = gql`
  335. query GetEligibilityCheckers {
  336. shippingEligibilityCheckers {
  337. code
  338. description
  339. args {
  340. name
  341. type
  342. description
  343. label
  344. ui
  345. }
  346. }
  347. }
  348. `;
  349. const GET_CALCULATORS = gql`
  350. query GetCalculators {
  351. shippingCalculators {
  352. code
  353. description
  354. args {
  355. name
  356. type
  357. description
  358. label
  359. ui
  360. }
  361. }
  362. }
  363. `;
  364. const TEST_SHIPPING_METHOD = gql`
  365. query TestShippingMethod($input: TestShippingMethodInput!) {
  366. testShippingMethod(input: $input) {
  367. eligible
  368. quote {
  369. price
  370. priceWithTax
  371. metadata
  372. }
  373. }
  374. }
  375. `;
  376. export const TEST_ELIGIBLE_SHIPPING_METHODS = gql`
  377. query TestEligibleMethods($input: TestEligibleShippingMethodsInput!) {
  378. testEligibleShippingMethods(input: $input) {
  379. id
  380. name
  381. description
  382. price
  383. priceWithTax
  384. metadata
  385. }
  386. }
  387. `;