From 73918f521112b1330c14f70e53bed1beef549fd1 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Thu, 4 Dec 2025 13:17:07 +0100 Subject: [PATCH] Fix test cases --- .../controllers/__tests__/Workflows.test.ts | 6 +- .../services/__tests__/SegmentService.test.ts | 95 +++++++++++++------ test/helpers/factories.ts | 29 ++++-- vitest.config.ts | 2 +- 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/apps/api/src/controllers/__tests__/Workflows.test.ts b/apps/api/src/controllers/__tests__/Workflows.test.ts index 257de47..0077cfe 100644 --- a/apps/api/src/controllers/__tests__/Workflows.test.ts +++ b/apps/api/src/controllers/__tests__/Workflows.test.ts @@ -43,9 +43,9 @@ describe('Workflows Controller', () => { expect(responseBody.fields).toContain('contact.subscribed'); // Should include custom contact data fields - expect(responseBody.fields).toContain('data.firstName'); - expect(responseBody.fields).toContain('data.lastName'); - expect(responseBody.fields).toContain('data.plan'); + expect(responseBody.fields).toContain('contact.data.firstName'); + expect(responseBody.fields).toContain('contact.data.lastName'); + expect(responseBody.fields).toContain('contact.data.plan'); // Should include event fields expect(responseBody.fields).toContain('event.subject'); diff --git a/apps/api/src/services/__tests__/SegmentService.test.ts b/apps/api/src/services/__tests__/SegmentService.test.ts index 3e01535..58005ac 100644 --- a/apps/api/src/services/__tests__/SegmentService.test.ts +++ b/apps/api/src/services/__tests__/SegmentService.test.ts @@ -233,7 +233,9 @@ describe('SegmentService', () => { expect(segment.name).toBe('VIP Customers'); expect(segment.projectId).toBe(projectId); - expect(Array.isArray(segment.filters)).toBe(true); + // Segments now use condition object with groups containing filters + expect(segment.condition).toBeDefined(); + expect(typeof segment.condition).toBe('object'); }); it('should list all segments for a project', async () => { @@ -387,7 +389,10 @@ describe('SegmentService', () => { await expect( SegmentService.create(projectId, { name: 'Invalid Segment', - filters: [], + condition: { + logic: 'AND', + groups: [{filters: []}], + }, }), ).rejects.toThrow(/at least one filter/i); }); @@ -396,13 +401,20 @@ describe('SegmentService', () => { await expect( SegmentService.create(projectId, { name: 'Invalid Segment', - filters: [ - { - // Intentionally missing field, cast to bypass compile-time validation - operator: 'equals', - value: 'test', - } as InvalidFilterInput as SegmentFilter, - ], + condition: { + logic: 'AND', + groups: [ + { + filters: [ + { + // Intentionally missing field, cast to bypass compile-time validation + operator: 'equals', + value: 'test', + } as InvalidFilterInput as SegmentFilter, + ], + }, + ], + }, }), ).rejects.toThrow(/field is required/i); }); @@ -411,14 +423,21 @@ describe('SegmentService', () => { await expect( SegmentService.create(projectId, { name: 'Invalid Segment', - filters: [ - { - field: 'email', - // Intentionally invalid operator - operator: 'DROP TABLE contacts;', - value: 'test', - } as InvalidFilterInput as SegmentFilter, - ], + condition: { + logic: 'AND', + groups: [ + { + filters: [ + { + field: 'email', + // Intentionally invalid operator + operator: 'DROP TABLE contacts;', + value: 'test', + } as InvalidFilterInput as SegmentFilter, + ], + }, + ], + }, }), ).rejects.toThrow(/invalid operator/i); }); @@ -427,13 +446,20 @@ describe('SegmentService', () => { await expect( SegmentService.create(projectId, { name: 'Invalid Segment', - filters: [ - { - field: 'email', - operator: 'equals', - // Value intentionally omitted - } as InvalidFilterInput as SegmentFilter, - ], + condition: { + logic: 'AND', + groups: [ + { + filters: [ + { + field: 'email', + operator: 'equals', + // Value intentionally omitted + } as InvalidFilterInput as SegmentFilter, + ], + }, + ], + }, }), ).rejects.toThrow(/requires a value/i); }); @@ -441,13 +467,20 @@ describe('SegmentService', () => { it('should ACCEPT valid filters', async () => { const segment = await SegmentService.create(projectId, { name: 'Valid Segment', - filters: [ - { - field: 'subscribed', - operator: 'equals', - value: true, - }, - ], + condition: { + logic: 'AND', + groups: [ + { + filters: [ + { + field: 'subscribed', + operator: 'equals', + value: true, + }, + ], + }, + ], + }, }); expect(segment.id).toBeDefined(); diff --git a/test/helpers/factories.ts b/test/helpers/factories.ts index f2eabb9..434210b 100644 --- a/test/helpers/factories.ts +++ b/test/helpers/factories.ts @@ -1,15 +1,15 @@ import { - PrismaClient, AuthMethod, + CampaignStatus, + EmailSourceType, + EmailStatus, + Prisma, + PrismaClient, Role, TemplateType, - CampaignStatus, - EmailStatus, - EmailSourceType, - WorkflowTriggerType, - WorkflowStepType, WorkflowExecutionStatus, - StepExecutionStatus, + WorkflowStepType, + WorkflowTriggerType } from '@plunk/db'; import {getPrismaClient} from './database'; import bcrypt from 'bcrypt'; @@ -513,20 +513,31 @@ export class TestFactories { /** * Create a segment + * Supports both old format (filters array) and new format (condition object) */ async createSegment( projectId: string, overrides: { name?: string; - filters?: unknown; + filters?: Array<{field: string; operator: string; value?: unknown; unit?: string}>; + condition?: { + logic: 'AND' | 'OR'; + groups: Array<{filters: Array<{field: string; operator: string; value?: unknown; unit?: string}>}>; + }; trackMembership?: boolean; } = {}, ) { + // Convert filters array to condition format if condition not provided + const condition = overrides.condition || { + logic: 'AND' as const, + groups: [{filters: overrides.filters || []}], + }; + return this.prisma.segment.create({ data: { projectId, name: overrides.name || `Segment ${uniqueId()}`, - filters: overrides.filters || [], + condition: condition as unknown as Prisma.InputJsonValue, trackMembership: overrides.trackMembership ?? false, }, }); diff --git a/vitest.config.ts b/vitest.config.ts index 168f407..61fa1a8 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -33,7 +33,7 @@ export default defineConfig({ // Run tests sequentially to avoid database cleanup conflicts fileParallelism: false, // Limit concurrent test files to reduce memory pressure - maxConcurrency: 1, + maxConcurrency: 3, // Only include our test files, not dependency tests include: [ 'apps/**/__tests__/**/*.{test,spec}.{ts,tsx}',