Parcourir la source

refactor(server): Switch to csv-import based data generation

Closes #64
Michael Bromley il y a 7 ans
Parent
commit
5758e3792c
65 fichiers modifiés avec 753 ajouts et 655 suppressions
  1. 1 0
      .gitignore
  2. 2 21
      server/cli/populate.ts
  3. 15 15
      server/dev-config.ts
  4. 7 7
      server/e2e/__snapshots__/facet.e2e-spec.ts.snap
  5. 36 36
      server/e2e/__snapshots__/import.e2e-spec.ts.snap
  6. 22 22
      server/e2e/__snapshots__/product-category.e2e-spec.ts.snap
  7. 55 51
      server/e2e/__snapshots__/product.e2e-spec.ts.snap
  8. 9 8
      server/e2e/administrator.e2e-spec.ts
  9. 2 2
      server/e2e/auth.e2e-spec.ts
  10. 1 1
      server/e2e/config/test-config.ts
  11. 3 2
      server/e2e/country.e2e-spec.ts
  12. 4 3
      server/e2e/customer.e2e-spec.ts
  13. 3 2
      server/e2e/facet.e2e-spec.ts
  14. BIN
      server/e2e/fixtures/assets/alexandru-acea-686569-unsplash.jpg
  15. 0 0
      server/e2e/fixtures/assets/box-of-12.jpg
  16. 0 0
      server/e2e/fixtures/assets/box-of-8.jpg
  17. BIN
      server/e2e/fixtures/assets/derick-david-409858-unsplash.jpg
  18. BIN
      server/e2e/fixtures/assets/florian-olivo-1166419-unsplash.jpg
  19. 0 0
      server/e2e/fixtures/assets/pps1.jpg
  20. 0 0
      server/e2e/fixtures/assets/pps2.jpg
  21. BIN
      server/e2e/fixtures/assets/vincent-botta-736919-unsplash.jpg
  22. 21 0
      server/e2e/fixtures/e2e-initial-data.ts
  23. 1 0
      server/e2e/fixtures/e2e-products-empty.csv
  24. 35 0
      server/e2e/fixtures/e2e-products-full.csv
  25. 5 0
      server/e2e/fixtures/e2e-products-minimal.csv
  26. 1 1
      server/e2e/import.e2e-spec.ts
  27. 2 1
      server/e2e/order.e2e-spec.ts
  28. 2 1
      server/e2e/product-category.e2e-spec.ts
  29. 11 9
      server/e2e/product.e2e-spec.ts
  30. 2 1
      server/e2e/promotion.e2e-spec.ts
  31. 5 4
      server/e2e/role.e2e-spec.ts
  32. 1 1
      server/e2e/test-client.ts
  33. 13 3
      server/e2e/test-server.ts
  34. 11 10
      server/e2e/zone.e2e-spec.ts
  35. BIN
      server/mock-data/assets/adam-birkett-239153-unsplash.jpg
  36. BIN
      server/mock-data/assets/alexandru-acea-686569-unsplash.jpg
  37. BIN
      server/mock-data/assets/brandi-redd-104140-unsplash.jpg
  38. BIN
      server/mock-data/assets/florian-klauer-14840-unsplash.jpg
  39. BIN
      server/mock-data/assets/florian-olivo-1166419-unsplash.jpg
  40. BIN
      server/mock-data/assets/juan-gomez-674574-unsplash.jpg
  41. BIN
      server/mock-data/assets/mark-tegethoff-667351-unsplash.jpg
  42. BIN
      server/mock-data/assets/max-tarkhov-737999-unsplash.jpg
  43. BIN
      server/mock-data/assets/michael-guite-571169-unsplash.jpg
  44. BIN
      server/mock-data/assets/neonbrand-428982-unsplash.jpg
  45. BIN
      server/mock-data/assets/neslihan-gunaydin-3493-unsplash.jpg
  46. BIN
      server/mock-data/assets/nik-shuliahin-619349-unsplash.jpg
  47. BIN
      server/mock-data/assets/paul-weaver-1120584-unsplash.jpg
  48. BIN
      server/mock-data/assets/pierre-chatel-innocenti-483198-unsplash.jpg
  49. BIN
      server/mock-data/assets/robert-shunev-528016-unsplash.jpg
  50. BIN
      server/mock-data/assets/stoica-ionela-530966-unsplash.jpg
  51. BIN
      server/mock-data/assets/vincent-botta-736919-unsplash.jpg
  52. BIN
      server/mock-data/assets/vincent-liu-525429-unsplash.jpg
  53. BIN
      server/mock-data/assets/zoltan-kovacs-642412-unsplash.jpg
  54. BIN
      server/mock-data/assets/zoltan-tasi-423051-unsplash.jpg
  55. 262 0
      server/mock-data/data-sources/initial-data.ts
  56. 40 0
      server/mock-data/data-sources/products.csv
  57. 1 347
      server/mock-data/mock-data.service.ts
  58. 7 2
      server/mock-data/populate-cli.ts
  59. 38 15
      server/mock-data/populate.ts
  60. 1 1
      server/package.json
  61. 2 0
      server/src/data-import/index.ts
  62. 16 1
      server/src/data-import/providers/importer/importer.ts
  63. 3 2
      server/src/data-import/providers/populator/populator.ts
  64. 2 2
      server/src/plugin/default-asset-server-plugin/default-asset-storage-strategy.ts
  65. 111 84
      server/yarn.lock

+ 1 - 0
.gitignore

@@ -390,6 +390,7 @@ dist
 server/e2e/__data__/*
 server/assets
 server/dist
+server/*.sqlite
 !server/e2e/__data__/.gitkeep
 server/test-emails
 server/src/email/preview/output

+ 2 - 21
server/cli/populate.ts

@@ -1,9 +1,6 @@
 import { INestApplication } from '@nestjs/common';
 import fs from 'fs-extra';
 import path from 'path';
-import ProgressBar from 'progress';
-import { tap } from 'rxjs/operators';
-import { Connection } from 'typeorm';
 
 import { logColored } from './cli-utils';
 // tslint:disable-next-line:no-var-requires
@@ -114,24 +111,8 @@ async function importProductsFromFile(app: INestApplication, csvPath: string, la
     // import the csv of same product data
     const importer = app.get(Importer);
     const productData = await fs.readFile(csvPath, 'utf-8');
-    let bar: ProgressBar | undefined;
-
-    const importResult = await importer
-        .parseAndImport(productData, languageCode)
-        .pipe(
-            tap((progress: any) => {
-                if (!bar) {
-                    bar = new ProgressBar('  importing [:bar] :percent :etas  Importing: :prodName', {
-                        complete: '=',
-                        incomplete: ' ',
-                        total: progress.processed,
-                        width: 40,
-                    });
-                }
-                bar.tick({ prodName: progress.currentProduct });
-            }),
-        )
-        .toPromise();
+
+    const importResult = await importer.parseAndImport(productData, languageCode, true).toPromise();
     if (importResult.errors.length) {
         const errorFile = path.join(process.cwd(), 'vendure-import-error.log');
         console.log(

+ 15 - 15
server/dev-config.ts

@@ -21,26 +21,26 @@ export const devConfig: VendureConfig = {
     port: API_PORT,
     apiPath: API_PATH,
     dbConnectionOptions: {
-        synchronize: false,
-        logging: true,
+        synchronize: true,
+        logging: false,
 
-        type: 'mysql',
-        host: '192.168.99.100',
-        port: 3306,
-        username: 'root',
-        password: '',
-        database: 'vendure-dev',
+        // type: 'mysql',
+        // host: '192.168.99.100',
+        // port: 3306,
+        // username: 'root',
+        // password: '',
+        // database: 'vendure-dev',
 
         // type: 'sqljs',
         // database: new Uint8Array([]),
         // location:  path.join(__dirname, 'vendure.sqlite'),
 
-        // type: 'postgres',
-        // host: '127.0.0.1',
-        // port: 5432,
-        // username: 'postgres',
-        // password: 'Be70',
-        // database: 'vendure',
+        type: 'postgres',
+        host: '127.0.0.1',
+        port: 5432,
+        username: 'postgres',
+        password: 'Be70',
+        database: 'vendure',
     },
     orderProcessOptions: {} as OrderProcessOptions<any>,
     paymentOptions: {
@@ -64,7 +64,7 @@ export const devConfig: VendureConfig = {
         new DefaultAssetServerPlugin({
             route: 'assets',
             assetUploadDir: path.join(__dirname, 'assets'),
-            port: 4000,
+            port: 3002,
         }),
         new DefaultSearchPlugin(),
         new AdminUiPlugin({

+ 7 - 7
server/e2e/__snapshots__/facet.e2e-spec.ts.snap

@@ -8,7 +8,7 @@ Object {
   "name": "Speaker Type",
   "translations": Array [
     Object {
-      "id": "T_3",
+      "id": "T_2",
       "languageCode": "en",
       "name": "Speaker Type",
     },
@@ -20,12 +20,12 @@ Object {
         "id": "T_2",
         "name": "Speaker Type",
       },
-      "id": "T_11",
+      "id": "T_7",
       "languageCode": "en",
       "name": "Portable",
       "translations": Array [
         Object {
-          "id": "T_21",
+          "id": "T_7",
           "languageCode": "en",
           "name": "Portable",
         },
@@ -43,12 +43,12 @@ Array [
       "id": "T_2",
       "name": "Speaker Category",
     },
-    "id": "T_13",
+    "id": "T_9",
     "languageCode": "en",
     "name": "PC Speakers",
     "translations": Array [
       Object {
-        "id": "T_23",
+        "id": "T_9",
         "languageCode": "en",
         "name": "PC Speakers",
       },
@@ -60,12 +60,12 @@ Array [
       "id": "T_2",
       "name": "Speaker Category",
     },
-    "id": "T_12",
+    "id": "T_8",
     "languageCode": "en",
     "name": "Hi Fi Speakers",
     "translations": Array [
       Object {
-        "id": "T_22",
+        "id": "T_8",
         "languageCode": "en",
         "name": "Hi Fi Speakers",
       },

+ 36 - 36
server/e2e/__snapshots__/import.e2e-spec.ts.snap

@@ -5,18 +5,18 @@ Array [
   Object {
     "assets": Array [
       Object {
-        "id": "T_6",
+        "id": "T_1",
         "name": "pps1.jpg",
       },
       Object {
-        "id": "T_7",
+        "id": "T_2",
         "name": "pps2.jpg",
       },
     ],
     "description": "A great device for stretching paper.",
     "facetValues": Array [],
     "featuredAsset": Object {
-      "id": "T_6",
+      "id": "T_1",
       "name": "pps1.jpg",
     },
     "id": "T_1",
@@ -24,7 +24,7 @@ Array [
     "optionGroups": Array [
       Object {
         "code": "perfect-paper-stretcher-size",
-        "id": "T_2",
+        "id": "T_1",
         "name": "size",
       },
     ],
@@ -39,7 +39,7 @@ Array [
               "id": "T_1",
               "name": "Brand",
             },
-            "id": "T_11",
+            "id": "T_1",
             "name": "KB",
           },
           Object {
@@ -48,7 +48,7 @@ Array [
               "id": "T_2",
               "name": "Type",
             },
-            "id": "T_12",
+            "id": "T_2",
             "name": "Accessory",
           },
         ],
@@ -58,7 +58,7 @@ Array [
         "options": Array [
           Object {
             "code": "half-imperial",
-            "id": "T_3",
+            "id": "T_1",
           },
         ],
         "price": 4530,
@@ -77,7 +77,7 @@ Array [
               "id": "T_1",
               "name": "Brand",
             },
-            "id": "T_11",
+            "id": "T_1",
             "name": "KB",
           },
           Object {
@@ -86,7 +86,7 @@ Array [
               "id": "T_2",
               "name": "Type",
             },
-            "id": "T_12",
+            "id": "T_2",
             "name": "Accessory",
           },
         ],
@@ -96,7 +96,7 @@ Array [
         "options": Array [
           Object {
             "code": "quarter-imperial",
-            "id": "T_4",
+            "id": "T_2",
           },
         ],
         "price": 3250,
@@ -115,7 +115,7 @@ Array [
               "id": "T_1",
               "name": "Brand",
             },
-            "id": "T_11",
+            "id": "T_1",
             "name": "KB",
           },
           Object {
@@ -124,7 +124,7 @@ Array [
               "id": "T_2",
               "name": "Type",
             },
-            "id": "T_12",
+            "id": "T_2",
             "name": "Accessory",
           },
         ],
@@ -134,7 +134,7 @@ Array [
         "options": Array [
           Object {
             "code": "full-imperial",
-            "id": "T_5",
+            "id": "T_3",
           },
         ],
         "price": 5950,
@@ -165,7 +165,7 @@ Array [
               "id": "T_1",
               "name": "Brand",
             },
-            "id": "T_13",
+            "id": "T_3",
             "name": "Mabef",
           },
           Object {
@@ -174,7 +174,7 @@ Array [
               "id": "T_2",
               "name": "Type",
             },
-            "id": "T_14",
+            "id": "T_4",
             "name": "Easel",
           },
         ],
@@ -201,7 +201,7 @@ Array [
     "optionGroups": Array [
       Object {
         "code": "giotto-mega-pencils-box-size",
-        "id": "T_3",
+        "id": "T_2",
         "name": "box size",
       },
     ],
@@ -210,7 +210,7 @@ Array [
       Object {
         "assets": Array [
           Object {
-            "id": "T_8",
+            "id": "T_3",
             "name": "box-of-8.jpg",
           },
         ],
@@ -221,12 +221,12 @@ Array [
               "id": "T_3",
               "name": "Collection",
             },
-            "id": "T_15",
+            "id": "T_5",
             "name": "Xmas Sale",
           },
         ],
         "featuredAsset": Object {
-          "id": "T_8",
+          "id": "T_3",
           "name": "box-of-8.jpg",
         },
         "id": "T_5",
@@ -234,7 +234,7 @@ Array [
         "options": Array [
           Object {
             "code": "box-of-8",
-            "id": "T_6",
+            "id": "T_4",
           },
         ],
         "price": 416,
@@ -247,7 +247,7 @@ Array [
       Object {
         "assets": Array [
           Object {
-            "id": "T_9",
+            "id": "T_4",
             "name": "box-of-12.jpg",
           },
         ],
@@ -258,12 +258,12 @@ Array [
               "id": "T_3",
               "name": "Collection",
             },
-            "id": "T_15",
+            "id": "T_5",
             "name": "Xmas Sale",
           },
         ],
         "featuredAsset": Object {
-          "id": "T_9",
+          "id": "T_4",
           "name": "box-of-12.jpg",
         },
         "id": "T_6",
@@ -271,7 +271,7 @@ Array [
         "options": Array [
           Object {
             "code": "box-of-12",
-            "id": "T_7",
+            "id": "T_5",
           },
         ],
         "price": 624,
@@ -292,7 +292,7 @@ Array [
           "id": "T_4",
           "name": "Material",
         },
-        "id": "T_16",
+        "id": "T_6",
         "name": "Denim",
       },
       Object {
@@ -300,7 +300,7 @@ Array [
           "id": "T_3",
           "name": "Collection",
         },
-        "id": "T_17",
+        "id": "T_7",
         "name": "clothes",
       },
     ],
@@ -310,12 +310,12 @@ Array [
     "optionGroups": Array [
       Object {
         "code": "artists-smock-size",
-        "id": "T_4",
+        "id": "T_3",
         "name": "size",
       },
       Object {
         "code": "artists-smock-colour",
-        "id": "T_5",
+        "id": "T_4",
         "name": "colour",
       },
     ],
@@ -330,11 +330,11 @@ Array [
         "options": Array [
           Object {
             "code": "small",
-            "id": "T_8",
+            "id": "T_6",
           },
           Object {
             "code": "beige",
-            "id": "T_10",
+            "id": "T_8",
           },
         ],
         "price": 1199,
@@ -353,11 +353,11 @@ Array [
         "options": Array [
           Object {
             "code": "large",
-            "id": "T_9",
+            "id": "T_7",
           },
           Object {
             "code": "beige",
-            "id": "T_10",
+            "id": "T_8",
           },
         ],
         "price": 1199,
@@ -376,11 +376,11 @@ Array [
         "options": Array [
           Object {
             "code": "small",
-            "id": "T_8",
+            "id": "T_6",
           },
           Object {
             "code": "navy",
-            "id": "T_11",
+            "id": "T_9",
           },
         ],
         "price": 1199,
@@ -399,11 +399,11 @@ Array [
         "options": Array [
           Object {
             "code": "large",
-            "id": "T_9",
+            "id": "T_7",
           },
           Object {
             "code": "navy",
-            "id": "T_11",
+            "id": "T_9",
           },
         ],
         "price": 1199,

+ 22 - 22
server/e2e/__snapshots__/product-category.e2e-spec.ts.snap

@@ -7,18 +7,18 @@ Object {
       "fileSize": 4,
       "id": "T_1",
       "mimeType": "image/jpeg",
-      "name": "charles-deluvio-695736-unsplash.jpg",
-      "preview": "test-url/test-assets/charles-deluvio-695736-unsplash__preview.jpg",
-      "source": "test-url/test-assets/charles-deluvio-695736-unsplash.jpg",
+      "name": "derick-david-409858-unsplash.jpg",
+      "preview": "test-url/test-assets/derick-david-409858-unsplash__preview.jpg",
+      "source": "test-url/test-assets/derick-david-409858-unsplash.jpg",
       "type": "IMAGE",
     },
     Object {
       "fileSize": 4,
       "id": "T_2",
       "mimeType": "image/jpeg",
-      "name": "chuttersnap-584518-unsplash.jpg",
-      "preview": "test-url/test-assets/chuttersnap-584518-unsplash__preview.jpg",
-      "source": "test-url/test-assets/chuttersnap-584518-unsplash.jpg",
+      "name": "alexandru-acea-686569-unsplash.jpg",
+      "preview": "test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg",
+      "source": "test-url/test-assets/alexandru-acea-686569-unsplash.jpg",
       "type": "IMAGE",
     },
   ],
@@ -26,18 +26,18 @@ Object {
   "description": "",
   "facetValues": Array [
     Object {
-      "code": "larkin-group",
+      "code": "electronics",
       "id": "T_1",
-      "name": "Larkin Group",
+      "name": "electronics",
     },
   ],
   "featuredAsset": Object {
     "fileSize": 4,
-    "id": "T_2",
+    "id": "T_1",
     "mimeType": "image/jpeg",
-    "name": "chuttersnap-584518-unsplash.jpg",
-    "preview": "test-url/test-assets/chuttersnap-584518-unsplash__preview.jpg",
-    "source": "test-url/test-assets/chuttersnap-584518-unsplash.jpg",
+    "name": "derick-david-409858-unsplash.jpg",
+    "preview": "test-url/test-assets/derick-david-409858-unsplash__preview.jpg",
+    "source": "test-url/test-assets/derick-david-409858-unsplash.jpg",
     "type": "IMAGE",
   },
   "id": "T_2",
@@ -63,11 +63,11 @@ Object {
   "assets": Array [
     Object {
       "fileSize": 4,
-      "id": "T_2",
+      "id": "T_1",
       "mimeType": "image/jpeg",
-      "name": "chuttersnap-584518-unsplash.jpg",
-      "preview": "test-url/test-assets/chuttersnap-584518-unsplash__preview.jpg",
-      "source": "test-url/test-assets/chuttersnap-584518-unsplash.jpg",
+      "name": "derick-david-409858-unsplash.jpg",
+      "preview": "test-url/test-assets/derick-david-409858-unsplash__preview.jpg",
+      "source": "test-url/test-assets/derick-david-409858-unsplash.jpg",
       "type": "IMAGE",
     },
   ],
@@ -75,18 +75,18 @@ Object {
   "description": "Apple stuff ",
   "facetValues": Array [
     Object {
-      "code": "lindgren-conn-and-king",
+      "code": "photo",
       "id": "T_3",
-      "name": "Lindgren, Conn and King",
+      "name": "photo",
     },
   ],
   "featuredAsset": Object {
     "fileSize": 4,
-    "id": "T_2",
+    "id": "T_1",
     "mimeType": "image/jpeg",
-    "name": "chuttersnap-584518-unsplash.jpg",
-    "preview": "test-url/test-assets/chuttersnap-584518-unsplash__preview.jpg",
-    "source": "test-url/test-assets/chuttersnap-584518-unsplash.jpg",
+    "name": "derick-david-409858-unsplash.jpg",
+    "preview": "test-url/test-assets/derick-david-409858-unsplash__preview.jpg",
+    "source": "test-url/test-assets/derick-david-409858-unsplash.jpg",
     "type": "IMAGE",
   },
   "id": "T_4",

+ 55 - 51
server/e2e/__snapshots__/product.e2e-spec.ts.snap

@@ -63,58 +63,62 @@ Object {
   "assets": Array [
     Object {
       "fileSize": 4,
-      "id": "T_1",
+      "id": "T_2",
       "mimeType": "image/jpeg",
-      "name": "charles-deluvio-695736-unsplash.jpg",
-      "preview": "test-url/test-assets/charles-deluvio-695736-unsplash__preview.jpg",
-      "source": "test-url/test-assets/charles-deluvio-695736-unsplash.jpg",
+      "name": "alexandru-acea-686569-unsplash.jpg",
+      "preview": "test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg",
+      "source": "test-url/test-assets/alexandru-acea-686569-unsplash.jpg",
       "type": "IMAGE",
     },
+  ],
+  "description": "Discover a truly immersive viewing experience with this monitor curved more deeply than any other. Wrapping around your field of vision the 1,800 R screencreates a wider field of view, enhances depth perception, and minimises peripheral distractions to draw you deeper in to your content.",
+  "facetValues": Array [
     Object {
-      "fileSize": 4,
-      "id": "T_5",
-      "mimeType": "image/jpeg",
-      "name": "mikkel-bech-748940-unsplash.jpg",
-      "preview": "test-url/test-assets/mikkel-bech-748940-unsplash__preview.jpg",
-      "source": "test-url/test-assets/mikkel-bech-748940-unsplash.jpg",
-      "type": "IMAGE",
+      "code": "electronics",
+      "facet": Object {
+        "id": "T_1",
+        "name": "category",
+      },
+      "id": "T_1",
+      "name": "electronics",
+    },
+    Object {
+      "code": "computers",
+      "facet": Object {
+        "id": "T_1",
+        "name": "category",
+      },
+      "id": "T_2",
+      "name": "computers",
     },
   ],
-  "description": "en Accusantium sed libero repudiandae.",
-  "facetValues": Array [],
   "featuredAsset": Object {
     "fileSize": 4,
-    "id": "T_5",
+    "id": "T_2",
     "mimeType": "image/jpeg",
-    "name": "mikkel-bech-748940-unsplash.jpg",
-    "preview": "test-url/test-assets/mikkel-bech-748940-unsplash__preview.jpg",
-    "source": "test-url/test-assets/mikkel-bech-748940-unsplash.jpg",
+    "name": "alexandru-acea-686569-unsplash.jpg",
+    "preview": "test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg",
+    "source": "test-url/test-assets/alexandru-acea-686569-unsplash.jpg",
     "type": "IMAGE",
   },
   "id": "T_2",
   "languageCode": "en",
-  "name": "en Intelligent Cotton Salad",
+  "name": "Curvy Monitor",
   "optionGroups": Array [
     Object {
-      "code": "size",
-      "id": "T_1",
+      "code": "curvy-monitor-monitor-size",
+      "id": "T_3",
       "languageCode": "en",
-      "name": "Size",
+      "name": "monitor size",
     },
   ],
-  "slug": "en intelligent-cotton-salad",
+  "slug": "curvy-monitor",
   "translations": Array [
     Object {
-      "description": "en Accusantium sed libero repudiandae.",
+      "description": "Discover a truly immersive viewing experience with this monitor curved more deeply than any other. Wrapping around your field of vision the 1,800 R screencreates a wider field of view, enhances depth perception, and minimises peripheral distractions to draw you deeper in to your content.",
       "languageCode": "en",
-      "name": "en Intelligent Cotton Salad",
-      "slug": "en intelligent-cotton-salad",
-    },
-    Object {
-      "description": "de Accusantium sed libero repudiandae.",
-      "languageCode": "de",
-      "name": "de Intelligent Cotton Salad",
-      "slug": "de intelligent-cotton-salad",
+      "name": "Curvy Monitor",
+      "slug": "curvy-monitor",
     },
   ],
 }
@@ -122,25 +126,25 @@ Object {
 
 exports[`Product resolver products list query sorts by name 1`] = `
 Array [
-  "en Awesome Cotton Keyboard",
-  "en Awesome Granite Chair",
-  "en Ergonomic Metal Sausages",
-  "en Fantastic Granite Towels",
-  "en Generic Frozen Tuna",
-  "en Generic Metal Keyboard",
-  "en Handcrafted Wooden Soap",
-  "en Handmade Soft Hat",
-  "en Handmade Wooden Car",
-  "en Intelligent Cotton Salad",
-  "en Intelligent Metal Shoes",
-  "en Intelligent Rubber Chips",
-  "en Intelligent Wooden Hat",
-  "en Licensed Frozen Car",
-  "en Practical Frozen Fish",
-  "en Practical Rubber Pants",
-  "en Rustic Steel Gloves",
-  "en Small Wooden Chair",
-  "en Tasty Soft Gloves",
-  "en Unbranded Fresh Hat",
+  "Bonsai Tree",
+  "Boxing Gloves",
+  "Camera Lens",
+  "Clacky Keyboard",
+  "Cruiser Skateboard",
+  "Curvy Monitor",
+  "Football",
+  "Gaming PC",
+  "Hard Drive",
+  "Instant Camera",
+  "Laptop",
+  "Orchid",
+  "Road Bike",
+  "Running Shoe",
+  "SLR Camera",
+  "Skipping Rope",
+  "Spiky Cactus",
+  "Tent",
+  "Tripod",
+  "USB Cable",
 ]
 `;

+ 9 - 8
server/e2e/administrator.e2e-spec.ts

@@ -1,10 +1,4 @@
-import {
-    Administrator,
-    CreateAdministrator,
-    GetAdministrator,
-    GetAdministrators,
-    UpdateAdministrator,
-} from '../../shared/generated-types';
+import path from 'path';
 
 import {
     CREATE_ADMINISTRATOR,
@@ -12,6 +6,13 @@ import {
     GET_ADMINISTRATORS,
     UPDATE_ADMINISTRATOR,
 } from '../../admin-ui/src/app/data/definitions/administrator-definitions';
+import {
+    Administrator,
+    CreateAdministrator,
+    GetAdministrator,
+    GetAdministrators,
+    UpdateAdministrator,
+} from '../../shared/generated-types';
 
 import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
 import { TestClient } from './test-client';
@@ -25,7 +26,7 @@ describe('Administrator resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 1,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
             customerCount: 1,
         });
         await client.init();

+ 2 - 2
server/e2e/auth.e2e-spec.ts

@@ -48,7 +48,7 @@ describe('Authorization & permissions', () => {
     beforeAll(async () => {
         const token = await server.init(
             {
-                productCount: 1,
+                productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
                 customerCount: 1,
             },
             {
@@ -354,7 +354,7 @@ describe('Expiring registration token', () => {
     beforeAll(async () => {
         const token = await server.init(
             {
-                productCount: 1,
+                productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
                 customerCount: 1,
             },
             {

+ 1 - 1
server/e2e/config/test-config.ts

@@ -48,7 +48,7 @@ export const testConfig: VendureConfig = {
         },
     },
     importExportOptions: {
-        importAssetsDir: path.join(__dirname, '..', 'fixtures'),
+        importAssetsDir: path.join(__dirname, '..', 'fixtures/assets'),
     },
     assetOptions: {
         assetNamingStrategy: new DefaultAssetNamingStrategy(),

+ 3 - 2
server/e2e/country.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     CREATE_COUNTRY,
@@ -32,7 +33,7 @@ describe('Facet resolver', () => {
 
     beforeAll(async () => {
         await server.init({
-            productCount: 2,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
             customerCount: 1,
         });
         await client.init();
@@ -45,7 +46,7 @@ describe('Facet resolver', () => {
     it('countries', async () => {
         const result = await client.query<GetCountryList.Query>(GET_COUNTRY_LIST, {});
 
-        expect(result.countries.totalItems).toBe(9);
+        expect(result.countries.totalItems).toBe(7);
         countries = result.countries.items;
         GB = countries.find(c => c.code === 'GB')!;
         AT = countries.find(c => c.code === 'AT')!;

+ 4 - 3
server/e2e/customer.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     CREATE_CUSTOMER_ADDRESS,
@@ -33,7 +34,7 @@ describe('Customer resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 1,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
             customerCount: 5,
         });
         await client.init();
@@ -100,7 +101,7 @@ describe('Customer resolver', () => {
                 postalCode: 'postalCode',
                 country: {
                     code: 'GB',
-                    name: 'United Kingdom of Great Britain and Northern Ireland',
+                    name: 'United Kingdom',
                 },
                 phoneNumber: 'phoneNumber',
                 defaultShippingAddress: false,
@@ -201,7 +202,7 @@ describe('Customer resolver', () => {
                 postalCode: '',
                 country: {
                     code: 'GB',
-                    name: 'United Kingdom of Great Britain and Northern Ireland',
+                    name: 'United Kingdom',
                 },
                 phoneNumber: '',
                 defaultShippingAddress: true,

+ 3 - 2
server/e2e/facet.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     CREATE_FACET,
@@ -44,7 +45,7 @@ describe('Facet resolver', () => {
 
     beforeAll(async () => {
         await server.init({
-            productCount: 2,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
             customerCount: 1,
         });
         await client.init();
@@ -126,7 +127,7 @@ describe('Facet resolver', () => {
 
         const { items } = result.facets;
         expect(items.length).toBe(2);
-        expect(items[0].name).toBe('Brand');
+        expect(items[0].name).toBe('category');
         expect(items[1].name).toBe('Speaker Category');
 
         brandFacet = items[0];

BIN
server/e2e/fixtures/assets/alexandru-acea-686569-unsplash.jpg


+ 0 - 0
server/e2e/fixtures/box-of-12.jpg → server/e2e/fixtures/assets/box-of-12.jpg


+ 0 - 0
server/e2e/fixtures/box-of-8.jpg → server/e2e/fixtures/assets/box-of-8.jpg


BIN
server/e2e/fixtures/assets/derick-david-409858-unsplash.jpg


BIN
server/e2e/fixtures/assets/florian-olivo-1166419-unsplash.jpg


+ 0 - 0
server/e2e/fixtures/pps1.jpg → server/e2e/fixtures/assets/pps1.jpg


+ 0 - 0
server/e2e/fixtures/pps2.jpg → server/e2e/fixtures/assets/pps2.jpg


BIN
server/e2e/fixtures/assets/vincent-botta-736919-unsplash.jpg


+ 21 - 0
server/e2e/fixtures/e2e-initial-data.ts

@@ -0,0 +1,21 @@
+import { LanguageCode } from '../../../shared/generated-types';
+import { InitialData } from '../../src/data-import';
+
+export const initialData: InitialData = {
+    defaultLanguage: LanguageCode.en,
+    defaultZone: 'Europe',
+    taxRates: [
+        { name: 'Standard Tax', percentage: 20 },
+        { name: 'Reduced Tax', percentage: 10 },
+        { name: 'Zero Tax', percentage: 0 },
+    ],
+    countries: [
+        { name: 'Australia', code: 'AU', zone: 'Oceania' },
+        { name: 'Austria', code: 'AT', zone: 'Europe' },
+        { name: 'Canada', code: 'CA', zone: 'Americas' },
+        { name: 'China', code: 'CN', zone: 'Asia' },
+        { name: 'South Africa', code: 'ZA', zone: 'Africa' },
+        { name: 'United Kingdom', code: 'GB', zone: 'Europe' },
+        { name: 'United States of America', code: 'US', zone: 'Americas' },
+    ],
+};

+ 1 - 0
server/e2e/fixtures/e2e-products-empty.csv

@@ -0,0 +1 @@
+name                 , slug                 , description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   , assets                                      , facets                                    , optionGroups       , optionValues         , sku          , price   , taxCategory , variantAssets , variantFacets

+ 35 - 0
server/e2e/fixtures/e2e-products-full.csv

@@ -0,0 +1,35 @@
+name               , slug               , description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   , assets                             , facets                                  , optionGroups      , optionValues        , sku          , price   , taxCategory , variantAssets , variantFacets
+Laptop             , laptop             , "Now equipped with seventh-generation Intel Core processors, Laptop is snappier than ever. From daily tasks like launching apps and opening files to more advanced computing, you can power through your day thanks to faster SSDs and Turbo Boost processing up to 3.6GHz."                                                                                                                                                                                                                  , derick-david-409858-unsplash.jpg   , category:electronics|category:computers , "screen size|RAM" , "13 inch|8GB"       , L2201308     , 1299.00 , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "15 inch|8GB"       , L2201508     , 1399.00 , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "13 inch|16GB"      , L2201316     , 2199.00 , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "15 inch|16GB"      , L2201516     , 2299.00 , standard    ,               ,
+Curvy Monitor      , curvy-monitor      , "Discover a truly immersive viewing experience with this monitor curved more deeply than any other. Wrapping around your field of vision the 1,800 R screencreates a wider field of view, enhances depth perception, and minimises peripheral distractions to draw you deeper in to your content."                                                                                                                                                                                            , alexandru-acea-686569-unsplash.jpg , category:electronics|category:computers , monitor size      , 24 inch             , C24F390      , 143.74  , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , 27 inch             , C27F390      , 169.94  , standard    ,               ,
+Gaming PC          , gaming-pc          , "This pc is optimised for gaming, and is also VR ready. The Intel Core-i7 CPU and High Performance GPU give the computer the raw power it needs to function at a high level."                                                                                                                                                                                                                                                                                                                 , florian-olivo-1166419-unsplash.jpg , category:electronics|category:computers , "cpu|HDD"         , "i7-8700|240GB SSD" , CGS480VR1063 , 1087.20 , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "R7-2700|240GB SSD" , CGS480VR1064 , 1099.95 , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "i7-8700|120GB SSD" , CGS480VR1065 , 931.20  , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , "R7-2700|120GB SSD" , CGS480VR1066 , 949.20  , standard    ,               ,
+Hard Drive         , hard-drive         , "Boost your PC storage with this internal hard drive, designed just for desktop and all-in-one PCs."                                                                                                                                                                                                                                                                                                                                                                                          , vincent-botta-736919-unsplash.jpg  , category:electronics|category:computers , "HDD capacity"    , 1TB                 , IHD455T1     , 37.99   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , 2TB                 , IHD455T2     , 53.74   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , 3TB                 , IHD455T3     , 78.96   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , 4TB                 , IHD455T4     , 92.99   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , 6TB                 , IHD455T6     , 134.35  , standard    ,               ,
+Clacky Keyboard    , clacky-keyboard    , "Let all your colleagues know that you are typing on this exclusive, colorful klicky-klacky keyboard. Huge travel on each keypress ensures maximum klack on each and every keystroke."                                                                                                                                                                                                                                                                                                        ,                                    , category:electronics|category:computers ,                   ,                     , A4TKLA45535  , 74.89   , standard    ,               ,
+USB Cable          , usb-cable          , "Solid conductors eliminate strand-interaction distortion and reduce jitter. As the surface is made of high-purity silver, the performance is very close to that of a solid silver cable, but priced much closer to solid copper cable."                                                                                                                                                                                                                                                      ,                                    , category:electronics|category:computers ,                   ,                     , USBCIN01.5MI , 69.00   , standard    ,               ,
+Instant Camera     , instant-camera     , "With its nostalgic design and simple point-and-shoot functionality, the Instant Camera is the perfect pick to get started with instant photography."                                                                                                                                                                                                                                                                                                                                         ,                                    , category:electronics|category:photo     ,                   ,                     , IC22MWDD     , 174.99  , standard    ,               ,
+Camera Lens        , camera-lens        , "This lens is a Di type lens using an optical system with improved multi-coating designed to function with digital SLR cameras as well as film cameras."                                                                                                                                                                                                                                                                                                                                      ,                                    , category:electronics|category:photo     ,                   ,                     , B0012UUP02   , 104.00  , standard    ,               ,
+Tripod             , tripod             , "Capture vivid, professional-style photographs with help from this lightweight tripod. The adjustable-height tripod makes it easy to achieve reliable stability and score just the right angle when going after that award-winning shot."                                                                                                                                                                                                                                                     ,                                    , category:electronics|category:photo     ,                   ,                     , B00XI87KV8   , 14.98   , standard    ,               ,
+SLR Camera         , slr-camera         , "Retro styled, portable in size and built around a powerful 24-megapixel APS-C CMOS sensor, this digital camera is the ideal companion for creative everyday photography. Packed full of high spec features such as an advanced hybrid autofocus system able to keep pace with even the most active subjects, a speedy 6fps continuous-shooting mode, high-resolution electronic viewfinder and intuitive swivelling touchscreen, it brings professional image making into everyone’s grasp." ,                                    , category:electronics|category:photo     ,                   ,                     , B07D75V44S   , 521.00  , standard    ,               ,
+Road Bike          , road-bike          , "Featuring a full carbon chassis - complete with cyclocross-specific carbon fork - and a component setup geared for hard use on the race circuit, it's got the low weight, exceptional efficiency and brilliant handling you'll need to stay at the front of the pack."                                                                                                                                                                                                                       ,                                    , category:sports equipment               ,                   ,                     , RB000844334  , 2499.00 , standard    ,               ,
+Skipping Rope      , skipping-rope      , "When you're working out you need a quality rope that doesn't tangle at every couple of jumps and with this sipping rope you won't have this problem."                                                                                                                                                                                                                                                                                                                                        ,                                    , category:sports equipment               ,                   ,                     , B07CNGXVXT   , 7.99    , standard    ,               ,
+Boxing Gloves      , boxing-gloves      , "Training gloves designed for optimum training. Our gloves promote proper punching technique because they are conformed to the natural shape of your fist. Dense, innovative two-layer foam provides better shock absorbency and full padding on the front, back and wrist to promote proper punching technique."                                                                                                                                                                             ,                                    , category:sports equipment               ,                   ,                     , B000ZYLPPU   , 33.04   , standard    ,               ,
+Tent               , tent               , "With tons of space inside (for max. 4 persons), full head height throughout the entire tent and an unusual and striking shape, this tent offers you everything you need."                                                                                                                                                                                                                                                                                                                    ,                                    , category:sports equipment               ,                   ,                     , 2000023510   , 214.93  , standard    ,               ,
+Cruiser Skateboard , cruiser-skateboard , "Based on the 1970s iconic shape, but made to a larger 69cm size, with updated, quality component, these skateboards are great for beginners to learn the foot spacing required, and are perfect for all-day cruising."                                                                                                                                                                                                                                                                       ,                                    , category:sports equipment               ,                   ,                     , 799872520    , 24.99   , standard    ,               ,
+Football           , football           , "This football features high-contrast graphics for high-visibility during play, while its machine-stitched tpu casing offers consistent performance."                                                                                                                                                                                                                                                                                                                                         ,                                    , category:sports equipment               ,                   ,                     , SC3137-056   , 57.07   , standard    ,               ,
+Running Shoe       , running-shoe       , "With its ultra-light, uber-responsive magic foam and a carbon fiber plate that feels like it’s propelling you forward, the Running Shoe is ready to push you to victories both large and small"                                                                                                                                                                                                                                                                                              ,                                    , category:sports equipment               , shoe size         , Size 40             , RS0040       , 99.99   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , Size 42             , RS0042       , 99.99   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , Size 44             , RS0044       , 99.99   , standard    ,               ,
+                   ,                    ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                    ,                                         ,                   , Size 46             , RS0046       , 99.99   , standard    ,               ,
+Spiky Cactus       , spiky-cactus       , "A spiky yet elegant house cactus - perfect for the home or office. Origin and habitat: Probably native only to the Andes of Peru"                                                                                                                                                                                                                                                                                                                                                            ,                                    , category:home & garden|category:plants  ,                   ,                     , SC011001     , 15.50   , standard    ,               ,
+Orchid             , orchid             , "Gloriously elegant. It can go along with any interior as it is a neutral color and the most popular Phalaenopsis overall. 2 to 3 foot stems host large white flowers that can last for over 2 months."                                                                                                                                                                                                                                                                                       ,                                    , category:home & garden|category:plants  ,                   ,                     , ROR00221     , 65.00   , standard    ,               ,
+Bonsai Tree        , bonsai-tree        , "Excellent semi-evergreen bonsai. Indoors or out but needs some winter protection. All trees sent will leave the nursery in excellent condition and will be of equal quality or better than the photograph shown."                                                                                                                                                                                                                                                                            ,                                    , category:home & garden|category:plants  ,                   ,                     , B01MXFLUSV   , 19.99   , standard    ,               ,

+ 5 - 0
server/e2e/fixtures/e2e-products-minimal.csv

@@ -0,0 +1,5 @@
+name                 , slug                 , description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   , assets                                      , facets                                    , optionGroups       , optionValues         , sku          , price   , taxCategory , variantAssets , variantFacets
+Laptop               , laptop               , "Now equipped with seventh-generation Intel Core processors, Laptop is snappier than ever. From daily tasks like launching apps and opening files to more advanced computing, you can power through your day thanks to faster SSDs and Turbo Boost processing up to 3.6GHz."                                                                                                                                                                                                                  , derick-david-409858-unsplash.jpg            , category:electronics|category:computers   , "screen size, RAM" , "13 inch, 8GB"       , L2201308     , 1299.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                    , "15 inch, 8GB"       , L2201508     , 1399.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                    , "13 inch, 16GB"      , L2201316     , 2199.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                    , "15 inch, 16GB"      , L2201516     , 2299.00 , standard    ,               ,

+ 1 - 1
server/e2e/import.e2e-spec.ts

@@ -11,7 +11,7 @@ describe('Import resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 0,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-empty.csv'),
             customerCount: 0,
         });
         await client.init();

+ 2 - 1
server/e2e/order.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import { GET_CUSTOMER_LIST } from '../../admin-ui/src/app/data/definitions/customer-definitions';
 import { CreateAddressInput, GetCustomerList } from '../../shared/generated-types';
@@ -16,7 +17,7 @@ describe('Orders', () => {
     beforeAll(async () => {
         const token = await server.init(
             {
-                productCount: 10,
+                productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
                 customerCount: 2,
             },
             {

+ 2 - 1
server/e2e/product-category.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     CREATE_PRODUCT_CATEGORY,
@@ -34,7 +35,7 @@ describe('ProductCategory resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 5,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
             customerCount: 1,
         });
         await client.init();

+ 11 - 9
server/e2e/product.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     ADD_OPTION_GROUP_TO_PRODUCT,
@@ -41,8 +42,8 @@ describe('Product resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 20,
             customerCount: 1,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
         });
         await client.init();
     }, TEST_SETUP_TIMEOUT_MS);
@@ -88,7 +89,7 @@ describe('Product resolver', () => {
                     options: {
                         filter: {
                             name: {
-                                contains: 'fish',
+                                contains: 'skateboard',
                             },
                         },
                     },
@@ -96,7 +97,7 @@ describe('Product resolver', () => {
             );
 
             expect(result.products.items.length).toBe(1);
-            expect(result.products.items[0].name).toBe('en Practical Frozen Fish');
+            expect(result.products.items[0].name).toBe('Cruiser Skateboard');
         });
 
         it('sorts by name', async () => {
@@ -147,7 +148,7 @@ describe('Product resolver', () => {
                 fail('Product not found');
                 return;
             }
-            expect(result.product.variants[0].price).toBe(745);
+            expect(result.product.variants[0].price).toBe(14374);
             expect(result.product.variants[0].taxCategory).toEqual({
                 id: 'T_1',
                 name: 'Standard Tax',
@@ -359,11 +360,11 @@ describe('Product resolver', () => {
                 AddOptionGroupToProduct.Mutation,
                 AddOptionGroupToProduct.Variables
             >(ADD_OPTION_GROUP_TO_PRODUCT, {
-                optionGroupId: 'T_1',
+                optionGroupId: 'T_2',
                 productId: newProduct.id,
             });
             expect(result.addOptionGroupToProduct.optionGroups.length).toBe(1);
-            expect(result.addOptionGroupToProduct.optionGroups[0].id).toBe('T_1');
+            expect(result.addOptionGroupToProduct.optionGroups[0].id).toBe('T_2');
         });
 
         it(
@@ -401,10 +402,11 @@ describe('Product resolver', () => {
                 RemoveOptionGroupFromProduct.Mutation,
                 RemoveOptionGroupFromProduct.Variables
             >(REMOVE_OPTION_GROUP_FROM_PRODUCT, {
-                optionGroupId: '1',
-                productId: '1',
+                optionGroupId: 'T_1',
+                productId: 'T_1',
             });
-            expect(result.removeOptionGroupFromProduct.optionGroups.length).toBe(0);
+            expect(result.removeOptionGroupFromProduct.optionGroups.length).toBe(1);
+            expect(result.removeOptionGroupFromProduct.optionGroups[0].code).toBe('laptop-ram');
         });
 
         it(

+ 2 - 1
server/e2e/promotion.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     CREATE_PROMOTION,
@@ -44,7 +45,7 @@ describe('Promotion resolver', () => {
     beforeAll(async () => {
         await server.init(
             {
-                productCount: 1,
+                productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
                 customerCount: 1,
             },
             {

+ 5 - 4
server/e2e/role.e2e-spec.ts

@@ -1,6 +1,4 @@
-import { CreateRole, GetRole, GetRoles, Permission, Role, UpdateRole } from '../../shared/generated-types';
-import { omit } from '../../shared/omit';
-import { CUSTOMER_ROLE_CODE, SUPER_ADMIN_ROLE_CODE } from '../../shared/shared-constants';
+import path from 'path';
 
 import {
     CREATE_ROLE,
@@ -8,6 +6,9 @@ import {
     GET_ROLES,
     UPDATE_ROLE,
 } from '../../admin-ui/src/app/data/definitions/administrator-definitions';
+import { CreateRole, GetRole, GetRoles, Permission, Role, UpdateRole } from '../../shared/generated-types';
+import { omit } from '../../shared/omit';
+import { CUSTOMER_ROLE_CODE, SUPER_ADMIN_ROLE_CODE } from '../../shared/shared-constants';
 
 import { TEST_SETUP_TIMEOUT_MS } from './config/test-config';
 import { TestClient } from './test-client';
@@ -22,7 +23,7 @@ describe('Role resolver', () => {
 
     beforeAll(async () => {
         const token = await server.init({
-            productCount: 1,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
             customerCount: 1,
         });
         await client.init();

+ 1 - 1
server/e2e/test-client.ts

@@ -13,7 +13,7 @@ export class TestClient extends SimpleGraphQLClient {
     }
 
     async init() {
-        const token = await getDefaultChannelToken();
+        const token = await getDefaultChannelToken(false);
         this.setChannelToken(token);
         await this.asSuperAdmin();
     }

+ 13 - 3
server/e2e/test-server.ts

@@ -5,6 +5,7 @@ import path from 'path';
 import { ConnectionOptions } from 'typeorm';
 import { SqljsConnectionOptions } from 'typeorm/driver/sqljs/SqljsConnectionOptions';
 
+import { Omit } from '../../shared/omit';
 import { populate, PopulateOptions } from '../mock-data/populate';
 import { preBootstrapConfig } from '../src/bootstrap';
 import { Mutable } from '../src/common/types/common-types';
@@ -27,7 +28,10 @@ export class TestServer {
      * The populated data is saved into an .sqlite file for each test file. On subsequent runs, this file
      * is loaded so that the populate step can be skipped, which speeds up the tests significantly.
      */
-    async init(options: PopulateOptions, customConfig: Partial<VendureConfig> = {}): Promise<void> {
+    async init(
+        options: Omit<PopulateOptions, 'initialDataPath'>,
+        customConfig: Partial<VendureConfig> = {},
+    ): Promise<void> {
         setTestEnvironment();
         const testingConfig = { ...testConfig, ...customConfig };
         if (options.logging) {
@@ -62,12 +66,18 @@ export class TestServer {
     /**
      * Populates an .sqlite database file based on the PopulateOptions.
      */
-    private async populateInitialData(testingConfig: VendureConfig, options: PopulateOptions): Promise<void> {
+    private async populateInitialData(
+        testingConfig: VendureConfig,
+        options: Omit<PopulateOptions, 'initialDataPath'>,
+    ): Promise<void> {
         (testingConfig.dbConnectionOptions as Mutable<SqljsConnectionOptions>).autoSave = true;
 
         const app = await populate(testingConfig, this.bootstrapForTesting, {
             logging: false,
-            ...options,
+            ...{
+                ...options,
+                initialDataPath: path.join(__dirname, 'fixtures/e2e-initial-data.ts'),
+            },
         });
         await app.close();
 

+ 11 - 10
server/e2e/zone.e2e-spec.ts

@@ -1,4 +1,5 @@
 import gql from 'graphql-tag';
+import path from 'path';
 
 import {
     ADD_MEMBERS_TO_ZONE,
@@ -34,7 +35,7 @@ describe('Facet resolver', () => {
 
     beforeAll(async () => {
         await server.init({
-            productCount: 2,
+            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
             customerCount: 1,
         });
         await client.init();
@@ -50,14 +51,14 @@ describe('Facet resolver', () => {
     it('zones', async () => {
         const result = await client.query(GET_ZONE_LIST);
 
-        expect(result.zones.length).toBe(6);
+        expect(result.zones.length).toBe(5);
         zones = result.zones;
         oceania = zones[0];
     });
 
     it('zone', async () => {
         const result = await client.query<GetZone.Query, GetZone.Variables>(GET_ZONE, {
-            id: zones[0].id,
+            id: oceania.id,
         });
 
         expect(result.zone!.name).toBe('Oceania');
@@ -96,11 +97,8 @@ describe('Facet resolver', () => {
             },
         );
 
-        expect(result.addMembersToZone.members.map(m => m.name)).toEqual([
-            countries[0].name,
-            countries[2].name,
-            countries[3].name,
-        ]);
+        expect(!!result.addMembersToZone.members.find(m => m.name === countries[2].name)).toBe(true);
+        expect(!!result.addMembersToZone.members.find(m => m.name === countries[3].name)).toBe(true);
     });
 
     it('removeMembersFromZone', async () => {
@@ -112,7 +110,9 @@ describe('Facet resolver', () => {
             },
         );
 
-        expect(result.removeMembersFromZone.members.map(m => m.name)).toEqual([countries[3].name]);
+        expect(!!result.removeMembersFromZone.members.find(m => m.name === countries[0].name)).toBe(false);
+        expect(!!result.removeMembersFromZone.members.find(m => m.name === countries[2].name)).toBe(false);
+        expect(!!result.removeMembersFromZone.members.find(m => m.name === countries[3].name)).toBe(true);
     });
 
     describe('deletion', () => {
@@ -134,7 +134,8 @@ describe('Facet resolver', () => {
             expect(result1.deleteZone).toEqual({
                 result: DeletionResult.NOT_DELETED,
                 message:
-                    'The selected Zone cannot be deleted as it is used in the following TaxRates: Standard Tax for Oceania',
+                    'The selected Zone cannot be deleted as it is used in the following ' +
+                    'TaxRates: Standard Tax Oceania, Reduced Tax Oceania, Zero Tax Oceania',
             });
 
             const result2 = await client.query(GET_ZONE_LIST, {});

BIN
server/mock-data/assets/adam-birkett-239153-unsplash.jpg


BIN
server/mock-data/assets/alexandru-acea-686569-unsplash.jpg


BIN
server/mock-data/assets/brandi-redd-104140-unsplash.jpg


BIN
server/mock-data/assets/florian-klauer-14840-unsplash.jpg


BIN
server/mock-data/assets/florian-olivo-1166419-unsplash.jpg


BIN
server/mock-data/assets/juan-gomez-674574-unsplash.jpg


BIN
server/mock-data/assets/mark-tegethoff-667351-unsplash.jpg


BIN
server/mock-data/assets/max-tarkhov-737999-unsplash.jpg


BIN
server/mock-data/assets/michael-guite-571169-unsplash.jpg


BIN
server/mock-data/assets/neonbrand-428982-unsplash.jpg


BIN
server/mock-data/assets/neslihan-gunaydin-3493-unsplash.jpg


BIN
server/mock-data/assets/nik-shuliahin-619349-unsplash.jpg


BIN
server/mock-data/assets/paul-weaver-1120584-unsplash.jpg


BIN
server/mock-data/assets/pierre-chatel-innocenti-483198-unsplash.jpg


BIN
server/mock-data/assets/robert-shunev-528016-unsplash.jpg


BIN
server/mock-data/assets/stoica-ionela-530966-unsplash.jpg


BIN
server/mock-data/assets/vincent-botta-736919-unsplash.jpg


BIN
server/mock-data/assets/vincent-liu-525429-unsplash.jpg


BIN
server/mock-data/assets/zoltan-kovacs-642412-unsplash.jpg


BIN
server/mock-data/assets/zoltan-tasi-423051-unsplash.jpg


+ 262 - 0
server/mock-data/data-sources/initial-data.ts

@@ -0,0 +1,262 @@
+import { LanguageCode } from '../../../shared/generated-types';
+import { InitialData } from '../../src/data-import';
+
+export const initialData: InitialData = {
+    defaultLanguage: LanguageCode.en,
+    defaultZone: 'Europe',
+    taxRates: [
+        { name: 'Standard Tax', percentage: 20 },
+        { name: 'Reduced Tax', percentage: 10 },
+        { name: 'Zero Tax', percentage: 0 },
+    ],
+    countries: [
+        { name: 'Afghanistan', code: 'AF', zone: 'Asia' },
+        { name: 'Åland Islands', code: 'AX', zone: 'Europe' },
+        { name: 'Albania', code: 'AL', zone: 'Europe' },
+        { name: 'Algeria', code: 'DZ', zone: 'Africa' },
+        { name: 'American Samoa', code: 'AS', zone: 'Oceania' },
+        { name: 'Andorra', code: 'AD', zone: 'Europe' },
+        { name: 'Angola', code: 'AO', zone: 'Africa' },
+        { name: 'Anguilla', code: 'AI', zone: 'Americas' },
+        { name: 'Antigua and Barbuda', code: 'AG', zone: 'Americas' },
+        { name: 'Argentina', code: 'AR', zone: 'Americas' },
+        { name: 'Armenia', code: 'AM', zone: 'Asia' },
+        { name: 'Aruba', code: 'AW', zone: 'Americas' },
+        { name: 'Australia', code: 'AU', zone: 'Oceania' },
+        { name: 'Austria', code: 'AT', zone: 'Europe' },
+        { name: 'Azerbaijan', code: 'AZ', zone: 'Asia' },
+        { name: 'Bahamas', code: 'BS', zone: 'Americas' },
+        { name: 'Bahrain', code: 'BH', zone: 'Asia' },
+        { name: 'Bangladesh', code: 'BD', zone: 'Asia' },
+        { name: 'Barbados', code: 'BB', zone: 'Americas' },
+        { name: 'Belarus', code: 'BY', zone: 'Europe' },
+        { name: 'Belgium', code: 'BE', zone: 'Europe' },
+        { name: 'Belize', code: 'BZ', zone: 'Americas' },
+        { name: 'Benin', code: 'BJ', zone: 'Africa' },
+        { name: 'Bermuda', code: 'BM', zone: 'Americas' },
+        { name: 'Bhutan', code: 'BT', zone: 'Asia' },
+        { name: 'Bolivia (Plurinational State of)', code: 'BO', zone: 'Americas' },
+        { name: 'Bonaire, Sint Eustatius and Saba', code: 'BQ', zone: 'Americas' },
+        { name: 'Bosnia and Herzegovina', code: 'BA', zone: 'Europe' },
+        { name: 'Botswana', code: 'BW', zone: 'Africa' },
+        { name: 'Bouvet Island', code: 'BV', zone: 'Americas' },
+        { name: 'Brazil', code: 'BR', zone: 'Americas' },
+        { name: 'British Indian Ocean Territory', code: 'IO', zone: 'Africa' },
+        { name: 'Brunei Darussalam', code: 'BN', zone: 'Asia' },
+        { name: 'Bulgaria', code: 'BG', zone: 'Europe' },
+        { name: 'Burkina Faso', code: 'BF', zone: 'Africa' },
+        { name: 'Burundi', code: 'BI', zone: 'Africa' },
+        { name: 'Cabo Verde', code: 'CV', zone: 'Africa' },
+        { name: 'Cambodia', code: 'KH', zone: 'Asia' },
+        { name: 'Cameroon', code: 'CM', zone: 'Africa' },
+        { name: 'Canada', code: 'CA', zone: 'Americas' },
+        { name: 'Cayman Islands', code: 'KY', zone: 'Americas' },
+        { name: 'Central African Republic', code: 'CF', zone: 'Africa' },
+        { name: 'Chad', code: 'TD', zone: 'Africa' },
+        { name: 'Chile', code: 'CL', zone: 'Americas' },
+        { name: 'China', code: 'CN', zone: 'Asia' },
+        { name: 'Christmas Island', code: 'CX', zone: 'Oceania' },
+        { name: 'Cocos (Keeling) Islands', code: 'CC', zone: 'Oceania' },
+        { name: 'Colombia', code: 'CO', zone: 'Americas' },
+        { name: 'Comoros', code: 'KM', zone: 'Africa' },
+        { name: 'Congo', code: 'CG', zone: 'Africa' },
+        { name: 'Congo (Democratic Republic of the)', code: 'CD', zone: 'Africa' },
+        { name: 'Cook Islands', code: 'CK', zone: 'Oceania' },
+        { name: 'Costa Rica', code: 'CR', zone: 'Americas' },
+        { name: "Côte d'Ivoire", code: 'CI', zone: 'Africa' },
+        { name: 'Croatia', code: 'HR', zone: 'Europe' },
+        { name: 'Cuba', code: 'CU', zone: 'Americas' },
+        { name: 'Curaçao', code: 'CW', zone: 'Americas' },
+        { name: 'Cyprus', code: 'CY', zone: 'Asia' },
+        { name: 'Czechia', code: 'CZ', zone: 'Europe' },
+        { name: 'Denmark', code: 'DK', zone: 'Europe' },
+        { name: 'Djibouti', code: 'DJ', zone: 'Africa' },
+        { name: 'Dominica', code: 'DM', zone: 'Americas' },
+        { name: 'Dominican Republic', code: 'DO', zone: 'Americas' },
+        { name: 'Ecuador', code: 'EC', zone: 'Americas' },
+        { name: 'Egypt', code: 'EG', zone: 'Africa' },
+        { name: 'El Salvador', code: 'SV', zone: 'Americas' },
+        { name: 'Equatorial Guinea', code: 'GQ', zone: 'Africa' },
+        { name: 'Eritrea', code: 'ER', zone: 'Africa' },
+        { name: 'Estonia', code: 'EE', zone: 'Europe' },
+        { name: 'Eswatini', code: 'SZ', zone: 'Africa' },
+        { name: 'Ethiopia', code: 'ET', zone: 'Africa' },
+        { name: 'Falkland Islands (Malvinas)', code: 'FK', zone: 'Americas' },
+        { name: 'Faroe Islands', code: 'FO', zone: 'Europe' },
+        { name: 'Fiji', code: 'FJ', zone: 'Oceania' },
+        { name: 'Finland', code: 'FI', zone: 'Europe' },
+        { name: 'France', code: 'FR', zone: 'Europe' },
+        { name: 'French Guiana', code: 'GF', zone: 'Americas' },
+        { name: 'French Polynesia', code: 'PF', zone: 'Oceania' },
+        { name: 'French Southern Territories', code: 'TF', zone: 'Africa' },
+        { name: 'Gabon', code: 'GA', zone: 'Africa' },
+        { name: 'Gambia', code: 'GM', zone: 'Africa' },
+        { name: 'Georgia', code: 'GE', zone: 'Asia' },
+        { name: 'Germany', code: 'DE', zone: 'Europe' },
+        { name: 'Ghana', code: 'GH', zone: 'Africa' },
+        { name: 'Gibraltar', code: 'GI', zone: 'Europe' },
+        { name: 'Greece', code: 'GR', zone: 'Europe' },
+        { name: 'Greenland', code: 'GL', zone: 'Americas' },
+        { name: 'Grenada', code: 'GD', zone: 'Americas' },
+        { name: 'Guadeloupe', code: 'GP', zone: 'Americas' },
+        { name: 'Guam', code: 'GU', zone: 'Oceania' },
+        { name: 'Guatemala', code: 'GT', zone: 'Americas' },
+        { name: 'Guernsey', code: 'GG', zone: 'Europe' },
+        { name: 'Guinea', code: 'GN', zone: 'Africa' },
+        { name: 'Guinea-Bissau', code: 'GW', zone: 'Africa' },
+        { name: 'Guyana', code: 'GY', zone: 'Americas' },
+        { name: 'Haiti', code: 'HT', zone: 'Americas' },
+        { name: 'Heard Island and McDonald Islands', code: 'HM', zone: 'Oceania' },
+        { name: 'Holy See', code: 'VA', zone: 'Europe' },
+        { name: 'Honduras', code: 'HN', zone: 'Americas' },
+        { name: 'Hong Kong', code: 'HK', zone: 'Asia' },
+        { name: 'Hungary', code: 'HU', zone: 'Europe' },
+        { name: 'Iceland', code: 'IS', zone: 'Europe' },
+        { name: 'India', code: 'IN', zone: 'Asia' },
+        { name: 'Indonesia', code: 'ID', zone: 'Asia' },
+        { name: 'Iran (Islamic Republic of)', code: 'IR', zone: 'Asia' },
+        { name: 'Iraq', code: 'IQ', zone: 'Asia' },
+        { name: 'Ireland', code: 'IE', zone: 'Europe' },
+        { name: 'Isle of Man', code: 'IM', zone: 'Europe' },
+        { name: 'Israel', code: 'IL', zone: 'Asia' },
+        { name: 'Italy', code: 'IT', zone: 'Europe' },
+        { name: 'Jamaica', code: 'JM', zone: 'Americas' },
+        { name: 'Japan', code: 'JP', zone: 'Asia' },
+        { name: 'Jersey', code: 'JE', zone: 'Europe' },
+        { name: 'Jordan', code: 'JO', zone: 'Asia' },
+        { name: 'Kazakhstan', code: 'KZ', zone: 'Asia' },
+        { name: 'Kenya', code: 'KE', zone: 'Africa' },
+        { name: 'Kiribati', code: 'KI', zone: 'Oceania' },
+        { name: "Korea (Democratic People's Republic of)", code: 'KP', zone: 'Asia' },
+        { name: 'Korea (Republic of)', code: 'KR', zone: 'Asia' },
+        { name: 'Kuwait', code: 'KW', zone: 'Asia' },
+        { name: 'Kyrgyzstan', code: 'KG', zone: 'Asia' },
+        { name: "Lao People's Democratic Republic", code: 'LA', zone: 'Asia' },
+        { name: 'Latvia', code: 'LV', zone: 'Europe' },
+        { name: 'Lebanon', code: 'LB', zone: 'Asia' },
+        { name: 'Lesotho', code: 'LS', zone: 'Africa' },
+        { name: 'Liberia', code: 'LR', zone: 'Africa' },
+        { name: 'Libya', code: 'LY', zone: 'Africa' },
+        { name: 'Liechtenstein', code: 'LI', zone: 'Europe' },
+        { name: 'Lithuania', code: 'LT', zone: 'Europe' },
+        { name: 'Luxembourg', code: 'LU', zone: 'Europe' },
+        { name: 'Macao', code: 'MO', zone: 'Asia' },
+        { name: 'Macedonia (the former Yugoslav Republic of)', code: 'MK', zone: 'Europe' },
+        { name: 'Madagascar', code: 'MG', zone: 'Africa' },
+        { name: 'Malawi', code: 'MW', zone: 'Africa' },
+        { name: 'Malaysia', code: 'MY', zone: 'Asia' },
+        { name: 'Maldives', code: 'MV', zone: 'Asia' },
+        { name: 'Mali', code: 'ML', zone: 'Africa' },
+        { name: 'Malta', code: 'MT', zone: 'Europe' },
+        { name: 'Marshall Islands', code: 'MH', zone: 'Oceania' },
+        { name: 'Martinique', code: 'MQ', zone: 'Americas' },
+        { name: 'Mauritania', code: 'MR', zone: 'Africa' },
+        { name: 'Mauritius', code: 'MU', zone: 'Africa' },
+        { name: 'Mayotte', code: 'YT', zone: 'Africa' },
+        { name: 'Mexico', code: 'MX', zone: 'Americas' },
+        { name: 'Micronesia (Federated States of)', code: 'FM', zone: 'Oceania' },
+        { name: 'Moldova (Republic of)', code: 'MD', zone: 'Europe' },
+        { name: 'Monaco', code: 'MC', zone: 'Europe' },
+        { name: 'Mongolia', code: 'MN', zone: 'Asia' },
+        { name: 'Montenegro', code: 'ME', zone: 'Europe' },
+        { name: 'Montserrat', code: 'MS', zone: 'Americas' },
+        { name: 'Morocco', code: 'MA', zone: 'Africa' },
+        { name: 'Mozambique', code: 'MZ', zone: 'Africa' },
+        { name: 'Myanmar', code: 'MM', zone: 'Asia' },
+        { name: 'Namibia', code: 'NA', zone: 'Africa' },
+        { name: 'Nauru', code: 'NR', zone: 'Oceania' },
+        { name: 'Nepal', code: 'NP', zone: 'Asia' },
+        { name: 'Netherlands', code: 'NL', zone: 'Europe' },
+        { name: 'New Caledonia', code: 'NC', zone: 'Oceania' },
+        { name: 'New Zealand', code: 'NZ', zone: 'Oceania' },
+        { name: 'Nicaragua', code: 'NI', zone: 'Americas' },
+        { name: 'Niger', code: 'NE', zone: 'Africa' },
+        { name: 'Nigeria', code: 'NG', zone: 'Africa' },
+        { name: 'Niue', code: 'NU', zone: 'Oceania' },
+        { name: 'Norfolk Island', code: 'NF', zone: 'Oceania' },
+        { name: 'Northern Mariana Islands', code: 'MP', zone: 'Oceania' },
+        { name: 'Norway', code: 'NO', zone: 'Europe' },
+        { name: 'Oman', code: 'OM', zone: 'Asia' },
+        { name: 'Pakistan', code: 'PK', zone: 'Asia' },
+        { name: 'Palau', code: 'PW', zone: 'Oceania' },
+        { name: 'Palestine, State of', code: 'PS', zone: 'Asia' },
+        { name: 'Panama', code: 'PA', zone: 'Americas' },
+        { name: 'Papua New Guinea', code: 'PG', zone: 'Oceania' },
+        { name: 'Paraguay', code: 'PY', zone: 'Americas' },
+        { name: 'Peru', code: 'PE', zone: 'Americas' },
+        { name: 'Philippines', code: 'PH', zone: 'Asia' },
+        { name: 'Pitcairn', code: 'PN', zone: 'Oceania' },
+        { name: 'Poland', code: 'PL', zone: 'Europe' },
+        { name: 'Portugal', code: 'PT', zone: 'Europe' },
+        { name: 'Puerto Rico', code: 'PR', zone: 'Americas' },
+        { name: 'Qatar', code: 'QA', zone: 'Asia' },
+        { name: 'Réunion', code: 'RE', zone: 'Africa' },
+        { name: 'Romania', code: 'RO', zone: 'Europe' },
+        { name: 'Russian Federation', code: 'RU', zone: 'Europe' },
+        { name: 'Rwanda', code: 'RW', zone: 'Africa' },
+        { name: 'Saint Barthélemy', code: 'BL', zone: 'Americas' },
+        { name: 'Saint Helena, Ascension and Tristan da Cunha', code: 'SH', zone: 'Africa' },
+        { name: 'Saint Kitts and Nevis', code: 'KN', zone: 'Americas' },
+        { name: 'Saint Lucia', code: 'LC', zone: 'Americas' },
+        { name: 'Saint Martin (French part)', code: 'MF', zone: 'Americas' },
+        { name: 'Saint Pierre and Miquelon', code: 'PM', zone: 'Americas' },
+        { name: 'Saint Vincent and the Grenadines', code: 'VC', zone: 'Americas' },
+        { name: 'Samoa', code: 'WS', zone: 'Oceania' },
+        { name: 'San Marino', code: 'SM', zone: 'Europe' },
+        { name: 'Sao Tome and Principe', code: 'ST', zone: 'Africa' },
+        { name: 'Saudi Arabia', code: 'SA', zone: 'Asia' },
+        { name: 'Senegal', code: 'SN', zone: 'Africa' },
+        { name: 'Serbia', code: 'RS', zone: 'Europe' },
+        { name: 'Seychelles', code: 'SC', zone: 'Africa' },
+        { name: 'Sierra Leone', code: 'SL', zone: 'Africa' },
+        { name: 'Singapore', code: 'SG', zone: 'Asia' },
+        { name: 'Sint Maarten (Dutch part)', code: 'SX', zone: 'Americas' },
+        { name: 'Slovakia', code: 'SK', zone: 'Europe' },
+        { name: 'Slovenia', code: 'SI', zone: 'Europe' },
+        { name: 'Solomon Islands', code: 'SB', zone: 'Oceania' },
+        { name: 'Somalia', code: 'SO', zone: 'Africa' },
+        { name: 'South Africa', code: 'ZA', zone: 'Africa' },
+        { name: 'South Georgia and the South Sandwich Islands', code: 'GS', zone: 'Americas' },
+        { name: 'South Sudan', code: 'SS', zone: 'Africa' },
+        { name: 'Spain', code: 'ES', zone: 'Europe' },
+        { name: 'Sri Lanka', code: 'LK', zone: 'Asia' },
+        { name: 'Sudan', code: 'SD', zone: 'Africa' },
+        { name: 'Suriname', code: 'SR', zone: 'Americas' },
+        { name: 'Svalbard and Jan Mayen', code: 'SJ', zone: 'Europe' },
+        { name: 'Sweden', code: 'SE', zone: 'Europe' },
+        { name: 'Switzerland', code: 'CH', zone: 'Europe' },
+        { name: 'Syrian Arab Republic', code: 'SY', zone: 'Asia' },
+        { name: 'Taiwan, Province of China', code: 'TW', zone: 'Asia' },
+        { name: 'Tajikistan', code: 'TJ', zone: 'Asia' },
+        { name: 'Tanzania, United Republic of', code: 'TZ', zone: 'Africa' },
+        { name: 'Thailand', code: 'TH', zone: 'Asia' },
+        { name: 'Timor-Leste', code: 'TL', zone: 'Asia' },
+        { name: 'Togo', code: 'TG', zone: 'Africa' },
+        { name: 'Tokelau', code: 'TK', zone: 'Oceania' },
+        { name: 'Tonga', code: 'TO', zone: 'Oceania' },
+        { name: 'Trinidad and Tobago', code: 'TT', zone: 'Americas' },
+        { name: 'Tunisia', code: 'TN', zone: 'Africa' },
+        { name: 'Turkey', code: 'TR', zone: 'Asia' },
+        { name: 'Turkmenistan', code: 'TM', zone: 'Asia' },
+        { name: 'Turks and Caicos Islands', code: 'TC', zone: 'Americas' },
+        { name: 'Tuvalu', code: 'TV', zone: 'Oceania' },
+        { name: 'Uganda', code: 'UG', zone: 'Africa' },
+        { name: 'Ukraine', code: 'UA', zone: 'Europe' },
+        { name: 'United Arab Emirates', code: 'AE', zone: 'Asia' },
+        { name: 'United Kingdom', code: 'GB', zone: 'Europe' },
+        { name: 'United States of America', code: 'US', zone: 'Americas' },
+        { name: 'United States Minor Outlying Islands', code: 'UM', zone: 'Oceania' },
+        { name: 'Uruguay', code: 'UY', zone: 'Americas' },
+        { name: 'Uzbekistan', code: 'UZ', zone: 'Asia' },
+        { name: 'Vanuatu', code: 'VU', zone: 'Oceania' },
+        { name: 'Venezuela (Bolivarian Republic of)', code: 'VE', zone: 'Americas' },
+        { name: 'Viet Nam', code: 'VN', zone: 'Asia' },
+        { name: 'Virgin Islands (British)', code: 'VG', zone: 'Americas' },
+        { name: 'Virgin Islands (U.S.)', code: 'VI', zone: 'Americas' },
+        { name: 'Wallis and Futuna', code: 'WF', zone: 'Oceania' },
+        { name: 'Western Sahara', code: 'EH', zone: 'Africa' },
+        { name: 'Yemen', code: 'YE', zone: 'Asia' },
+        { name: 'Zambia', code: 'ZM', zone: 'Africa' },
+        { name: 'Zimbabwe', code: 'ZW', zone: 'Africa' },
+    ],
+};

+ 40 - 0
server/mock-data/data-sources/products.csv

@@ -0,0 +1,40 @@
+name                 , slug                 , description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   , assets                                      , facets                                    , optionGroups      , optionValues        , sku          , price   , taxCategory , variantAssets , variantFacets
+Laptop               , laptop               , "Now equipped with seventh-generation Intel Core processors, Laptop is snappier than ever. From daily tasks like launching apps and opening files to more advanced computing, you can power through your day thanks to faster SSDs and Turbo Boost processing up to 3.6GHz."                                                                                                                                                                                                                  , derick-david-409858-unsplash.jpg            , category:electronics|category:computers   , "screen size|RAM" , "13 inch|8GB"       , L2201308     , 1299.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "15 inch|8GB"       , L2201508     , 1399.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "13 inch|16GB"      , L2201316     , 2199.00 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "15 inch|16GB"      , L2201516     , 2299.00 , standard    ,               ,
+Curvy Monitor        , curvy-monitor        , "Discover a truly immersive viewing experience with this monitor curved more deeply than any other. Wrapping around your field of vision the 1,800 R screencreates a wider field of view, enhances depth perception, and minimises peripheral distractions to draw you deeper in to your content."                                                                                                                                                                                            , alexandru-acea-686569-unsplash.jpg          , category:electronics|category:computers   , monitor size      , 24 inch             , C24F390      , 143.74  , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , 27 inch             , C27F390      , 169.94  , standard    ,               ,
+Gaming PC            , gaming-pc            , "This pc is optimised for gaming, and is also VR ready. The Intel Core-i7 CPU and High Performance GPU give the computer the raw power it needs to function at a high level."                                                                                                                                                                                                                                                                                                                 , florian-olivo-1166419-unsplash.jpg          , category:electronics|category:computers   , "cpu|HDD"         , "i7-8700|240GB SSD" , CGS480VR1063 , 1087.20 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "R7-2700|240GB SSD" , CGS480VR1064 , 1099.95 , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "i7-8700|120GB SSD" , CGS480VR1065 , 931.20  , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , "R7-2700|120GB SSD" , CGS480VR1066 , 949.20  , standard    ,               ,
+Hard Drive           , hard-drive           , "Boost your PC storage with this internal hard drive, designed just for desktop and all-in-one PCs."                                                                                                                                                                                                                                                                                                                                                                                          , vincent-botta-736919-unsplash.jpg           , category:electronics|category:computers   , "HDD"             , 1TB                 , IHD455T1     , 37.99   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , 2TB                 , IHD455T2     , 53.74   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , 3TB                 , IHD455T3     , 78.96   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , 4TB                 , IHD455T4     , 92.99   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , 6TB                 , IHD455T6     , 134.35  , standard    ,               ,
+Clacky Keyboard      , clacky-keyboard      , "Let all your colleagues know that you are typing on this exclusive, colorful klicky-klacky keyboard. Huge travel on each keypress ensures maximum klack on each and every keystroke."                                                                                                                                                                                                                                                                                                        , juan-gomez-674574-unsplash.jpg              , category:electronics|category:computers   ,                   ,                     , A4TKLA45535  , 74.89   , standard    ,               ,
+USB Cable            , usb-cable            , "Solid conductors eliminate strand-interaction distortion and reduce jitter. As the surface is made of high-purity silver, the performance is very close to that of a solid silver cable, but priced much closer to solid copper cable."                                                                                                                                                                                                                                                      , adam-birkett-239153-unsplash.jpg            , category:electronics|category:computers   ,                   ,                     , USBCIN01.5MI , 69.00   , standard    ,               ,
+Instant Camera       , instant-camera       , "With its nostalgic design and simple point-and-shoot functionality, the Instant Camera is the perfect pick to get started with instant photography."                                                                                                                                                                                                                                                                                                                                         , eniko-kis-663725-unsplash.jpg               , category:electronics|category:photo       ,                   ,                     , IC22MWDD     , 174.99  , standard    ,               ,
+Camera Lens          , camera-lens          , "This lens is a Di type lens using an optical system with improved multi-coating designed to function with digital SLR cameras as well as film cameras."                                                                                                                                                                                                                                                                                                                                      , brandi-redd-104140-unsplash.jpg             , category:electronics|category:photo       ,                   ,                     , B0012UUP02   , 104.00  , standard    ,               ,
+Tripod               , tripod               , "Capture vivid, professional-style photographs with help from this lightweight tripod. The adjustable-height tripod makes it easy to achieve reliable stability and score just the right angle when going after that award-winning shot."                                                                                                                                                                                                                                                     , zoltan-tasi-423051-unsplash.jpg             , category:electronics|category:photo       ,                   ,                     , B00XI87KV8   , 14.98   , standard    ,               ,
+SLR Camera           , slr-camera           , "Retro styled, portable in size and built around a powerful 24-megapixel APS-C CMOS sensor, this digital camera is the ideal companion for creative everyday photography. Packed full of high spec features such as an advanced hybrid autofocus system able to keep pace with even the most active subjects, a speedy 6fps continuous-shooting mode, high-resolution electronic viewfinder and intuitive swivelling touchscreen, it brings professional image making into everyone’s grasp." , robert-shunev-528016-unsplash.jpg           , category:electronics|category:photo       ,                   ,                     , B07D75V44S   , 521.00  , standard    ,               ,
+Road Bike            , road-bike            , "Featuring a full carbon chassis - complete with cyclocross-specific carbon fork - and a component setup geared for hard use on the race circuit, it's got the low weight, exceptional efficiency and brilliant handling you'll need to stay at the front of the pack."                                                                                                                                                                                                                       , mikkel-bech-748940-unsplash.jpg             , category:sports equipment                 ,                   ,                     , RB000844334  , 2499.00 , standard    ,               ,
+Skipping Rope        , skipping-rope        , "When you're working out you need a quality rope that doesn't tangle at every couple of jumps and with this sipping rope you won't have this problem."                                                                                                                                                                                                                                                                                                                                        , stoica-ionela-530966-unsplash.jpg           , category:sports equipment                 ,                   ,                     , B07CNGXVXT   , 7.99    , standard    ,               ,
+Boxing Gloves        , boxing-gloves        , "Training gloves designed for optimum training. Our gloves promote proper punching technique because they are conformed to the natural shape of your fist. Dense, innovative two-layer foam provides better shock absorbency and full padding on the front, back and wrist to promote proper punching technique."                                                                                                                                                                             , neonbrand-428982-unsplash.jpg               , category:sports equipment                 ,                   ,                     , B000ZYLPPU   , 33.04   , standard    ,               ,
+Tent                 , tent                 , "With tons of space inside (for max. 4 persons), full head height throughout the entire tent and an unusual and striking shape, this tent offers you everything you need."                                                                                                                                                                                                                                                                                                                    , michael-guite-571169-unsplash.jpg           , category:sports equipment                 ,                   ,                     , 2000023510   , 214.93  , standard    ,               ,
+Cruiser Skateboard   , cruiser-skateboard   , "Based on the 1970s iconic shape, but made to a larger 69cm size, with updated, quality component, these skateboards are great for beginners to learn the foot spacing required, and are perfect for all-day cruising."                                                                                                                                                                                                                                                                       , max-tarkhov-737999-unsplash.jpg             , category:sports equipment                 ,                   ,                     , 799872520    , 24.99   , standard    ,               ,
+Football             , football             , "This football features high-contrast graphics for high-visibility during play, while its machine-stitched tpu casing offers consistent performance."                                                                                                                                                                                                                                                                                                                                         , nik-shuliahin-619349-unsplash.jpg           , category:sports equipment                 ,                   ,                     , SC3137-056   , 57.07   , standard    ,               ,
+Running Shoe         , running-shoe         , "With its ultra-light, uber-responsive magic foam and a carbon fiber plate that feels like it’s propelling you forward, the Running Shoe is ready to push you to victories both large and small"                                                                                                                                                                                                                                                                                              , chuttersnap-584518-unsplash.jpg             , category:sports equipment                 , size              , Size 40             , RS0040       , 99.99   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , Size 42             , RS0042       , 99.99   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , Size 44             , RS0044       , 99.99   , standard    ,               ,
+                     ,                      ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                             ,                                           ,                   , Size 46             , RS0046       , 99.99   , standard    ,               ,
+Spiky Cactus         , spiky-cactus         , "A spiky yet elegant house cactus - perfect for the home or office. Origin and habitat: Probably native only to the Andes of Peru"                                                                                                                                                                                                                                                                                                                                                            , charles-deluvio-695736-unsplash.jpg         , category:home & garden|category:plants    ,                   ,                     , SC011001     , 15.50   , standard    ,               ,
+Orchid               , orchid               , "Gloriously elegant. It can go along with any interior as it is a neutral color and the most popular Phalaenopsis overall. 2 to 3 foot stems host large white flowers that can last for over 2 months."                                                                                                                                                                                                                                                                                       , zoltan-kovacs-642412-unsplash.jpg           , category:home & garden|category:plants    ,                   ,                     , ROR00221     , 65.00   , standard    ,               ,
+Bonsai Tree          , bonsai-tree          , "Excellent semi-evergreen bonsai. Indoors or out but needs some winter protection. All trees sent will leave the nursery in excellent condition and will be of equal quality or better than the photograph shown."                                                                                                                                                                                                                                                                            , mark-tegethoff-667351-unsplash.jpg          , category:home & garden|category:plants    ,                   ,                     , B01MXFLUSV   , 19.99   , standard    ,               ,
+Guardian Lion Statue , guardian-lion-statue , "Placing it at home or office can bring you fortune and prosperity, guard your house and ward off ill fortune."                                                                                                                                                                                                                                                                                                                                                                               , vincent-liu-525429-unsplash.jpg             , category:home & garden                    ,                   ,                     , GL34LLW11    , 188.53  , standard    ,               ,
+Hand Trowel          , hand-trowel          , "Hand trowel for garden cultivating hammer finish epoxy-coated head for improved resistance to rust, scratches, humidity and alkalines in the soil."                                                                                                                                                                                                                                                                                                                                          , neslihan-gunaydin-3493-unsplash.jpg         , category:home & garden                    ,                   ,                     , 4058NB/09    , 4.99    , standard    ,               ,
+Balloon Chair        , balloon-chair        , "A charming vintage white wooden chair featuring an extremely spherical pink balloon. The balloon may be detached and used for other purposes, for example as a party decoration."                                                                                                                                                                                                                                                                                                            , florian-klauer-14840-unsplash.jpg           , category:home & garden|category:furniture ,                   ,                     , 34-BC82444   , 65.00   , standard    ,               ,
+Leather Sofa         , leather-sofa         , "This premium, tan-brown bonded leather seat is part of the 'chill' sofa range. The lever activated recline feature makes it easy to adjust to any position. This smart, bustle back design with rounded tight padded arms has been designed with your comfort in mind. This well-padded chair has foam pocket sprung seat cushions and fibre-filled back cushions."                                                                                                                          , paul-weaver-1120584-unsplash.jpg            , category:home & garden|category:furniture ,                   ,                     , CH00001-02   , 1245.00 , standard    ,               ,
+Light Shade          , light-shade          , "Modern tapered white polycotton pendant shade with a metallic silver chrome interior finish for maximum light reflection. Reversible gimble so it can be used as a ceiling shade or as a lamp shade."                                                                                                                                                                                                                                                                                        , pierre-chatel-innocenti-483198-unsplash.jpg , category:home & garden|category:furniture ,                   ,                     , B45809LSW    , 28.45   , standard    ,               ,

+ 1 - 347
server/mock-data/mock-data.service.ts

@@ -1,56 +1,23 @@
 import faker from 'faker/locale/en_GB';
-import fs from 'fs-extra';
 import gql from 'graphql-tag';
-import path from 'path';
 
-import { CREATE_FACET } from '../../admin-ui/src/app/data/definitions/facet-definitions';
-import {
-    ADD_OPTION_GROUP_TO_PRODUCT,
-    CREATE_PRODUCT,
-    CREATE_PRODUCT_OPTION_GROUP,
-    GENERATE_PRODUCT_VARIANTS,
-    UPDATE_PRODUCT_VARIANTS,
-} from '../../admin-ui/src/app/data/definitions/product-definitions';
-import {
-    CREATE_CHANNEL,
-    CREATE_COUNTRY,
-    CREATE_TAX_RATE,
-    CREATE_ZONE,
-    GET_CHANNELS,
-    UPDATE_CHANNEL,
-} from '../../admin-ui/src/app/data/definitions/settings-definitions';
+import { CREATE_CHANNEL } from '../../admin-ui/src/app/data/definitions/settings-definitions';
 import { CREATE_SHIPPING_METHOD } from '../../admin-ui/src/app/data/definitions/shipping-definitions';
 import {
-    AddOptionGroupToProduct,
-    Asset,
     Channel,
     CreateAddressInput,
     CreateChannel,
-    CreateCountry,
     CreateCustomerInput,
-    CreateFacet,
-    CreateFacetValueWithFacetInput,
-    CreateProduct,
-    CreateProductOptionGroup,
     CreateShippingMethod,
-    CreateTaxRate,
-    CreateZone,
     CurrencyCode,
-    GenerateProductVariants,
-    GetChannels,
     LanguageCode,
-    ProductTranslationInput,
     ProductVariant,
-    UpdateChannel,
-    UpdateProductVariants,
-    Zone,
 } from '../../shared/generated-types';
 import { defaultShippingCalculator } from '../src/config/shipping-method/default-shipping-calculator';
 import { defaultShippingEligibilityChecker } from '../src/config/shipping-method/default-shipping-eligibility-checker';
 import { Customer } from '../src/entity/customer/customer.entity';
 
 import { SimpleGraphQLClient } from './simple-graphql-client';
-import TaxCategory = ProductVariant.TaxCategory;
 
 // tslint:disable:no-console
 /**
@@ -85,146 +52,6 @@ export class MockDataService {
         return channels;
     }
 
-    async populateCountries(all = false): Promise<Zone.Fragment[]> {
-        const countriesFile = await fs.readFile(
-            path.join(__dirname, 'data-sources', 'countries.json'),
-            'utf8',
-        );
-        const limitedCountries = ['GB', 'DE', 'FR', 'AT', 'US', 'CN', 'JP', 'AU', 'ZA'];
-        const countries: any[] = JSON.parse(countriesFile).filter(c => {
-            if (all) {
-                return true;
-            } else {
-                return limitedCountries.includes(c['alpha-2']);
-            }
-        });
-        const zones: { [zoneName: string]: string[] } = {};
-        for (const country of countries) {
-            const result = await this.client.query<CreateCountry.Mutation, CreateCountry.Variables>(
-                CREATE_COUNTRY,
-                {
-                    input: {
-                        code: country['alpha-2'],
-                        translations: [{ languageCode: LanguageCode.en, name: country.name }],
-                        enabled: true,
-                    },
-                },
-            );
-            if (!zones[country.region]) {
-                zones[country.region] = [];
-            }
-            zones[country.region].push(result.createCountry.id);
-        }
-
-        const createdZones: Zone.Fragment[] = [];
-        for (const [name, memberIds] of Object.entries(zones)) {
-            const result = await this.client.query<CreateZone.Mutation, CreateZone.Variables>(CREATE_ZONE, {
-                input: {
-                    name,
-                    memberIds,
-                },
-            });
-            createdZones.push(result.createZone);
-        }
-        this.log(`Created ${countries.length} Countries in ${Object.keys(zones).length} Zones`);
-        return createdZones;
-    }
-
-    async setChannelDefaultZones(zones: Zone.Fragment[]) {
-        const defaultZone = zones.find(z => z.name === 'UK');
-        if (!defaultZone) {
-            this.log(`Default zone could not be found`);
-            return;
-        }
-        const result = await this.client.query<GetChannels.Query>(GET_CHANNELS);
-        for (const channel of result.channels) {
-            await this.client.query<UpdateChannel.Mutation, UpdateChannel.Variables>(UPDATE_CHANNEL, {
-                input: {
-                    id: channel.id,
-                    defaultTaxZoneId: defaultZone.id,
-                    defaultShippingZoneId: defaultZone.id,
-                },
-            });
-        }
-        this.log(`Set default zones for ${result.channels.length} Channels`);
-    }
-
-    async populateOptions(): Promise<string> {
-        return this.client
-            .query<CreateProductOptionGroup.Mutation, CreateProductOptionGroup.Variables>(
-                CREATE_PRODUCT_OPTION_GROUP,
-                {
-                    input: {
-                        code: 'size',
-                        translations: [
-                            { languageCode: LanguageCode.en, name: 'Size' },
-                            { languageCode: LanguageCode.de, name: 'Größe' },
-                        ],
-                        options: [
-                            {
-                                code: 'small',
-                                translations: [
-                                    { languageCode: LanguageCode.en, name: 'Small' },
-                                    { languageCode: LanguageCode.de, name: 'Klein' },
-                                ],
-                            },
-                            {
-                                code: 'large',
-                                translations: [
-                                    { languageCode: LanguageCode.en, name: 'Large' },
-                                    { languageCode: LanguageCode.de, name: 'Groß' },
-                                ],
-                            },
-                        ],
-                    },
-                },
-            )
-            .then(data => {
-                this.log('Created option group:', data.createProductOptionGroup.name);
-                return data.createProductOptionGroup.id;
-            });
-    }
-
-    async populateTaxCategories(zones: Zone.Fragment[]) {
-        const taxCategories = [{ name: 'Standard Tax' }, { name: 'Reduced Tax' }, { name: 'Zero Tax' }];
-
-        const createdTaxCategories: TaxCategory[] = [];
-
-        for (const category of taxCategories) {
-            const result = await this.client.query(
-                gql`
-                    mutation($input: CreateTaxCategoryInput!) {
-                        createTaxCategory(input: $input) {
-                            id
-                        }
-                    }
-                `,
-                {
-                    input: {
-                        name: category.name,
-                    },
-                },
-            );
-            createdTaxCategories.push(result.createTaxCategory);
-        }
-        this.log(`Created ${createdTaxCategories.length} tax categories`);
-
-        // create tax rates
-        for (const zone of zones) {
-            await this.client.query<CreateTaxRate.Mutation, CreateTaxRate.Variables>(CREATE_TAX_RATE, {
-                input: {
-                    name: `Standard Tax for ${zone.name}`,
-                    enabled: true,
-                    value: 20,
-                    categoryId: createdTaxCategories[0].id,
-                    zoneId: zone.id,
-                },
-            });
-        }
-
-        return createdTaxCategories;
-    }
-
     async populateShippingMethods() {
         await this.client.query<CreateShippingMethod.Mutation, CreateShippingMethod.Variables>(
             CREATE_SHIPPING_METHOD,
@@ -325,182 +152,9 @@ export class MockDataService {
         }
     }
 
-    async populateAssets(): Promise<Asset[]> {
-        const fileNames = await fs.readdir(path.join(__dirname, 'assets'));
-        const filePaths = fileNames
-            .map(fileName => path.join(__dirname, 'assets', fileName))
-            // Sorting is needed because readdir order is not determnistic on Windows.
-            // See https://github.com/nodejs/node/issues/3232
-            .sort((a, b) => (a > b ? 1 : -1));
-        return this.client.uploadAssets(filePaths).then(response => {
-            this.log(`Created ${response.createAssets.length} Assets`);
-            return response.createAssets;
-        });
-    }
-
-    async populateProducts(
-        count: number = 5,
-        optionGroupId: string,
-        assets: Asset[],
-        taxCategories: TaxCategory[],
-    ): Promise<any> {
-        for (let i = 0; i < count; i++) {
-            const query = CREATE_PRODUCT;
-
-            const name = faker.commerce.productName();
-            const slug = name.toLowerCase().replace(/\s+/g, '-');
-            const description = faker.lorem.sentence();
-            const languageCodes = [LanguageCode.en, LanguageCode.de];
-
-            // get 2 (pseudo) random asset ids
-            const randomAssets = this.shuffleArray(assets).slice(0, 2);
-
-            const variables: CreateProduct.Variables = {
-                input: {
-                    translations: languageCodes.map(code =>
-                        this.makeProductTranslation(code, name, slug, description),
-                    ),
-                    assetIds: randomAssets.map(a => a.id),
-                    featuredAssetId: randomAssets[0].id,
-                },
-            };
-
-            const product = await this.client
-                .query<CreateProduct.Mutation, CreateProduct.Variables>(query, variables)
-                .then(
-                    data => {
-                        this.log(`Created Product ${i + 1}:`, data.createProduct.name);
-                        return data;
-                    },
-                    err => this.log(err),
-                );
-
-            if (product) {
-                await this.client.query<AddOptionGroupToProduct.Mutation, AddOptionGroupToProduct.Variables>(
-                    ADD_OPTION_GROUP_TO_PRODUCT,
-                    {
-                        productId: product.createProduct.id,
-                        optionGroupId,
-                    },
-                );
-                const prodWithVariants = await this.makeProductVariant(
-                    product.createProduct.id,
-                    taxCategories[0],
-                );
-                const variants = prodWithVariants.generateVariantsForProduct.variants;
-                for (const variant of variants) {
-                    const variantEN = variant.translations[0];
-                    const variantDE = { ...variantEN };
-                    variantDE.languageCode = LanguageCode.de;
-                    variantDE.name = variantDE.name.replace(LanguageCode.en, LanguageCode.de);
-                    delete variantDE.id;
-                    variant.translations.push(variantDE);
-                }
-                await this.client.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
-                    UPDATE_PRODUCT_VARIANTS,
-                    {
-                        input: variants.map(({ id, translations, sku, price }) => ({
-                            id,
-                            translations,
-                            sku,
-                            price,
-                        })),
-                    },
-                );
-            }
-        }
-    }
-
-    async populateFacets() {
-        await this.client.query<CreateFacet.Mutation, CreateFacet.Variables>(CREATE_FACET, {
-            input: {
-                code: 'brand',
-                translations: [
-                    {
-                        languageCode: LanguageCode.en,
-                        name: 'Brand',
-                    },
-                    {
-                        languageCode: LanguageCode.en,
-                        name: 'Marke',
-                    },
-                ],
-                values: this.makeFacetValues(10),
-            },
-        });
-        this.log('Created "brand" Facet');
-    }
-
-    private makeFacetValues(count: number): CreateFacetValueWithFacetInput[] {
-        return Array.from({ length: count }).map(() => {
-            const brand = faker.company.companyName();
-            return {
-                code: brand.toLowerCase().replace(/[^a-zA-Z]+/g, '-'),
-                translations: [
-                    {
-                        languageCode: LanguageCode.en,
-                        name: brand,
-                    },
-                    {
-                        languageCode: LanguageCode.de,
-                        name: brand,
-                    },
-                ],
-            };
-        });
-    }
-
-    private makeProductTranslation(
-        languageCode: LanguageCode,
-        name: string,
-        slug: string,
-        description: string,
-    ): ProductTranslationInput {
-        return {
-            languageCode,
-            name: `${languageCode} ${name}`,
-            slug: `${languageCode} ${slug}`,
-            description: `${languageCode} ${description}`,
-        };
-    }
-
-    private async makeProductVariant(
-        productId: string,
-        taxCategory: TaxCategory,
-    ): Promise<GenerateProductVariants.Mutation> {
-        const query = GENERATE_PRODUCT_VARIANTS;
-        return this.client.query<GenerateProductVariants.Mutation, GenerateProductVariants.Variables>(query, {
-            productId,
-            defaultTaxCategoryId: taxCategory.id,
-            defaultSku: faker.random.alphaNumeric(5),
-            defaultPrice: faker.random.number({
-                min: 100,
-                max: 1000,
-            }),
-        });
-    }
-
     private log(...args: any[]) {
         if (this.logging) {
             console.log(...args);
         }
     }
-
-    /**
-     * Deterministacally randomize array element order. Returns a new
-     * shuffled array and leaves the input array intact.
-     * Using Durstenfeld shuffle algorithm.
-     *
-     * Source: https://stackoverflow.com/a/12646864/772859
-     */
-    private shuffleArray<T>(array: T[]): T[] {
-        const clone = array.slice(0);
-        for (let i = clone.length - 1; i > 0; i--) {
-            const j = Math.floor((faker.random.number(1000) / 1000) * (i + 1));
-            const temp = clone[i];
-            clone[i] = clone[j];
-            clone[j] = temp;
-        }
-        return clone;
-    }
 }

+ 7 - 2
server/mock-data/populate-cli.ts

@@ -1,3 +1,5 @@
+import path from 'path';
+
 import { devConfig } from '../dev-config';
 import { bootstrap } from '../src';
 import { VendureConfig } from '../src/config/vendure-config';
@@ -14,14 +16,17 @@ if (require.main === module) {
         authOptions: {
             tokenMethod: 'bearer',
         },
+        importExportOptions: {
+            importAssetsDir: path.join(__dirname, 'assets'),
+        },
         customFields: {},
     };
     // tslint:disable
     populate(populateConfig, bootstrap, {
         logging: true,
         customerCount: 10,
-        productCount: 20,
-        channels: ['mobile-app'],
+        productsCsvPath: path.join(__dirname, 'data-sources/products.csv'),
+        initialDataPath: path.join(__dirname, 'data-sources/initial-data'),
     })
         .then(app => app.close())
         .then(

+ 38 - 15
server/mock-data/populate.ts

@@ -1,6 +1,9 @@
+/* tslint:disable:no-console */
 import { INestApplication } from '@nestjs/common';
+import fs from 'fs-extra';
+import path from 'path';
 
-import { Channel } from '../../shared/generated-types';
+import { LanguageCode } from '../../shared/generated-types';
 import { VendureBootstrapFunction } from '../src/bootstrap';
 import { setConfig } from '../src/config/config-helpers';
 import { VendureConfig } from '../src/config/vendure-config';
@@ -12,10 +15,9 @@ import { SimpleGraphQLClient } from './simple-graphql-client';
 
 export interface PopulateOptions {
     logging?: boolean;
-    productCount: number;
     customerCount: number;
-    allCountries?: boolean;
-    channels?: string[];
+    productsCsvPath: string;
+    initialDataPath: string;
 }
 
 // tslint:disable:no-floating-promises
@@ -35,24 +37,45 @@ export async function populate(
     setConfig(config);
     await clearAllTables(config.dbConnectionOptions, logging);
     const app = await bootstrapFn(config);
+
+    await populateInitialData(app, options.initialDataPath);
+    await populateProducts(app, options.productsCsvPath, logging);
+
     const defaultChannelToken = await getDefaultChannelToken(logging);
     const client = new SimpleGraphQLClient(`http://localhost:${config.port}/${config.apiPath}`);
     client.setChannelToken(defaultChannelToken);
     await client.asSuperAdmin();
     const mockDataService = new MockDataService(client, logging);
-    if (options.channels) {
-        await mockDataService.populateChannels(options.channels);
-    }
-    const zones = await mockDataService.populateCountries(options.allCountries);
-    await mockDataService.setChannelDefaultZones(zones);
-    await mockDataService.populateShippingMethods();
-    const assets = await mockDataService.populateAssets();
-    const optionGroupId = await mockDataService.populateOptions();
-    const taxCategories = await mockDataService.populateTaxCategories(zones);
-    await mockDataService.populateProducts(options.productCount, optionGroupId, assets, taxCategories);
     await mockDataService.populateCustomers(options.customerCount);
-    await mockDataService.populateFacets();
+    await mockDataService.populateShippingMethods();
 
     config.authOptions.requireVerification = originalRequireVerification;
     return app;
 }
+
+async function populateInitialData(app: INestApplication, initialDataPath: string) {
+    const { Populator } = await import('../src/data-import/providers/populator/populator');
+    const { initialData } = await import(initialDataPath);
+    const populator = app.get(Populator);
+    try {
+        await populator.populateInitialData(initialData);
+    } catch (err) {
+        console.error(err.message);
+    }
+}
+
+async function populateProducts(app: INestApplication, productsCsvPath: string, logging: boolean) {
+    const { Importer } = await import('../src/data-import/providers/importer/importer');
+    const importer = app.get(Importer);
+    const productData = await fs.readFile(productsCsvPath, 'utf-8');
+
+    const importResult = await importer.parseAndImport(productData, LanguageCode.en, true).toPromise();
+    if (importResult.errors && importResult.errors.length) {
+        console.log(`${importResult.errors.length} errors encountered when importing product data:`);
+        await console.log(importResult.errors.join('\n'));
+    }
+
+    if (logging) {
+        console.log(`\nImported ${importResult.imported} products`);
+    }
+}

+ 1 - 1
server/package.json

@@ -35,7 +35,7 @@
     "@nestjs/testing": "5.5.0",
     "@nestjs/typeorm": "^5.2.2",
     "@types/progress": "^2.0.3",
-    "apollo-server-express": "^2.3.1",
+    "apollo-server-express": "^2.4.0",
     "bcrypt": "^3.0.3",
     "body-parser": "^1.18.3",
     "commander": "^2.19.0",

+ 2 - 0
server/src/data-import/index.ts

@@ -1,2 +1,4 @@
 export * from './providers/populator/populator';
 export * from './providers/importer/importer';
+export { InitialData } from './providers/populator/populator';
+export { CountryData } from './providers/populator/populator';

+ 16 - 1
server/src/data-import/providers/importer/importer.ts

@@ -1,6 +1,7 @@
 import { Injectable } from '@nestjs/common';
 import fs from 'fs-extra';
 import path from 'path';
+import ProgressBar from 'progress';
 import { Observable } from 'rxjs';
 import { Stream } from 'stream';
 
@@ -58,9 +59,23 @@ export class Importer {
     parseAndImport(
         input: string | Stream,
         ctxOrLanguageCode: RequestContext | LanguageCode,
+        reportProgress: boolean = false,
     ): Observable<ImportProgress> {
+        let bar: ProgressBar | undefined;
+
         return new Observable(subscriber => {
             const p = this.doParseAndImport(input, ctxOrLanguageCode, progress => {
+                if (reportProgress) {
+                    if (!bar) {
+                        bar = new ProgressBar('  importing [:bar] :percent :etas  Importing: :prodName', {
+                            complete: '=',
+                            incomplete: ' ',
+                            total: progress.processed,
+                            width: 40,
+                        });
+                    }
+                    bar.tick({ prodName: progress.currentProduct });
+                }
                 subscriber.next(progress);
             }).then(value => {
                 subscriber.next({ ...value, currentProduct: 'Complete' });
@@ -98,7 +113,7 @@ export class Importer {
             }
         } else {
             return {
-                errors: ['nothing to parse!'],
+                errors: [],
                 imported: 0,
                 processed: parsed.processed,
             };

+ 3 - 2
server/src/data-import/providers/populator/populator.ts

@@ -10,11 +10,14 @@ import { TaxCategoryService } from '../../../service/services/tax-category.servi
 import { TaxRateService } from '../../../service/services/tax-rate.service';
 import { ZoneService } from '../../../service/services/zone.service';
 
+type ZoneMap = Map<string, { entity: Zone; members: string[] }>;
+
 export interface CountryData {
     code: string;
     name: string;
     zone: string;
 }
+
 export interface InitialData {
     defaultLanguage: LanguageCode;
     defaultZone: string;
@@ -22,8 +25,6 @@ export interface InitialData {
     taxRates: Array<{ name: string; percentage: number }>;
 }
 
-type ZoneMap = Map<string, { entity: Zone; members: string[] }>;
-
 /**
  * Responsible for populating the database with initial data.
  */

+ 2 - 2
server/src/plugin/default-asset-server-plugin/default-asset-storage-strategy.ts

@@ -18,8 +18,8 @@ export class DefaultAssetStorageStrategy implements AssetStorageStrategy {
         const filePath = path.join(this.uploadPath, fileName);
         const writeStream = fs.createWriteStream(filePath, 'binary');
         return new Promise<string>((resolve, reject) => {
-            data.on('data', chunk => writeStream.write(chunk));
-            data.on('close', () => resolve(this.filePathToIdentifier(filePath)));
+            data.pipe(writeStream);
+            writeStream.on('close', () => resolve(this.filePathToIdentifier(filePath)));
             writeStream.on('error', reject);
         });
     }

+ 111 - 84
server/yarn.lock

@@ -2,11 +2,12 @@
 # yarn lockfile v1
 
 
-"@apollographql/apollo-tools@^0.2.6":
-  version "0.2.7"
-  resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.2.7.tgz#550502b315e49040e07d7e5065d15c5116c506e6"
+"@apollographql/apollo-tools@^0.3.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.3.2.tgz#415c984955c4ae249550def698cbffab8d27bda4"
+  integrity sha512-IiuO1XaxxvbZa19gGHBOEgQKmMHB+ghXaNjSbY5dWqCEQgBDgJBA/2a1Oq9tMPhEPAmEY2FOuhaWRxxKxmVdlQ==
   dependencies:
-    apollo-env "0.2.4"
+    apollo-env "0.3.2"
 
 "@apollographql/graphql-playground-html@^1.6.6":
   version "1.6.6"
@@ -220,7 +221,7 @@
     "@types/node" "*"
     "@types/range-parser" "*"
 
-"@types/express@*", "@types/express@4.16.0", "@types/express@^4.0.39":
+"@types/express@*", "@types/express@^4.0.39":
   version "4.16.0"
   resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19"
   dependencies:
@@ -228,6 +229,15 @@
     "@types/express-serve-static-core" "*"
     "@types/serve-static" "*"
 
+"@types/express@4.16.1":
+  version "4.16.1"
+  resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0"
+  integrity sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg==
+  dependencies:
+    "@types/body-parser" "*"
+    "@types/express-serve-static-core" "*"
+    "@types/serve-static" "*"
+
 "@types/faker@^4.1.4":
   version "4.1.4"
   resolved "https://registry.yarnpkg.com/@types/faker/-/faker-4.1.4.tgz#5e5bcd81a6ecf85fb6150f7eb857e755a09fd91f"
@@ -523,20 +533,20 @@ anymatch@^2.0.0:
     micromatch "^3.1.4"
     normalize-path "^2.1.1"
 
-apollo-cache-control@0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.4.0.tgz#fec343e6ec95aa4f1b88e07e62f067bee0c48397"
-  integrity sha512-WuriaNQIugTE8gYwfBWWCbbQTSKul/cV4JMi5UgqNIUvjHvnKZQLKbt5uYWow6QQNMkLT9hey8QPYkWpogkeSA==
+apollo-cache-control@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.5.0.tgz#78cfefec57c5c0a9648137e3250b91172998061e"
+  integrity sha512-zu26CFj7CboxLB6cckZQEiSUGXIr8MViEGIC5Vesz2yd37sjtevMfRwQhxFuK0HinR0T/WC3dz2k5cj+33vQQQ==
   dependencies:
     apollo-server-env "2.2.0"
-    graphql-extensions "0.4.0"
+    graphql-extensions "0.5.0"
 
-apollo-datasource@0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.2.1.tgz#3ecef4efe64f7a04a43862f32027d38ac09e142c"
-  integrity sha512-r185+JTa5KuF1INeTAk7AEP76zwMN6c8Ph1lmpzJMNwBUEzTGnLClrccCskCBx4SxfnkdKbuQdwn9JwCJUWrdg==
+apollo-datasource@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.3.0.tgz#88c680edd63a2f7ea05fc25da290a430632d39f4"
+  integrity sha512-+jWs3ezhx4lcAAPIHtlj0Zoiv2tvwfzn7feHuhxub3xFwkJm39T8hPjb3aMQCsuS7TukBD+F5ndgVob5hL/5Nw==
   dependencies:
-    apollo-server-caching "0.2.1"
+    apollo-server-caching "0.3.0"
     apollo-server-env "2.2.0"
 
 apollo-engine-reporting-protobuf@0.2.0:
@@ -546,24 +556,33 @@ apollo-engine-reporting-protobuf@0.2.0:
   dependencies:
     protobufjs "^6.8.6"
 
-apollo-engine-reporting@0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-0.2.0.tgz#e71816b1f46e782f8538c5a118148d4c0e628e25"
-  integrity sha512-Q6FfVb10v/nrv8FaFsPjIYlWh62jaYav3LuMgM9PsHWGK/zRQFXOEwLxcY2UCvG7O1moxF3XGmfBhMgo54py+Q==
+apollo-engine-reporting@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.0.0.tgz#af93b755482ad5a6c52f9f728f3e24e801aa2385"
+  integrity sha512-9gZSME9ggZwL1nBBvfgSehwc+PtcvZC1/3NYrBOFgidJbrEFita2w5A0jM8Brjo+N2FMKNYWGj8WQ1ywO21JPg==
   dependencies:
     apollo-engine-reporting-protobuf "0.2.0"
+    apollo-graphql "0.1.0"
+    apollo-server-core "2.4.0"
     apollo-server-env "2.2.0"
     async-retry "^1.2.1"
-    graphql-extensions "0.4.0"
-    lodash "^4.17.10"
+    graphql-extensions "0.5.0"
 
-apollo-env@0.2.4:
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/apollo-env/-/apollo-env-0.2.4.tgz#6af44ef0af1b8c8a4d7da5d66ff55909858a88fa"
+apollo-env@0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/apollo-env/-/apollo-env-0.3.2.tgz#7cd9abd7a65cb0e00c4cfc057a999864f6157b55"
+  integrity sha512-r6nrOw5Pyk6YLNKEtvBiTguJK+oPI1sthKogd7tp6jfkJ+q8SR/9sOoTxyV3vsmR/mMENuBHF89BGLLo9rxDiA==
   dependencies:
-    core-js "^3.0.0-beta.3"
+    core-js "3.0.0-beta.3"
     node-fetch "^2.2.0"
 
+apollo-graphql@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/apollo-graphql/-/apollo-graphql-0.1.0.tgz#e453b133daa8b686644da05ec8e556cf31c57037"
+  integrity sha512-Mi5GqZJz1A/0i8SEm9EVHWe/LkGbYzV5wzobUY+1Q0SI1NdFtRgqHZUdHU0hz1jDnL+dpRqK1huVmtOO/DGa/A==
+  dependencies:
+    lodash.sortby "^4.7.0"
+
 apollo-link@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.2.tgz#54c84199b18ac1af8d63553a68ca389c05217a03"
@@ -579,35 +598,35 @@ apollo-link@^1.2.3:
     apollo-utilities "^1.0.0"
     zen-observable-ts "^0.8.11"
 
-apollo-server-caching@0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.2.1.tgz#7e67f8c8cac829e622b394f0fb82579cabbeadfd"
-  integrity sha512-+U9F3X297LL8Gqy6ypfDNEv/DfV/tDht9Dr2z3AMaEkNW1bwO6rmdDL01zYxDuVDVq6Z3qSiNCSO2pXE2F0zmA==
+apollo-server-caching@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.3.0.tgz#96669b5e3bf693e6a54683edfab4b9495deb17d8"
+  integrity sha512-dHwWUsRZu7I1yUfzTwPJgOigMsftgp8w3X96Zdch1ICWN7cM6aNxks9tTnLd+liUSEzdYLlTmEy5VUturF2IAw==
   dependencies:
     lru-cache "^5.0.0"
 
-apollo-server-core@2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.3.1.tgz#cbdc0020a0dfecf2220cf5062dbb304fdf56edf2"
-  integrity sha512-8jMWYOQIZi9mDJlHe2rXg8Cp4xKYogeRu23jkcNy+k5UjZL+eO+kHXbNFiTaP4HLYYEpe2XE3asxp6q5YUEQeQ==
+apollo-server-core@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.4.0.tgz#928c563f68d9f69a4288e7a4bf14ca79f8599f2b"
+  integrity sha512-rTFJa12NzTWC9IJrXDr8AZMs1Slbes9YxbyaI+cMC5fs8O9wkCkb34C/1Tp7xKX0fgauXrKZpXv7yPTSm+4YFg==
   dependencies:
-    "@apollographql/apollo-tools" "^0.2.6"
+    "@apollographql/apollo-tools" "^0.3.0"
     "@apollographql/graphql-playground-html" "^1.6.6"
     "@types/ws" "^6.0.0"
-    apollo-cache-control "0.4.0"
-    apollo-datasource "0.2.1"
-    apollo-engine-reporting "0.2.0"
-    apollo-server-caching "0.2.1"
+    apollo-cache-control "0.5.0"
+    apollo-datasource "0.3.0"
+    apollo-engine-reporting "1.0.0"
+    apollo-server-caching "0.3.0"
     apollo-server-env "2.2.0"
     apollo-server-errors "2.2.0"
-    apollo-server-plugin-base "0.2.1"
-    apollo-tracing "0.4.0"
-    graphql-extensions "0.4.1"
+    apollo-server-plugin-base "0.3.0"
+    apollo-tracing "0.5.0"
+    fast-json-stable-stringify "^2.0.0"
+    graphql-extensions "0.5.0"
     graphql-subscriptions "^1.0.0"
     graphql-tag "^2.9.2"
     graphql-tools "^4.0.0"
     graphql-upload "^8.0.2"
-    json-stable-stringify "^1.0.1"
     lodash "^4.17.10"
     subscriptions-transport-ws "^0.9.11"
     ws "^6.0.0"
@@ -623,36 +642,36 @@ apollo-server-errors@2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.2.0.tgz#5b452a1d6ff76440eb0f127511dc58031a8f3cb5"
 
-apollo-server-express@^2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.3.1.tgz#0598e2fa0a0d9e6eb570c0bb6ce65c31810a9c09"
-  integrity sha512-J+rObr4GdT/5j6qTByUJoSvZSjTAX/7VqIkr2t+GxwcVUFGet2MdOHuV6rtWKc8CRgvVKfKN6iBrb2EOFcp2LQ==
+apollo-server-express@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.4.0.tgz#fe8e748f07f01a837d1449e4c28ab27ae7b7d054"
+  integrity sha512-uDS7OZJ3EwFr4eZ9k1MiBtUTaqKgCXUUTCknPTdCbTzBel7TjNsa6PNKrSQk+jrLja2H8VwNjbra8uBF5z70Pw==
   dependencies:
     "@apollographql/graphql-playground-html" "^1.6.6"
     "@types/accepts" "^1.3.5"
     "@types/body-parser" "1.17.0"
     "@types/cors" "^2.8.4"
-    "@types/express" "4.16.0"
+    "@types/express" "4.16.1"
     accepts "^1.3.5"
-    apollo-server-core "2.3.1"
+    apollo-server-core "2.4.0"
     body-parser "^1.18.3"
     cors "^2.8.4"
     graphql-subscriptions "^1.0.0"
     graphql-tools "^4.0.0"
     type-is "^1.6.16"
 
-apollo-server-plugin-base@0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.2.1.tgz#d08c9576f7f11ab6e212f352d482faaa4059a31e"
-  integrity sha512-497NIY9VWRYCrMSkgR11IrIUO4Fsy6aGgnpOJoTdLQAnkDD9SJDSRzwKj4gypUoTT2unfKDng4eMxXVZlHvjOw==
+apollo-server-plugin-base@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.3.0.tgz#26c7f9c020b2d444de5bebd2e3c406bebd9c302e"
+  integrity sha512-SOwp4cpZwyklvP1MkMcY6+12c1hrb5gwC4vK4a23kL5rr9FC0sENcXo3uVVM4XlDGOXIkY+sCM8ngKFuef2flw==
 
-apollo-tracing@0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.4.0.tgz#4b939063f4292422ac5a3564b76d1d88dec0a916"
-  integrity sha512-BlM8iQUQva4fm0xD/pLwkcz0degfB9a/aAn4k4cK36eLVD8XUkl7ptEB0c+cwcj7tOYpV1r5QX1XwdayBzlHSg==
+apollo-tracing@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.5.0.tgz#6eebaf1e840ece99299103def689d39fe49780a3"
+  integrity sha512-j0icEhLYf0xS6Q/iCXA2j9KfpYw0a/XvLSUio7fm5yUwtXP2Pp11x5BtK1dI8sLMiaOqUrREz2XjV4PKLzQPuA==
   dependencies:
     apollo-server-env "2.2.0"
-    graphql-extensions "0.4.0"
+    graphql-extensions "0.5.0"
 
 apollo-utilities@^1.0.0, apollo-utilities@^1.0.1:
   version "1.0.16"
@@ -1243,13 +1262,20 @@ builtin-modules@^1.0.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
 
-busboy@^0.2.11, busboy@^0.2.14:
+busboy@^0.2.11:
   version "0.2.14"
   resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
   dependencies:
     dicer "0.2.5"
     readable-stream "1.1.x"
 
+busboy@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.0.tgz#6ee3cb1c844fc1f691d8f9d824f70128b3b5e485"
+  integrity sha512-e+kzZRAbbvJPLjQz2z+zAyr78BSi9IFeBTyLwF76g78Q2zRt/RZ1NtS3MS17v2yLqYfLz69zHdC+1L4ja8PwqQ==
+  dependencies:
+    dicer "0.3.0"
+
 bytes@3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@@ -1684,14 +1710,15 @@ copy-props@^2.0.1:
     each-props "^1.3.0"
     is-plain-object "^2.0.1"
 
+core-js@3.0.0-beta.3:
+  version "3.0.0-beta.3"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.0-beta.3.tgz#b0f22009972b8c6c04550ebf38513ca4b3cc9559"
+  integrity sha512-kM/OfrnMThP5PwGAj5HhQLdjUqzjrllqN2EVnk/X9qrLsfYjR2hzZ+E/8CzH0xuosexZtqMTLQrk//BULrBj9w==
+
 core-js@^2.4.0, core-js@^2.5.0:
   version "2.5.7"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
 
-core-js@^3.0.0-beta.3:
-  version "3.0.0-beta.3"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.0-beta.3.tgz#b0f22009972b8c6c04550ebf38513ca4b3cc9559"
-
 core-util-is@1.0.2, core-util-is@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -1942,6 +1969,13 @@ dicer@0.2.5:
     readable-stream "1.1.x"
     streamsearch "0.1.2"
 
+dicer@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
+  integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==
+  dependencies:
+    streamsearch "0.1.2"
+
 diff@^3.2.0:
   version "3.5.0"
   resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@@ -2579,10 +2613,10 @@ fresh@0.5.2:
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
 
-fs-capacitor@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-1.0.1.tgz#ff9dbfa14dfaf4472537720f19c3088ed9278df0"
-  integrity sha512-XdZK0Q78WP29Vm3FGgJRhRhrBm51PagovzWtW2kJ3Q6cYJbGtZqWSGTSPwvtEkyjIirFd7b8Yes/dpOYjt4RRQ==
+fs-capacitor@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.0.tgz#6cbafaa39313eebf9c49ecff8795aadc08337fc5"
+  integrity sha512-CIJZpxbVWhO+qyODeCR55Q+6vj0p2oL8DAWd/DZi3Ev+25PimUoScw07K0fPgluaH3lFoqNvwW13BDYfHWFQJw==
 
 fs-constants@^1.0.0:
   version "1.0.0"
@@ -2833,19 +2867,12 @@ graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
   version "4.1.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
 
-graphql-extensions@0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.4.0.tgz#5857c7b7b9f20dbccbfd88730fffa5963b3c61ee"
-  integrity sha512-8TUgIIUVpXWOcqq9RdmTSHUrhc3a/s+saKv9cCl8TYWHK9vyJIdea7ZaSKHGDthZNcsN+C3LulZYRL3Ah8ukoA==
-  dependencies:
-    "@apollographql/apollo-tools" "^0.2.6"
-
-graphql-extensions@0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.4.1.tgz#92c49a8409ffbfb24559d7661ab60cc90d6086e4"
-  integrity sha512-Xei4rBxbsTHU6dYiq9y1xxbpRMU3+Os7yD3vXV5W4HbTaxRMizDmu6LAvV4oBEi0ttwICHARQjYTjDTDhHnxrQ==
+graphql-extensions@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.5.0.tgz#117b9872e5cafbebef5254ad795b41fa97037c14"
+  integrity sha512-2i0rpe4/D8jZj6XmxXGLFDAsGLhkFrSdpS5WfvTAzoXOc52hUAxNdsbgRQGeKMFhmanqA6FDXxO/s+BtPHChVA==
   dependencies:
-    "@apollographql/apollo-tools" "^0.2.6"
+    "@apollographql/apollo-tools" "^0.3.0"
 
 graphql-iso-date@^3.6.1:
   version "3.6.1"
@@ -2896,12 +2923,12 @@ graphql-type-json@^0.2.1:
   resolved "https://registry.yarnpkg.com/graphql-type-json/-/graphql-type-json-0.2.1.tgz#d2c177e2f1b17d87f81072cd05311c0754baa420"
 
 graphql-upload@^8.0.2:
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-8.0.2.tgz#1c1f116f15b7f8485cf40ff593a21368f0f58856"
-  integrity sha512-u8a5tKPfJ0rU4MY+B3skabL8pEjMkm3tUzq25KBx6nT0yEWmqUO7Z5tdwvwYLFpkLwew94Gue0ARbZtar3gLTw==
+  version "8.0.4"
+  resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-8.0.4.tgz#ed7cbde883b5cca493de77e39f95cddf40dfd514"
+  integrity sha512-jsTfVYXJ5mU6BXiiJ20CUCAcf41ICCQJ2ltwQFUuaFKiY4JhlG99uZZp5S3hbpQ/oA1kS7hz4pRtsnxPCa7Yfg==
   dependencies:
-    busboy "^0.2.14"
-    fs-capacitor "^1.0.0"
+    busboy "^0.3.0"
+    fs-capacitor "^2.0.0"
     http-errors "^1.7.1"
     object-path "^0.11.4"
 
@@ -4026,7 +4053,7 @@ json-schema@0.2.3:
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
 
-json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
+json-stable-stringify@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
   dependencies: