test-server.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { INestApplication } from '@nestjs/common';
  2. import { NestFactory } from '@nestjs/core';
  3. import { Omit } from '@vendure/common/lib/omit';
  4. import fs from 'fs';
  5. import path from 'path';
  6. import { ConnectionOptions } from 'typeorm';
  7. import { SqljsConnectionOptions } from 'typeorm/driver/sqljs/SqljsConnectionOptions';
  8. import { populateForTesting, PopulateOptions } from '../mock-data/populate-for-testing';
  9. import { preBootstrapConfig, runPluginOnBootstrapMethods } from '../src/bootstrap';
  10. import { Mutable } from '../src/common/types/common-types';
  11. import { VendureConfig } from '../src/config/vendure-config';
  12. import { testConfig } from './config/test-config';
  13. import { setTestEnvironment } from './utils/test-environment';
  14. // tslint:disable:no-console
  15. /**
  16. * A server against which the e2e tests should be run.
  17. */
  18. export class TestServer {
  19. app: INestApplication;
  20. /**
  21. * Bootstraps an instance of Vendure server and populates the database according to the options
  22. * passed in. Should be called immediately after creating the client in the `beforeAll` function.
  23. *
  24. * The populated data is saved into an .sqlite file for each test file. On subsequent runs, this file
  25. * is loaded so that the populate step can be skipped, which speeds up the tests significantly.
  26. */
  27. async init(
  28. options: Omit<PopulateOptions, 'initialDataPath'>,
  29. customConfig: Partial<VendureConfig> = {},
  30. ): Promise<void> {
  31. setTestEnvironment();
  32. const testingConfig = { ...testConfig, ...customConfig };
  33. if (options.logging) {
  34. (testingConfig.dbConnectionOptions as Mutable<ConnectionOptions>).logging = true;
  35. }
  36. const dbFilePath = this.getDbFilePath();
  37. (testingConfig.dbConnectionOptions as Mutable<SqljsConnectionOptions>).location = dbFilePath;
  38. if (!fs.existsSync(dbFilePath)) {
  39. if (options.logging) {
  40. console.log(`Test data not found. Populating database and caching...`);
  41. }
  42. await this.populateInitialData(testingConfig, options);
  43. }
  44. if (options.logging) {
  45. console.log(`Loading test data from "${dbFilePath}"`);
  46. }
  47. this.app = await this.bootstrapForTesting(testingConfig);
  48. }
  49. /**
  50. * Destroy the Vendure instance. Should be called in the `afterAll` function.
  51. */
  52. async destroy() {
  53. await this.app.close();
  54. }
  55. private getDbFilePath() {
  56. const dbDataDir = '__data__';
  57. // tslint:disable-next-line:no-non-null-assertion
  58. const testFilePath = module!.parent!.filename;
  59. const dbFileName = path.basename(testFilePath) + '.sqlite';
  60. const dbFilePath = path.join(path.dirname(testFilePath), dbDataDir, dbFileName);
  61. return dbFilePath;
  62. }
  63. /**
  64. * Populates an .sqlite database file based on the PopulateOptions.
  65. */
  66. private async populateInitialData(
  67. testingConfig: VendureConfig,
  68. options: Omit<PopulateOptions, 'initialDataPath'>,
  69. ): Promise<void> {
  70. (testingConfig.dbConnectionOptions as Mutable<SqljsConnectionOptions>).autoSave = true;
  71. const app = await populateForTesting(testingConfig, this.bootstrapForTesting, {
  72. logging: false,
  73. ...{
  74. ...options,
  75. initialDataPath: path.join(__dirname, 'fixtures/e2e-initial-data.ts'),
  76. },
  77. });
  78. await app.close();
  79. (testingConfig.dbConnectionOptions as Mutable<SqljsConnectionOptions>).autoSave = false;
  80. }
  81. /**
  82. * Bootstraps an instance of the Vendure server for testing against.
  83. */
  84. private async bootstrapForTesting(userConfig: Partial<VendureConfig>): Promise<INestApplication> {
  85. const config = await preBootstrapConfig(userConfig);
  86. const appModule = await import('../src/app.module');
  87. const app = await NestFactory.create(appModule.AppModule, { cors: config.cors, logger: false });
  88. await runPluginOnBootstrapMethods(config, app);
  89. await app.listen(config.port);
  90. return app;
  91. }
  92. }