test: add unit tests

This commit is contained in:
Mohamed Marrouchi
2025-06-05 15:29:33 +01:00
parent 7b13bd07ba
commit 1d837ca51d
4 changed files with 212 additions and 21 deletions

View File

@@ -182,6 +182,40 @@ describe('NlpSampleController', () => {
})),
);
});
it('should find nlp samples with patterns', async () => {
const pageQuery = getPageQuery<NlpSample>({ sort: ['text', 'desc'] });
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const result = await nlpSampleController.findPage(
pageQuery,
['language', 'entities'],
{},
patterns,
);
// Should only return samples matching the pattern
const nlpSamples = await nlpSampleService.findByPatternsAndPopulate(
{ filters: {}, patterns },
pageQuery,
);
expect(result).toEqualPayload(nlpSamples);
});
it('should return empty array if no samples match the patterns', async () => {
const pageQuery = getPageQuery<NlpSample>({ sort: ['text', 'desc'] });
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'nonexistent' },
];
const result = await nlpSampleController.findPage(
pageQuery,
['language', 'entities'],
{},
patterns,
);
expect(Array.isArray(result)).toBe(true);
expect(result).toHaveLength(0);
});
});
describe('count', () => {

View File

@@ -78,9 +78,12 @@ export class NlpSampleRepository extends BaseRepository<
}));
return [
// Apply sample-side filters early
{
$match: {
// @todo: think of a better way to handle language to objectId conversion
// This is a workaround for the fact that language is stored as an ObjectId
// in the database, but we want to filter by its string representation.
...filters,
...(filters?.$and
? {
$and: filters.$and?.map((condition) => {
@@ -266,7 +269,7 @@ export class NlpSampleRepository extends BaseRepository<
* Returns the count of samples by filters, entities and/or values
*
* @param criterias `{ filters, entities, values }`
* @returns Promise resolving to `{ count: number }`.
* @returns Promise resolving to the count.
*/
async countByEntities(criterias: {
filters: TFilterQuery<NlpSample>;

View File

@@ -10,9 +10,11 @@ import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { BadRequestException, NotFoundException } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { NlpValueMatchPattern } from '@/chat/schemas/types/pattern';
import { LanguageRepository } from '@/i18n/repositories/language.repository';
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
import { LanguageService } from '@/i18n/services/language.service';
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
import { nlpSampleFixtures } from '@/utils/test/fixtures/nlpsample';
import { installNlpSampleEntityFixtures } from '@/utils/test/fixtures/nlpsampleentity';
import { getPageQuery } from '@/utils/test/pagination';
@@ -360,4 +362,153 @@ describe('NlpSampleService', () => {
expect(extractSpy).not.toHaveBeenCalled();
});
});
describe('findByPatterns', () => {
it('should return samples matching the given patterns', async () => {
// Assume pattern: entity 'intent', value 'greeting'
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const result = await nlpSampleService.findByPatterns(
{ filters: {}, patterns },
undefined,
);
expect(Array.isArray(result)).toBe(true);
expect(result[0].text).toBe('Hello');
});
it('should return an empty array if no samples match the patterns', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'nonexistent' },
];
const result = await nlpSampleService.findByPatterns(
{ filters: {}, patterns },
undefined,
);
expect(Array.isArray(result)).toBe(true);
expect(result).toHaveLength(0);
});
it('should support pagination', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const page: PageQueryDto<NlpSample> = {
limit: 1,
skip: 0,
sort: ['text', 'asc'],
};
const result = await nlpSampleService.findByPatterns(
{ filters: {}, patterns },
page,
);
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(1);
});
});
describe('findByPatternsAndPopulate', () => {
it('should return populated NlpSampleFull instances for matching patterns', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const result = await nlpSampleService.findByPatternsAndPopulate(
{ filters: {}, patterns },
undefined,
);
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBeGreaterThan(0);
result.forEach((sample) => {
expect(sample).toBeInstanceOf(NlpSampleFull);
expect(sample.entities).toBeDefined();
expect(Array.isArray(sample.entities)).toBe(true);
expect(sample.language).toBeDefined();
});
});
it('should return an empty array if no samples match the patterns', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'nonexistent' },
];
const result = await nlpSampleService.findByPatternsAndPopulate(
{ filters: {}, patterns },
undefined,
);
expect(Array.isArray(result)).toBe(true);
expect(result).toHaveLength(0);
});
it('should support pagination and projection', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const page: PageQueryDto<NlpSample> = {
limit: 1,
skip: 0,
sort: ['text', 'asc'],
};
const result = await nlpSampleService.findByPatternsAndPopulate(
{ filters: {}, patterns },
page,
);
expect(Array.isArray(result)).toBe(true);
expect(result.length).toBe(1);
});
});
describe('countByPatterns', () => {
it('should return the correct count for matching patterns', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const count = await nlpSampleService.countByPatterns({
filters: {},
patterns,
});
expect(typeof count).toBe('number');
expect(count).toBe(2);
});
it('should return 0 if no samples match the patterns', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'nonexistent' },
];
const count = await nlpSampleService.countByPatterns({
filters: {},
patterns,
});
expect(count).toBe(0);
});
it('should respect filters (e.g. language)', async () => {
const patterns: NlpValueMatchPattern[] = [
{ entity: 'intent', match: 'value', value: 'greeting' },
];
const filters = { text: 'Hello' };
const count = await nlpSampleService.countByPatterns({
filters,
patterns,
});
expect(typeof count).toBe('number');
expect(count).toBe(1);
});
});
});

View File

@@ -80,15 +80,16 @@ export class NlpSampleService extends BaseService<
page?: PageQueryDto<NlpSample>,
projection?: ProjectionType<NlpSample>,
): Promise<NlpSample[]> {
const values =
patterns.length > 0
? await this.nlpValueService.findByPatterns(patterns)
: [];
if (values.length === 0) {
if (!patterns.length) {
return await this.repository.find(filters, page, projection);
}
const values = await this.nlpValueService.findByPatterns(patterns);
if (!values.length) {
return [];
}
return await this.repository.findByEntities(
{
filters,
@@ -119,15 +120,16 @@ export class NlpSampleService extends BaseService<
page?: PageQueryDto<NlpSample>,
projection?: ProjectionType<NlpSample>,
): Promise<NlpSampleFull[]> {
const values =
patterns.length > 0
? await this.nlpValueService.findByPatterns(patterns)
: [];
if (values.length === 0) {
if (!patterns.length) {
return await this.repository.findAndPopulate(filters, page, projection);
}
const values = await this.nlpValueService.findByPatterns(patterns);
if (!values.length) {
return [];
}
return await this.repository.findByEntitiesAndPopulate(
{
filters,
@@ -143,7 +145,7 @@ export class NlpSampleService extends BaseService<
* present in `patterns`.
*
* @param param0 `{ filters, patterns }`
* @returns Promise resolving to `{ count }`.
* @returns Promise resolving to the count.
*/
async countByPatterns({
filters,
@@ -152,15 +154,16 @@ export class NlpSampleService extends BaseService<
filters: TFilterQuery<NlpSample>;
patterns: NlpValueMatchPattern[];
}): Promise<number> {
const values =
patterns.length > 0
? await this.nlpValueService.findByPatterns(patterns)
: [];
if (values.length === 0) {
if (!patterns.length) {
return await this.repository.count(filters);
}
const values = await this.nlpValueService.findByPatterns(patterns);
if (!values.length) {
return 0;
}
return await this.repository.countByEntities({
filters,
values,