feat: initial setup with WhatsApp CRM apps and sync services
This commit is contained in:
253
apps/whatsapp-crm/tests/integration.test.ts
Normal file
253
apps/whatsapp-crm/tests/integration.test.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
import { initDB, createContact, createTask, createMessage, getContactById, getTasksByContactId, getMessagesByContactId, updateContact, updateTask, closeDB } from '@/lib/db'
|
||||
import { STAGES } from '@/lib/types'
|
||||
|
||||
beforeAll(async () => {
|
||||
await initDB()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
closeDB()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
const db = require('@/lib/db').getDB()
|
||||
db.run('DELETE FROM tasks')
|
||||
db.run('DELETE FROM messages')
|
||||
db.run('DELETE FROM contacts')
|
||||
})
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
describe('10.1 Full Pipeline Tests', () => {
|
||||
it('test_full_contact_lifecycle', async () => {
|
||||
const contact = createContact({ name: 'Test User', phone: '+5511999999991' })
|
||||
expect(contact.id).toBeGreaterThan(0)
|
||||
|
||||
const updated = updateContact(contact.id, { stage: STAGES.DECIDINDO })
|
||||
expect(updated?.stage).toBe(STAGES.DECIDINDO)
|
||||
|
||||
const fetched = getContactById(contact.id)
|
||||
expect(fetched?.name).toBe('Test User')
|
||||
expect(fetched?.stage).toBe(STAGES.DECIDINDO)
|
||||
})
|
||||
|
||||
it('test_contact_with_tasks_lifecycle', async () => {
|
||||
const contact = createContact({ name: 'Task User', phone: '+5511999999992' })
|
||||
|
||||
const task1 = createTask({ contact_id: contact.id, title: 'Task 1', due_date: '2026-04-10' })
|
||||
const task2 = createTask({ contact_id: contact.id, title: 'Task 2', due_date: '2026-04-15' })
|
||||
|
||||
const tasks = getTasksByContactId(contact.id)
|
||||
expect(tasks).toHaveLength(2)
|
||||
|
||||
updateTask(task1.id, { status: 'completed' })
|
||||
|
||||
const allTasks = getTasksByContactId(contact.id)
|
||||
const pending = allTasks.filter(t => t.status === 'pending')
|
||||
expect(pending).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('test_contact_with_messages_lifecycle', async () => {
|
||||
const contact = createContact({ name: 'Message User', phone: '+5511999999993' })
|
||||
|
||||
const msg1 = createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'msg-1',
|
||||
body: 'Hello',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704067200,
|
||||
has_media: false,
|
||||
})
|
||||
|
||||
const msg2 = createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'msg-2',
|
||||
body: 'How are you?',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704070800,
|
||||
has_media: false,
|
||||
})
|
||||
|
||||
const messages = getMessagesByContactId(contact.id)
|
||||
expect(messages).toHaveLength(2)
|
||||
expect(messages[0].body).toBe('How are you?')
|
||||
})
|
||||
|
||||
it('test_duplicate_message_filtered', async () => {
|
||||
const contact = createContact({ name: 'Dupe User', phone: '+5511999999994' })
|
||||
|
||||
createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'same-id',
|
||||
body: 'First message',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704067200,
|
||||
})
|
||||
|
||||
const duplicate = createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'same-id',
|
||||
body: 'Duplicate message',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704070800,
|
||||
})
|
||||
|
||||
expect(duplicate).toBeNull()
|
||||
|
||||
const messages = getMessagesByContactId(contact.id)
|
||||
expect(messages).toHaveLength(1)
|
||||
expect(messages[0].body).toBe('First message')
|
||||
})
|
||||
})
|
||||
|
||||
describe('10.2 Multi-Feature Tests', () => {
|
||||
it('test_search_finds_contact_with_tasks', async () => {
|
||||
createContact({ name: 'Searchable Contact', phone: '+5511999999991' })
|
||||
const contact2 = createContact({ name: 'Other Contact', phone: '+5511999999992' })
|
||||
|
||||
createTask({ contact_id: contact2.id, title: 'Important Task', due_date: '2026-04-10' })
|
||||
|
||||
const { searchContacts } = require('@/lib/db')
|
||||
const results = searchContacts('Searchable')
|
||||
expect(results).toHaveLength(1)
|
||||
expect(results[0].name).toBe('Searchable Contact')
|
||||
})
|
||||
|
||||
it('test_filter_stage_preserves_tasks', async () => {
|
||||
const contact1 = createContact({ name: 'Lead 1', phone: '+5511999999991' })
|
||||
const contact2 = createContact({ name: 'Lead 2', phone: '+5511999999992' })
|
||||
|
||||
updateContact(contact1.id, { stage: STAGES.DECIDINDO })
|
||||
|
||||
createTask({ contact_id: contact1.id, title: 'Task for Decidindo', due_date: '2026-04-10' })
|
||||
createTask({ contact_id: contact2.id, title: 'Task for Leads', due_date: '2026-04-10' })
|
||||
|
||||
const { getContactsByStage } = require('@/lib/db')
|
||||
const leads = getContactsByStage(STAGES.LEADS_DE_ENTRADA)
|
||||
const decidindo = getContactsByStage(STAGES.DECIDINDO)
|
||||
|
||||
expect(leads).toHaveLength(1)
|
||||
expect(decidindo).toHaveLength(1)
|
||||
|
||||
const decidindoTasks = getTasksByContactId(decidindo[0].id)
|
||||
expect(decidindoTasks).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('test_payment_status_update_preserves_all_data', async () => {
|
||||
const contact = createContact({ name: 'Payment User', phone: '+5511999999991', notes: 'Initial note' })
|
||||
|
||||
createTask({ contact_id: contact.id, title: 'Task 1', due_date: '2026-04-10' })
|
||||
createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'msg-1',
|
||||
body: 'Message 1',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704067200,
|
||||
})
|
||||
|
||||
updateContact(contact.id, { payment_status: 'paid', notes: 'Updated note' })
|
||||
|
||||
const updated = getContactById(contact.id)
|
||||
expect(updated?.payment_status).toBe('paid')
|
||||
expect(updated?.notes).toBe('Updated note')
|
||||
|
||||
const tasks = getTasksByContactId(contact.id)
|
||||
expect(tasks).toHaveLength(1)
|
||||
|
||||
const messages = getMessagesByContactId(contact.id)
|
||||
expect(messages).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('10.3 Performance Tests', () => {
|
||||
it('test_bulk_contact_creation', async () => {
|
||||
const startTime = Date.now()
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
createContact({ name: `Contact ${i}`, phone: `+551199999${String(i).padStart(4, '0')}` })
|
||||
}
|
||||
|
||||
const elapsed = Date.now() - startTime
|
||||
expect(elapsed).toBeLessThan(2000)
|
||||
})
|
||||
|
||||
it('test_bulk_task_creation', async () => {
|
||||
const contact = createContact({ name: 'Bulk User', phone: '+5511999999991' })
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
createTask({ contact_id: contact.id, title: `Task ${i}`, due_date: '2026-04-10' })
|
||||
}
|
||||
|
||||
const tasks = getTasksByContactId(contact.id)
|
||||
expect(tasks).toHaveLength(20)
|
||||
})
|
||||
|
||||
it('test_bulk_message_creation', async () => {
|
||||
const contact = createContact({ name: 'Bulk Msg User', phone: '+5511999999991' })
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: `msg-${i}`,
|
||||
body: `Message ${i}`,
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704067200 + i * 3600,
|
||||
})
|
||||
}
|
||||
|
||||
const messages = getMessagesByContactId(contact.id)
|
||||
expect(messages).toHaveLength(20)
|
||||
})
|
||||
})
|
||||
|
||||
describe('10.4 Edge Cases', () => {
|
||||
it('test_delete_contact_cascades_tasks_and_messages', async () => {
|
||||
const contact = createContact({ name: 'To Delete', phone: '+5511999999991' })
|
||||
|
||||
createTask({ contact_id: contact.id, title: 'Task', due_date: '2026-04-10' })
|
||||
createMessage({
|
||||
contact_id: contact.id,
|
||||
external_id: 'msg-1',
|
||||
body: 'Message',
|
||||
from_phone: contact.phone,
|
||||
timestamp: 1704067200,
|
||||
})
|
||||
|
||||
const { deleteContact } = require('@/lib/db')
|
||||
deleteContact(contact.id)
|
||||
|
||||
const tasks = getTasksByContactId(contact.id)
|
||||
const messages = getMessagesByContactId(contact.id)
|
||||
|
||||
expect(tasks).toHaveLength(0)
|
||||
expect(messages).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('test_stage_transitions_all_stages', async () => {
|
||||
const contact = createContact({ name: 'Stage User', phone: '+5511999999991' })
|
||||
|
||||
expect(contact.stage).toBe(STAGES.LEADS_DE_ENTRADA)
|
||||
|
||||
let updated = updateContact(contact.id, { stage: STAGES.DECIDINDO })
|
||||
expect(updated?.stage).toBe(STAGES.DECIDINDO)
|
||||
|
||||
updated = updateContact(contact.id, { stage: STAGES.DISCUSSAO_DE_CONTRATO })
|
||||
expect(updated?.stage).toBe(STAGES.DISCUSSAO_DE_CONTRATO)
|
||||
|
||||
updated = updateContact(contact.id, { stage: STAGES.DECISAO_FINAL })
|
||||
expect(updated?.stage).toBe(STAGES.DECISAO_FINAL)
|
||||
})
|
||||
|
||||
it('test_task_completion_updates_correctly', async () => {
|
||||
const contact = createContact({ name: 'Task User', phone: '+5511999999991' })
|
||||
const task = createTask({ contact_id: contact.id, title: 'To Complete', due_date: '2026-04-10' })
|
||||
|
||||
const completed = updateTask(task.id, { status: 'completed' })
|
||||
expect(completed?.status).toBe('completed')
|
||||
expect(completed?.completed_at).not.toBeNull()
|
||||
|
||||
const reOpened = updateTask(task.id, { status: 'pending' })
|
||||
expect(reOpened?.status).toBe('pending')
|
||||
expect(reOpened?.completed_at).toBeNull()
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user