payment-method.e2e-spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. import {
  2. DefaultLogger,
  3. dummyPaymentHandler,
  4. LanguageCode,
  5. PaymentMethodEligibilityChecker,
  6. } from '@vendure/core';
  7. import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } 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 {
  13. CreatePaymentMethod,
  14. GetPaymentMethod,
  15. GetPaymentMethodCheckers,
  16. GetPaymentMethodHandlers,
  17. UpdatePaymentMethod,
  18. } from './graphql/generated-e2e-admin-types';
  19. import {
  20. AddItemToOrder,
  21. AddPaymentToOrder,
  22. ErrorCode,
  23. GetEligiblePaymentMethods,
  24. TestOrderWithPaymentsFragment,
  25. } from './graphql/generated-e2e-shop-types';
  26. import { ADD_ITEM_TO_ORDER, ADD_PAYMENT, GET_ELIGIBLE_PAYMENT_METHODS } from './graphql/shop-definitions';
  27. import { proceedToArrangingPayment } from './utils/test-order-utils';
  28. const checkerSpy = jest.fn();
  29. const minPriceChecker = new PaymentMethodEligibilityChecker({
  30. code: 'min-price-checker',
  31. description: [{ languageCode: LanguageCode.en, value: 'Min price checker' }],
  32. args: {
  33. minPrice: {
  34. type: 'int',
  35. },
  36. },
  37. check(ctx, order, args) {
  38. checkerSpy();
  39. if (order.totalWithTax >= args.minPrice) {
  40. return true;
  41. } else {
  42. return `Order total too low`;
  43. }
  44. },
  45. });
  46. describe('PaymentMethod resolver', () => {
  47. const orderGuard: ErrorResultGuard<TestOrderWithPaymentsFragment> = createErrorResultGuard(
  48. input => !!input.lines,
  49. );
  50. const { server, adminClient, shopClient } = createTestEnvironment({
  51. ...testConfig,
  52. logger: new DefaultLogger(),
  53. paymentOptions: {
  54. paymentMethodEligibilityCheckers: [minPriceChecker],
  55. paymentMethodHandlers: [dummyPaymentHandler],
  56. },
  57. });
  58. beforeAll(async () => {
  59. await server.init({
  60. initialData,
  61. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  62. customerCount: 2,
  63. });
  64. await adminClient.asSuperAdmin();
  65. }, TEST_SETUP_TIMEOUT_MS);
  66. afterAll(async () => {
  67. await server.destroy();
  68. });
  69. it('create', async () => {
  70. const { createPaymentMethod } = await adminClient.query<
  71. CreatePaymentMethod.Mutation,
  72. CreatePaymentMethod.Variables
  73. >(CREATE_PAYMENT_METHOD, {
  74. input: {
  75. code: 'no-checks',
  76. name: 'No Checker',
  77. description: 'This is a test payment method',
  78. enabled: true,
  79. handler: {
  80. code: dummyPaymentHandler.code,
  81. arguments: [{ name: 'automaticSettle', value: 'true' }],
  82. },
  83. },
  84. });
  85. expect(createPaymentMethod).toEqual({
  86. id: 'T_1',
  87. name: 'No Checker',
  88. code: 'no-checks',
  89. description: 'This is a test payment method',
  90. enabled: true,
  91. checker: null,
  92. handler: {
  93. args: [
  94. {
  95. name: 'automaticSettle',
  96. value: 'true',
  97. },
  98. ],
  99. code: 'dummy-payment-handler',
  100. },
  101. });
  102. });
  103. it('update', async () => {
  104. const { updatePaymentMethod } = await adminClient.query<
  105. UpdatePaymentMethod.Mutation,
  106. UpdatePaymentMethod.Variables
  107. >(UPDATE_PAYMENT_METHOD, {
  108. input: {
  109. id: 'T_1',
  110. description: 'modified',
  111. checker: {
  112. code: minPriceChecker.code,
  113. arguments: [{ name: 'minPrice', value: '0' }],
  114. },
  115. handler: {
  116. code: dummyPaymentHandler.code,
  117. arguments: [{ name: 'automaticSettle', value: 'false' }],
  118. },
  119. },
  120. });
  121. expect(updatePaymentMethod).toEqual({
  122. id: 'T_1',
  123. name: 'No Checker',
  124. code: 'no-checks',
  125. description: 'modified',
  126. enabled: true,
  127. checker: {
  128. args: [{ name: 'minPrice', value: '0' }],
  129. code: minPriceChecker.code,
  130. },
  131. handler: {
  132. args: [
  133. {
  134. name: 'automaticSettle',
  135. value: 'false',
  136. },
  137. ],
  138. code: dummyPaymentHandler.code,
  139. },
  140. });
  141. });
  142. it('unset checker', async () => {
  143. const { updatePaymentMethod } = await adminClient.query<
  144. UpdatePaymentMethod.Mutation,
  145. UpdatePaymentMethod.Variables
  146. >(UPDATE_PAYMENT_METHOD, {
  147. input: {
  148. id: 'T_1',
  149. checker: null,
  150. },
  151. });
  152. expect(updatePaymentMethod.checker).toEqual(null);
  153. const { paymentMethod } = await adminClient.query<GetPaymentMethod.Query, GetPaymentMethod.Variables>(
  154. GET_PAYMENT_METHOD,
  155. { id: 'T_1' },
  156. );
  157. expect(paymentMethod.checker).toEqual(null);
  158. });
  159. it('paymentMethodEligibilityCheckers', async () => {
  160. const { paymentMethodEligibilityCheckers } = await adminClient.query<GetPaymentMethodCheckers.Query>(
  161. GET_PAYMENT_METHOD_CHECKERS,
  162. );
  163. expect(paymentMethodEligibilityCheckers).toEqual([
  164. {
  165. code: minPriceChecker.code,
  166. args: [{ name: 'minPrice', type: 'int' }],
  167. },
  168. ]);
  169. });
  170. it('paymentMethodHandlers', async () => {
  171. const { paymentMethodHandlers } = await adminClient.query<GetPaymentMethodHandlers.Query>(
  172. GET_PAYMENT_METHOD_HANDLERS,
  173. );
  174. expect(paymentMethodHandlers).toEqual([
  175. {
  176. code: dummyPaymentHandler.code,
  177. args: [{ name: 'automaticSettle', type: 'boolean' }],
  178. },
  179. ]);
  180. });
  181. describe('eligibility checks', () => {
  182. beforeAll(async () => {
  183. await adminClient.query<CreatePaymentMethod.Mutation, CreatePaymentMethod.Variables>(
  184. CREATE_PAYMENT_METHOD,
  185. {
  186. input: {
  187. code: 'price-check',
  188. name: 'With Min Price Checker',
  189. description: 'Order total must be more than 2k',
  190. enabled: true,
  191. checker: {
  192. code: minPriceChecker.code,
  193. arguments: [{ name: 'minPrice', value: '200000' }],
  194. },
  195. handler: {
  196. code: dummyPaymentHandler.code,
  197. arguments: [{ name: 'automaticSettle', value: 'true' }],
  198. },
  199. },
  200. },
  201. );
  202. await adminClient.query<CreatePaymentMethod.Mutation, CreatePaymentMethod.Variables>(
  203. CREATE_PAYMENT_METHOD,
  204. {
  205. input: {
  206. code: 'disabled-method',
  207. name: 'Disabled ones',
  208. description: 'This method is disabled',
  209. enabled: false,
  210. handler: {
  211. code: dummyPaymentHandler.code,
  212. arguments: [{ name: 'automaticSettle', value: 'true' }],
  213. },
  214. },
  215. },
  216. );
  217. await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test');
  218. await shopClient.query<AddItemToOrder.Mutation, AddItemToOrder.Variables>(ADD_ITEM_TO_ORDER, {
  219. productVariantId: 'T_1',
  220. quantity: 1,
  221. });
  222. await proceedToArrangingPayment(shopClient);
  223. });
  224. it('eligiblePaymentMethods', async () => {
  225. const { eligiblePaymentMethods } = await shopClient.query<GetEligiblePaymentMethods.Query>(
  226. GET_ELIGIBLE_PAYMENT_METHODS,
  227. );
  228. expect(eligiblePaymentMethods).toEqual([
  229. {
  230. id: 'T_1',
  231. code: 'no-checks',
  232. isEligible: true,
  233. eligibilityMessage: null,
  234. },
  235. {
  236. id: 'T_2',
  237. code: 'price-check',
  238. isEligible: false,
  239. eligibilityMessage: 'Order total too low',
  240. },
  241. ]);
  242. });
  243. it('addPaymentToOrder does not allow ineligible method', async () => {
  244. checkerSpy.mockClear();
  245. const { addPaymentToOrder } = await shopClient.query<
  246. AddPaymentToOrder.Mutation,
  247. AddPaymentToOrder.Variables
  248. >(ADD_PAYMENT, {
  249. input: {
  250. method: 'price-check',
  251. metadata: {},
  252. },
  253. });
  254. orderGuard.assertErrorResult(addPaymentToOrder);
  255. expect(addPaymentToOrder.errorCode).toBe(ErrorCode.INELIGIBLE_PAYMENT_METHOD_ERROR);
  256. expect(addPaymentToOrder.eligibilityCheckerMessage).toBe('Order total too low');
  257. expect(checkerSpy).toHaveBeenCalledTimes(1);
  258. });
  259. });
  260. });
  261. export const PAYMENT_METHOD_FRAGMENT = gql`
  262. fragment PaymentMethod on PaymentMethod {
  263. id
  264. code
  265. name
  266. description
  267. enabled
  268. checker {
  269. code
  270. args {
  271. name
  272. value
  273. }
  274. }
  275. handler {
  276. code
  277. args {
  278. name
  279. value
  280. }
  281. }
  282. }
  283. `;
  284. export const CREATE_PAYMENT_METHOD = gql`
  285. mutation CreatePaymentMethod($input: CreatePaymentMethodInput!) {
  286. createPaymentMethod(input: $input) {
  287. ...PaymentMethod
  288. }
  289. }
  290. ${PAYMENT_METHOD_FRAGMENT}
  291. `;
  292. export const UPDATE_PAYMENT_METHOD = gql`
  293. mutation UpdatePaymentMethod($input: UpdatePaymentMethodInput!) {
  294. updatePaymentMethod(input: $input) {
  295. ...PaymentMethod
  296. }
  297. }
  298. ${PAYMENT_METHOD_FRAGMENT}
  299. `;
  300. export const GET_PAYMENT_METHOD_HANDLERS = gql`
  301. query GetPaymentMethodHandlers {
  302. paymentMethodHandlers {
  303. code
  304. args {
  305. name
  306. type
  307. }
  308. }
  309. }
  310. `;
  311. export const GET_PAYMENT_METHOD_CHECKERS = gql`
  312. query GetPaymentMethodCheckers {
  313. paymentMethodEligibilityCheckers {
  314. code
  315. args {
  316. name
  317. type
  318. }
  319. }
  320. }
  321. `;
  322. export const GET_PAYMENT_METHOD = gql`
  323. query GetPaymentMethod($id: ID!) {
  324. paymentMethod(id: $id) {
  325. ...PaymentMethod
  326. }
  327. }
  328. ${PAYMENT_METHOD_FRAGMENT}
  329. `;