I'm using the NestJS framework, and I created a Mongoose schema using the @nestjs/mongoose package. To ensure everything works properly, I wrote an integration to verify that my search indexes are correctly configured.
My schema with search indexes
@Schema({ timestamps: true })
export class Customer {
@Prop({
type: mongoose.Schema.Types.ObjectId,
required: [true, 'companyId is required'],
immutable: true,
ref: 'Company',
})
companyId: mongoose.Types.ObjectId
@Prop({
type: String,
required: [true, 'reference is required'],
immutable: true,
match: [CUSTOMER_REFERENCE_PATTERN, 'reference must follow the format: ...'],
})
reference: string
@Prop(nameType)
name: string
@Prop({
type: String,
default: null,
trim: true,
minlength: [2, 'shortName must be between 2 and 10 characters long'],
maxlength: [10, 'shortName must be between 2 and 10 characters long'],
})
shortName: string | null
}
export const CustomerFeature = {
name: Customer.name,
useFactory: () => {
const schema = SchemaFactory.createForClass(Customer)
schema.searchIndex({
name: 'default',
type: 'search',
definition: {
mappings: {
dynamic: false,
fields: {
companyId: { type: 'token' },
name: { type: 'autocomplete' },
shortName: { type: 'autocomplete', maxGrams: 10 },
reference: { type: 'autocomplete' },
},
},
},
})
return schema
},
}
My integration test using TestContainers to start a MongoDB container
describe('CustomerService (Integration)', () => {
let module: TestingModule
let mongoContainer: StartedTestContainer
let customerService: CustomerService
let customerModel: Model
const companyId = faker.database.mongodbObjectId()
beforeAll(async () => {
mongoContainer = await new GenericContainer('mongodb/mongodb-atlas-local:8.0.4')
.withExposedPorts(27017)
.start()
const mongodbHost = mongoContainer.getHost()
const mongodbPort = mongoContainer.getMappedPort(27017)
module = await Test.createTestingModule({
imports: [
MongooseModule.forRoot(`mongodb://${mongodbHost}:${mongodbPort}`, { directConnection: true }),
MongooseModule.forFeatureAsync([ CustomerFeature]),
],
providers: [CustomerService],
}).compile()
customerModel = module.get(getModelToken(Customer.name))
await customerModel.syncIndexes()
customerService = module.get(CustomerService)
})
beforeEach(async () => {
await Promise.all([customerModel.deleteMany()])
vi.restoreAllMocks()
})
afterAll(async () => {
if (mongoContainer) await mongoContainer.stop()
if (module) await module.close()
})
describe('searchCustomers', () => {
it('should found customer', async () => {
await customerModel.insertOne({
...generateCustomer(),
name: 'John Doe',
companyId,
})
const result = await customerService.searchCustomers(companyId, 'doe')
expect(result).toEqual(
expect.arrayContaining([
{
_id: expect.any(Types.ObjectId),
name: 'John Doe',
shortName: expect.any(String),
reference: expect.any(String),
score: expect.any(Number),
},
]),
)
})
})
})
But my test throw this error MongoServerError: Error connecting to localhost:27027 (127.0.0.1:27027) :: caused by :: onInvoke :: caused by :: Connection refused
I even created another instance of my container using Docker, went inside it, and was able to create a search index and make it work. But when I try to do the same from my test container setup, it doesn’t work.
I think the error is due to MongoDB Atlas Search inside my test container, but I have no idea what’s wrong or how to fix it.