Просмотр исходного кода

test(core): Add e2e tests for PriceCalculationStrategy

Relates to #237
Michael Bromley 5 лет назад
Родитель
Сommit
e9bf90c823

Разница между файлами не показана из-за своего большого размера
+ 834 - 838
packages/common/src/generated-types.ts


+ 20 - 0
packages/core/e2e/fixtures/test-price-calculation-strategy.ts

@@ -0,0 +1,20 @@
+import { CalculatedPrice, PriceCalculationStrategy, ProductVariant } from '@vendure/core';
+
+/**
+ * Adds $5 for items with gift wrapping.
+ */
+export class TestPriceCalculationStrategy implements PriceCalculationStrategy {
+    calculateUnitPrice(
+        productVariant: ProductVariant,
+        orderLineCustomFields: { [p: string]: any },
+    ): CalculatedPrice | Promise<CalculatedPrice> {
+        let price = productVariant.price;
+        if (orderLineCustomFields.giftWrap) {
+            price += 500;
+        }
+        return {
+            price,
+            priceIncludesTax: productVariant.priceIncludesTax,
+        };
+    }
+}

+ 18 - 1
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -2323,7 +2323,11 @@ export type SearchProductsShopQuery = { __typename?: 'Query' } & {
                     | 'productVariantPreview'
                     | 'sku'
                     | 'collectionIds'
-                >
+                > & {
+                        price:
+                            | ({ __typename?: 'PriceRange' } & Pick<PriceRange, 'min' | 'max'>)
+                            | ({ __typename?: 'SinglePrice' } & Pick<SinglePrice, 'value'>);
+                    }
             >;
         };
 };
@@ -2655,6 +2659,10 @@ export type RemoveCouponCodeMutation = { __typename?: 'Mutation' } & {
     removeCouponCode?: Maybe<{ __typename?: 'Order' } & TestOrderFragmentFragment>;
 };
 
+type DiscriminateUnion<T, U> = T extends U ? T : never;
+
+type RequireField<T, TNames extends string> = T & { [P in TNames]: (T & { [name: string]: never })[P] };
+
 export namespace TestOrderFragment {
     export type Fragment = TestOrderFragmentFragment;
     export type Adjustments = NonNullable<TestOrderFragmentFragment['adjustments'][0]>;
@@ -2685,6 +2693,15 @@ export namespace SearchProductsShop {
     export type Query = SearchProductsShopQuery;
     export type Search = SearchProductsShopQuery['search'];
     export type Items = NonNullable<SearchProductsShopQuery['search']['items'][0]>;
+    export type Price = NonNullable<SearchProductsShopQuery['search']['items'][0]>['price'];
+    export type SinglePriceInlineFragment = DiscriminateUnion<
+        RequireField<NonNullable<SearchProductsShopQuery['search']['items'][0]>['price'], '__typename'>,
+        { __typename: 'SinglePrice' }
+    >;
+    export type PriceRangeInlineFragment = DiscriminateUnion<
+        RequireField<NonNullable<SearchProductsShopQuery['search']['items'][0]>['price'], '__typename'>,
+        { __typename: 'PriceRange' }
+    >;
 }
 
 export namespace Register {

+ 9 - 0
packages/core/e2e/graphql/shop-definitions.ts

@@ -81,6 +81,15 @@ export const SEARCH_PRODUCTS_SHOP = gql`
                 productVariantPreview
                 sku
                 collectionIds
+                price {
+                    ... on SinglePrice {
+                        value
+                    }
+                    ... on PriceRange {
+                        min
+                        max
+                    }
+                }
             }
         }
     }

+ 107 - 0
packages/core/e2e/price-calculation-strategy.e2e-spec.ts

@@ -0,0 +1,107 @@
+import { DefaultSearchPlugin, mergeConfig } from '@vendure/core';
+import { createTestEnvironment } from '@vendure/testing';
+import gql from 'graphql-tag';
+import path from 'path';
+
+import { initialData } from '../../../e2e-common/e2e-initial-data';
+import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
+
+import { TestPriceCalculationStrategy } from './fixtures/test-price-calculation-strategy';
+import { AddItemToOrder, SearchProductsShop, SinglePrice } from './graphql/generated-e2e-shop-types';
+import { ADD_ITEM_TO_ORDER, SEARCH_PRODUCTS_SHOP } from './graphql/shop-definitions';
+
+describe('custom PriceCalculationStrategy', () => {
+    let variants: SearchProductsShop.Items[];
+    const { server, adminClient, shopClient } = createTestEnvironment(
+        mergeConfig(testConfig, {
+            customFields: {
+                OrderLine: [{ name: 'giftWrap', type: 'boolean' }],
+            },
+            orderOptions: {
+                priceCalculationStrategy: new TestPriceCalculationStrategy(),
+            },
+            plugins: [DefaultSearchPlugin],
+        }),
+    );
+
+    beforeAll(async () => {
+        await server.init({
+            initialData,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
+            customerCount: 3,
+        });
+        const { search } = await shopClient.query<SearchProductsShop.Query, SearchProductsShop.Variables>(
+            SEARCH_PRODUCTS_SHOP,
+            {
+                input: { take: 3, groupByProduct: false },
+            },
+        );
+        variants = search.items;
+    }, TEST_SETUP_TIMEOUT_MS);
+
+    afterAll(async () => {
+        await server.destroy();
+    });
+
+    it('does not add surcharge', async () => {
+        const variant0 = variants[0];
+
+        const { addItemToOrder } = await shopClient.query(ADD_ITEM_TO_ORDER_CUSTOM_FIELDS, {
+            productVariantId: variant0.productVariantId,
+            quantity: 1,
+            customFields: {
+                giftWrap: false,
+            },
+        });
+
+        expect(addItemToOrder.lines[0].unitPrice).toEqual((variant0.price as SinglePrice).value);
+    });
+
+    it('adds a surcharge', async () => {
+        const variant0 = variants[0];
+
+        const { addItemToOrder } = await shopClient.query(ADD_ITEM_TO_ORDER_CUSTOM_FIELDS, {
+            productVariantId: variant0.productVariantId,
+            quantity: 1,
+            customFields: {
+                giftWrap: true,
+            },
+        });
+
+        const variantPrice = (variant0.price as SinglePrice).value as number;
+        expect(addItemToOrder.lines[0].unitPrice).toEqual(variantPrice);
+        expect(addItemToOrder.lines[1].unitPrice).toEqual(variantPrice + 500);
+        expect(addItemToOrder.subTotalBeforeTax).toEqual(variantPrice + variantPrice + 500);
+    });
+});
+
+const ADD_ITEM_TO_ORDER_CUSTOM_FIELDS = gql`
+    mutation AddItemToOrderCustomFields(
+        $productVariantId: ID!
+        $quantity: Int!
+        $customFields: OrderLineCustomFieldsInput
+    ) {
+        addItemToOrder(
+            productVariantId: $productVariantId
+            quantity: $quantity
+            customFields: $customFields
+        ) {
+            id
+            subTotalBeforeTax
+            subTotal
+            shipping
+            total
+            lines {
+                id
+                quantity
+                unitPrice
+                unitPriceWithTax
+                items {
+                    unitPrice
+                    unitPriceWithTax
+                    unitPriceIncludesTax
+                }
+            }
+        }
+    }
+`;

+ 1 - 1
packages/core/src/api/schema/shop-api/shop.api.graphql

@@ -20,7 +20,7 @@ type Mutation {
     "Adds an item to the order. If custom fields are defined on the OrderLine entity, a third argument 'customFields' will be available."
     addItemToOrder(productVariantId: ID!, quantity: Int!): Order
     removeOrderLine(orderLineId: ID!): Order
-    "Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a third argument 'customFields' will be available."
+    "Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a third argument 'customFields' of type `OrderLineCustomFieldsInput` will be available."
     adjustOrderLine(orderLineId: ID!, quantity: Int): Order
     "Applies the given coupon code to the active Order"
     applyCouponCode(couponCode: String!): Order

+ 37 - 22
scripts/codegen/generate-graphql-types.ts

@@ -8,13 +8,23 @@ import { ADMIN_API_PATH, API_PORT, SHOP_API_PATH } from '../../packages/common/s
 
 import { downloadIntrospectionSchema } from './download-introspection-schema';
 
-const CLIENT_QUERY_FILES = path.join(__dirname, '../../packages/admin-ui/src/lib/core/src/data/definitions/**/*.ts');
-const E2E_ADMIN_QUERY_FILES = path.join(__dirname, '../../packages/core/e2e/**/!(import.e2e-spec|plugin.e2e-spec|shop-definitions|custom-fields.e2e-spec|list-query-builder.e2e-spec).ts');
-const E2E_SHOP_QUERY_FILES = [
-    path.join(__dirname, '../../packages/core/e2e/graphql/shop-definitions.ts'),
-];
-const E2E_ELASTICSEARCH_PLUGIN_QUERY_FILES = path.join(__dirname, '../../packages/elasticsearch-plugin/e2e/**/*.ts');
-const E2E_ASSET_SERVER_PLUGIN_QUERY_FILES = path.join(__dirname, '../../packages/asset-server-plugin/e2e/**/*.ts');
+const CLIENT_QUERY_FILES = path.join(
+    __dirname,
+    '../../packages/admin-ui/src/lib/core/src/data/definitions/**/*.ts',
+);
+const E2E_ADMIN_QUERY_FILES = path.join(
+    __dirname,
+    '../../packages/core/e2e/**/!(import.e2e-spec|plugin.e2e-spec|shop-definitions|custom-fields.e2e-spec|price-calculation-strategy.e2e-spec|list-query-builder.e2e-spec).ts',
+);
+const E2E_SHOP_QUERY_FILES = [path.join(__dirname, '../../packages/core/e2e/graphql/shop-definitions.ts')];
+const E2E_ELASTICSEARCH_PLUGIN_QUERY_FILES = path.join(
+    __dirname,
+    '../../packages/elasticsearch-plugin/e2e/**/*.ts',
+);
+const E2E_ASSET_SERVER_PLUGIN_QUERY_FILES = path.join(
+    __dirname,
+    '../../packages/asset-server-plugin/e2e/**/*.ts',
+);
 const ADMIN_SCHEMA_OUTPUT_FILE = path.join(__dirname, '../../schema-admin.json');
 const SHOP_SCHEMA_OUTPUT_FILE = path.join(__dirname, '../../schema-shop.json');
 
@@ -40,15 +50,8 @@ Promise.all([
             },
             strict: true,
         };
-        const commonPlugins = [
-            { add: '// tslint:disable' },
-            'typescript',
-        ];
-        const clientPlugins = [
-            ...commonPlugins,
-            'typescript-operations',
-            'typescript-compatibility',
-        ];
+        const commonPlugins = [{ add: '// tslint:disable' }, 'typescript'];
+        const clientPlugins = [...commonPlugins, 'typescript-operations', 'typescript-compatibility'];
 
         return generate({
             overwrite: true,
@@ -65,25 +68,37 @@ Promise.all([
                     plugins: clientPlugins,
                     config,
                 },
-                [path.join(__dirname, '../../packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts')]: {
+                [path.join(
+                    __dirname,
+                    '../../packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts',
+                )]: {
                     schema: [ADMIN_SCHEMA_OUTPUT_FILE],
                     documents: E2E_ELASTICSEARCH_PLUGIN_QUERY_FILES,
                     plugins: clientPlugins,
                     config,
                 },
-                [path.join(__dirname, '../../packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts')]: {
+                [path.join(
+                    __dirname,
+                    '../../packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts',
+                )]: {
                     schema: [ADMIN_SCHEMA_OUTPUT_FILE],
                     documents: E2E_ASSET_SERVER_PLUGIN_QUERY_FILES,
                     plugins: clientPlugins,
                     config,
                 },
-                [path.join(__dirname, '../../packages/admin-ui/src/lib/core/src/common/generated-types.ts')]: {
+                [path.join(
+                    __dirname,
+                    '../../packages/admin-ui/src/lib/core/src/common/generated-types.ts',
+                )]: {
                     schema: [ADMIN_SCHEMA_OUTPUT_FILE, path.join(__dirname, 'client-schema.ts')],
                     documents: CLIENT_QUERY_FILES,
                     plugins: clientPlugins,
                     config,
                 },
-                [path.join(__dirname, '../../packages/admin-ui/src/lib/core/src/common/introspection-result.ts')]: {
+                [path.join(
+                    __dirname,
+                    '../../packages/admin-ui/src/lib/core/src/common/introspection-result.ts',
+                )]: {
                     schema: [ADMIN_SCHEMA_OUTPUT_FILE, path.join(__dirname, 'client-schema.ts')],
                     documents: CLIENT_QUERY_FILES,
                     plugins: [{ add: '// tslint:disable' }, 'fragment-matcher'],
@@ -103,10 +118,10 @@ Promise.all([
         });
     })
     .then(
-        result => {
+        (result) => {
             process.exit(0);
         },
-        err => {
+        (err) => {
             console.error(err);
             process.exit(1);
         },

Некоторые файлы не были показаны из-за большого количества измененных файлов