mongo.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import ConnectionString from 'mongodb-connection-string-url';
  2. import { MongoMemoryServer } from 'mongodb-memory-server-core';
  3. import mongoose from 'mongoose';
  4. import { afterAll, beforeAll } from 'vitest';
  5. import { mongoOptions } from '~/server/util/mongoose-utils';
  6. let mongoServer: MongoMemoryServer | undefined;
  7. /**
  8. * Replace the database name in a MongoDB connection URI.
  9. * Uses mongodb-connection-string-url package for robust parsing.
  10. * Supports various URI formats including authentication, replica sets, and query parameters.
  11. *
  12. * @param uri - MongoDB connection URI
  13. * @param newDbName - New database name to use
  14. * @returns Modified URI with the new database name
  15. */
  16. export function replaceMongoDbName(uri: string, newDbName: string): string {
  17. const cs = new ConnectionString(uri);
  18. cs.pathname = `/${newDbName}`;
  19. return cs.href;
  20. }
  21. /**
  22. * Get test database configuration for the current Vitest worker.
  23. * Each worker gets a unique database name to avoid conflicts in parallel execution.
  24. */
  25. export function getTestDbConfig(): {
  26. workerId: string;
  27. dbName: string;
  28. mongoUri: string | null;
  29. } {
  30. // VITEST_WORKER_ID is provided by Vitest (e.g., "1", "2", "3"...)
  31. const workerId = process.env.VITEST_WORKER_ID || '1';
  32. const dbName = `growi_test_${workerId}`;
  33. const mongoUri = process.env.MONGO_URI
  34. ? replaceMongoDbName(process.env.MONGO_URI, dbName)
  35. : null;
  36. return { workerId, dbName, mongoUri };
  37. }
  38. beforeAll(async () => {
  39. // Skip if already connected (setupFiles run per test file, but connection persists per worker)
  40. if (mongoose.connection.readyState === 1) {
  41. return;
  42. }
  43. const { workerId, dbName, mongoUri } = getTestDbConfig();
  44. // Use external MongoDB if MONGO_URI is provided (e.g., in CI with GitHub Actions services)
  45. if (mongoUri != null) {
  46. // biome-ignore lint/suspicious/noConsole: Allow logging
  47. console.log(`Using external MongoDB at ${mongoUri} (worker: ${workerId})`);
  48. // Migrations are run by migrate-mongo.ts setup file
  49. await mongoose.connect(mongoUri, mongoOptions);
  50. return;
  51. }
  52. // Use MongoMemoryServer for local development
  53. // set debug flag
  54. process.env.MONGOMS_DEBUG = process.env.VITE_MONGOMS_DEBUG;
  55. // set version
  56. mongoServer = await MongoMemoryServer.create({
  57. instance: {
  58. dbName,
  59. },
  60. binary: {
  61. version: process.env.VITE_MONGOMS_VERSION,
  62. downloadDir: 'node_modules/.cache/mongodb-binaries',
  63. },
  64. });
  65. // biome-ignore lint/suspicious/noConsole: Allow logging
  66. console.log(
  67. `MongoMemoryServer is running on ${mongoServer.getUri()} (worker: ${workerId})`,
  68. );
  69. await mongoose.connect(mongoServer.getUri(), mongoOptions);
  70. });
  71. afterAll(async () => {
  72. await mongoose.disconnect();
  73. // Stop MongoMemoryServer if it was created
  74. if (mongoServer) {
  75. await mongoServer.stop();
  76. }
  77. });