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

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