Преглед изворни кода

Merge branch 'master' into minor

Michael Bromley пре 4 година
родитељ
комит
1c2e01b6ee
100 измењених фајлова са 487 додато и 239 уклоњено
  1. 34 6
      .github/workflows/build_and_test.yml
  2. 18 3
      .github/workflows/publish_and_install.yml
  3. 1 0
      .gitignore
  4. 12 0
      CHANGELOG.md
  5. 1 1
      docs/content/developer-guide/overview/_index.md
  6. 5 0
      docs/content/plugins/extending-the-admin-ui/using-other-frameworks/_index.md
  7. 2 2
      e2e-common/get-package-dir.js
  8. 5 0
      e2e-common/jest-config.js
  9. 39 11
      e2e-common/test-config.ts
  10. 1 1
      lerna.json
  11. 3 3
      packages/admin-ui-plugin/package.json
  12. 2 2
      packages/admin-ui/package.json
  13. 4 4
      packages/admin-ui/src/lib/core/src/common/generated-types.ts
  14. 1 1
      packages/admin-ui/src/lib/core/src/common/version.ts
  15. 33 18
      packages/admin-ui/src/lib/core/src/shared/components/channel-assignment-control/channel-assignment-control.component.ts
  16. 3 3
      packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.html
  17. 1 1
      packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.ts
  18. 1 5
      packages/asset-server-plugin/e2e/asset-server-plugin.e2e-spec.ts
  19. 4 4
      packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts
  20. 4 4
      packages/asset-server-plugin/package.json
  21. 1 1
      packages/common/package.json
  22. 4 4
      packages/common/src/generated-shop-types.ts
  23. 4 4
      packages/common/src/generated-types.ts
  24. 1 1
      packages/core/e2e/administrator.e2e-spec.ts
  25. 1 1
      packages/core/e2e/apollo-server-plugin.e2e-spec.ts
  26. 1 1
      packages/core/e2e/asset-channel.e2e-spec.ts
  27. 1 1
      packages/core/e2e/asset.e2e-spec.ts
  28. 1 1
      packages/core/e2e/auth.e2e-spec.ts
  29. 1 1
      packages/core/e2e/authentication-strategy.e2e-spec.ts
  30. 1 1
      packages/core/e2e/channel.e2e-spec.ts
  31. 3 18
      packages/core/e2e/collection.e2e-spec.ts
  32. 1 1
      packages/core/e2e/configurable-operation.e2e-spec.ts
  33. 1 1
      packages/core/e2e/country.e2e-spec.ts
  34. 5 2
      packages/core/e2e/custom-field-relations.e2e-spec.ts
  35. 2 2
      packages/core/e2e/custom-fields.e2e-spec.ts
  36. 1 1
      packages/core/e2e/custom-permissions.e2e-spec.ts
  37. 1 1
      packages/core/e2e/customer-channel.e2e-spec.ts
  38. 2 2
      packages/core/e2e/customer-group.e2e-spec.ts
  39. 1 1
      packages/core/e2e/customer.e2e-spec.ts
  40. 1 1
      packages/core/e2e/database-transactions.e2e-spec.ts
  41. 2 2
      packages/core/e2e/default-search-plugin.e2e-spec.ts
  42. 1 1
      packages/core/e2e/entity-hydrator.e2e-spec.ts
  43. 1 1
      packages/core/e2e/entity-id-strategy.e2e-spec.ts
  44. 1 1
      packages/core/e2e/entity-uuid-strategy.e2e-spec.ts
  45. 4 3
      packages/core/e2e/facet.e2e-spec.ts
  46. 2 2
      packages/core/e2e/fulfillment-process.e2e-spec.ts
  47. 1 1
      packages/core/e2e/global-settings.e2e-spec.ts
  48. 35 4
      packages/core/e2e/graphql/generated-e2e-admin-types.ts
  49. 4 4
      packages/core/e2e/graphql/generated-e2e-shop-types.ts
  50. 1 1
      packages/core/e2e/import.e2e-spec.ts
  51. 6 5
      packages/core/e2e/job-queue.e2e-spec.ts
  52. 1 1
      packages/core/e2e/lifecycle.e2e-spec.ts
  53. 1 1
      packages/core/e2e/list-query-builder.e2e-spec.ts
  54. 1 1
      packages/core/e2e/localization.e2e-spec.ts
  55. 1 1
      packages/core/e2e/order-changed-price-handling.e2e-spec.ts
  56. 1 1
      packages/core/e2e/order-channel.e2e-spec.ts
  57. 1 1
      packages/core/e2e/order-fulfillment.e2e-spec.ts
  58. 1 1
      packages/core/e2e/order-item-price-calculation-strategy.e2e-spec.ts
  59. 1 1
      packages/core/e2e/order-merge.e2e-spec.ts
  60. 1 1
      packages/core/e2e/order-modification.e2e-spec.ts
  61. 3 4
      packages/core/e2e/order-process.e2e-spec.ts
  62. 1 1
      packages/core/e2e/order-promotion.e2e-spec.ts
  63. 1 1
      packages/core/e2e/order-taxes.e2e-spec.ts
  64. 1 1
      packages/core/e2e/order.e2e-spec.ts
  65. 1 1
      packages/core/e2e/parallel-transactions.e2e-spec.ts
  66. 1 1
      packages/core/e2e/payment-method.e2e-spec.ts
  67. 1 1
      packages/core/e2e/payment-process.e2e-spec.ts
  68. 3 2
      packages/core/e2e/plugin.e2e-spec.ts
  69. 1 1
      packages/core/e2e/product-channel.e2e-spec.ts
  70. 1 1
      packages/core/e2e/product-option.e2e-spec.ts
  71. 1 1
      packages/core/e2e/product.e2e-spec.ts
  72. 1 1
      packages/core/e2e/promotion.e2e-spec.ts
  73. 1 1
      packages/core/e2e/role.e2e-spec.ts
  74. 3 3
      packages/core/e2e/session-management.e2e-spec.ts
  75. 3 4
      packages/core/e2e/shipping-method-eligibility.e2e-spec.ts
  76. 1 1
      packages/core/e2e/shipping-method.e2e-spec.ts
  77. 4 4
      packages/core/e2e/shop-auth.e2e-spec.ts
  78. 1 1
      packages/core/e2e/shop-catalog.e2e-spec.ts
  79. 1 1
      packages/core/e2e/shop-customer.e2e-spec.ts
  80. 2 3
      packages/core/e2e/shop-order.e2e-spec.ts
  81. 120 4
      packages/core/e2e/stock-control.e2e-spec.ts
  82. 1 1
      packages/core/e2e/tag.e2e-spec.ts
  83. 1 1
      packages/core/e2e/tax-category.e2e-spec.ts
  84. 2 2
      packages/core/e2e/tax-rate.e2e-spec.ts
  85. 1 1
      packages/core/e2e/translations.e2e-spec.ts
  86. 2 2
      packages/core/e2e/zone.e2e-spec.ts
  87. 3 3
      packages/core/package.json
  88. 1 0
      packages/core/src/api/resolvers/shop/shop-order.resolver.ts
  89. 9 5
      packages/core/src/config/index.ts
  90. 10 1
      packages/core/src/service/helpers/fulfillment-state-machine/fulfillment-state-machine.ts
  91. 3 3
      packages/create/package.json
  92. 9 9
      packages/dev-server/package.json
  93. 1 4
      packages/elasticsearch-plugin/e2e/elasticsearch-plugin-uuid.e2e-spec.ts
  94. 1 4
      packages/elasticsearch-plugin/e2e/elasticsearch-plugin.e2e-spec.ts
  95. 4 4
      packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts
  96. 4 4
      packages/elasticsearch-plugin/package.json
  97. 3 3
      packages/email-plugin/package.json
  98. 1 1
      packages/job-queue-plugin/e2e/bullmq-job-queue-plugin.e2e-spec.ts
  99. 3 3
      packages/job-queue-plugin/package.json
  100. 1 1
      packages/payment-plugin/package.json

+ 34 - 6
.github/workflows/build_and_test.yml

@@ -6,6 +6,7 @@ on:
       - master
       - major
       - minor
+      - parallel-e2e
   pull_request:
     branches:
       - master
@@ -24,9 +25,18 @@ jobs:
       uses: actions/setup-node@v1
       with:
         node-version: ${{ env.node }}
-    - name: Install & build
+    - uses: actions/cache@v2
+      id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+      with:
+        path: '**/node_modules'
+        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          ${{ runner.os }}-yarn-
+    - name: Yarn install
+      if: steps.yarn-cache.outputs.cache-hit != 'true'
+      run: yarn install
+    - name: Build
       run: |
-        yarn install
         yarn bootstrap
         yarn build
   unit-tests:
@@ -38,9 +48,18 @@ jobs:
         uses: actions/setup-node@v1
         with:
           node-version: ${{ env.node }}
-      - name: Install & build
+      - uses: actions/cache@v2
+        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+        with:
+          path: '**/node_modules'
+          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn-
+      - name: Yarn install
+        if: steps.yarn-cache.outputs.cache-hit != 'true'
+        run: yarn install --prefer-offline
+      - name: Build
         run: |
-          yarn install
           yarn bootstrap
           yarn lerna run ci
       - name: Unit tests
@@ -97,9 +116,18 @@ jobs:
         uses: actions/setup-node@v1
         with:
           node-version: ${{ env.node }}
-      - name: Install & build
+      - uses: actions/cache@v2
+        id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+        with:
+          path: '**/node_modules'
+          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn-
+      - name: Yarn install
+        if: steps.yarn-cache.outputs.cache-hit != 'true'
+        run: yarn install --prefer-offline
+      - name: Build
         run: |
-          yarn install
           yarn bootstrap
           yarn lerna run ci
       - name: df

+ 18 - 3
.github/workflows/publish_and_install.yml

@@ -5,6 +5,7 @@ on:
       - master
       - major
       - minor
+      - parallel-e2e
   pull_request:
     branches:
       - master
@@ -41,11 +42,25 @@ jobs:
     - name: Windows dependencies
       if: matrix.os == 'windows-latest'
       run: npm install -g @angular/cli
-    - name: Install & bootstrap
+    - name: Get yarn cache directory path
+      id: yarn-cache-dir-path
+      run: echo "::set-output name=dir::$(yarn cache dir)"
+    - uses: actions/cache@v2
+      id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
+      with:
+        path: '**/node_modules'
+        key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+        restore-keys: |
+          ${{ runner.os }}-yarn-
+    - name: Yarn install
+      if: steps.yarn-cache.outputs.cache-hit != 'true'
       run: |
         yarn config set unsafe-perm true
-        yarn install --network-timeout 1000000
-        yarn bootstrap
+        yarn install --network-timeout 1000000 --prefer-offline
+      env:
+        CI: true
+    - name: Bootstrap
+      run: yarn bootstrap
       env:
         CI: true
     - name: Publish to Verdaccio

+ 1 - 0
.gitignore

@@ -26,6 +26,7 @@ docs/content/graphql-api/*
 !docs/content/graphql-api/admin/_index.md
 .vscode/
 yarn-error.log
+e2e-common/ports.json
 
 # Sensitive or high-churn files:
 .idea/**/dataSources/

+ 12 - 0
CHANGELOG.md

@@ -1,3 +1,15 @@
+## <small>1.3.3 (2021-11-09)</small>
+
+
+#### Fixes
+
+* **admin-ui** Correctly display primitive value job queue results ([d8c2195](https://github.com/vendure-ecommerce/vendure/commit/d8c2195)), closes [#881](https://github.com/vendure-ecommerce/vendure/issues/881)
+* **admin-ui** Fix display of channels in Role detail ([dee331a](https://github.com/vendure-ecommerce/vendure/commit/dee331a)), closes [#1211](https://github.com/vendure-ecommerce/vendure/issues/1211)
+* **core** Correctly cancel sales when cancelling Fulfillment ([00ac70d](https://github.com/vendure-ecommerce/vendure/commit/00ac70d)), closes [#1198](https://github.com/vendure-ecommerce/vendure/issues/1198)
+* **core** Export missing tax config types ([08951b3](https://github.com/vendure-ecommerce/vendure/commit/08951b3))
+* **core** Fix error thrown when shipping address company is null ([303a216](https://github.com/vendure-ecommerce/vendure/commit/303a216)), closes [#744](https://github.com/vendure-ecommerce/vendure/issues/744)
+* **core** Make populator.populateCollections more robust to bad input ([15762e0](https://github.com/vendure-ecommerce/vendure/commit/15762e0))
+
 ## <small>1.3.2 (2021-10-28)</small>
 
 

+ 1 - 1
docs/content/developer-guide/overview/_index.md

@@ -28,7 +28,7 @@ There are 2 separate GraphQL APIs: shop and admin.
 
 ## Database
 
-Vendure supports multiple databases. Currently it is tested with MySQL/MariaDB, PostgreSQL, SQLite and SQL.js. Since Vendure uses [TypeORM](https://typeorm.io/#/) to manage data access, it can theoretically also work with CockroachDB, Microsoft SQL Server and MongoDB, though these are as yet untested.
+Vendure officially supports multiple databases: MySQL/MariaDB, PostgreSQL, SQLite and SQL.js, plus API-compatible cloud versions of these such as Amazon Aurora. Since Vendure uses [TypeORM](https://typeorm.io/#/) to manage data access, it can theoretically also work with other relational databases supported by TypeORM such as CockroachDB, Microsoft SQL Server, though these are as yet untested.
 
 ## Custom Business Logic (Plugins)
 

+ 5 - 0
docs/content/plugins/extending-the-admin-ui/using-other-frameworks/_index.md

@@ -66,6 +66,11 @@ import { hostExternalFrame } from '@vendure/admin-ui/core';
 export class ReactUiExtensionModule {}
 ```
 
+{{< alert "primary" >}}
+Note: If you are using **Create React App**, you should additionally update your package.json file to include the [homepage property](https://create-react-app.dev/docs/deployment/#building-for-relative-paths) so that it works when run from the admin ui assets directory:
+`"homepage": "/admin/assets/react-app/"`
+{{< /alert >}}
+
 ## 4. Define the AdminUiExtension config
 
 Next we will define an [AdminUiExtension]({{< relref "admin-ui-extension" >}}) object which is passed to the `compileUiExtensions()` function in your Vendure config:

+ 2 - 2
e2e-common/get-package-dir.js

@@ -4,14 +4,14 @@ const path = require('path');
  * @return {string}
  */
 function getPackageDir() {
-    const packageArg = process.argv.find(arg => arg.startsWith('--package='));
+    const packageArg = process.env.packageArg || process.argv.find(arg => arg.startsWith('--package='));
 
     if (!packageArg) {
         console.error('No package specified! Please pass --package=<packageDirName>');
         process.exit(1);
     }
     const packageDirname = packageArg.split('=')[1];
-    return path.join(__dirname, '../packages', packageDirname, 'e2e')
+    return path.join(__dirname, '../packages', packageDirname, 'e2e');
 }
 
 module.exports = { getPackageDir };

+ 5 - 0
e2e-common/jest-config.js

@@ -1,6 +1,11 @@
 const path = require('path');
 const { getPackageDir } = require('./get-package-dir');
 
+const packageArg = process.argv.find(arg => arg.startsWith('--package='));
+// We transfer the CLI argument to the env vars because when Jest runs concurrently,
+// it spawns child processes and the argv array data gets lost, but env vars will persist
+// between the processes.
+process.env.packageArg = packageArg;
 const packageDirname = getPackageDir();
 
 module.exports = {

+ 39 - 11
e2e-common/test-config.ts

@@ -6,11 +6,20 @@ import {
     SqljsInitializer,
     testConfig as defaultTestConfig,
 } from '@vendure/testing';
+import fs from 'fs-extra';
 import path from 'path';
 import { ConnectionOptions } from 'typeorm';
 
 import { getPackageDir } from './get-package-dir';
 
+declare global {
+    namespace NodeJS {
+        interface Global {
+            e2eServerPortsUsed: number[];
+        }
+    }
+}
+
 /**
  * We use a relatively long timeout on the initial beforeAll() function of the
  * e2e tests because on the first run (and always in CI) the sqlite databases
@@ -35,22 +44,41 @@ if (process.env.E2E_DEBUG) {
     jest.setTimeout(1800 * 1000);
 }
 /**
- * Increase default timeout in CI to 10 seconds because occasionally valid tests fail due to
+ * Increase default timeout in CI because occasionally valid tests fail due to
  * timeouts.
  */
 if (process.env.CI) {
-    jest.setTimeout(10 * 1000);
+    jest.setTimeout(30 * 1000);
+} else {
+    jest.setTimeout(15 * 1000);
 }
 
-export const testConfig = mergeConfig(defaultTestConfig, {
-    importExportOptions: {
-        importAssetsDir: path.join(packageDir, 'fixtures/assets'),
-    },
-    jobQueueOptions: {
-        pollInterval: 100,
-    },
-    dbConnectionOptions: getDbConfig(),
-});
+export const testConfig = () => {
+    const portsFile = path.join(__dirname, 'ports.json');
+    fs.ensureFileSync(portsFile);
+    let usedPorts: number[];
+    try {
+        usedPorts = fs.readJSONSync(portsFile) ?? [3010];
+    } catch (e) {
+        usedPorts = [3010];
+    }
+    const nextPort = Math.max(...usedPorts) + 1;
+    usedPorts.push(nextPort);
+    if (100 < usedPorts.length) {
+        // reset the used ports after it gets 100 entries long
+        usedPorts = [3010];
+    }
+    fs.writeJSONSync(portsFile, usedPorts);
+    return mergeConfig(defaultTestConfig, {
+        apiOptions: {
+            port: nextPort,
+        },
+        importExportOptions: {
+            importAssetsDir: path.join(packageDir, 'fixtures/assets'),
+        },
+        dbConnectionOptions: getDbConfig(),
+    });
+};
 
 function getDbConfig(): ConnectionOptions {
     const dbType = process.env.DB || 'sqljs';

+ 1 - 1
lerna.json

@@ -2,7 +2,7 @@
   "packages": [
     "packages/*"
   ],
-  "version": "1.3.2",
+  "version": "1.3.3",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "command": {

+ 3 - 3
packages/admin-ui-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui-plugin",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -21,8 +21,8 @@
   "devDependencies": {
     "@types/express": "^4.17.8",
     "@types/fs-extra": "^9.0.1",
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
     "express": "^4.17.1",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"

+ 2 - 2
packages/admin-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "license": "MIT",
   "scripts": {
     "ng": "ng",
@@ -39,7 +39,7 @@
     "@ng-select/ng-select": "^7.2.0",
     "@ngx-translate/core": "^13.0.0",
     "@ngx-translate/http-loader": "^6.0.0",
-    "@vendure/common": "^1.3.2",
+    "@vendure/common": "^1.3.3",
     "@webcomponents/custom-elements": "^1.4.3",
     "apollo-angular": "^2.4.0",
     "apollo-upload-client": "^14.1.3",

+ 4 - 4
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -3177,7 +3177,7 @@ export type OrderItem = Node & {
   /** The price of a single unit including discounts and tax */
   discountedUnitPriceWithTax: Scalars['Int'];
   /**
-   * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
    * and refund calculations.
    */
@@ -3227,7 +3227,7 @@ export type OrderLine = Node & {
   /** The price of a single unit including discounts and tax */
   discountedUnitPriceWithTax: Scalars['Int'];
   /**
-   * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
    * and refund calculations.
    */
@@ -3239,14 +3239,14 @@ export type OrderLine = Node & {
   taxRate: Scalars['Float'];
   /** The total price of the line excluding tax and discounts. */
   linePrice: Scalars['Int'];
-  /** The total price of the line including tax bit excluding discounts. */
+  /** The total price of the line including tax but excluding discounts. */
   linePriceWithTax: Scalars['Int'];
   /** The price of the line including discounts, excluding tax */
   discountedLinePrice: Scalars['Int'];
   /** The price of the line including discounts and tax */
   discountedLinePriceWithTax: Scalars['Int'];
   /**
-   * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
    * and refund calculations.
    */

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/version.ts

@@ -1,2 +1,2 @@
 // Auto-generated by the set-version.js script.
-export const ADMIN_UI_VERSION = '1.3.2';
+export const ADMIN_UI_VERSION = '1.3.3';

+ 33 - 18
packages/admin-ui/src/lib/core/src/shared/components/channel-assignment-control/channel-assignment-control.component.ts

@@ -31,7 +31,8 @@ export class ChannelAssignmentControlComponent implements OnInit, ControlValueAc
     disabled = false;
     private onChange: (value: any) => void;
     private onTouched: () => void;
-    private channels: CurrentUserChannel[];
+    private channels: CurrentUserChannel[] | undefined;
+    private lastIncomingValue: any;
 
     constructor(private dataService: DataService) {}
 
@@ -42,7 +43,14 @@ export class ChannelAssignmentControlComponent implements OnInit, ControlValueAc
                     this.includeDefaultChannel ? true : c.code !== DEFAULT_CHANNEL_CODE,
                 ),
             ),
-            tap(channels => (this.channels = channels)),
+            tap(channels => {
+                if (!this.channels) {
+                    this.channels = channels;
+                    this.mapIncomingValueToChannels(this.lastIncomingValue);
+                } else {
+                    this.channels = channels;
+                }
+            }),
         );
     }
 
@@ -59,22 +67,8 @@ export class ChannelAssignmentControlComponent implements OnInit, ControlValueAc
     }
 
     writeValue(obj: unknown): void {
-        if (Array.isArray(obj)) {
-            if (typeof obj[0] === 'string') {
-                this.value = obj.map(id => this.channels?.find(c => c.id === id)).filter(notNullOrUndefined);
-            } else {
-                this.value = obj;
-            }
-        } else {
-            if (typeof obj === 'string') {
-                const channel = this.channels?.find(c => c.id === obj);
-                if (channel) {
-                    this.value = [channel];
-                }
-            } else if (obj && (obj as any).id) {
-                this.value = [obj as any];
-            }
-        }
+        this.lastIncomingValue = obj;
+        this.mapIncomingValueToChannels(obj);
     }
 
     focussed() {
@@ -100,4 +94,25 @@ export class ChannelAssignmentControlComponent implements OnInit, ControlValueAc
         const c2id = typeof c2 === 'string' ? c2 : c2.id;
         return c1id === c2id;
     }
+
+    private mapIncomingValueToChannels(value: unknown) {
+        if (Array.isArray(value)) {
+            if (typeof value[0] === 'string') {
+                this.value = value
+                    .map(id => this.channels?.find(c => c.id === id))
+                    .filter(notNullOrUndefined);
+            } else {
+                this.value = value;
+            }
+        } else {
+            if (typeof value === 'string') {
+                const channel = this.channels?.find(c => c.id === value);
+                if (channel) {
+                    this.value = [channel];
+                }
+            } else if (value && (value as any).id) {
+                this.value = [value as any];
+            }
+        }
+    }
 }

+ 3 - 3
packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.html

@@ -10,11 +10,11 @@
 >
     <li *ngFor="let entry of entries">
         <span class="key" *ngIf="entry.key">{{ entry.key }}:</span>
-        <ng-container *ngIf="isObject(entry.value)">
+        <ng-container *ngIf="isObject(entry.value); else primitive">
             <vdr-object-tree [value]="entry.value" [isArrayItem]="valueIsArray"></vdr-object-tree>
         </ng-container>
-        <ng-container *ngIf="!isObject(entry.value)">
+        <ng-template #primitive>
             {{ entry.value }}
-        </ng-container>
+        </ng-template>
     </li>
 </ul>

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.ts

@@ -35,7 +35,7 @@ export class ObjectTreeComponent implements OnInit {
     }
 
     private getEntries(inputValue: { [key: string]: any } | string): Array<{ key: string; value: any }> {
-        if (typeof inputValue === 'string') {
+        if (!this.isObject(inputValue)) {
             return [{ key: '', value: inputValue }];
         }
         return Object.entries(inputValue).map(([key, value]) => ({ key, value }));

+ 1 - 5
packages/asset-server-plugin/e2e/asset-server-plugin.e2e-spec.ts

@@ -21,14 +21,10 @@ describe('AssetServerPlugin', () => {
     const previewFilePath = path.join(__dirname, TEST_ASSET_DIR, `preview/71/${IMAGE_BASENAME}__preview.jpg`);
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
-            apiOptions: {
-                port: 5050,
-            },
+        mergeConfig(testConfig(), {
             logger: new DefaultLogger({ level: LogLevel.Info }),
             plugins: [
                 AssetServerPlugin.init({
-                    port: 3060,
                     assetUploadDir: path.join(__dirname, TEST_ASSET_DIR),
                     route: 'assets',
                 }),

+ 4 - 4
packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts

@@ -2966,7 +2966,7 @@ export type OrderItem = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3014,7 +3014,7 @@ export type OrderLine = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3026,14 +3026,14 @@ export type OrderLine = Node & {
     taxRate: Scalars['Float'];
     /** The total price of the line excluding tax and discounts. */
     linePrice: Scalars['Int'];
-    /** The total price of the line including tax bit excluding discounts. */
+    /** The total price of the line including tax but excluding discounts. */
     linePriceWithTax: Scalars['Int'];
     /** The price of the line including discounts, excluding tax */
     discountedLinePrice: Scalars['Int'];
     /** The price of the line including discounts and tax */
     discountedLinePriceWithTax: Scalars['Int'];
     /**
-     * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
      * and refund calculations.
      */

+ 4 - 4
packages/asset-server-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/asset-server-plugin",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -12,7 +12,7 @@
     "build": "rimraf lib && tsc -p ./tsconfig.build.json && node build.js",
     "lint": "tslint --fix --project ./",
     "test": "jest --config ./jest.config.js",
-    "e2e": "jest --config ../../e2e-common/jest-config.js --runInBand --package=asset-server-plugin"
+    "e2e": "jest --config ../../e2e-common/jest-config.js --package=asset-server-plugin"
   },
   "homepage": "https://www.vendure.io/",
   "funding": "https://github.com/sponsors/michaelbromley",
@@ -24,8 +24,8 @@
     "@types/fs-extra": "^9.0.8",
     "@types/node-fetch": "^2.5.8",
     "@types/sharp": "^0.27.1",
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
     "aws-sdk": "^2.856.0",
     "express": "^4.17.1",
     "node-fetch": "^2.6.1",

+ 1 - 1
packages/common/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/common",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "main": "index.js",
   "license": "MIT",
   "scripts": {

+ 4 - 4
packages/common/src/generated-shop-types.ts

@@ -1898,7 +1898,7 @@ export type OrderItem = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -1948,7 +1948,7 @@ export type OrderLine = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -1960,14 +1960,14 @@ export type OrderLine = Node & {
     taxRate: Scalars['Float'];
     /** The total price of the line excluding tax and discounts. */
     linePrice: Scalars['Int'];
-    /** The total price of the line including tax bit excluding discounts. */
+    /** The total price of the line including tax but excluding discounts. */
     linePriceWithTax: Scalars['Int'];
     /** The price of the line including discounts, excluding tax */
     discountedLinePrice: Scalars['Int'];
     /** The price of the line including discounts and tax */
     discountedLinePriceWithTax: Scalars['Int'];
     /**
-     * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
      * and refund calculations.
      */

+ 4 - 4
packages/common/src/generated-types.ts

@@ -3125,7 +3125,7 @@ export type OrderItem = Node & {
   /** The price of a single unit including discounts and tax */
   discountedUnitPriceWithTax: Scalars['Int'];
   /**
-   * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
    * and refund calculations.
    */
@@ -3175,7 +3175,7 @@ export type OrderLine = Node & {
   /** The price of a single unit including discounts and tax */
   discountedUnitPriceWithTax: Scalars['Int'];
   /**
-   * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
    * and refund calculations.
    */
@@ -3187,14 +3187,14 @@ export type OrderLine = Node & {
   taxRate: Scalars['Float'];
   /** The total price of the line excluding tax and discounts. */
   linePrice: Scalars['Int'];
-  /** The total price of the line including tax bit excluding discounts. */
+  /** The total price of the line including tax but excluding discounts. */
   linePriceWithTax: Scalars['Int'];
   /** The price of the line including discounts, excluding tax */
   discountedLinePrice: Scalars['Int'];
   /** The price of the line including discounts and tax */
   discountedLinePriceWithTax: Scalars['Int'];
   /**
-   * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+   * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
    * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
    * and refund calculations.
    */

+ 1 - 1
packages/core/e2e/administrator.e2e-spec.ts

@@ -22,7 +22,7 @@ import { CREATE_ADMINISTRATOR } from './graphql/shared-definitions';
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Administrator resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
     let createdAdmin: Administrator.Fragment;
 
     beforeAll(async () => {

+ 1 - 1
packages/core/e2e/apollo-server-plugin.e2e-spec.ts

@@ -40,7 +40,7 @@ class MyApolloServerPlugin implements ApolloServerPlugin {
 
 describe('custom apolloServerPlugins', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             apiOptions: {
                 apolloServerPlugins: [new MyApolloServerPlugin()],
             },

+ 1 - 1
packages/core/e2e/asset-channel.e2e-spec.ts

@@ -32,7 +32,7 @@ import {
 } from './graphql/shared-definitions';
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
-const { server, adminClient } = createTestEnvironment(testConfig);
+const { server, adminClient } = createTestEnvironment(testConfig());
 const SECOND_CHANNEL_TOKEN = 'second_channel_token';
 let createdAssetId: string;
 let channel2Id: string;

+ 1 - 1
packages/core/e2e/asset.e2e-spec.ts

@@ -34,7 +34,7 @@ import {
 
 describe('Asset resolver', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             assetOptions: {
                 permittedFileTypes: ['image/*', '.pdf', '.zip'],
             },

+ 1 - 1
packages/core/e2e/auth.e2e-spec.ts

@@ -40,7 +40,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Authorization & permissions', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         plugins: [ProtectedFieldsPlugin],
     });
 

+ 1 - 1
packages/core/e2e/authentication-strategy.e2e-spec.ts

@@ -35,7 +35,7 @@ import { REGISTER_ACCOUNT } from './graphql/shop-definitions';
 
 describe('AuthenticationStrategy', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             authOptions: {
                 shopAuthenticationStrategy: [
                     new NativeAuthenticationStrategy(),

+ 1 - 1
packages/core/e2e/channel.e2e-spec.ts

@@ -45,7 +45,7 @@ import { GET_ACTIVE_ORDER } from './graphql/shop-definitions';
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Channels', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
     const SECOND_CHANNEL_TOKEN = 'second_channel_token';
     let secondChannelAdminRole: CreateRole.CreateRole;
     let customerUser: GetCustomerList.Items;

+ 3 - 18
packages/core/e2e/collection.e2e-spec.ts

@@ -56,7 +56,7 @@ import { sortById } from './utils/test-order-utils';
 
 describe('Collection resolver', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         plugins: [DefaultJobQueuePlugin],
     });
 
@@ -678,23 +678,8 @@ describe('Collection resolver', () => {
                 },
             );
             expect(collection!.productVariants.items.map(i => i.price)).toEqual([
-                3799,
-                5374,
-                6900,
-                7489,
-                7896,
-                9299,
-                13435,
-                14374,
-                16994,
-                93120,
-                94920,
-                108720,
-                109995,
-                129900,
-                139900,
-                219900,
-                229900,
+                3799, 5374, 6900, 7489, 7896, 9299, 13435, 14374, 16994, 93120, 94920, 108720, 109995, 129900,
+                139900, 219900, 229900,
             ]);
         });
     });

+ 1 - 1
packages/core/e2e/configurable-operation.e2e-spec.ts

@@ -43,7 +43,7 @@ const testShippingEligibilityChecker = new ShippingEligibilityChecker({
 
 describe('Configurable operations', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             shippingOptions: {
                 shippingEligibilityCheckers: [
                     defaultShippingEligibilityChecker,

+ 1 - 1
packages/core/e2e/country.e2e-spec.ts

@@ -20,7 +20,7 @@ import { GET_COUNTRY_LIST, UPDATE_COUNTRY } from './graphql/shared-definitions';
 // tslint:disable:no-non-null-assertion
 
 describe('Country resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
     let countries: GetCountryList.Items[];
     let GB: GetCountryList.Items;
     let AT: GetCountryList.Items;

+ 5 - 2
packages/core/e2e/custom-field-relations.e2e-spec.ts

@@ -31,7 +31,10 @@ import { sortById } from './utils/test-order-utils';
 type ValueOf<T> = T[keyof T];
 type NonEmptyArray<T> = [T, ...T[]];
 type MustInclude<T, U extends T[]> = [T] extends [ValueOf<U>] ? U : never;
-const enumerate = <T>() => <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) => elements;
+const enumerate =
+    <T>() =>
+    <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) =>
+        elements;
 
 const entitiesWithCustomFields = enumerate<keyof CustomFields>()(
     'Address',
@@ -73,7 +76,7 @@ customFieldConfig.Product?.push(
     { name: 'cfShippingMethod', type: 'relation', entity: ShippingMethod, list: false },
 );
 
-const customConfig = mergeConfig(testConfig, {
+const customConfig = mergeConfig(testConfig(), {
     dbConnectionOptions: {
         timezone: 'Z',
     },

+ 2 - 2
packages/core/e2e/custom-fields.e2e-spec.ts

@@ -16,7 +16,7 @@ fixPostgresTimezone();
 
 const validateInjectorSpy = jest.fn();
 
-const customConfig = mergeConfig(testConfig, {
+const customConfig = mergeConfig(testConfig(), {
     dbConnectionOptions: {
         timezone: 'Z',
     },
@@ -322,7 +322,7 @@ describe('Custom fields', () => {
             dateTimeWithDefault: '2019-04-30T12:59:16.415Z',
             // MySQL does not support defaults on TEXT fields, which is what "simple-json" uses
             // internally. See https://stackoverflow.com/q/3466872/772859
-            stringListWithDefault: testConfig.dbConnectionOptions.type === 'mysql' ? null : ['cat'],
+            stringListWithDefault: customConfig.dbConnectionOptions.type === 'mysql' ? null : ['cat'],
         };
 
         expect(product).toEqual({

+ 1 - 1
packages/core/e2e/custom-permissions.e2e-spec.ts

@@ -23,7 +23,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Custom permissions', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TestPluginWithCustomPermissions],
         }),
     );

+ 1 - 1
packages/core/e2e/customer-channel.e2e-spec.ts

@@ -41,7 +41,7 @@ import { DELETE_ADDRESS, REGISTER_ACCOUNT } from './graphql/shop-definitions';
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('ChannelAware Customers', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
     const SECOND_CHANNEL_TOKEN = 'second_channel_token';
     let firstCustomer: GetCustomerList.Items;
     let secondCustomer: GetCustomerList.Items;

+ 2 - 2
packages/core/e2e/customer-group.e2e-spec.ts

@@ -3,7 +3,7 @@ import { createTestEnvironment } from '@vendure/testing';
 import path from 'path';
 
 import { initialData } from '../../../e2e-common/e2e-initial-data';
-import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
+import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
 
 import {
     AddCustomersToGroup,
@@ -35,7 +35,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 import { sortById } from './utils/test-order-utils';
 
 describe('CustomerGroup resolver', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     let customers: GetCustomerList.Items[];
 

+ 1 - 1
packages/core/e2e/customer.e2e-spec.ts

@@ -76,7 +76,7 @@ class TestEmailPlugin implements OnModuleInit {
 
 describe('Customer resolver', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, { plugins: [TestEmailPlugin] }),
+        mergeConfig(testConfig(), { plugins: [TestEmailPlugin] }),
     );
 
     let firstCustomer: GetCustomerList.Items;

+ 1 - 1
packages/core/e2e/database-transactions.e2e-spec.ts

@@ -15,7 +15,7 @@ import {
 
 describe('Transaction infrastructure', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TransactionTestPlugin],
         }),
     );

+ 2 - 2
packages/core/e2e/default-search-plugin.e2e-spec.ts

@@ -82,7 +82,7 @@ interface SearchProductShopVariables extends SearchProductsShop.Variables {
 
 describe('Default search plugin', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             logger: new DefaultLogger(),
             plugins: [DefaultSearchPlugin.init({ indexStockStatus: true }), DefaultJobQueuePlugin],
         }),
@@ -95,7 +95,7 @@ describe('Default search plugin', () => {
             customerCount: 1,
         });
         await adminClient.asSuperAdmin();
-        if (testConfig.dbConnectionOptions.type === 'mysql') {
+        if (testConfig().dbConnectionOptions.type === 'mysql') {
             // Mysql seems to occasionally run into some kind of race condition
             // relating to the populating of data, so we add a pause here.
             await new Promise(resolve => setTimeout(resolve, 10000));

+ 1 - 1
packages/core/e2e/entity-hydrator.e2e-spec.ts

@@ -17,7 +17,7 @@ const orderResultGuard: ErrorResultGuard<UpdatedOrderFragment> = createErrorResu
 
 describe('Entity hydration', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [HydrationTestPlugin],
         }),
     );

+ 1 - 1
packages/core/e2e/entity-id-strategy.e2e-spec.ts

@@ -20,7 +20,7 @@ import {
 import { sortById } from './utils/test-order-utils';
 
 describe('EntityIdStrategy', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 1 - 1
packages/core/e2e/entity-uuid-strategy.e2e-spec.ts

@@ -18,7 +18,7 @@ import { GET_PRODUCT_LIST } from './graphql/shared-definitions';
 
 describe('UuidIdStrategy', () => {
     const { server, adminClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         entityOptions: { entityIdStrategy: new UuidIdStrategy() },
     });
 

+ 4 - 3
packages/core/e2e/facet.e2e-spec.ts

@@ -32,7 +32,8 @@ import {
     ASSIGN_PRODUCT_TO_CHANNEL,
     CREATE_CHANNEL,
     CREATE_FACET,
-    GET_FACET_LIST, GET_FACET_LIST_SIMPLE,
+    GET_FACET_LIST,
+    GET_FACET_LIST_SIMPLE,
     GET_PRODUCT_WITH_VARIANTS,
     UPDATE_FACET,
     UPDATE_PRODUCT,
@@ -43,7 +44,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 // tslint:disable:no-non-null-assertion
 
 describe('Facet resolver', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     let brandFacet: FacetWithValues.Fragment;
     let speakerTypeFacet: FacetWithValues.Fragment;
@@ -85,7 +86,7 @@ describe('Facet resolver', () => {
             input: {
                 id: speakerTypeFacet.id,
                 translations: [{ languageCode: LanguageCode.en, name: 'Speaker Category' }],
-                isPrivate: true
+                isPrivate: true,
             },
         });
 

+ 2 - 2
packages/core/e2e/fulfillment-process.e2e-spec.ts

@@ -82,9 +82,9 @@ describe('Fulfillment process', () => {
     };
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             shippingOptions: {
-                ...testConfig.shippingOptions,
+                ...testConfig().shippingOptions,
                 customFulfillmentProcess: [customOrderProcess as any, customOrderProcess2 as any],
             },
             paymentOptions: {

+ 1 - 1
packages/core/e2e/global-settings.e2e-spec.ts

@@ -16,7 +16,7 @@ import { UPDATE_GLOBAL_SETTINGS } from './graphql/shared-definitions';
 
 describe('GlobalSettings resolver', () => {
     const { server, adminClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         ...{
             customFields: {
                 Customer: [{ name: 'age', type: 'int' }],

+ 35 - 4
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -2966,7 +2966,7 @@ export type OrderItem = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3014,7 +3014,7 @@ export type OrderLine = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3026,14 +3026,14 @@ export type OrderLine = Node & {
     taxRate: Scalars['Float'];
     /** The total price of the line excluding tax and discounts. */
     linePrice: Scalars['Int'];
-    /** The total price of the line including tax bit excluding discounts. */
+    /** The total price of the line including tax but excluding discounts. */
     linePriceWithTax: Scalars['Int'];
     /** The price of the line including discounts, excluding tax */
     discountedLinePrice: Scalars['Int'];
     /** The price of the line including discounts and tax */
     discountedLinePriceWithTax: Scalars['Int'];
     /**
-     * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
      * and refund calculations.
      */
@@ -6865,6 +6865,17 @@ export type UpdateStockMutationVariables = Exact<{
 
 export type UpdateStockMutation = { updateProductVariants: Array<Maybe<VariantWithStockFragment>> };
 
+export type TransitionFulfillmentToStateMutationVariables = Exact<{
+    id: Scalars['ID'];
+    state: Scalars['String'];
+}>;
+
+export type TransitionFulfillmentToStateMutation = {
+    transitionFulfillmentToState:
+        | Pick<Fulfillment, 'id' | 'state' | 'nextStates' | 'createdAt'>
+        | Pick<FulfillmentStateTransitionError, 'errorCode' | 'message' | 'transitionError'>;
+};
+
 export type GetTagListQueryVariables = Exact<{
     options?: Maybe<TagListOptions>;
 }>;
@@ -9248,6 +9259,26 @@ export namespace UpdateStock {
     >;
 }
 
+export namespace TransitionFulfillmentToState {
+    export type Variables = TransitionFulfillmentToStateMutationVariables;
+    export type Mutation = TransitionFulfillmentToStateMutation;
+    export type TransitionFulfillmentToState = NonNullable<
+        TransitionFulfillmentToStateMutation['transitionFulfillmentToState']
+    >;
+    export type FulfillmentInlineFragment = DiscriminateUnion<
+        NonNullable<TransitionFulfillmentToStateMutation['transitionFulfillmentToState']>,
+        { __typename?: 'Fulfillment' }
+    >;
+    export type ErrorResultInlineFragment = DiscriminateUnion<
+        NonNullable<TransitionFulfillmentToStateMutation['transitionFulfillmentToState']>,
+        { __typename?: 'ErrorResult' }
+    >;
+    export type FulfillmentStateTransitionErrorInlineFragment = DiscriminateUnion<
+        NonNullable<TransitionFulfillmentToStateMutation['transitionFulfillmentToState']>,
+        { __typename?: 'FulfillmentStateTransitionError' }
+    >;
+}
+
 export namespace GetTagList {
     export type Variables = GetTagListQueryVariables;
     export type Query = GetTagListQuery;

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

@@ -1837,7 +1837,7 @@ export type OrderItem = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -1885,7 +1885,7 @@ export type OrderLine = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -1897,14 +1897,14 @@ export type OrderLine = Node & {
     taxRate: Scalars['Float'];
     /** The total price of the line excluding tax and discounts. */
     linePrice: Scalars['Int'];
-    /** The total price of the line including tax bit excluding discounts. */
+    /** The total price of the line including tax but excluding discounts. */
     linePriceWithTax: Scalars['Int'];
     /** The price of the line including discounts, excluding tax */
     discountedLinePrice: Scalars['Int'];
     /** The price of the line including discounts and tax */
     discountedLinePriceWithTax: Scalars['Int'];
     /**
-     * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
      * and refund calculations.
      */

+ 1 - 1
packages/core/e2e/import.e2e-spec.ts

@@ -9,7 +9,7 @@ import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-conf
 
 describe('Import resolver', () => {
     const { server, adminClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         customFields: {
             Product: [
                 { type: 'string', name: 'pageType' },

+ 6 - 5
packages/core/e2e/job-queue.e2e-spec.ts

@@ -11,7 +11,8 @@ import { CancelJob, GetRunningJobs, JobState } from './graphql/generated-e2e-adm
 import { GET_RUNNING_JOBS } from './graphql/shared-definitions';
 
 describe('JobQueue', () => {
-    if (testConfig.dbConnectionOptions.type === 'sqljs') {
+    const activeConfig = testConfig();
+    if (activeConfig.dbConnectionOptions.type === 'sqljs') {
         it.only('skip JobQueue tests for sqljs', () => {
             // The tests in this suite will fail when running on sqljs because
             // the DB state is not persisted after shutdown. In this case it is
@@ -22,7 +23,7 @@ describe('JobQueue', () => {
     }
 
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(activeConfig, {
             plugins: [DefaultJobQueuePlugin, PluginWithJobQueue],
         }),
     );
@@ -64,7 +65,7 @@ describe('JobQueue', () => {
     let testJobId: string;
 
     it('creates and starts running a job', async () => {
-        const restControllerUrl = `http://localhost:${testConfig.apiOptions.port}/run-job`;
+        const restControllerUrl = `http://localhost:${activeConfig.apiOptions.port}/run-job`;
         await adminClient.fetch(restControllerUrl);
 
         await sleep(300);
@@ -108,7 +109,7 @@ describe('JobQueue', () => {
 
     it('cancels a running job', async () => {
         PluginWithJobQueue.jobHasDoneWork = false;
-        const restControllerUrl = `http://localhost:${testConfig.apiOptions.port}/run-job`;
+        const restControllerUrl = `http://localhost:${activeConfig.apiOptions.port}/run-job`;
         await adminClient.fetch(restControllerUrl);
 
         await sleep(300);
@@ -133,7 +134,7 @@ describe('JobQueue', () => {
     });
 
     it('subscribe to result of job', async () => {
-        const restControllerUrl = `http://localhost:${testConfig.apiOptions.port}/run-job/subscribe`;
+        const restControllerUrl = `http://localhost:${activeConfig.apiOptions.port}/run-job/subscribe`;
         const result = await adminClient.fetch(restControllerUrl);
 
         expect(await result.text()).toBe('42!');

+ 1 - 1
packages/core/e2e/lifecycle.e2e-spec.ts

@@ -52,7 +52,7 @@ const testShippingEligChecker = new ShippingEligibilityChecker({
 
 describe('lifecycle hooks for configurable objects', () => {
     const { server, adminClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         entityOptions: { entityIdStrategy: new TestIdStrategy() },
         shippingOptions: {
             shippingEligibilityCheckers: [defaultShippingEligibilityChecker, testShippingEligChecker],

+ 1 - 1
packages/core/e2e/list-query-builder.e2e-spec.ts

@@ -16,7 +16,7 @@ fixPostgresTimezone();
 
 describe('ListQueryBuilder', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             apiOptions: {
                 shopListQueryLimit: 10,
                 adminListQueryLimit: 30,

+ 1 - 1
packages/core/e2e/localization.e2e-spec.ts

@@ -16,7 +16,7 @@ import { GET_PRODUCT_WITH_VARIANTS, UPDATE_PRODUCT } from './graphql/shared-defi
 
 /* tslint:disable:no-non-null-assertion */
 describe('Localization', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 1 - 1
packages/core/e2e/order-changed-price-handling.e2e-spec.ts

@@ -40,7 +40,7 @@ class TestChangedPriceStrategy implements ChangedPriceHandlingStrategy {
 
 describe('ChangedPriceHandlingStrategy', () => {
     const { server, shopClient, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             orderOptions: {
                 changedPriceHandlingStrategy: new TestChangedPriceStrategy(),
             },

+ 1 - 1
packages/core/e2e/order-channel.e2e-spec.ts

@@ -35,7 +35,7 @@ import {
 import { ADD_ITEM_TO_ORDER, GET_ACTIVE_ORDER, GET_ORDER_SHOP } from './graphql/shop-definitions';
 
 describe('Channelaware orders', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
     const SECOND_CHANNEL_TOKEN = 'second_channel_token';
     const THIRD_CHANNEL_TOKEN = 'third_channel_token';
     let customerUser: GetCustomerList.Items;

+ 1 - 1
packages/core/e2e/order-fulfillment.e2e-spec.ts

@@ -71,7 +71,7 @@ describe('Order fulfillments', () => {
     let f1Id: string;
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             paymentOptions: {
                 paymentMethodHandlers: [testSuccessfulPaymentMethod],
             },

+ 1 - 1
packages/core/e2e/order-item-price-calculation-strategy.e2e-spec.ts

@@ -13,7 +13,7 @@ import { ADD_ITEM_TO_ORDER, SEARCH_PRODUCTS_SHOP } from './graphql/shop-definiti
 describe('custom OrderItemPriceCalculationStrategy', () => {
     let variants: SearchProductsShop.Items[];
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             customFields: {
                 OrderLine: [{ name: 'giftWrap', type: 'boolean' }],
             },

+ 1 - 1
packages/core/e2e/order-merge.e2e-spec.ts

@@ -51,7 +51,7 @@ describe('Order merging', () => {
     let customers: GetCustomerList.Items[];
 
     const { server, shopClient, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             orderOptions: {
                 mergeStrategy: new DelegateMergeStrategy(),
             },

+ 1 - 1
packages/core/e2e/order-modification.e2e-spec.ts

@@ -97,7 +97,7 @@ const testCalculator = new ShippingCalculator({
 
 describe('Order modification', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             paymentOptions: {
                 paymentMethodHandlers: [
                     testSuccessfulPaymentMethod,

+ 3 - 4
packages/core/e2e/order-process.e2e-spec.ts

@@ -83,12 +83,11 @@ describe('Order process', () => {
         },
     };
 
-    const orderErrorGuard: ErrorResultGuard<
-        TestOrderFragmentFragment | OrderFragment
-    > = createErrorResultGuard(input => !!input.total);
+    const orderErrorGuard: ErrorResultGuard<TestOrderFragmentFragment | OrderFragment> =
+        createErrorResultGuard(input => !!input.total);
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             orderOptions: { process: [customOrderProcess as any, customOrderProcess2 as any] },
             paymentOptions: {
                 paymentMethodHandlers: [testSuccessfulPaymentMethod],

+ 1 - 1
packages/core/e2e/order-promotion.e2e-spec.ts

@@ -87,7 +87,7 @@ import { addPaymentToOrder, proceedToArrangingPayment } from './utils/test-order
 
 describe('Promotions applied to Orders', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         paymentOptions: {
             paymentMethodHandlers: [testSuccessfulPaymentMethod],
         },

+ 1 - 1
packages/core/e2e/order-taxes.e2e-spec.ts

@@ -20,7 +20,7 @@ import { sortById } from './utils/test-order-utils';
 
 describe('Order taxes', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         paymentOptions: {
             paymentMethodHandlers: [testSuccessfulPaymentMethod],
         },

+ 1 - 1
packages/core/e2e/order.e2e-spec.ts

@@ -111,7 +111,7 @@ import { addPaymentToOrder, proceedToArrangingPayment, sortById } from './utils/
 
 describe('Orders resolver', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             paymentOptions: {
                 paymentMethodHandlers: [
                     twoStagePaymentMethod,

+ 1 - 1
packages/core/e2e/parallel-transactions.e2e-spec.ts

@@ -22,7 +22,7 @@ import {
 
 describe('Parallel transactions', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         plugins: [SlowMutationPlugin],
     });
 

+ 1 - 1
packages/core/e2e/payment-method.e2e-spec.ts

@@ -65,7 +65,7 @@ describe('PaymentMethod resolver', () => {
     );
 
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         logger: new DefaultLogger(),
         paymentOptions: {
             paymentMethodEligibilityCheckers: [minPriceChecker],

+ 1 - 1
packages/core/e2e/payment-process.e2e-spec.ts

@@ -128,7 +128,7 @@ describe('Payment process', () => {
     const paymentGuard: ErrorResultGuard<PaymentFragment> = createErrorResultGuard(input => !!input.id);
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             logger: new DefaultLogger(),
             orderOptions: {
                 process: [customOrderProcess as any],

+ 3 - 2
packages/core/e2e/plugin.e2e-spec.ts

@@ -17,8 +17,9 @@ import { TestRestPlugin } from './fixtures/test-plugins/with-rest-controller';
 
 describe('Plugins', () => {
     const onConstructorFn = jest.fn();
+    const activeConfig = testConfig();
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...activeConfig,
         plugins: [
             TestPluginWithAllLifecycleHooks.init(onConstructorFn),
             TestPluginWithConfig.setup(),
@@ -104,7 +105,7 @@ describe('Plugins', () => {
     });
 
     describe('REST plugins', () => {
-        const restControllerUrl = `http://localhost:${testConfig.apiOptions.port}/test`;
+        const restControllerUrl = `http://localhost:${activeConfig.apiOptions.port}/test`;
 
         it('public route', async () => {
             const response = await shopClient.fetch(restControllerUrl + '/public');

+ 1 - 1
packages/core/e2e/product-channel.e2e-spec.ts

@@ -38,7 +38,7 @@ import {
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('ChannelAware Products and ProductVariants', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
     const SECOND_CHANNEL_TOKEN = 'second_channel_token';
     const THIRD_CHANNEL_TOKEN = 'third_channel_token';
     let secondChannelAdminRole: CreateRole.CreateRole;

+ 1 - 1
packages/core/e2e/product-option.e2e-spec.ts

@@ -21,7 +21,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 // tslint:disable:no-non-null-assertion
 
 describe('ProductOption resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
     let sizeGroup: ProductOptionGroupFragment;
     let mediumOption: CreateProductOption.CreateProductOption;
 

+ 1 - 1
packages/core/e2e/product.e2e-spec.ts

@@ -52,7 +52,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 // tslint:disable:no-non-null-assertion
 
 describe('Product resolver', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     const removeOptionGuard: ErrorResultGuard<ProductWithOptionsFragment> = createErrorResultGuard(
         input => !!input.optionGroups,

+ 1 - 1
packages/core/e2e/promotion.e2e-spec.ts

@@ -47,7 +47,7 @@ describe('Promotion resolver', () => {
     const promoAction = generateTestAction('promo_action');
 
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         promotionOptions: {
             promotionConditions: [promoCondition, promoCondition2],
             promotionActions: [promoAction],

+ 1 - 1
packages/core/e2e/role.e2e-spec.ts

@@ -31,7 +31,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 import { sortById } from './utils/test-order-utils';
 
 describe('Role resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
     let createdRole: Role.Fragment;
     let defaultRoles: Role.Fragment[];
 

+ 3 - 3
packages/core/e2e/session-management.e2e-spec.ts

@@ -5,7 +5,7 @@ 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 { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
 import { SUPER_ADMIN_USER_IDENTIFIER, SUPER_ADMIN_USER_PASSWORD } from '../../common/src/shared-constants';
 
 import { AttemptLogin, Me } from './graphql/generated-e2e-admin-types';
@@ -41,7 +41,7 @@ class TestingSessionCacheStrategy implements SessionCacheStrategy {
 
 describe('Session caching', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             authOptions: {
                 sessionCacheStrategy: new TestingSessionCacheStrategy(),
                 sessionCacheTTL: 2,
@@ -118,7 +118,7 @@ describe('Session caching', () => {
 
 describe('Session expiry', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             authOptions: {
                 sessionDuration: '3s',
                 sessionCacheTTL: 1,

+ 3 - 4
packages/core/e2e/shipping-method-eligibility.e2e-spec.ts

@@ -90,16 +90,15 @@ const calculator = new ShippingCalculator({
 
 describe('ShippingMethod eligibility', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         shippingOptions: {
             shippingEligibilityCheckers: [defaultShippingEligibilityChecker, checker1, checker2, checker3],
             shippingCalculators: [defaultShippingCalculator, calculator],
         },
     });
 
-    const orderGuard: ErrorResultGuard<
-        UpdatedOrderFragment | TestOrderFragmentFragment
-    > = createErrorResultGuard(input => !!input.lines);
+    const orderGuard: ErrorResultGuard<UpdatedOrderFragment | TestOrderFragmentFragment> =
+        createErrorResultGuard(input => !!input.lines);
 
     let singleLineShippingMethod: ShippingMethodFragment;
     let multiLineShippingMethod: ShippingMethodFragment;

+ 1 - 1
packages/core/e2e/shipping-method.e2e-spec.ts

@@ -53,7 +53,7 @@ const calculatorWithMetadata = new ShippingCalculator({
 
 describe('ShippingMethod resolver', () => {
     const { server, adminClient, shopClient } = createTestEnvironment({
-        ...testConfig,
+        ...testConfig(),
         shippingOptions: {
             shippingEligibilityCheckers: [defaultShippingEligibilityChecker],
             shippingCalculators: [defaultShippingCalculator, calculatorWithMetadata],

+ 4 - 4
packages/core/e2e/shop-auth.e2e-spec.ts

@@ -96,7 +96,7 @@ const currentUserErrorGuard: ErrorResultGuard<CurrentUserShopFragment> = createE
 
 describe('Shop auth & accounts', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TestEmailPlugin as any],
         }),
     );
@@ -774,7 +774,7 @@ describe('Shop auth & accounts', () => {
 
 describe('Expiring tokens', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TestEmailPlugin as any],
             authOptions: {
                 verificationTokenDuration: '1ms',
@@ -876,7 +876,7 @@ describe('Expiring tokens', () => {
 
 describe('Registration without email verification', () => {
     const { server, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TestEmailPlugin as any],
             authOptions: {
                 requireVerification: false,
@@ -956,7 +956,7 @@ describe('Registration without email verification', () => {
 
 describe('Updating email address without email verification', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TestEmailPlugin as any],
             authOptions: {
                 requireVerification: false,

+ 1 - 1
packages/core/e2e/shop-catalog.e2e-spec.ts

@@ -43,7 +43,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 import { awaitRunningJobs } from './utils/await-running-jobs';
 
 describe('Shop catalog', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 1 - 1
packages/core/e2e/shop-customer.e2e-spec.ts

@@ -37,7 +37,7 @@ import {
 import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Shop customers', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
     let customer: GetCustomer.Customer;
 
     const successErrorGuard: ErrorResultGuard<{ success: boolean }> = createErrorResultGuard(

+ 2 - 3
packages/core/e2e/shop-order.e2e-spec.ts

@@ -64,7 +64,6 @@ import {
 } from './graphql/shared-definitions';
 import {
     ADD_ITEM_TO_ORDER,
-    ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS,
     ADD_PAYMENT,
     ADJUST_ITEM_QUANTITY,
     GET_ACTIVE_ORDER,
@@ -89,7 +88,7 @@ import { assertThrowsWithMessage } from './utils/assert-throws-with-message';
 
 describe('Shop orders', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             paymentOptions: {
                 paymentMethodHandlers: [
                     testSuccessfulPaymentMethod,
@@ -422,7 +421,7 @@ describe('Shop orders', () => {
                 const { activeOrder } = await shopClient.query(GET_ORDER_WITH_ORDER_LINE_CUSTOM_FIELDS);
 
                 const ADJUST_ORDER_LINE_WITH_CUSTOM_FIELDS = gql`
-                    mutation($orderLineId: ID!, $quantity: Int!, $customFields: OrderLineCustomFieldsInput) {
+                    mutation ($orderLineId: ID!, $quantity: Int!, $customFields: OrderLineCustomFieldsInput) {
                         adjustOrderLine(
                             orderLineId: $orderLineId
                             quantity: $quantity

+ 120 - 4
packages/core/e2e/stock-control.e2e-spec.ts

@@ -20,6 +20,8 @@ import {
     GlobalFlag,
     SettlePayment,
     StockMovementType,
+    TransitFulfillment,
+    TransitionFulfillmentToState,
     UpdateGlobalSettings,
     UpdateProductVariantInput,
     UpdateProductVariants,
@@ -59,7 +61,7 @@ import { addPaymentToOrder, proceedToArrangingPayment } from './utils/test-order
 
 describe('Stock control', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             paymentOptions: {
                 paymentMethodHandlers: [testSuccessfulPaymentMethod, twoStagePaymentMethod],
             },
@@ -69,9 +71,8 @@ describe('Stock control', () => {
         }),
     );
 
-    const orderGuard: ErrorResultGuard<
-        TestOrderFragmentFragment | UpdatedOrderFragment
-    > = createErrorResultGuard(input => !!input.lines);
+    const orderGuard: ErrorResultGuard<TestOrderFragmentFragment | UpdatedOrderFragment> =
+        createErrorResultGuard(input => !!input.lines);
 
     const fulfillmentGuard: ErrorResultGuard<FulfillmentFragment> = createErrorResultGuard(
         input => !!input.state,
@@ -412,6 +413,101 @@ describe('Stock control', () => {
             expect(variant3.stockMovements.items[5].type).toBe(StockMovementType.CANCELLATION);
             expect(variant3.stockMovements.items[6].type).toBe(StockMovementType.CANCELLATION);
         });
+
+        // https://github.com/vendure-ecommerce/vendure/issues/1198
+        it('creates Cancellations & adjusts stock when cancelling a Fulfillment', async () => {
+            async function getTrackedVariant() {
+                const result = await getProductWithStockMovement('T_2');
+                return result?.variants[1]!;
+            }
+
+            const trackedVariant1 = await getTrackedVariant();
+
+            expect(trackedVariant1.stockOnHand).toBe(5);
+
+            // Add items to order and check out
+            await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test');
+            await shopClient.query<AddItemToOrder.Mutation, AddItemToOrder.Variables>(ADD_ITEM_TO_ORDER, {
+                productVariantId: trackedVariant1.id,
+                quantity: 1,
+            });
+            await shopClient.query<SetShippingAddress.Mutation, SetShippingAddress.Variables>(
+                SET_SHIPPING_ADDRESS,
+                {
+                    input: {
+                        streetLine1: '1 Test Street',
+                        countryCode: 'GB',
+                    } as CreateAddressInput,
+                },
+            );
+            await shopClient.query<TransitionToState.Mutation, TransitionToState.Variables>(
+                TRANSITION_TO_STATE,
+                { state: 'ArrangingPayment' as OrderState },
+            );
+            const { addPaymentToOrder: order } = await shopClient.query<
+                AddPaymentToOrder.Mutation,
+                AddPaymentToOrder.Variables
+            >(ADD_PAYMENT, {
+                input: {
+                    method: testSuccessfulPaymentMethod.code,
+                    metadata: {},
+                } as PaymentInput,
+            });
+            orderGuard.assertSuccess(order);
+            expect(order).not.toBeNull();
+
+            const trackedVariant2 = await getTrackedVariant();
+            expect(trackedVariant2.stockOnHand).toBe(5);
+
+            const linesInput =
+                order?.lines
+                    .filter(l => l.productVariant.id === trackedVariant2.id)
+                    .map(l => ({ orderLineId: l.id, quantity: l.quantity })) ?? [];
+
+            const { addFulfillmentToOrder } = await adminClient.query<
+                CreateFulfillment.Mutation,
+                CreateFulfillment.Variables
+            >(CREATE_FULFILLMENT, {
+                input: {
+                    lines: linesInput,
+                    handler: {
+                        code: manualFulfillmentHandler.code,
+                        arguments: [
+                            { name: 'method', value: 'test method' },
+                            { name: 'trackingCode', value: 'ABC123' },
+                        ],
+                    },
+                },
+            });
+
+            const trackedVariant3 = await getTrackedVariant();
+
+            expect(trackedVariant3.stockOnHand).toBe(4);
+
+            const { transitionFulfillmentToState } = await adminClient.query<
+                TransitionFulfillmentToState.Mutation,
+                TransitionFulfillmentToState.Variables
+            >(TRANSITION_FULFILLMENT_TO_STATE, {
+                state: 'Cancelled',
+                id: (addFulfillmentToOrder as any).id,
+            });
+
+            const trackedVariant4 = await getTrackedVariant();
+
+            expect(trackedVariant4.stockOnHand).toBe(5);
+            expect(trackedVariant4.stockMovements.items).toEqual([
+                { id: 'T_4', quantity: 5, type: 'ADJUSTMENT' },
+                { id: 'T_7', quantity: 3, type: 'ALLOCATION' },
+                { id: 'T_9', quantity: 1, type: 'RELEASE' },
+                { id: 'T_11', quantity: -2, type: 'SALE' },
+                { id: 'T_15', quantity: 1, type: 'CANCELLATION' },
+                { id: 'T_16', quantity: 1, type: 'CANCELLATION' },
+                { id: 'T_21', quantity: 1, type: 'ALLOCATION' },
+                { id: 'T_22', quantity: -1, type: 'SALE' },
+                // This is the cancellation we are testing for
+                { id: 'T_23', quantity: 1, type: 'CANCELLATION' },
+            ]);
+        });
     });
 
     describe('saleable stock level', () => {
@@ -1061,3 +1157,23 @@ const UPDATE_STOCK_ON_HAND = gql`
     }
     ${VARIANT_WITH_STOCK_FRAGMENT}
 `;
+
+export const TRANSITION_FULFILLMENT_TO_STATE = gql`
+    mutation TransitionFulfillmentToState($id: ID!, $state: String!) {
+        transitionFulfillmentToState(id: $id, state: $state) {
+            ... on Fulfillment {
+                id
+                state
+                nextStates
+                createdAt
+            }
+            ... on ErrorResult {
+                errorCode
+                message
+            }
+            ... on FulfillmentStateTransitionError {
+                transitionError
+            }
+        }
+    }
+`;

+ 1 - 1
packages/core/e2e/tag.e2e-spec.ts

@@ -8,7 +8,7 @@ import { createTestEnvironment } from '../../testing/lib/create-test-environment
 import { CreateTag, GetTag, GetTagList, UpdateTag } from './graphql/generated-e2e-admin-types';
 
 describe('Tag resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 1 - 1
packages/core/e2e/tax-category.e2e-spec.ts

@@ -16,7 +16,7 @@ import {
 import { sortById } from './utils/test-order-utils';
 
 describe('TaxCategory resolver', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 2 - 2
packages/core/e2e/tax-rate.e2e-spec.ts

@@ -5,7 +5,7 @@ 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 { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
 
 import { TAX_RATE_FRAGMENT } from './graphql/fragments';
 import {
@@ -19,7 +19,7 @@ import {
 import { GET_TAX_RATES_LIST, UPDATE_TAX_RATE } from './graphql/shared-definitions';
 
 describe('TaxRate resolver', () => {
-    const { server, adminClient, shopClient } = createTestEnvironment(testConfig);
+    const { server, adminClient, shopClient } = createTestEnvironment(testConfig());
 
     beforeAll(async () => {
         await server.init({

+ 1 - 1
packages/core/e2e/translations.e2e-spec.ts

@@ -15,7 +15,7 @@ import {
 
 describe('Translation', () => {
     const { server, adminClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             plugins: [TranslationTestPlugin],
         }),
     );

+ 2 - 2
packages/core/e2e/zone.e2e-spec.ts

@@ -3,7 +3,7 @@ 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 { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
 
 import { ZONE_FRAGMENT } from './graphql/fragments';
 import {
@@ -23,7 +23,7 @@ import { GET_COUNTRY_LIST, UPDATE_CHANNEL } from './graphql/shared-definitions';
 // tslint:disable:no-non-null-assertion
 
 describe('Zone resolver', () => {
-    const { server, adminClient } = createTestEnvironment(testConfig);
+    const { server, adminClient } = createTestEnvironment(testConfig());
     let countries: GetCountryList.Items[];
     let zones: Array<{ id: string; name: string }>;
     let oceania: { id: string; name: string };

+ 3 - 3
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/core",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "description": "A modern, headless ecommerce framework",
   "repository": {
     "type": "git",
@@ -24,7 +24,7 @@
     "watch": "concurrently yarn:tsc:watch yarn:gulp:watch",
     "lint": "tslint --fix --project ./",
     "test": "jest --config ./jest.config.js",
-    "e2e": "jest --config ../../e2e-common/jest-config.js --runInBand --package=core",
+    "e2e": "jest --config ../../e2e-common/jest-config.js --package=core",
     "ci": "yarn build"
   },
   "publishConfig": {
@@ -49,7 +49,7 @@
     "@nestjs/testing": "7.6.17",
     "@nestjs/typeorm": "7.1.5",
     "@types/fs-extra": "^9.0.1",
-    "@vendure/common": "^1.3.2",
+    "@vendure/common": "^1.3.3",
     "apollo-server-express": "2.24.1",
     "bcrypt": "^5.0.0",
     "body-parser": "^1.19.0",

+ 1 - 0
packages/core/src/api/resolvers/shop/shop-order.resolver.ts

@@ -332,6 +332,7 @@ export class ShopOrderResolver {
                             const address = order.shippingAddress;
                             await this.customerService.createAddress(ctx, order.customer.id, {
                                 ...address,
+                                company: address.company || '',
                                 streetLine1: address.streetLine1 || '',
                                 streetLine2: address.streetLine2 || '',
                                 countryCode: address.countryCode || '',

+ 9 - 5
packages/core/src/config/index.ts

@@ -22,25 +22,25 @@ export * from './logger/default-logger';
 export * from './logger/noop-logger';
 export * from './logger/vendure-logger';
 export * from './merge-config';
-export * from './order/custom-order-process';
 export * from './order/changed-price-handling-strategy';
+export * from './order/custom-order-process';
 export * from './order/default-changed-price-handling-strategy';
 export * from './order/default-order-placed-strategy';
 export * from './order/default-stock-allocation-strategy';
 export * from './order/merge-orders-strategy';
 export * from './order/order-code-strategy';
+export * from './order/order-item-price-calculation-strategy';
 export * from './order/order-merge-strategy';
 export * from './order/order-placed-strategy';
+export * from './order/stock-allocation-strategy';
 export * from './order/use-existing-strategy';
-export * from './order/use-guest-strategy';
 export * from './order/use-guest-if-existing-empty-strategy';
-export * from './order/order-item-price-calculation-strategy';
-export * from './order/stock-allocation-strategy';
+export * from './order/use-guest-strategy';
 export * from './payment/custom-payment-process';
 export * from './payment/dummy-payment-method-handler';
 export * from './payment/example-payment-method-handler';
-export * from './payment/payment-method-handler';
 export * from './payment/payment-method-eligibility-checker';
+export * from './payment/payment-method-handler';
 export * from './promotion';
 export * from './session-cache/in-memory-session-cache-strategy';
 export * from './session-cache/noop-session-cache-strategy';
@@ -49,4 +49,8 @@ export * from './shipping-method/default-shipping-calculator';
 export * from './shipping-method/default-shipping-eligibility-checker';
 export * from './shipping-method/shipping-calculator';
 export * from './shipping-method/shipping-eligibility-checker';
+export * from './tax/default-tax-line-calculation-strategy';
+export * from './tax/default-tax-zone-strategy';
+export * from './tax/tax-line-calculation-strategy';
+export * from './tax/tax-zone-strategy';
 export * from './vendure-config';

+ 10 - 1
packages/core/src/service/helpers/fulfillment-state-machine/fulfillment-state-machine.ts

@@ -12,6 +12,7 @@ import { ConfigService } from '../../../config/config.service';
 import { Fulfillment } from '../../../entity/fulfillment/fulfillment.entity';
 import { Order } from '../../../entity/order/order.entity';
 import { HistoryService } from '../../services/history.service';
+import { StockMovementService } from '../../services/stock-movement.service';
 
 import {
     FulfillmentState,
@@ -24,7 +25,11 @@ export class FulfillmentStateMachine {
     readonly config: StateMachineConfig<FulfillmentState, FulfillmentTransitionData>;
     private readonly initialState: FulfillmentState = 'Created';
 
-    constructor(private configService: ConfigService, private historyService: HistoryService) {
+    constructor(
+        private configService: ConfigService,
+        private historyService: HistoryService,
+        private stockMovementService: StockMovementService,
+    ) {
         this.config = this.initConfig();
     }
 
@@ -93,6 +98,10 @@ export class FulfillmentStateMachine {
             }),
         );
         await Promise.all(historyEntryPromises);
+        if (toState === 'Cancelled') {
+            const { ctx, orders, fulfillment } = data;
+            await this.stockMovementService.createCancellationsForOrderItems(ctx, fulfillment.orderItems);
+        }
     }
 
     private initConfig(): StateMachineConfig<FulfillmentState, FulfillmentTransitionData> {

+ 3 - 3
packages/create/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/create",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "license": "MIT",
   "bin": {
     "create": "./index.js"
@@ -28,13 +28,13 @@
     "@types/handlebars": "^4.1.0",
     "@types/listr": "^0.14.2",
     "@types/semver": "^6.2.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/core": "^1.3.3",
     "rimraf": "^3.0.2",
     "ts-node": "^10.2.1",
     "typescript": "4.3.5"
   },
   "dependencies": {
-    "@vendure/common": "^1.3.2",
+    "@vendure/common": "^1.3.3",
     "chalk": "^4.1.0",
     "commander": "^7.1.0",
     "cross-spawn": "^7.0.3",

+ 9 - 9
packages/dev-server/package.json

@@ -1,6 +1,6 @@
 {
   "name": "dev-server",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "main": "index.js",
   "license": "MIT",
   "private": true,
@@ -14,18 +14,18 @@
     "load-test:100k": "node -r ts-node/register load-testing/run-load-test.ts 100000"
   },
   "dependencies": {
-    "@vendure/admin-ui-plugin": "^1.3.2",
-    "@vendure/asset-server-plugin": "^1.3.2",
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
-    "@vendure/elasticsearch-plugin": "^1.3.2",
-    "@vendure/email-plugin": "^1.3.2",
+    "@vendure/admin-ui-plugin": "^1.3.3",
+    "@vendure/asset-server-plugin": "^1.3.3",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
+    "@vendure/elasticsearch-plugin": "^1.3.3",
+    "@vendure/email-plugin": "^1.3.3",
     "typescript": "4.3.5"
   },
   "devDependencies": {
     "@types/csv-stringify": "^3.1.0",
-    "@vendure/testing": "^1.3.2",
-    "@vendure/ui-devkit": "^1.3.2",
+    "@vendure/testing": "^1.3.3",
+    "@vendure/ui-devkit": "^1.3.3",
     "concurrently": "^5.0.0",
     "csv-stringify": "^5.3.3"
   }

+ 1 - 4
packages/elasticsearch-plugin/e2e/elasticsearch-plugin-uuid.e2e-spec.ts

@@ -25,10 +25,7 @@ if (process.env.CI) {
 // https://github.com/vendure-ecommerce/vendure/issues/494
 describe('Elasticsearch plugin with UuidIdStrategy', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
-            apiOptions: {
-                port: 4050,
-            },
+        mergeConfig(testConfig(), {
             entityOptions: { entityIdStrategy: new UuidIdStrategy() },
             logger: new DefaultLogger({ level: LogLevel.Info }),
             plugins: [

+ 1 - 4
packages/elasticsearch-plugin/e2e/elasticsearch-plugin.e2e-spec.ts

@@ -114,10 +114,7 @@ const INDEX_PREFIX = 'e2e-tests';
 
 describe('Elasticsearch plugin', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
-            apiOptions: {
-                port: 4050,
-            },
+        mergeConfig(testConfig(), {
             logger: new DefaultLogger({ level: LogLevel.Info }),
             plugins: [
                 ElasticsearchPlugin.init({

+ 4 - 4
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -2966,7 +2966,7 @@ export type OrderItem = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3014,7 +3014,7 @@ export type OrderLine = Node & {
     /** The price of a single unit including discounts and tax */
     discountedUnitPriceWithTax: Scalars['Int'];
     /**
-     * The actual unit price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual unit price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderItem, and is used in tax
      * and refund calculations.
      */
@@ -3026,14 +3026,14 @@ export type OrderLine = Node & {
     taxRate: Scalars['Float'];
     /** The total price of the line excluding tax and discounts. */
     linePrice: Scalars['Int'];
-    /** The total price of the line including tax bit excluding discounts. */
+    /** The total price of the line including tax but excluding discounts. */
     linePriceWithTax: Scalars['Int'];
     /** The price of the line including discounts, excluding tax */
     discountedLinePrice: Scalars['Int'];
     /** The price of the line including discounts and tax */
     discountedLinePriceWithTax: Scalars['Int'];
     /**
-     * The actual line price, taking into account both item discounts _and_ prorated (proportially-distributed)
+     * The actual line price, taking into account both item discounts _and_ prorated (proportionally-distributed)
      * Order-level discounts. This value is the true economic value of the OrderLine, and is used in tax
      * and refund calculations.
      */

+ 4 - 4
packages/elasticsearch-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/elasticsearch-plugin",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -12,7 +12,7 @@
     "build": "rimraf lib && tsc -p ./tsconfig.build.json",
     "lint": "tslint --fix --project ./",
     "test": "jest --config ./jest.config.js",
-    "e2e": "node e2e/check-connection.js || jest --config ../../e2e-common/jest-config.js --runInBand --package=elasticsearch-plugin"
+    "e2e": "node e2e/check-connection.js || jest --config ../../e2e-common/jest-config.js --package=elasticsearch-plugin"
   },
   "homepage": "https://www.vendure.io/",
   "funding": "https://github.com/sponsors/michaelbromley",
@@ -25,8 +25,8 @@
     "fast-deep-equal": "^3.1.3"
   },
   "devDependencies": {
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"
   }

+ 3 - 3
packages/email-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/email-plugin",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -35,8 +35,8 @@
     "@types/fs-extra": "^9.0.1",
     "@types/handlebars": "^4.1.0",
     "@types/mjml": "^4.0.4",
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
     "rimraf": "^3.0.2",
     "typescript": "4.3.5"
   }

+ 1 - 1
packages/job-queue-plugin/e2e/bullmq-job-queue-plugin.e2e-spec.ts

@@ -24,7 +24,7 @@ describe('BullMQJobQueuePlugin', () => {
     });
 
     const { server, adminClient, shopClient } = createTestEnvironment(
-        mergeConfig(testConfig, {
+        mergeConfig(testConfig(), {
             apiOptions: {
                 port: 4050,
             },

+ 3 - 3
packages/job-queue-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/job-queue-plugin",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "license": "MIT",
   "main": "package/index.js",
   "types": "package/index.d.ts",
@@ -24,8 +24,8 @@
   "devDependencies": {
     "@google-cloud/pubsub": "^2.8.0",
     "@types/redis": "^2.8.28",
-    "@vendure/common": "^1.3.2",
-    "@vendure/core": "^1.3.2",
+    "@vendure/common": "^1.3.3",
+    "@vendure/core": "^1.3.3",
     "bullmq": "^1.40.1",
     "redis": "^3.0.2",
     "rimraf": "^3.0.2",

+ 1 - 1
packages/payment-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/payments-plugin",
-    "version": "1.3.2",
+    "version": "1.3.3",
     "license": "MIT",
     "main": "package/index.js",
     "types": "package/index.d.ts",

Неке датотеке нису приказане због велике количине промена