diff --git a/.changeset/little-bottles-switch.md b/.changeset/little-bottles-switch.md new file mode 100644 index 000000000..d3cb256cc --- /dev/null +++ b/.changeset/little-bottles-switch.md @@ -0,0 +1,8 @@ +--- +"@vue-storefront/magento-api": minor +"@vue-storefront/magento-sdk": minor +--- + +[ADDED] addBundleProductsToCart method to add one or more bundle products to the specified cart. +[ADDED] addConfigurableProductsToCart method to add one or more configurable products to the specified cart. + diff --git a/packages/api-client/src/api/addBundleProductsToCart/addBundleProductsToCart.ts b/packages/api-client/src/api/addBundleProductsToCart/addBundleProductsToCart.ts index ce6329c88..528121646 100644 --- a/packages/api-client/src/api/addBundleProductsToCart/addBundleProductsToCart.ts +++ b/packages/api-client/src/api/addBundleProductsToCart/addBundleProductsToCart.ts @@ -1,6 +1,4 @@ -import gql from "graphql-tag"; - -export default gql` +export default ` mutation addBundleProductsToCart($input: AddBundleProductsToCartInput) { addBundleProductsToCart(input: $input) { cart { diff --git a/packages/api-client/src/api/addBundleProductsToCart/index.ts b/packages/api-client/src/api/addBundleProductsToCart/index.ts index 531e6640b..6cca39524 100644 --- a/packages/api-client/src/api/addBundleProductsToCart/index.ts +++ b/packages/api-client/src/api/addBundleProductsToCart/index.ts @@ -6,7 +6,7 @@ import type { AddBundleProductsToCartMutationVariables, CustomHeaders, } from "@vue-storefront/magento-types"; - +import gql from "graphql-tag"; import addBundleProductsToCart from "./addBundleProductsToCart"; import { Context } from "../../types/context"; import getHeaders from "../getHeaders"; @@ -25,7 +25,9 @@ export default async ( }); return context.client.mutate({ - mutation: addBundleProductsToCartGQL.query, + mutation: gql` + ${addBundleProductsToCartGQL.query} + `, variables: addBundleProductsToCartGQL.variables, context: { headers: getHeaders(context, customHeaders), diff --git a/packages/api-client/src/api/addConfigurableProductsToCart/addConfigurableProductsToCart.ts b/packages/api-client/src/api/addConfigurableProductsToCart/addConfigurableProductsToCart.ts index 4504793ee..e77c0c1f4 100644 --- a/packages/api-client/src/api/addConfigurableProductsToCart/addConfigurableProductsToCart.ts +++ b/packages/api-client/src/api/addConfigurableProductsToCart/addConfigurableProductsToCart.ts @@ -1,7 +1,5 @@ -import gql from "graphql-tag"; - /** GraphQL Mutation that adds configurable products to shopping cart */ -export default gql` +export default ` mutation addConfigurableProductsToCart($input: AddConfigurableProductsToCartInput) { addConfigurableProductsToCart(input: $input) { cart { diff --git a/packages/api-client/src/api/addConfigurableProductsToCart/index.ts b/packages/api-client/src/api/addConfigurableProductsToCart/index.ts index 59ab547ce..770721baa 100644 --- a/packages/api-client/src/api/addConfigurableProductsToCart/index.ts +++ b/packages/api-client/src/api/addConfigurableProductsToCart/index.ts @@ -5,6 +5,7 @@ import { AddConfigurableProductsToCartMutation, AddConfigurableProductsToCartMutationVariables, } from "@vue-storefront/magento-types"; +import gql from "graphql-tag"; import type { CustomHeaders } from "@vue-storefront/magento-types"; import type { Context } from "../../types/context"; import addConfigurableProductsToCartMutation from "./addConfigurableProductsToCart"; @@ -30,7 +31,9 @@ export default async function addConfigurableProductsToCart( }, }); return context.client.mutate({ - mutation: addConfigurableProductsToCartGQL.query, + mutation: gql` + ${addConfigurableProductsToCartGQL.query} + `, variables: addConfigurableProductsToCartGQL.variables, context: { headers: getHeaders(context, customHeaders), diff --git a/packages/sdk/__tests__/integration/__config__/customQueries/addBundleProductsToCart/index.ts b/packages/sdk/__tests__/integration/__config__/customQueries/addBundleProductsToCart/index.ts new file mode 100644 index 000000000..8983b9e9c --- /dev/null +++ b/packages/sdk/__tests__/integration/__config__/customQueries/addBundleProductsToCart/index.ts @@ -0,0 +1,13 @@ +export const addBundleProductsToCart = ({ variables, metadata }: { variables: any; metadata: any }) => { + return { + variables, + query: ` + mutation addBundleProductsToCart($input: AddBundleProductsToCartInput) { + addBundleProductsToCart(input: $input) { + cart { + ${metadata.fields} + } + } + }`, + }; +}; diff --git a/packages/sdk/__tests__/integration/__config__/customQueries/addConfigurableProductsToCart/index.ts b/packages/sdk/__tests__/integration/__config__/customQueries/addConfigurableProductsToCart/index.ts new file mode 100644 index 000000000..7a3857d18 --- /dev/null +++ b/packages/sdk/__tests__/integration/__config__/customQueries/addConfigurableProductsToCart/index.ts @@ -0,0 +1,13 @@ +export const addConfigurableProductsToCart = ({ variables, metadata }: { variables: any; metadata: any }) => { + return { + variables, + query: ` + mutation addConfigurableProductsToCart($input: AddConfigurableProductsToCartInput) { + addConfigurableProductsToCart(input: $input) { + cart { + ${metadata.fields} + } + } + }`, + }; +}; diff --git a/packages/sdk/__tests__/integration/__config__/customQueries/jest.customQueries.ts b/packages/sdk/__tests__/integration/__config__/customQueries/jest.customQueries.ts index d04e0c3e3..93393ec63 100644 --- a/packages/sdk/__tests__/integration/__config__/customQueries/jest.customQueries.ts +++ b/packages/sdk/__tests__/integration/__config__/customQueries/jest.customQueries.ts @@ -39,6 +39,8 @@ import { setPaymentMethodOnCart } from './setPaymentMethodOnCart'; import { updateCartItems } from './updateCartItems'; import { generateCustomerToken } from './generateCustomerToken'; import { route } from './route'; +import { addConfigurableProductsToCart } from './addConfigurableProductsToCart'; +import { addBundleProductsToCart } from './addBundleProductsToCart'; export const customQueries = { 'apply-coupon-to-cart-custom-query': applyCouponToCart, @@ -82,4 +84,6 @@ export const customQueries = { 'store-config-custom-query': storeConfig, 'route-custom-query': route, 'generate-customer-token-custom-query': generateCustomerToken, + 'add-configurable-products-to-cart-custom-query': addConfigurableProductsToCart, + 'add-bundle-products-to-cart-custom-query': addBundleProductsToCart, }; diff --git a/packages/sdk/__tests__/integration/__config__/jest.const.ts b/packages/sdk/__tests__/integration/__config__/jest.const.ts index e2b72cc06..39b0891ae 100644 --- a/packages/sdk/__tests__/integration/__config__/jest.const.ts +++ b/packages/sdk/__tests__/integration/__config__/jest.const.ts @@ -4,6 +4,10 @@ export const TEST_USER_PASSWORD = '9uvPv!Vvn2!Uaz.yNy4a'; export const TEST_CART_ID = 'pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp'; export const TEST_COUPON_CODE = 'integration-tests'; export const TEST_PRODUCT_SKU = 'WSH12'; +export const TEST_CONF_SKU_PARENT = 'MH01'; +export const TEST_CONF_SKU_VARIANT = 'MH01-XS-Black'; +export const TEST_BUNDLE_SKU = '24-WG080'; + export const TEST_ADDRESS = { firstname: 'John', lastname: 'Doe', diff --git a/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart new file mode 100644 index 000000000..09f5681c1 --- /dev/null +++ b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart @@ -0,0 +1,103 @@ +[ + { + "scope": "https://magento2-instance.vuestorefront.io:443", + "method": "POST", + "path": "/graphql", + "body": { + "operationName": "addBundleProductsToCart", + "variables": { + "input": { + "cart_id": "pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp", + "cart_items": [ + { + "data": { + "quantity": 1, + "sku": "24-WG080" + }, + "bundle_options": [ + { + "id": 1, + "quantity": 1, + "value": [ + "1" + ] + }, + { + "id": 2, + "quantity": 1, + "value": [ + "4" + ] + }, + { + "id": 3, + "quantity": 1, + "value": [ + "5" + ] + }, + { + "id": 4, + "quantity": 1, + "value": [ + "8" + ] + } + ] + } + ] + } + }, + "query": "mutation addBundleProductsToCart($input: AddBundleProductsToCartInput) {\n addBundleProductsToCart(input: $input) {\n cart {\n id\n email\n is_virtual\n applied_coupons {\n code\n __typename\n }\n prices {\n subtotal_excluding_tax {\n value\n __typename\n }\n subtotal_including_tax {\n value\n __typename\n }\n applied_taxes {\n amount {\n value\n __typename\n }\n label\n __typename\n }\n discounts {\n amount {\n value\n __typename\n }\n label\n __typename\n }\n grand_total {\n value\n __typename\n }\n __typename\n }\n items {\n uid\n product {\n uid\n __typename\n sku\n name\n stock_status\n only_x_left_in_stock\n rating_summary\n thumbnail {\n url\n position\n disabled\n label\n __typename\n }\n url_key\n url_rewrites {\n url\n __typename\n }\n price_range {\n maximum_price {\n final_price {\n currency\n value\n __typename\n }\n regular_price {\n currency\n value\n __typename\n }\n __typename\n }\n minimum_price {\n final_price {\n currency\n value\n __typename\n }\n regular_price {\n currency\n value\n __typename\n }\n __typename\n }\n __typename\n }\n categories {\n uid\n name\n url_suffix\n url_path\n breadcrumbs {\n category_name\n category_url_path\n __typename\n }\n __typename\n }\n review_count\n reviews {\n items {\n average_rating\n ratings_breakdown {\n name\n value\n __typename\n }\n __typename\n }\n __typename\n }\n }\n prices {\n row_total {\n value\n __typename\n }\n row_total_including_tax {\n value\n __typename\n }\n total_item_discount {\n value\n __typename\n }\n __typename\n }\n quantity\n ... on ConfigurableCartItem {\n configurable_options {\n configurable_product_option_uid\n option_label\n configurable_product_option_value_uid\n value_label\n __typename\n }\n configured_variant {\n sku\n thumbnail {\n url\n __typename\n }\n __typename\n }\n __typename\n }\n ... on BundleCartItem {\n bundle_options {\n uid\n label\n type\n values {\n id\n label\n price\n quantity\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n total_quantity\n shipping_addresses {\n firstname\n lastname\n street\n city\n company\n region {\n code\n region_id\n label\n __typename\n }\n postcode\n telephone\n country {\n code\n label\n __typename\n }\n selected_shipping_method {\n carrier_code\n carrier_title\n method_code\n method_title\n amount {\n value\n currency\n __typename\n }\n __typename\n }\n __typename\n }\n billing_address {\n firstname\n lastname\n street\n city\n company\n region {\n code\n region_id\n label\n __typename\n }\n postcode\n telephone\n country {\n code\n label\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}" + }, + "status": 200, + "response": [ + "1f8b0800000000000003ed5c6b739b3a13fe2b0c1fde4f8118df9399cebcb9b5cd699d367172da9ca6c3c820dbc4802888387627fffdac40d8d85c828d9df874f2a1ae41dad5ee6ab57a1e23f25bd41145e2e16f11e9fab16feb26feea12ddd7a8774d4e904b5993c6ff3774f150744eba95c9083b8a591b7f30bf7eea4ebe7dfeeb57a3df534e1fcf2f3547dc13b1850c13ba3e787dd942036c53221b36c503175183d832c51e957d0fbbff1fb09eb2462c90323cf5c170a98f40b48f4c0fef89c8714c03ebaa467c87d89e7868fba6b9273aaea1618f59e4f93d4a283255fca899be6ed80395a247d6f2804c1f8b8775a525375a7ba2aad289836d64c13db1436c3c119ff6e6e286bd8e78641ec830737efcdc1375c303636dca2e21a616fb1ed3d7aec90d254b9d897a9885ed94eb10973aceee3fc140104b1b4666d6c7f4d7da15b9d1cc1a60e12e9bdcaf6120a1c9a0d80a6df68359ee5c1f8de1df3b91453bc807364ad876311d4c966d3b2176df18f82eeacd1208ba78239fe9fa5aa9c305efd9f51decdae401095d87b854f88a024f3d4ab491ea51447db0433cbf50bbd75f4e3e410bb1cd89faa89ab84f619ed4a06394092ca160d23cdfb2903b81f836f6443af4ad9e1d642058ecb2880e2975bcc3bbfdbb7d9e8e55c9b0612c5bc3f2830fd9485cdc77894d6583401fac1be86e5f83856192c1dd3e0f00bba30df1dd3e6e1cd47bad03add7efe15eb3de6ed7da4abbd1c20d74d06b2a8d36680021f8742a7509e669a24296dbaa22df3b03164fe2196c19443e40cab0a8e9d175940619815a083b0ff539738b4d23b8ab8e60b20f21b5b9b4e43169c909a55907178f5d986f3edd4180d27acb436a99cb03deb8e655280ec345d216b6eff67b845262795270c1e4f9d772aa21f61661d1f222a5c834cb2add805d4997d7d2f7931733155633cc2024ac851e0dcbb7d4e036bbd1376c2850b34bcd775d6c6b6c8acf6eae40f7ac52c92cf9d317be8b07be89dc925ad2322fa820acd132ecb5ecaeb6e483d266e729c9b57aa911ee5e0513014db0fcf180b8065e2c8b67efe6a5ac836dbea43cbfdf3760e310a31967371d448761aac08d9e8b91aeb9509a66dbd852390e869b5cbb98e7191fb0131bf0384cb862832ee4e7b2053f7e470e4ed4056f6677131e2c987b3c53162471315706315758355bc791586dd9a64f7b495df3e067e85b0e78e9804dcfd708586ac55c39017fb2d5f760e0b11a428ec37a7423c05d73b8801eb00b9b8f1aeec4b00357a25dd953d990239d8ceda0271fe72aec385bbb623d6353bb0a86e3dd13315be814046d772d512a2b9bd2f8b38292db0c00f4290eea5d324e00dbfced2d12c8c1f139e25c14525a8de07b1cb2cbb54c029000d4e7a0640eaa7ff9b0fe0c0adb15607e2d869055e2042b34ac59f1068e357907352c04b7d503ff1fcbb4f5ef7f0d6fad47f3f354ab778c76a3337ec70a04ef1be1c613621257dccbd51bf896a97d34fd3cbd9946393053fc012a43a2ae75b189358af53801f8120c1216d1759d7bbc38bd4c71ae6b4c7129dfce2a1727a07caabd4bf8574ba47a9e733fe75600057c40ae81c2bc99931ea95697a2a0ed1a2b01ab1669492eaf588c8a61397396975806b158454b6201059c3f7ec920969dfba369e728c8e9c2e4f25bf7a3a2cc77c9731b0927c4725cec79304d427708587c63f4b2b91bf4720c6c033ebda1a2483d96c16bf1cbac5015249800ef256d2e2e795c3c8361a6762fceb7c6640160f1cb40c9ecaae4101a31d96a0f9113760d5b7231a803d5ba575af9664c4c8fc27a4a37483d1b39bf9115a79e795ab6423d5fdbee95c9e7fd518c0f7c235621fa3926e508e8fdf95a04342d550b10b6c8ab348a15e928cdabeee34434287beb7ab45882b6eddfcaa4346312ca13d3cb5800cfa0540a57b3525920927995f6e5986a7d652a547de3872f479a5f697a4a33d5034556eaeb33d55cf17ca6aab4e56aad3455ad6e98aa9e8f3bd3a3872fe1ef98dba1aae304953b6601d93e530d7deb5c5f56b6c854cf924cb5dade20530d1894546d4b3c683b4f705e88a95e9cde343ad75a1653ad5c0c5667aad5856d7384842bdfb6a1086c98a7b62a3b368dd5b45f1c8a12d5f44815a4a998094b6e28fc1c494de9bc598a5a6a807c82ba09dbb7e0ff3a2adf9e8ac2569e798aa3b0d9794ade88e91b317d23a6bb494c77880e5657b644d99225cd952da9fd616cbd3433adb5e4eafac4344f3a9f97b6e47a26a37d455a7a717abb5d5afa7a4f5043e7fe005e5a65bc74871ea13ec3685e8c990eaa17f79df4c3b92186287e38f76325f6f8f46488a6c22706f65c42848f84e806de182b0d0ae70e4ca275b73f84cf614529713a3723520559a906d2d2884b4bc3483a8396a6f55ef1a82a250e3f3e178a7b12b275c91b6344bda1e1468775cb8db4089f3422f58128d8ba3929ab7803b62d45612d651be4a56db9569ee0e56ad9ce69dd03b9f59a76ff07ceebc659e935e45bb111e7b95980ab6dffa4ee4dcc89b0b679c2ff84eebc5cacea556eddd9a6cb29d494cf4ae629ded84c9427a4b77142aa11e13d2f892bb3d158392d4f45951da7a2a5b98e7250cb611dcfb39d7cf97cbe536bcbcd62af23e4119efa8609cf6d9dd1926d919dcb46ca3338045870fb648739069ce428ed2ceca6c8cefd6d92ec7cef6e90ec30182e7def4a51d0760b26f79855af4775a61954e7f4264175165e619d919c6a5dfaf6a1d2aec47e5c7518a4136ec9203c04896c7604f293f1c73d8333eff67df8f42d244dc059696450a9aa2a359846bcd2db8839012b487abc4045688616a9600665339f4c91e2c07f80910bac7d538afa06b5b1e749f8976f3800126819dd9b23142d456e66be585c1898e76ad90aa168d4e483ec6dbaa8dd8da6dc2a76f2a534a1085fb9e0021f20250a00b941d86d4d4a7171191ff27d987fc259947f05c74fc9dc02b09b3b980695b9536b22e40422adfee7de2f7ba52712a5a171fe927b1619e78ae703e34a69500cc5a917ecf00b70988337fb6fff9f0f016863eb6569e3ea52e4199e701cbe0cc986833617e906892628d4c5542979d242a3216896c8a30c89abc8b583251b535161084d423cf8771090c45ca6758d5582b987e7291ebe27c80af7e763b06cf4ac97f5021ab88f7599bdf9f2b22e76525c0c6ceb521739cf7ad7c811169a429f103af74fa90427275fd6c1cbac39bc62bcdf7dd6c3f633d2916f2db9d9daaa6fcbbdc2d63998ff19d585980d500abca1e138acbe205d67afae70d7fa86eb51aee92f32b48320cdee9c92f079046c2250597e88dde09bc01e61f0af559151ad6014f1028f61dadd51400119309bccd03a1e04a097514e9d293efa2c4677d5a51a70045f9085124f55c0c1a3d0f4ab50db5300a729d7a8542ac1a3150a41738650ead8bd6a4de0ff029ba03e32ae30b3e2a61bcb899b04c18c0d79c265614c8fcf8a3a8ba885e990e8fc4ff700827155aebf6f22580034e0c4bc0526c40c8005340957615b289f22c41b6632c6233085bde4dfb9a93765588009b856a0fa4729d6e5be74425712dd78732c2241a2f50cd38ce5548844df126ab5845a5ccd614417029da22571f328fdef497df1a9e343efa7a77f0101b14f977b4a0000" + ], + "rawHeaders": [ + "Server", + "nginx/1.14.2", + "Date", + "Thu, 04 Apr 2024 08:19:44 GMT", + "Content-Type", + "application/json", + "Transfer-Encoding", + "chunked", + "Connection", + "keep-alive", + "Vary", + "Accept-Encoding", + "Set-Cookie", + "PHPSESSID=pqgtneeuaa6qamluak8emhdh5o; expires=Thu, 04-Apr-2024 09:19:43 GMT; Max-Age=3600; path=/; domain=magento2-instance.vuestorefront.io; secure; HttpOnly; SameSite=Lax", + "Set-Cookie", + "private_content_version=20f92e7b3b5b4d2ad95ea06072ed1971; expires=Sun, 02-Apr-2034 08:19:43 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=53b98595a264b66e6ca48906c0cdccc7; expires=Sun, 02-Apr-2034 08:19:44 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=4ad1e098ac218968778d4812df8ff42b; expires=Sun, 02-Apr-2034 08:19:44 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "X-Magento-Cache-Id", + "b309d3e32ec01e2fccaf4dd92e430e3576b7d1135b436c3a91b354bb36cec2ec", + "X-Content-Type-Options", + "nosniff", + "X-XSS-Protection", + "1; mode=block", + "X-Frame-Options", + "SAMEORIGIN", + "Content-Encoding", + "gzip", + "X-Varnish", + "63689177", + "Age", + "0", + "Pragma", + "no-cache", + "Expires", + "-1", + "Cache-Control", + "no-store, no-cache, must-revalidate, max-age=0", + "Accept-Ranges", + "bytes" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart-and-return-custom-query-fields b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart-and-return-custom-query-fields new file mode 100644 index 000000000..549ef2750 --- /dev/null +++ b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addBundleProductsToCart-should-add-product-to-cart-and-return-custom-query-fields @@ -0,0 +1,103 @@ +[ + { + "scope": "https://magento2-instance.vuestorefront.io:443", + "method": "POST", + "path": "/graphql", + "body": { + "operationName": "addBundleProductsToCart", + "variables": { + "input": { + "cart_id": "pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp", + "cart_items": [ + { + "data": { + "quantity": 1, + "sku": "24-WG080" + }, + "bundle_options": [ + { + "id": 1, + "quantity": 1, + "value": [ + "1" + ] + }, + { + "id": 2, + "quantity": 1, + "value": [ + "4" + ] + }, + { + "id": 3, + "quantity": 1, + "value": [ + "5" + ] + }, + { + "id": 4, + "quantity": 1, + "value": [ + "8" + ] + } + ] + } + ] + } + }, + "query": "mutation addBundleProductsToCart($input: AddBundleProductsToCartInput) {\n addBundleProductsToCart(input: $input) {\n cart {\n id\n items {\n uid\n product {\n uid\n sku\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}" + }, + "status": 200, + "response": [ + "1f8b0800000000000003b592516b83301485ff4b9e3788ae8521f8e0145ab7c53ab4f83046498d15add54c135a15fffb92392a73756f3e84907b4eeef9486e0b086618682dc0843cf19c64915b168487acf20b13974c4ae1cf9e10a0016a7ab03e4654c91eceabcc7df1eae0f5f97379d82bd6c57e0b29b803098b4e15d0de5bc0bfaf20df388ba50b89f6cd65b75e739ab816f5eac8a5d1850b71d8ed584da31c9f2251338bfc90c4bcc4fb2b1ae8fef148685b0008d3906f5f3613f928351a64e8fa9521f0d68a320384636d97c80fa720a0138f20d4592062d549d1ed9f48e30100ade13c8f20f29b897c6b3be4ab8bfb60051fe198e1d788fe49efd521f7634c2707797cc9b83df81bce2817eeaefb0246d9a3b724030000" + ], + "rawHeaders": [ + "Server", + "nginx/1.14.2", + "Date", + "Thu, 04 Apr 2024 08:22:33 GMT", + "Content-Type", + "application/json", + "Content-Length", + "282", + "Connection", + "keep-alive", + "Vary", + "Accept-Encoding", + "Set-Cookie", + "PHPSESSID=qp9p894m3nd4ob79r8vfshl9ur; expires=Thu, 04-Apr-2024 09:22:32 GMT; Max-Age=3600; path=/; domain=magento2-instance.vuestorefront.io; secure; HttpOnly; SameSite=Lax", + "Set-Cookie", + "private_content_version=49915dd66425d7e901dccac3541c1d5e; expires=Sun, 02-Apr-2034 08:22:32 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=f0118632a5fb7cb8bde953132aed3bd5; expires=Sun, 02-Apr-2034 08:22:33 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=155c15d67869228246d4f05ce006fbcc; expires=Sun, 02-Apr-2034 08:22:33 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "X-Magento-Cache-Id", + "b309d3e32ec01e2fccaf4dd92e430e3576b7d1135b436c3a91b354bb36cec2ec", + "X-Content-Type-Options", + "nosniff", + "X-XSS-Protection", + "1; mode=block", + "X-Frame-Options", + "SAMEORIGIN", + "Content-Encoding", + "gzip", + "X-Varnish", + "63335937", + "Age", + "0", + "Pragma", + "no-cache", + "Expires", + "-1", + "Cache-Control", + "no-store, no-cache, must-revalidate, max-age=0", + "Accept-Ranges", + "bytes" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart new file mode 100644 index 000000000..1a2e4dbb0 --- /dev/null +++ b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart @@ -0,0 +1,75 @@ +[ + { + "scope": "https://magento2-instance.vuestorefront.io:443", + "method": "POST", + "path": "/graphql", + "body": { + "operationName": "addConfigurableProductsToCart", + "variables": { + "input": { + "cart_id": "pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp", + "cart_items": [ + { + "data": { + "quantity": 1, + "sku": "MH01-XS-Black" + }, + "parent_sku": "MH01", + "customizable_options": [] + } + ] + } + }, + "query": "mutation addConfigurableProductsToCart($input: AddConfigurableProductsToCartInput) {\n addConfigurableProductsToCart(input: $input) {\n cart {\n id\n email\n is_virtual\n applied_coupons {\n code\n __typename\n }\n prices {\n subtotal_excluding_tax {\n value\n __typename\n }\n subtotal_including_tax {\n value\n __typename\n }\n applied_taxes {\n amount {\n value\n __typename\n }\n label\n __typename\n }\n discounts {\n amount {\n value\n __typename\n }\n label\n __typename\n }\n grand_total {\n value\n __typename\n }\n __typename\n }\n items {\n uid\n product {\n uid\n __typename\n sku\n name\n stock_status\n only_x_left_in_stock\n rating_summary\n thumbnail {\n url\n position\n disabled\n label\n __typename\n }\n url_key\n url_rewrites {\n url\n __typename\n }\n price_range {\n maximum_price {\n final_price {\n currency\n value\n __typename\n }\n regular_price {\n currency\n value\n __typename\n }\n __typename\n }\n minimum_price {\n final_price {\n currency\n value\n __typename\n }\n regular_price {\n currency\n value\n __typename\n }\n __typename\n }\n __typename\n }\n categories {\n uid\n name\n url_suffix\n url_path\n breadcrumbs {\n category_name\n category_url_path\n __typename\n }\n __typename\n }\n review_count\n reviews {\n items {\n average_rating\n ratings_breakdown {\n name\n value\n __typename\n }\n __typename\n }\n __typename\n }\n }\n prices {\n row_total {\n value\n __typename\n }\n row_total_including_tax {\n value\n __typename\n }\n total_item_discount {\n value\n __typename\n }\n __typename\n }\n quantity\n ... on ConfigurableCartItem {\n configurable_options {\n configurable_product_option_uid\n option_label\n configurable_product_option_value_uid\n value_label\n __typename\n }\n configured_variant {\n sku\n thumbnail {\n url\n __typename\n }\n __typename\n }\n __typename\n }\n ... on BundleCartItem {\n bundle_options {\n uid\n label\n type\n values {\n id\n label\n price\n quantity\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n total_quantity\n shipping_addresses {\n firstname\n lastname\n street\n city\n company\n region {\n code\n region_id\n label\n __typename\n }\n postcode\n telephone\n country {\n code\n label\n __typename\n }\n selected_shipping_method {\n carrier_code\n carrier_title\n method_code\n method_title\n amount {\n value\n currency\n __typename\n }\n __typename\n }\n __typename\n }\n billing_address {\n firstname\n lastname\n street\n city\n company\n region {\n code\n region_id\n label\n __typename\n }\n postcode\n telephone\n country {\n code\n label\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}" + }, + "status": 200, + "response": [ + "1f8b0800000000000003ed9b6d53e2481080ff0a950ff78944c28ba2555b75ac7ab7ee2ea8a0b5ebad566a4806882699dc6422c296fffd7a920904f3b24040b92d3fa83033ddd3ddd3d3338f849f928118928e7e4ac8308e893330873e457d0b5f5062f83af3aec831a28c0fd0c55fd3908e24f7b857993c6057b56ae3bfad8b2fbdc9b7af9fff6d0cfaeac9d3d9a5ee4a6509dbc8b460e8a337506c34c40e238ae9303ca48899c45118f698e27b98fe39e423159dd820657adaa349998f4074802c0f9725e4ba96890d4d27be4b1c4f3a727ccb2a4b2e3575ec718b3cbfcf084396869f74cb374c67a831f4c47b1e91e563e9a8a63694ea4159d2343671b1836c6893dac4c113e9b93c17379d75c423f340869bf3e3ae2c19a607c63a8cbf85c8dafc754cdf7e4da934b2d459a88f79d84e840ee9c5c059fb334c04b17460666e7d4c7fb579a8d4ab59132cb4f2c5bd0803095d26c37668b31fac72fbaa35869f0f128f76900f7c96b0af331d4e5eda96924030c47bf0b9ae8b4a1dde88913ddfc5d4218fa8d4730965a50b1478ea31a23f681e43cc073ba4b38ed6bb3a3ffe023dc4b126da9366e1018375d282815126f0848245f37cdb4674221d3521b86ce4db7d27c840b098f2888e1873bda3dbbddb3d918e55d974602e47c7caa30fd948281e50e230c52430061b26baddd3617b586478bb2702c05bf411beddc38dc37affe050ef0ffab8bf5f6f366b4db5d938c00d74d8df571b4dd00042f0dbadd46558a7890659ee68aa72ef0e793c8967f26d10f90029c3a36644efa334c808d442d845a8cfb85b7c19c15ded0116fb08525b48cb1e9796dd509a0fa0784c61bdc57207014a1bad8c986dbd9cf09a5add501ca68ba46decdceef50963c4f6e4e00d97172f8ba986d8db8447cb8b9422cb2aaa740376255d5e4bdf9d28661aec66584148581b3d99b66f6b41336f18980e14a8d95bdda7143b3a5fe2d3eb2ee8163bbfae2acdccca42f1d0b7102da8252df3820ac23b6dd359cbeeea817258d8ec3c25b956bfe884d66eb010d005db1f0f0935f162593cfd302f656dec882de5f9838109078714ad386f74111b85a9020d7d8a91a153284db363ec45390ea69b5c512cf24c4cd88e4df8314cb8e5265dc8cf9716fcf8193938d116bc99b5263c5830f7e34c5990c4cbb9328cb9c2abd93a8ec46acb367d2a2775cd839fa1ef65c00b076c7ab646c0522be6ca0978c777dfa389c75a78e538aa470dc1bd6b7e5d408f98c2e1a38527319cc095e854f6343ee58341c64e3052ccd30d07cef6ae54cf38d4bac174627822660b8382a0edae256a6565531abf575072bbe102fa1cbfd453324e5c6cf38fb74820f31e9f2b2e4421a5b5e8fa1e136d2ab54c00485ca8cf40c9fc52fdaf0ffbcf64705ca950346237648db8c10e0d6b56bc43dc35c5002d2c0437d543ff1fdb728cef9f4737f693f575aad7db66b3d11e7fe005428c8dee8dc7c422542ae7ea0d7ccbd4fe30fd3abd9e46393053fc375486445deb610beb0c2f10e47930495844d775eea9737299e25ccf9ce242be9d563ac7a07caa7f48f8574ba47a9e7377732b00011f113551983773e8916b75390adaae510958b58825b95cb11815d376e79497d806b158455b62e11670f6749e0196edfbd6b4dd0a727a69b8fcd6fba4aaf353f2cc41a56362bb147b1e2c53a93782bbf8c6f0727f37f0720cb401bfbd91aaca7d9ec16bf16556a896044cb8decbfa5c5cf684780661a60e5f9eb7c664e18225de064a66ef0a4ea1138beff6f0e684a9e9c814833a506d7885956fc6c4f428aca77483e8d9501a9947e4f2e899a7652be8f9d676af0c9ff7ad180f7c23f652f83926c500f4fe6c2d004d4bd525802df22a0db1221d85b9ea3e0ea241d95bd7a3c512b46dff5686d28c45280ea697b1009e42a92c7567a5728948e655dad723d5faca28547de7c3d783e6375a9ec2a47aa82a6a7d7d52cd15cf2755b5a9546b8551b5ba61543d1bb7a7adc7f3f0ff98db41d57102e53ef2806c9f5443dfda5797952d92ea699254abcd0d926a405072b5298ba0ed3ce0bc12a9764eae1bed2b3d8b542b9de1eaa45a5d38361f50a9eb3b0e14810d73ea4165c796b19af61f876541353d524b622ae6c2320d857f05a92983378ba88526c807d44dd8be05ffd751f9fea9281ce5fb85cdce53f20ea6ef60fa0ea6bb09a63b8483d5952d51b764c9feca96d47e335a2f4ca6b50325f3d1c05f83699e743e971e28f54ca27d432ced9cdc6c174bdfee13d4d0b9df804bab9c4b77e823d45f10cdab91e9b0dab96fa73f9c1bde21967f38f75325f6f1e9f1084d4b5ff8658f1252fa448861e28d51695038776011eddbbd11fc1e55d4024fe766446a492ad5415a7e10d2f22892cec0d2b4d12b3eaaca882b1e9f0bc53d193986ec8d3162dec8a4d1c3bac5665abc3ee9441e002838863529aa7803b6bd88c25aca36c8a54da5561cf072b56ce769dd43e5e02dedfe1f3caf1ba7d22bc8b7e5669ce7e612acb6fd2775af634e84b5cd2bfd51eacdcbc5aa5ee5d69d6dba9c82a66255329fe28dad447120bd8903a94e4a7f8992b8328dc6ca69711455771c450bb38e5a6f2895e6fab4932f9fcf3b50242b6a61e0a96d18786eea1c4bb6053b978d94cfe010dc05b70f3bdc31609256dab3b09b829dfb9b24ec7cef6d1076f8355cfede93a3a0edd635b9cfad7a4dd4b98bf6d87c3fc0668413c375f95e4586c11f761347fdc0a41e13ea3e9311afdb169ab59c909060a01042bc7f48bde05589438f785995f8e20493481d3c2edd10fa10248ded226732a3193c0cb08027a9c115b7be4a51abc6b3479dc3410b5e201b25380cfc6b85a677436dcf017030a111aa6d00630cf2c81d41c5e06dd55a49fc043641a9e12c35b3e2ba27cde7bd4ea4646cca6321cbbff72a12559b45d4c66c440cf1655f3866a826f40f2cc4e000087691e881f5b078d75fd055ea867da17c8a90e898c9984fc052e5e43763c37f2f256e8c4b14d168d7f5842fedd095c430d11d8b4890677dd3b26239155e86df136ab5845abc2785115d08748a9644632bef7be8e73e737d90797efe0f4ee34f89b93e0000" + ], + "rawHeaders": [ + "Server", + "nginx/1.14.2", + "Date", + "Thu, 04 Apr 2024 07:46:56 GMT", + "Content-Type", + "application/json", + "Transfer-Encoding", + "chunked", + "Connection", + "keep-alive", + "Vary", + "Accept-Encoding", + "Set-Cookie", + "PHPSESSID=5r7pckt34lgie8hhj39l5oa19f; expires=Thu, 04-Apr-2024 08:46:55 GMT; Max-Age=3600; path=/; domain=magento2-instance.vuestorefront.io; secure; HttpOnly; SameSite=Lax", + "Set-Cookie", + "private_content_version=aa680da2379c4eef3f06ab9a281fe75b; expires=Sun, 02-Apr-2034 07:46:55 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=260113521626f0415ef7e40e555defa4; expires=Sun, 02-Apr-2034 07:46:56 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=f48b5916036147fc433c61bcdf2922d6; expires=Sun, 02-Apr-2034 07:46:56 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "X-Magento-Cache-Id", + "b309d3e32ec01e2fccaf4dd92e430e3576b7d1135b436c3a91b354bb36cec2ec", + "X-Content-Type-Options", + "nosniff", + "X-XSS-Protection", + "1; mode=block", + "X-Frame-Options", + "SAMEORIGIN", + "Content-Encoding", + "gzip", + "X-Varnish", + "63618994", + "Age", + "0", + "Pragma", + "no-cache", + "Expires", + "-1", + "Cache-Control", + "no-store, no-cache, must-revalidate, max-age=0", + "Accept-Ranges", + "bytes" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart-and-return-custom-query-fields b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart-and-return-custom-query-fields new file mode 100644 index 000000000..3f3d9918f --- /dev/null +++ b/packages/sdk/__tests__/integration/__nock-fixtures__/[SDK][Integration-Tests]-addConfigurableProductsToCart-should-add-product-to-cart-and-return-custom-query-fields @@ -0,0 +1,75 @@ +[ + { + "scope": "https://magento2-instance.vuestorefront.io:443", + "method": "POST", + "path": "/graphql", + "body": { + "operationName": "addConfigurableProductsToCart", + "variables": { + "input": { + "cart_id": "pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp", + "cart_items": [ + { + "data": { + "quantity": 1, + "sku": "MH01-XS-Black" + }, + "parent_sku": "MH01", + "customizable_options": [] + } + ] + } + }, + "query": "mutation addConfigurableProductsToCart($input: AddConfigurableProductsToCartInput) {\n addConfigurableProductsToCart(input: $input) {\n cart {\n id\n items {\n uid\n product {\n uid\n sku\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}" + }, + "status": 200, + "response": [ + "1f8b0800000000000003b592cdae82301085df65d67701fe6c4858104c14ef2d62c0b830c6545a1b10a517da2812dedd568d26445de9a2693a73cecc97e9d440b0c060d5800971f3fd2661b2c0eb8c06454e642cca28777121b420bedd09010bb81b1ad5967233eb1e8659f01b56f3bff17f7fb33607476f1a73f88144d05d09d6a20679b1a0c839a863ab14bf16d7d5ae39ffc42a152fb7520b03a3a71eab95a838dde31d55b12768d0bcd168684f0128d1a3bf779cbce88f52e7841cdbbe33ccc391697e01c21fccfa288a5f41183e6b4174be02c13a7e8a9eff44ca1e0068647c7008cbb64a2f54dbeabc5bc389145c2a4fd39c019c916ab7b8020000" + ], + "rawHeaders": [ + "Server", + "nginx/1.14.2", + "Date", + "Thu, 04 Apr 2024 07:48:14 GMT", + "Content-Type", + "application/json", + "Content-Length", + "254", + "Connection", + "keep-alive", + "Vary", + "Accept-Encoding", + "Set-Cookie", + "PHPSESSID=a5oeoeuk65qhqqb06en87nrh3f; expires=Thu, 04-Apr-2024 08:48:14 GMT; Max-Age=3600; path=/; domain=magento2-instance.vuestorefront.io; secure; HttpOnly; SameSite=Lax", + "Set-Cookie", + "private_content_version=f7a18f873a400ce467c9d4c41061cc7f; expires=Sun, 02-Apr-2034 07:48:14 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=9932afb718db5bbd1ea1350658b18923; expires=Sun, 02-Apr-2034 07:48:14 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "Set-Cookie", + "private_content_version=5d717c5bdb95ea0c2fb16a4f837b9f65; expires=Sun, 02-Apr-2034 07:48:14 GMT; Max-Age=315360000; path=/; secure; SameSite=Lax", + "X-Magento-Cache-Id", + "b309d3e32ec01e2fccaf4dd92e430e3576b7d1135b436c3a91b354bb36cec2ec", + "X-Content-Type-Options", + "nosniff", + "X-XSS-Protection", + "1; mode=block", + "X-Frame-Options", + "SAMEORIGIN", + "Content-Encoding", + "gzip", + "X-Varnish", + "63619032", + "Age", + "0", + "Pragma", + "no-cache", + "Expires", + "-1", + "Cache-Control", + "no-store, no-cache, must-revalidate, max-age=0", + "Accept-Ranges", + "bytes" + ], + "responseIsBinary": false + } +] \ No newline at end of file diff --git a/packages/sdk/__tests__/integration/addBundleProductsToCart.spec.ts b/packages/sdk/__tests__/integration/addBundleProductsToCart.spec.ts new file mode 100644 index 000000000..ccd0956de --- /dev/null +++ b/packages/sdk/__tests__/integration/addBundleProductsToCart.spec.ts @@ -0,0 +1,69 @@ +import { AddBundleProductsToCartInput } from '@vue-storefront/magento-types'; +import { sdk } from './__config__/sdk.config'; +import { describeGroup } from './__config__/jest.setup'; +import { TEST_CART_ID, TEST_BUNDLE_SKU } from './__config__/jest.const'; + +const PARAMS: AddBundleProductsToCartInput = { + cart_id: TEST_CART_ID, + cart_items: [ + { + data: { + quantity: 1, + sku: TEST_BUNDLE_SKU, + }, + bundle_options: [ + { + id: 1, + quantity: 1, + value: ['1'], + }, + { + id: 2, + quantity: 1, + value: ['4'], + }, + { + id: 3, + quantity: 1, + value: ['5'], + }, + { + id: 4, + quantity: 1, + value: ['8'], + }, + ], + }, + ], +}; + +describe(describeGroup('addBundleProductsToCart'), () => { + it('should add product to cart', async () => { + const result = await sdk.magento.addBundleProductsToCart(PARAMS); + console.log(result); + const item = result.data.addBundleProductsToCart!.cart!.items!.find( + (cartItem) => cartItem!.product.sku === TEST_BUNDLE_SKU, + ); + expect(result.data.addBundleProductsToCart!.cart!.id).toEqual(PARAMS.cart_id); + expect(item).not.toBe(undefined); + }); + + it('should add product to cart and return custom query fields', async () => { + const customQuery = { + addBundleProductsToCart: 'add-bundle-products-to-cart-custom-query', + metadata: { + fields: 'id items { uid product { uid sku }}', + }, + }; + + const result = await sdk.magento.addBundleProductsToCart(PARAMS, { customQuery }); + + const item = result.data.addBundleProductsToCart!.cart!.items!.find( + (cartItem) => cartItem!.product.sku === TEST_BUNDLE_SKU, + ); + expect(item).not.toBe(undefined); + expect(result.data.addBundleProductsToCart!.cart!.id).toEqual(PARAMS.cart_id); + // make sure default query is not called by accident + expect(result.data.addBundleProductsToCart!.cart!.email).toBe(undefined); + }); +}); diff --git a/packages/sdk/__tests__/integration/addConfigurableProductsToCart.spec.ts b/packages/sdk/__tests__/integration/addConfigurableProductsToCart.spec.ts new file mode 100644 index 000000000..f1a9d2310 --- /dev/null +++ b/packages/sdk/__tests__/integration/addConfigurableProductsToCart.spec.ts @@ -0,0 +1,49 @@ +import { AddConfigurableProductsToCartInput } from '@vue-storefront/magento-types'; +import { sdk } from './__config__/sdk.config'; +import { describeGroup } from './__config__/jest.setup'; +import { TEST_CART_ID, TEST_CONF_SKU_PARENT, TEST_CONF_SKU_VARIANT } from './__config__/jest.const'; + +const PARAMS: AddConfigurableProductsToCartInput = { + cart_id: TEST_CART_ID, + cart_items: [ + { + data: { + quantity: 1, + sku: TEST_CONF_SKU_VARIANT, + }, + parent_sku: TEST_CONF_SKU_PARENT, + customizable_options: [], + }, + ], +}; + +describe(describeGroup('addConfigurableProductsToCart'), () => { + it('should add product to cart', async () => { + const result = await sdk.magento.addConfigurableProductsToCart(PARAMS); + + const item = result.data.addConfigurableProductsToCart!.cart!.items!.find( + (cartItem) => cartItem!.product.sku === TEST_CONF_SKU_PARENT, + ); + expect(result.data.addConfigurableProductsToCart!.cart!.id).toEqual(PARAMS.cart_id); + expect(item).not.toBe(undefined); + }); + + it('should add product to cart and return custom query fields', async () => { + const customQuery = { + addConfigurableProductsToCart: 'add-configurable-products-to-cart-custom-query', + metadata: { + fields: 'id items { uid product { uid sku }}', + }, + }; + + const result = await sdk.magento.addConfigurableProductsToCart(PARAMS, { customQuery }); + + const item = result.data.addConfigurableProductsToCart!.cart!.items!.find( + (cartItem) => cartItem!.product.sku === TEST_CONF_SKU_PARENT, + ); + expect(item).not.toBe(undefined); + expect(result.data.addConfigurableProductsToCart!.cart!.id).toEqual(PARAMS.cart_id); + // make sure default query is not called by accident + expect(result.data.addConfigurableProductsToCart!.cart!.email).toBe(undefined); + }); +}); diff --git a/packages/sdk/__tests__/unit/addBundleProductsToCart.unit.spec.ts b/packages/sdk/__tests__/unit/addBundleProductsToCart.unit.spec.ts new file mode 100644 index 000000000..c0f73ba28 --- /dev/null +++ b/packages/sdk/__tests__/unit/addBundleProductsToCart.unit.spec.ts @@ -0,0 +1,90 @@ +import { AddBundleProductsToCartInput } from '@vue-storefront/magento-types'; +import { addBundleProductsToCart } from '../../src/methods'; +import { describeGroup } from './__config__/jest.setup'; +import { client } from '../../src'; +import { CustomQuery, MethodOptions } from '../../src/types'; +import { TEST_BUNDLE_SKU, TEST_CART_ID } from '../integration/__config__/jest.const'; + +const PARAMS_MOCK: AddBundleProductsToCartInput = { + cart_id: TEST_CART_ID, + cart_items: [ + { + data: { + quantity: 1, + sku: TEST_BUNDLE_SKU, + }, + bundle_options: [ + { + id: 1, + quantity: 1, + value: ['1'], + }, + { + id: 2, + quantity: 1, + value: ['4'], + }, + { + id: 3, + quantity: 1, + value: ['5'], + }, + { + id: 4, + quantity: 1, + value: ['8'], + }, + ], + }, + ], +}; +const OPTIONS_MOCK = { clientConfig: {}, customHeaders: { 'x-header': 'true' } } as MethodOptions< + CustomQuery<'addBundleProductsToCart'> +>; +const RESPONSE_MOCK = { data: { data: 'some_data', error: null } }; +const ERROR_MOCK = new Error('error'); + +jest.mock('../../src/client', () => ({ + client: { + post: jest.fn(() => RESPONSE_MOCK), + }, +})); + +describe(describeGroup('addBundleProductsToCart'), () => { + it('makes a single call to API Middleware', async () => { + await addBundleProductsToCart(PARAMS_MOCK); + + expect(client.post).toBeCalledTimes(1); + }); + + it('makes a call to API Middleware with proper params and options', async () => { + await addBundleProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + + expect(client.post).toBeCalledWith( + 'addBundleProductsToCart', + [ + { cart_id: 'pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp', cart_items: expect.any(Array) }, + undefined, + { 'x-header': 'true' }, + ], + {}, + ); + }); + + it('extracts and returns a response', async () => { + const response = await addBundleProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + + expect(response).toEqual({ data: 'some_data', error: null }); + }); + + it('throws an exception in case of network error', async () => { + expect.hasAssertions(); + (client.post as jest.Mock).mockRejectedValueOnce(ERROR_MOCK); + + try { + await addBundleProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + } catch (err) { + expect(err).toBe(ERROR_MOCK); + } + }); +}); diff --git a/packages/sdk/__tests__/unit/addConfigurableProductsToCart.unit.spec.ts b/packages/sdk/__tests__/unit/addConfigurableProductsToCart.unit.spec.ts new file mode 100644 index 000000000..cebe4e344 --- /dev/null +++ b/packages/sdk/__tests__/unit/addConfigurableProductsToCart.unit.spec.ts @@ -0,0 +1,70 @@ +import { AddConfigurableProductsToCartInput } from '@vue-storefront/magento-types'; +import { addConfigurableProductsToCart } from '../../src/methods'; +import { describeGroup } from './__config__/jest.setup'; +import { client } from '../../src'; +import { CustomQuery, MethodOptions } from '../../src/types'; +import { TEST_CART_ID, TEST_CONF_SKU_PARENT, TEST_CONF_SKU_VARIANT } from '../integration/__config__/jest.const'; + +const PARAMS_MOCK: AddConfigurableProductsToCartInput = { + cart_id: TEST_CART_ID, + cart_items: [ + { + data: { + quantity: 1, + sku: TEST_CONF_SKU_VARIANT, + }, + parent_sku: TEST_CONF_SKU_PARENT, + customizable_options: [], + }, + ], +}; +const OPTIONS_MOCK = { clientConfig: {}, customHeaders: { 'x-header': 'true' } } as MethodOptions< + CustomQuery<'addConfigurableProductsToCart'> +>; +const RESPONSE_MOCK = { data: { data: 'some_data', error: null } }; +const ERROR_MOCK = new Error('error'); + +jest.mock('../../src/client', () => ({ + client: { + post: jest.fn(() => RESPONSE_MOCK), + }, +})); + +describe(describeGroup('addConfigurableProductsToCart'), () => { + it('makes a single call to API Middleware', async () => { + await addConfigurableProductsToCart(PARAMS_MOCK); + + expect(client.post).toBeCalledTimes(1); + }); + + it('makes a call to API Middleware with proper params and options', async () => { + await addConfigurableProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + + expect(client.post).toBeCalledWith( + 'addConfigurableProductsToCart', + [ + { cart_id: 'pCS0ykep1l3wGlPKSyWLJq5fb1DxIQcp', cart_items: expect.any(Array) }, + undefined, + { 'x-header': 'true' }, + ], + {}, + ); + }); + + it('extracts and returns a response', async () => { + const response = await addConfigurableProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + + expect(response).toEqual({ data: 'some_data', error: null }); + }); + + it('throws an exception in case of network error', async () => { + expect.hasAssertions(); + (client.post as jest.Mock).mockRejectedValueOnce(ERROR_MOCK); + + try { + await addConfigurableProductsToCart(PARAMS_MOCK, OPTIONS_MOCK); + } catch (err) { + expect(err).toBe(ERROR_MOCK); + } + }); +}); diff --git a/packages/sdk/src/methods/addBundleProductsToCart/index.ts b/packages/sdk/src/methods/addBundleProductsToCart/index.ts new file mode 100644 index 000000000..df52bdb34 --- /dev/null +++ b/packages/sdk/src/methods/addBundleProductsToCart/index.ts @@ -0,0 +1,142 @@ +import type { AddBundleProductsToCartInput, Mutation } from '@vue-storefront/magento-types'; +import { DeepPartial } from 'ts-essentials'; +import { ApolloQueryResult } from '@apollo/client'; +import { AxiosRequestSender } from '@vue-storefront/sdk-axios-request-sender'; +import { client } from '../../client'; +import { CustomQuery, MethodOptions } from '../../types'; + +/** + * mutation type for the {@link addBundleProductsToCart} method. + */ +export type AddBundleProductsToCart = { + addBundleProductsToCart: Mutation['addBundleProductsToCart']; +}; + +/** + * Add bundle products to cart response type + */ +export type AddBundleProductsToCartResponse = AddBundleProductsToCart> = + ApolloQueryResult; + +/** + * Method to add bundle products to cart (returns cart) + * + * @remarks + * This method sends a POST request to the + * {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/addBundleProductsToCart | addBundleProductsToCart} endpoint + * of the Vue Storefront API Middleware. + * The default GraphQL query used by this method can be found + * {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/addBundleProductsToCart | here}. + * + * @param params - + * Parameter object which can be used with this method. + * Refer to its type definition to learn about possible properties. + * + * @param options - + * Options that can be passed to additionally configure the request + * or customize the logic in a plugin. + * + * @typeParam Res - Customizable response interface to be used with custom queries. + * + * @returns + * Returns a representation of the {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/AddProductsToCartResponse | AddProductsToCartResponse}. + * + * @example + * Adding bundle products to cart with default parameters. + * ```ts + * import { sdk } from '~/sdk.config.ts'; + * + * const cart = await sdk.magento.addBundleProductsToCart( + * { + * cart_id: '123', + * cart_items: [ + * { + * data: { + * quantity: 1, + * sku: TEST_BUNDLE_SKU, + * }, + * bundle_options: [ + * { + * id: 1, + * quantity: 1, + * value: ['1'], + * }, + * { + * id: 2, + * quantity: 1, + * value: ['4'], + * }, + * { + * id: 3, + * quantity: 1, + * value: ['5'], + * }, + * { + * id: 4, + * quantity: 1, + * value: ['8'], + * }, + * ] + * } + * ); + * ``` + * + * @example + * Creating a custom GraphQL query for adding bundle products to cart + * + * ```ts + * module.exports = { + * integrations: { + * magento: { + * customQueries: { + * 'add-bundle-products-to-cart-custom-query': ({ variables, metadata }) => ({ + * variables, + * query: ` + * mutation addBundleProductsToCart($input: AddBundleProductsToCartInput) { + * addBundleProductsToCart(input: $input) { + * cart { + * ${metadata.fields} + * } + * } + * }`, + * }), + * }, + * } + * } + * }; + * ``` + * + * @example + * Using a custom GraphQL query to modify response containing the cart, which is sent as part of the adding product to cart mutation + * + * ```ts + * import { sdk } from '~/sdk.config.ts'; + * // reduce the amount of fields returned by the query, when compared to the default query + * const customQuery = { + * cart: 'add-bundle-products-to-cart-custom-query', + * metadata: { + * fields: 'id items { uid }' + * } + * }; + * + * + * const cart = await sdk.magento.addBundleProductsToCart( + * { + * // use the payload from the previous example + * }, { customQuery } + * ); + * + * // Result will contain only the fields specified in the custom query. + * ``` + */ +export async function addBundleProductsToCart( + params: AddBundleProductsToCartInput, + options?: MethodOptions>, +) { + return new AxiosRequestSender(client) + .setUrl('addBundleProductsToCart') + .setMethod('POST') + .setProps([params, options?.customQuery, options?.customHeaders]) + .setConfig(options?.clientConfig) + .send(); +} diff --git a/packages/sdk/src/methods/addConfigurableProductsToCart/index.ts b/packages/sdk/src/methods/addConfigurableProductsToCart/index.ts new file mode 100644 index 000000000..b5e9c2ac8 --- /dev/null +++ b/packages/sdk/src/methods/addConfigurableProductsToCart/index.ts @@ -0,0 +1,136 @@ +import type { AddConfigurableProductsToCartInput, Mutation } from '@vue-storefront/magento-types'; +import { DeepPartial } from 'ts-essentials'; +import { ApolloQueryResult } from '@apollo/client'; +import { AxiosRequestSender } from '@vue-storefront/sdk-axios-request-sender'; +import { client } from '../../client'; +import { CustomQuery, MethodOptions } from '../../types'; + +/** + * mutation type for the {@link addConfigurableProductsToCart} method. + */ +export type AddConfigurableProductsToCart = { + addConfigurableProductsToCart: Mutation['addConfigurableProductsToCart']; +}; + +/** + * Add products to cart response type + */ +export type AddConfigurableProductsToCartResponse< + T extends DeepPartial = AddConfigurableProductsToCart, +> = ApolloQueryResult; + +/** + * Method to add configurable products to cart (returns cart) + * + * @remarks + * This method sends a POST request to the + * {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/addConfigurableProductsToCart | addConfigurableProductsToCart} endpoint + * of the Vue Storefront API Middleware. + * The default GraphQL query used by this method can be found + * {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/addConfigurableProductsToCart | here}. + * + * @param params - + * Parameter object which can be used with this method. + * Refer to its type definition to learn about possible properties. + * + * @param options - + * Options that can be passed to additionally configure the request + * or customize the logic in a plugin. + * + * @typeParam Res - Customizable response interface to be used with custom queries. + * + * @returns + * Returns a representation of the {@link https://docs.vuestorefront.io/integrations/magento/api/magento-api/AddProductsToCartResponse | AddProductsToCartResponse}. + * + * @example + * Adding configurable products to cart with default parameters. + * ```ts + * import { sdk } from '~/sdk.config.ts'; + * + * const cart = await sdk.magento.addConfigurableProductsToCart( + * { + * cart_id: '123', + * cart_items: [ + * { + * data: { + * quantity: 1, + * sku: 'MH01-XS-Black', + * }, + * parent_sku: 'MH01', + * customizable_options: [], + * } + * ] + * } + * ); + * ``` + * + * @example + * Creating a custom GraphQL query for adding configurable products to cart + * + * ```ts + * module.exports = { + * integrations: { + * magento: { + * customQueries: { + * 'add-configurable-products-to-cart-custom-query': ({ variables, metadata }) => ({ + * variables, + * query: ` + * mutation addConfigurableProductsToCart($input: AddConfigurableProductsToCartInput) { + * addConfigurableProductsToCart(input: $input) { + * cart { + * ${metadata.fields} + * } + * } + * }`, + * }), + * }, + * } + * } + * }; + * ``` + * + * @example + * Using a custom GraphQL query to modify response containing the cart, which is sent as part of the adding product to cart mutation + * + * ```ts + * import { sdk } from '~/sdk.config.ts'; + * // reduce the amount of fields returned by the query, when compared to the default query + * const customQuery = { + * cart: 'add-configurable-products-to-cart-custom-query', + * metadata: { + * fields: 'id items { uid }' + * } + * }; + * + * + * const cart = await sdk.magento.addConfigurableProductsToCart( + * { + * cart_id: '123', + * cart_items: [ + * { + * data: { + * quantity: 1, + * sku: 'MH01-XS-Black', + * }, + * parent_sku: 'MH01', + * customizable_options: [], + * } + * ] + * }, + * { customQuery } + * ); + * + * // Result will contain only the fields specified in the custom query. + * ``` + */ +export async function addConfigurableProductsToCart( + params: AddConfigurableProductsToCartInput, + options?: MethodOptions>, +) { + return new AxiosRequestSender(client) + .setUrl('addConfigurableProductsToCart') + .setMethod('POST') + .setProps([params, options?.customQuery, options?.customHeaders]) + .setConfig(options?.clientConfig) + .send(); +} diff --git a/packages/sdk/src/methods/index.ts b/packages/sdk/src/methods/index.ts index cb6a31cd0..f7209323a 100644 --- a/packages/sdk/src/methods/index.ts +++ b/packages/sdk/src/methods/index.ts @@ -13,6 +13,8 @@ export * from './createEmptyCart'; export * from './setShippingAddressesOnCart'; export * from './removeCouponFromCart'; export * from './addProductsToCart'; +export * from './addConfigurableProductsToCart'; +export * from './addBundleProductsToCart'; export * from './setBillingAddressOnCart'; export * from './setShippingMethodsOnCart'; export * from './removeItemFromCart';