diff --git a/packages/testing/package.json b/packages/testing/package.json index bd6501b912..c448b46a00 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -40,7 +40,9 @@ "sql.js": "^1.0.0" }, "devDependencies": { + "@types/mysql": "^2.15.8", "@vendure/core": "^0.7.0", + "mysql": "^2.17.1", "rimraf": "^3.0.0", "typescript": "^3.6.4" } diff --git a/packages/testing/src/data-population/clear-all-tables.ts b/packages/testing/src/data-population/clear-all-tables.ts index 7a4c7792c8..141bb75c82 100644 --- a/packages/testing/src/data-population/clear-all-tables.ts +++ b/packages/testing/src/data-population/clear-all-tables.ts @@ -11,9 +11,6 @@ export async function clearAllTables(config: VendureConfig, logging = true) { config = await preBootstrapConfig(config); const entityIdStrategy = config.entityIdStrategy; const connection = await createConnection({ ...config.dbConnectionOptions }); - if (logging) { - console.log('Clearing all tables...'); - } try { await connection.synchronize(true); } catch (err) { diff --git a/packages/testing/src/data-population/populate-for-testing.ts b/packages/testing/src/data-population/populate-for-testing.ts index e670cda742..4a18e1fba2 100644 --- a/packages/testing/src/data-population/populate-for-testing.ts +++ b/packages/testing/src/data-population/populate-for-testing.ts @@ -6,7 +6,6 @@ import fs from 'fs-extra'; import { TestServerOptions } from '../types'; -import { clearAllTables } from './clear-all-tables'; import { populateCustomers } from './populate-customers'; // tslint:disable:no-floating-promises @@ -23,7 +22,6 @@ export async function populateForTesting( const originalRequireVerification = config.authOptions.requireVerification; config.authOptions.requireVerification = false; - await clearAllTables(config, logging); const [app, worker] = await bootstrapFn(config); await populateInitialData(app, options.initialData, logging); diff --git a/packages/testing/src/test-server.ts b/packages/testing/src/test-server.ts index be49e3aee2..a2b95718c7 100644 --- a/packages/testing/src/test-server.ts +++ b/packages/testing/src/test-server.ts @@ -3,7 +3,9 @@ import { NestFactory } from '@nestjs/core'; import { DefaultLogger, Logger, VendureConfig } from '@vendure/core'; import { preBootstrapConfig } from '@vendure/core/dist/bootstrap'; import fs from 'fs'; +import { Connection } from 'mysql'; import path from 'path'; +import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'; import { SqljsConnectionOptions } from 'typeorm/driver/sqljs/SqljsConnectionOptions'; import { populateForTesting } from './data-population/populate-for-testing'; @@ -31,16 +33,19 @@ export class TestServer { * is loaded so that the populate step can be skipped, which speeds up the tests significantly. */ async init(options: TestServerOptions): Promise { - const dbFilePath = this.getDbFilePath(options.dataDir); - (this.vendureConfig.dbConnectionOptions as Mutable).location = dbFilePath; - if (!fs.existsSync(dbFilePath)) { - if (options.logging) { - console.log(`Test data not found. Populating database and caching...`); - } - await this.populateInitialData(this.vendureConfig, options); - } - if (options.logging) { - console.log(`Loading test data from "${dbFilePath}"`); + const { type } = this.vendureConfig.dbConnectionOptions; + switch (type) { + case 'sqljs': + await this.initSqljs(options); + break; + case 'mysql': + await this.initMysql( + this.vendureConfig.dbConnectionOptions as MysqlConnectionOptions, + options, + ); + break; + default: + throw new Error(`The TestServer does not support the database type "${type}"`); } const [app, worker] = await this.bootstrapForTesting(this.vendureConfig); if (app) { @@ -68,15 +73,79 @@ export class TestServer { } } + private async initSqljs(options: TestServerOptions) { + const dbFilePath = this.getDbFilePath(options.dataDir); + (this.vendureConfig.dbConnectionOptions as Mutable).location = dbFilePath; + if (!fs.existsSync(dbFilePath)) { + if (options.logging) { + console.log(`Test data not found. Populating database and caching...`); + } + await this.populateInitialData(this.vendureConfig, options); + } + if (options.logging) { + console.log(`Loading test data from "${dbFilePath}"`); + } + } + + private async initMysql(connectionOptions: MysqlConnectionOptions, options: TestServerOptions) { + const filename = this.getCallerFilename(2); + const conn = await this.getMysqlConnection(connectionOptions); + const dbName = 'e2e_' + path.basename(filename).replace(/[^a-z0-9_]/gi, '_'); + (connectionOptions as any).database = dbName; + (connectionOptions as any).synchronize = true; + await new Promise((resolve, reject) => { + conn.query(`DROP DATABASE IF EXISTS ${dbName}`, err => { + if (err) { + console.log(err); + reject(err); + return; + } + resolve(); + }); + }); + await new Promise((resolve, reject) => { + conn.query(`CREATE DATABASE IF NOT EXISTS ${dbName}`, err => { + if (err) { + console.log(err); + reject(err); + return; + } + resolve(); + }); + }); + await this.populateInitialData(this.vendureConfig, options); + conn.destroy(); + } + + private async getMysqlConnection(connectionOptions: MysqlConnectionOptions): Promise { + const { createConnection } = await import('mysql'); + const conn = createConnection({ + host: connectionOptions.host, + port: connectionOptions.port, + user: connectionOptions.username, + password: connectionOptions.password, + }); + await new Promise((resolve, reject) => { + conn.connect(err => { + if (err) { + reject(err); + return; + } + resolve(); + }); + }); + return conn; + } + private getDbFilePath(dataDir: string) { // tslint:disable-next-line:no-non-null-assertion - const testFilePath = this.getCallerFilename(2); + const testFilePath = this.getCallerFilename(3); const dbFileName = path.basename(testFilePath) + '.sqlite'; const dbFilePath = path.join(dataDir, dbFileName); return dbFilePath; } - private getCallerFilename(depth: number) { + private getCallerFilename(depth: number): string { let pst: ErrorConstructor['prepareStackTrace']; let stack: any; let file: any; @@ -106,7 +175,11 @@ export class TestServer { testingConfig: Required, options: TestServerOptions, ): Promise { - (testingConfig.dbConnectionOptions as Mutable).autoSave = true; + const isSqljs = testingConfig.dbConnectionOptions.type === 'sqljs'; + if (isSqljs) { + (testingConfig.dbConnectionOptions as Mutable).autoSave = true; + (testingConfig.dbConnectionOptions as Mutable).synchronize = true; + } const [app, worker] = await populateForTesting(testingConfig, this.bootstrapForTesting, { logging: false, @@ -117,7 +190,9 @@ export class TestServer { } await app.close(); - (testingConfig.dbConnectionOptions as Mutable).autoSave = false; + if (isSqljs) { + (testingConfig.dbConnectionOptions as Mutable).autoSave = false; + } } /** diff --git a/yarn.lock b/yarn.lock index c78423689d..72a5d2f4be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2295,6 +2295,13 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/mysql@^2.15.8": + version "2.15.8" + resolved "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.8.tgz#305172ee6ec530acd16a713f680dbfb4399960a8" + integrity sha512-l0TUdg6KDEaLO75/yjdjksobJDRWv8iZlpRfv/WW1lQZCQDKdTDnKCkeH10oapzP/JTuKiTy6Cvq/sm/0GgcUw== + dependencies: + "@types/node" "*" + "@types/nanoid@^2.1.0": version "2.1.0" resolved "https://registry.npmjs.org/@types/nanoid/-/nanoid-2.1.0.tgz#41edfda78986e9127d0dc14de982de766f994020" @@ -10904,7 +10911,7 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mysql@^2.16.0: +mysql@^2.16.0, mysql@^2.17.1: version "2.17.1" resolved "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz#62bba4a039a9b2f73638cd1652ce50fc6f682899" integrity sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==