custom-field-relations.e2e-spec.ts 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. import {
  2. Asset,
  3. Collection,
  4. Country,
  5. CustomFields,
  6. defaultShippingCalculator,
  7. defaultShippingEligibilityChecker,
  8. Facet,
  9. FacetValue,
  10. manualFulfillmentHandler,
  11. mergeConfig,
  12. Product,
  13. ProductOption,
  14. ProductOptionGroup,
  15. ProductVariant,
  16. ShippingMethod,
  17. } from '@vendure/core';
  18. import { createTestEnvironment } from '@vendure/testing';
  19. import gql from 'graphql-tag';
  20. import path from 'path';
  21. import { initialData } from '../../../e2e-common/e2e-initial-data';
  22. import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
  23. import { AddItemToOrder } from './graphql/generated-e2e-shop-types';
  24. import { ADD_ITEM_TO_ORDER } from './graphql/shop-definitions';
  25. import { sortById } from './utils/test-order-utils';
  26. // From https://github.com/microsoft/TypeScript/issues/13298#issuecomment-654906323
  27. // to ensure that we _always_ test all entities which support custom fields
  28. type ValueOf<T> = T[keyof T];
  29. type NonEmptyArray<T> = [T, ...T[]];
  30. type MustInclude<T, U extends T[]> = [T] extends [ValueOf<U>] ? U : never;
  31. const enumerate = <T>() => <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) => elements;
  32. const entitiesWithCustomFields = enumerate<keyof CustomFields>()(
  33. 'Address',
  34. 'Collection',
  35. 'Customer',
  36. 'Facet',
  37. 'FacetValue',
  38. 'Fulfillment',
  39. 'GlobalSettings',
  40. 'Order',
  41. 'OrderLine',
  42. 'Product',
  43. 'ProductOption',
  44. 'ProductOptionGroup',
  45. 'ProductVariant',
  46. 'User',
  47. 'ShippingMethod',
  48. );
  49. const customFieldConfig: CustomFields = {};
  50. for (const entity of entitiesWithCustomFields) {
  51. customFieldConfig[entity] = [
  52. { name: 'single', type: 'relation', entity: Asset, graphQLType: 'Asset', list: false },
  53. { name: 'multi', type: 'relation', entity: Asset, graphQLType: 'Asset', list: true },
  54. ];
  55. }
  56. customFieldConfig.Product?.push(
  57. { name: 'cfCollection', type: 'relation', entity: Collection, list: false },
  58. { name: 'cfCountry', type: 'relation', entity: Country, list: false },
  59. { name: 'cfFacetValue', type: 'relation', entity: FacetValue, list: false },
  60. { name: 'cfFacet', type: 'relation', entity: Facet, list: false },
  61. { name: 'cfProductOptionGroup', type: 'relation', entity: ProductOptionGroup, list: false },
  62. { name: 'cfProductOption', type: 'relation', entity: ProductOption, list: false },
  63. { name: 'cfProductVariant', type: 'relation', entity: ProductVariant, list: false },
  64. { name: 'cfProduct', type: 'relation', entity: Product, list: false },
  65. { name: 'cfShippingMethod', type: 'relation', entity: ShippingMethod, list: false },
  66. );
  67. const customConfig = mergeConfig(testConfig, {
  68. dbConnectionOptions: {
  69. timezone: 'Z',
  70. },
  71. customFields: customFieldConfig,
  72. });
  73. describe('Custom field relations', () => {
  74. const { server, adminClient, shopClient } = createTestEnvironment(customConfig);
  75. beforeAll(async () => {
  76. await server.init({
  77. initialData,
  78. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
  79. customerCount: 3,
  80. });
  81. await adminClient.asSuperAdmin();
  82. }, TEST_SETUP_TIMEOUT_MS);
  83. afterAll(async () => {
  84. await server.destroy();
  85. });
  86. it('customFieldConfig query returns entity and scalar fields', async () => {
  87. const { globalSettings } = await adminClient.query(gql`
  88. query {
  89. globalSettings {
  90. serverConfig {
  91. customFieldConfig {
  92. Customer {
  93. ... on RelationCustomFieldConfig {
  94. name
  95. entity
  96. scalarFields
  97. }
  98. }
  99. }
  100. }
  101. }
  102. }
  103. `);
  104. const single = globalSettings.serverConfig.customFieldConfig.Customer[0];
  105. expect(single.entity).toBe('Asset');
  106. expect(single.scalarFields).toEqual([
  107. 'id',
  108. 'createdAt',
  109. 'updatedAt',
  110. 'name',
  111. 'type',
  112. 'fileSize',
  113. 'mimeType',
  114. 'width',
  115. 'height',
  116. 'source',
  117. 'preview',
  118. ]);
  119. });
  120. describe('special data resolution', () => {
  121. let productId: string;
  122. it('translatable entities get translated', async () => {
  123. const { createProduct } = await adminClient.query(gql`
  124. mutation {
  125. createProduct(
  126. input: {
  127. translations: [
  128. {
  129. languageCode: en
  130. name: "Test product"
  131. description: ""
  132. slug: "test-product"
  133. }
  134. ]
  135. customFields: {
  136. cfCollectionId: "T_1"
  137. cfCountryId: "T_1"
  138. cfFacetValueId: "T_1"
  139. cfFacetId: "T_1"
  140. cfProductOptionGroupId: "T_1"
  141. cfProductOptionId: "T_1"
  142. cfProductVariantId: "T_1"
  143. cfProductId: "T_1"
  144. cfShippingMethodId: "T_1"
  145. }
  146. }
  147. ) {
  148. id
  149. customFields {
  150. cfCollection {
  151. languageCode
  152. name
  153. }
  154. cfCountry {
  155. languageCode
  156. name
  157. }
  158. cfFacetValue {
  159. languageCode
  160. name
  161. }
  162. cfFacet {
  163. languageCode
  164. name
  165. }
  166. cfProductOptionGroup {
  167. languageCode
  168. name
  169. }
  170. cfProductOption {
  171. languageCode
  172. name
  173. }
  174. cfProductVariant {
  175. languageCode
  176. name
  177. }
  178. cfProduct {
  179. languageCode
  180. name
  181. }
  182. cfShippingMethod {
  183. name
  184. }
  185. }
  186. }
  187. }
  188. `);
  189. productId = createProduct.id;
  190. expect(createProduct.customFields.cfCollection).toEqual({
  191. languageCode: 'en',
  192. name: '__root_collection__',
  193. });
  194. expect(createProduct.customFields.cfCountry).toEqual({ languageCode: 'en', name: 'Australia' });
  195. expect(createProduct.customFields.cfFacetValue).toEqual({
  196. languageCode: 'en',
  197. name: 'electronics',
  198. });
  199. expect(createProduct.customFields.cfFacet).toEqual({ languageCode: 'en', name: 'category' });
  200. expect(createProduct.customFields.cfProductOptionGroup).toEqual({
  201. languageCode: 'en',
  202. name: 'screen size',
  203. });
  204. expect(createProduct.customFields.cfProductOption).toEqual({
  205. languageCode: 'en',
  206. name: '13 inch',
  207. });
  208. expect(createProduct.customFields.cfProductVariant).toEqual({
  209. languageCode: 'en',
  210. name: 'Laptop 13 inch 8GB',
  211. });
  212. expect(createProduct.customFields.cfProduct).toEqual({ languageCode: 'en', name: 'Laptop' });
  213. expect(createProduct.customFields.cfShippingMethod).toEqual({ name: 'Standard Shipping' });
  214. });
  215. it('ProductVariant prices get resolved', async () => {
  216. const { product } = await adminClient.query(gql`
  217. query {
  218. product(id: "${productId}") {
  219. id
  220. customFields {
  221. cfProductVariant {
  222. price
  223. currencyCode
  224. priceWithTax
  225. }
  226. }
  227. }
  228. }`);
  229. expect(product.customFields.cfProductVariant).toEqual({
  230. price: 129900,
  231. currencyCode: 'USD',
  232. priceWithTax: 155880,
  233. });
  234. });
  235. });
  236. describe('entity-specific implementation', () => {
  237. function assertCustomFieldIds(customFields: any, single: string, multi: string[]) {
  238. expect(customFields.single).toEqual({ id: single });
  239. expect(customFields.multi.sort(sortById)).toEqual(multi.map(id => ({ id })));
  240. }
  241. const customFieldsSelection = `
  242. customFields {
  243. single {
  244. id
  245. }
  246. multi {
  247. id
  248. }
  249. }`;
  250. describe('Address entity', () => {
  251. it('admin createCustomerAddress', async () => {
  252. const { createCustomerAddress } = await adminClient.query(gql`
  253. mutation {
  254. createCustomerAddress(
  255. customerId: "T_1"
  256. input: {
  257. countryCode: "GB"
  258. streetLine1: "Test Street"
  259. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  260. }
  261. ) {
  262. id
  263. ${customFieldsSelection}
  264. }
  265. }
  266. `);
  267. assertCustomFieldIds(createCustomerAddress.customFields, 'T_1', ['T_1', 'T_2']);
  268. });
  269. it('shop createCustomerAddress', async () => {
  270. await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test');
  271. const { createCustomerAddress } = await shopClient.query(gql`
  272. mutation {
  273. createCustomerAddress(
  274. input: {
  275. countryCode: "GB"
  276. streetLine1: "Test Street"
  277. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  278. }
  279. ) {
  280. id
  281. ${customFieldsSelection}
  282. }
  283. }
  284. `);
  285. assertCustomFieldIds(createCustomerAddress.customFields, 'T_1', ['T_1', 'T_2']);
  286. });
  287. it('admin updateCustomerAddress', async () => {
  288. const { updateCustomerAddress } = await adminClient.query(gql`
  289. mutation {
  290. updateCustomerAddress(
  291. input: { id: "T_1", customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] } }
  292. ) {
  293. id
  294. ${customFieldsSelection}
  295. }
  296. }
  297. `);
  298. assertCustomFieldIds(updateCustomerAddress.customFields, 'T_2', ['T_3', 'T_4']);
  299. });
  300. it('shop updateCustomerAddress', async () => {
  301. const { updateCustomerAddress } = await shopClient.query(gql`
  302. mutation {
  303. updateCustomerAddress(
  304. input: { id: "T_1", customFields: { singleId: "T_3", multiIds: ["T_4", "T_2"] } }
  305. ) {
  306. id
  307. ${customFieldsSelection}
  308. }
  309. }
  310. `);
  311. assertCustomFieldIds(updateCustomerAddress.customFields, 'T_3', ['T_2', 'T_4']);
  312. });
  313. });
  314. describe('Collection entity', () => {
  315. let collectionId: string;
  316. it('admin createCollection', async () => {
  317. const { createCollection } = await adminClient.query(gql`
  318. mutation {
  319. createCollection(
  320. input: {
  321. translations: [
  322. { languageCode: en, name: "Test", description: "test", slug: "test" }
  323. ]
  324. filters: []
  325. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  326. }
  327. ) {
  328. id
  329. ${customFieldsSelection}
  330. }
  331. }
  332. `);
  333. assertCustomFieldIds(createCollection.customFields, 'T_1', ['T_1', 'T_2']);
  334. collectionId = createCollection.id;
  335. });
  336. it('admin updateCollection', async () => {
  337. const { updateCollection } = await adminClient.query(gql`
  338. mutation {
  339. updateCollection(
  340. input: {
  341. id: "${collectionId}"
  342. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  343. }
  344. ) {
  345. id
  346. ${customFieldsSelection}
  347. }
  348. }
  349. `);
  350. assertCustomFieldIds(updateCollection.customFields, 'T_2', ['T_3', 'T_4']);
  351. });
  352. });
  353. describe('Customer entity', () => {
  354. let customerId: string;
  355. it('admin createCustomer', async () => {
  356. const { createCustomer } = await adminClient.query(gql`
  357. mutation {
  358. createCustomer(
  359. input: {
  360. emailAddress: "test@test.com"
  361. firstName: "Test"
  362. lastName: "Person"
  363. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  364. }
  365. ) {
  366. ... on Customer {
  367. id
  368. ${customFieldsSelection}
  369. }
  370. }
  371. }
  372. `);
  373. assertCustomFieldIds(createCustomer.customFields, 'T_1', ['T_1', 'T_2']);
  374. customerId = createCustomer.id;
  375. });
  376. it('admin updateCustomer', async () => {
  377. const { updateCustomer } = await adminClient.query(gql`
  378. mutation {
  379. updateCustomer(
  380. input: {
  381. id: "${customerId}"
  382. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  383. }
  384. ) {
  385. ...on Customer {
  386. id
  387. ${customFieldsSelection}
  388. }
  389. }
  390. }
  391. `);
  392. assertCustomFieldIds(updateCustomer.customFields, 'T_2', ['T_3', 'T_4']);
  393. });
  394. it('shop updateCustomer', async () => {
  395. const { updateCustomer } = await shopClient.query(gql`
  396. mutation {
  397. updateCustomer(input: { customFields: { singleId: "T_4", multiIds: ["T_2", "T_4"] } }) {
  398. id
  399. ${customFieldsSelection}
  400. }
  401. }
  402. `);
  403. assertCustomFieldIds(updateCustomer.customFields, 'T_4', ['T_2', 'T_4']);
  404. });
  405. });
  406. describe('Facet entity', () => {
  407. let facetId: string;
  408. it('admin createFacet', async () => {
  409. const { createFacet } = await adminClient.query(gql`
  410. mutation {
  411. createFacet(
  412. input: {
  413. code: "test"
  414. isPrivate: false
  415. translations: [{ languageCode: en, name: "test" }]
  416. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  417. }
  418. ) {
  419. id
  420. ${customFieldsSelection}
  421. }
  422. }
  423. `);
  424. assertCustomFieldIds(createFacet.customFields, 'T_1', ['T_1', 'T_2']);
  425. facetId = createFacet.id;
  426. });
  427. it('admin updateFacet', async () => {
  428. const { updateFacet } = await adminClient.query(gql`
  429. mutation {
  430. updateFacet(
  431. input: {
  432. id: "${facetId}"
  433. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  434. }
  435. ) {
  436. id
  437. ${customFieldsSelection}
  438. }
  439. }
  440. `);
  441. assertCustomFieldIds(updateFacet.customFields, 'T_2', ['T_3', 'T_4']);
  442. });
  443. });
  444. describe('FacetValue entity', () => {
  445. let facetValueId: string;
  446. it('admin createFacetValues', async () => {
  447. const { createFacetValues } = await adminClient.query(gql`
  448. mutation {
  449. createFacetValues(
  450. input: {
  451. code: "test"
  452. facetId: "T_1"
  453. translations: [{ languageCode: en, name: "test" }]
  454. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  455. }
  456. ) {
  457. id
  458. ${customFieldsSelection}
  459. }
  460. }
  461. `);
  462. assertCustomFieldIds(createFacetValues[0].customFields, 'T_1', ['T_1', 'T_2']);
  463. facetValueId = createFacetValues[0].id;
  464. });
  465. it('admin updateFacetValues', async () => {
  466. const { updateFacetValues } = await adminClient.query(gql`
  467. mutation {
  468. updateFacetValues(
  469. input: {
  470. id: "${facetValueId}"
  471. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  472. }
  473. ) {
  474. id
  475. ${customFieldsSelection}
  476. }
  477. }
  478. `);
  479. assertCustomFieldIds(updateFacetValues[0].customFields, 'T_2', ['T_3', 'T_4']);
  480. });
  481. });
  482. describe('Fulfillment entity', () => {
  483. // Currently no GraphQL API to set customFields on fulfillments
  484. });
  485. describe('GlobalSettings entity', () => {
  486. it('admin updateGlobalSettings', async () => {
  487. const { updateGlobalSettings } = await adminClient.query(gql`
  488. mutation {
  489. updateGlobalSettings(
  490. input: {
  491. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  492. }
  493. ) {
  494. ... on GlobalSettings {
  495. id
  496. ${customFieldsSelection}
  497. }
  498. }
  499. }
  500. `);
  501. assertCustomFieldIds(updateGlobalSettings.customFields, 'T_2', ['T_3', 'T_4']);
  502. });
  503. });
  504. describe('Order entity', () => {
  505. let orderId: string;
  506. beforeAll(async () => {
  507. const { addItemToOrder } = await shopClient.query<any, AddItemToOrder.Variables>(
  508. ADD_ITEM_TO_ORDER,
  509. {
  510. productVariantId: 'T_1',
  511. quantity: 1,
  512. },
  513. );
  514. orderId = addItemToOrder.id;
  515. });
  516. it('shop setOrderCustomFields', async () => {
  517. const { setOrderCustomFields } = await shopClient.query(gql`
  518. mutation {
  519. setOrderCustomFields(
  520. input: {
  521. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  522. }
  523. ) {
  524. ... on Order {
  525. id
  526. ${customFieldsSelection}
  527. }
  528. }
  529. }
  530. `);
  531. assertCustomFieldIds(setOrderCustomFields.customFields, 'T_2', ['T_3', 'T_4']);
  532. });
  533. it('admin setOrderCustomFields', async () => {
  534. const { setOrderCustomFields } = await adminClient.query(gql`
  535. mutation {
  536. setOrderCustomFields(
  537. input: {
  538. id: "${orderId}"
  539. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  540. }
  541. ) {
  542. ... on Order {
  543. id
  544. ${customFieldsSelection}
  545. }
  546. }
  547. }
  548. `);
  549. assertCustomFieldIds(setOrderCustomFields.customFields, 'T_1', ['T_1', 'T_2']);
  550. });
  551. });
  552. describe('OrderLine entity', () => {
  553. it('shop addItemToOrder', async () => {
  554. const { addItemToOrder } = await shopClient.query(
  555. gql`mutation {
  556. addItemToOrder(productVariantId: "T_1", quantity: 1, customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }) {
  557. ... on Order {
  558. id
  559. ${customFieldsSelection}
  560. }
  561. }
  562. }`,
  563. );
  564. assertCustomFieldIds(addItemToOrder.customFields, 'T_1', ['T_1', 'T_2']);
  565. });
  566. });
  567. describe('Product, ProductVariant entity', () => {
  568. let productId: string;
  569. it('admin createProduct', async () => {
  570. const { createProduct } = await adminClient.query(gql`
  571. mutation {
  572. createProduct(
  573. input: {
  574. translations: [{ languageCode: en, name: "test" slug: "test" description: "test" }]
  575. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  576. }
  577. ) {
  578. id
  579. ${customFieldsSelection}
  580. }
  581. }
  582. `);
  583. assertCustomFieldIds(createProduct.customFields, 'T_1', ['T_1', 'T_2']);
  584. productId = createProduct.id;
  585. });
  586. it('admin updateProduct', async () => {
  587. const { updateProduct } = await adminClient.query(gql`
  588. mutation {
  589. updateProduct(
  590. input: {
  591. id: "${productId}"
  592. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  593. }
  594. ) {
  595. id
  596. ${customFieldsSelection}
  597. }
  598. }
  599. `);
  600. assertCustomFieldIds(updateProduct.customFields, 'T_2', ['T_3', 'T_4']);
  601. });
  602. let productVariantId: string;
  603. it('admin createProductVariant', async () => {
  604. const { createProductVariants } = await adminClient.query(gql`
  605. mutation {
  606. createProductVariants(
  607. input: [{
  608. sku: "TEST01"
  609. productId: "${productId}"
  610. translations: [{ languageCode: en, name: "test" }]
  611. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  612. }]
  613. ) {
  614. id
  615. ${customFieldsSelection}
  616. }
  617. }
  618. `);
  619. assertCustomFieldIds(createProductVariants[0].customFields, 'T_1', ['T_1', 'T_2']);
  620. productVariantId = createProductVariants[0].id;
  621. });
  622. it('admin updateProductVariant', async () => {
  623. const { updateProductVariants } = await adminClient.query(gql`
  624. mutation {
  625. updateProductVariants(
  626. input: [{
  627. id: "${productVariantId}"
  628. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  629. }]
  630. ) {
  631. id
  632. ${customFieldsSelection}
  633. }
  634. }
  635. `);
  636. assertCustomFieldIds(updateProductVariants[0].customFields, 'T_2', ['T_3', 'T_4']);
  637. });
  638. });
  639. describe('ProductOptionGroup, ProductOption entity', () => {
  640. let productOptionGroupId: string;
  641. it('admin createProductOptionGroup', async () => {
  642. const { createProductOptionGroup } = await adminClient.query(gql`
  643. mutation {
  644. createProductOptionGroup(
  645. input: {
  646. code: "test"
  647. options: []
  648. translations: [{ languageCode: en, name: "test" }]
  649. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  650. }
  651. ) {
  652. id
  653. ${customFieldsSelection}
  654. }
  655. }
  656. `);
  657. assertCustomFieldIds(createProductOptionGroup.customFields, 'T_1', ['T_1', 'T_2']);
  658. productOptionGroupId = createProductOptionGroup.id;
  659. });
  660. it('admin updateProductOptionGroup', async () => {
  661. const { updateProductOptionGroup } = await adminClient.query(gql`
  662. mutation {
  663. updateProductOptionGroup(
  664. input: {
  665. id: "${productOptionGroupId}"
  666. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  667. }
  668. ) {
  669. id
  670. ${customFieldsSelection}
  671. }
  672. }
  673. `);
  674. assertCustomFieldIds(updateProductOptionGroup.customFields, 'T_2', ['T_3', 'T_4']);
  675. });
  676. let productOptionId: string;
  677. it('admin createProductOption', async () => {
  678. const { createProductOption } = await adminClient.query(gql`
  679. mutation {
  680. createProductOption(
  681. input: {
  682. productOptionGroupId: "${productOptionGroupId}"
  683. code: "test-option"
  684. translations: [{ languageCode: en, name: "test-option" }]
  685. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  686. }
  687. ) {
  688. id
  689. ${customFieldsSelection}
  690. }
  691. }
  692. `);
  693. assertCustomFieldIds(createProductOption.customFields, 'T_1', ['T_1', 'T_2']);
  694. productOptionId = createProductOption.id;
  695. });
  696. it('admin updateProductOption', async () => {
  697. const { updateProductOption } = await adminClient.query(gql`
  698. mutation {
  699. updateProductOption(
  700. input: {
  701. id: "${productOptionId}"
  702. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  703. }
  704. ) {
  705. id
  706. ${customFieldsSelection}
  707. }
  708. }
  709. `);
  710. assertCustomFieldIds(updateProductOption.customFields, 'T_2', ['T_3', 'T_4']);
  711. });
  712. });
  713. describe('User entity', () => {
  714. // Currently no GraphQL API to set User custom fields
  715. });
  716. describe('ShippingMethod entity', () => {
  717. let shippingMethodId: string;
  718. it('admin createShippingMethod', async () => {
  719. const { createShippingMethod } = await adminClient.query(gql`
  720. mutation {
  721. createShippingMethod(
  722. input: {
  723. code: "test"
  724. calculator: {
  725. code: "${defaultShippingCalculator.code}"
  726. arguments: [
  727. { name: "rate" value: "10"},
  728. { name: "includesTax" value: "true"},
  729. { name: "taxRate" value: "10"},
  730. ]
  731. }
  732. checker: {
  733. code: "${defaultShippingEligibilityChecker.code}"
  734. arguments: [
  735. { name: "orderMinimum" value: "0"},
  736. ]
  737. }
  738. fulfillmentHandler: "${manualFulfillmentHandler.code}"
  739. translations: [{ languageCode: en, name: "test" description: "test" }]
  740. customFields: { singleId: "T_1", multiIds: ["T_1", "T_2"] }
  741. }
  742. ) {
  743. id
  744. ${customFieldsSelection}
  745. }
  746. }
  747. `);
  748. assertCustomFieldIds(createShippingMethod.customFields, 'T_1', ['T_1', 'T_2']);
  749. shippingMethodId = createShippingMethod.id;
  750. });
  751. it('admin updateShippingMethod', async () => {
  752. const { updateShippingMethod } = await adminClient.query(gql`
  753. mutation {
  754. updateShippingMethod(
  755. input: {
  756. id: "${shippingMethodId}"
  757. translations: []
  758. customFields: { singleId: "T_2", multiIds: ["T_3", "T_4"] }
  759. }
  760. ) {
  761. id
  762. ${customFieldsSelection}
  763. }
  764. }
  765. `);
  766. assertCustomFieldIds(updateShippingMethod.customFields, 'T_2', ['T_3', 'T_4']);
  767. });
  768. });
  769. });
  770. it('null values', async () => {
  771. const { updateCustomerAddress } = await adminClient.query(gql`
  772. mutation {
  773. updateCustomerAddress(
  774. input: { id: "T_1", customFields: { singleId: null, multiIds: ["T_1", "null"] } }
  775. ) {
  776. id
  777. customFields {
  778. single {
  779. id
  780. }
  781. multi {
  782. id
  783. }
  784. }
  785. }
  786. }
  787. `);
  788. expect(updateCustomerAddress.customFields.single).toEqual(null);
  789. expect(updateCustomerAddress.customFields.multi).toEqual([{ id: 'T_1' }]);
  790. });
  791. });