mirror of
https://github.com/acedanger/finance.git
synced 2025-12-06 07:00:13 -08:00
Fix: Update button remaining disabled in transaction edit mode
This commit resolves an issue where the Update button in the transaction form would remain disabled when attempting to edit a transaction. The problem was in how the transactionStore was managing state updates during transaction editing. Key changes: - Enhanced startEditingTransaction function in transactionStore.ts to ensure proper reactivity - Added clean copy creation of transaction objects to avoid reference issues - Implemented a state update cycle with null value first to force reactivity - Added a small timeout to ensure state changes are properly detected by components The Transaction form now correctly enables the Update button when in edit mode, regardless of account selection state.
This commit is contained in:
238
src/test/db-integration.test.ts
Normal file
238
src/test/db-integration.test.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import supertest from 'supertest';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { accountService, transactionService } from '../data/db.service';
|
||||
import { prisma } from '../data/prisma';
|
||||
|
||||
// Define a test server
|
||||
// Note: In a real scenario, you might want to start an actual server or mock the Astro API routes
|
||||
const BASE_URL = 'http://localhost:3000';
|
||||
const request = supertest(BASE_URL);
|
||||
|
||||
// Test variables to store IDs across tests
|
||||
let testAccountId = '';
|
||||
let testTransactionId = '';
|
||||
|
||||
// Skip these tests if we detect we're not in an environment with a database
|
||||
// This helps avoid failing tests in CI/CD environments without DB setup
|
||||
const shouldSkipTests = process.env.NODE_ENV === 'test' && !process.env.DATABASE_URL;
|
||||
|
||||
// Run this entire test suite conditionally
|
||||
describe('Database Integration Tests', () => {
|
||||
// Setup before all tests
|
||||
beforeAll(async () => {
|
||||
if (shouldSkipTests) {
|
||||
console.warn('Skipping database tests: No database connection available');
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify database connection
|
||||
try {
|
||||
await prisma.$connect();
|
||||
console.log('Database connection successful');
|
||||
|
||||
// Create a test account
|
||||
const testAccount = await accountService.create({
|
||||
bankName: 'Test Bank',
|
||||
accountNumber: '123456',
|
||||
name: 'Test Account',
|
||||
type: 'CHECKING',
|
||||
balance: 1000,
|
||||
notes: 'Created for automated testing',
|
||||
});
|
||||
testAccountId = testAccount.id;
|
||||
console.log(`Created test account with ID: ${testAccountId}`);
|
||||
} catch (error) {
|
||||
console.error('Database connection failed:', error);
|
||||
// We'll check this in the first test and skip as needed
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup after all tests
|
||||
afterAll(async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
try {
|
||||
// Clean up the test data
|
||||
if (testTransactionId) {
|
||||
await transactionService.delete(testTransactionId);
|
||||
console.log(`Cleaned up test transaction: ${testTransactionId}`);
|
||||
}
|
||||
|
||||
if (testAccountId) {
|
||||
await accountService.delete(testAccountId);
|
||||
console.log(`Cleaned up test account: ${testAccountId}`);
|
||||
}
|
||||
|
||||
await prisma.$disconnect();
|
||||
} catch (error) {
|
||||
console.error('Cleanup failed:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// Conditional test execution - checks if DB is available
|
||||
it('should connect to the database', () => {
|
||||
if (shouldSkipTests) {
|
||||
return it.skip('Database tests are disabled in this environment');
|
||||
}
|
||||
|
||||
// This is just a placeholder test - real connection check happens in beforeAll
|
||||
expect(prisma).toBeDefined();
|
||||
});
|
||||
|
||||
// Test Account API
|
||||
describe('Account API', () => {
|
||||
it('should get all accounts', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const response = await request.get('/api/accounts');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(Array.isArray(response.body)).toBe(true);
|
||||
expect(response.body.length).toBeGreaterThan(0);
|
||||
|
||||
// Check if our test account is in the response
|
||||
const foundAccount = response.body.find((account: any) => account.id === testAccountId);
|
||||
expect(foundAccount).toBeDefined();
|
||||
});
|
||||
|
||||
it('should get a single account by ID', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const response = await request.get(`/api/accounts/${testAccountId}`);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.id).toBe(testAccountId);
|
||||
expect(response.body.name).toBe('Test Account');
|
||||
expect(response.body.bankName).toBe('Test Bank');
|
||||
expect(response.body.accountNumber).toBe('123456');
|
||||
});
|
||||
});
|
||||
|
||||
// Test Transaction API
|
||||
describe('Transaction API', () => {
|
||||
it('should create a new transaction', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const transactionData = {
|
||||
accountId: testAccountId,
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
description: 'Test Transaction',
|
||||
amount: -50.25,
|
||||
category: 'Testing',
|
||||
type: 'WITHDRAWAL',
|
||||
};
|
||||
|
||||
const response = await request
|
||||
.post('/api/transactions')
|
||||
.send(transactionData)
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Accept', 'application/json');
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body.id).toBeDefined();
|
||||
expect(response.body.description).toBe('Test Transaction');
|
||||
expect(response.body.amount).toBe(-50.25);
|
||||
|
||||
// Save the transaction ID for later tests
|
||||
testTransactionId = response.body.id;
|
||||
});
|
||||
|
||||
it('should get account transactions', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const response = await request.get(`/api/accounts/${testAccountId}/transactions`);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(Array.isArray(response.body)).toBe(true);
|
||||
|
||||
// Check if our test transaction is in the response
|
||||
const foundTransaction = response.body.find((txn: any) => txn.id === testTransactionId);
|
||||
expect(foundTransaction).toBeDefined();
|
||||
expect(foundTransaction.description).toBe('Test Transaction');
|
||||
});
|
||||
|
||||
it('should update a transaction', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const updateData = {
|
||||
description: 'Updated Transaction',
|
||||
amount: -75.5,
|
||||
};
|
||||
|
||||
const response = await request
|
||||
.put(`/api/transactions/${testTransactionId}`)
|
||||
.send(updateData)
|
||||
.set('Content-Type', 'application/json')
|
||||
.set('Accept', 'application/json');
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.description).toBe('Updated Transaction');
|
||||
expect(response.body.amount).toBe(-75.5);
|
||||
});
|
||||
|
||||
it('should verify account balance updates after transaction changes', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
// Get the latest account data
|
||||
const account = await accountService.getById(testAccountId);
|
||||
expect(account).toBeDefined();
|
||||
|
||||
if (account) {
|
||||
// The account should have been debited by the transaction amount
|
||||
expect(account.balance).toBe(1000 - 75.5);
|
||||
}
|
||||
});
|
||||
|
||||
it('should delete a transaction', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
// Get the initial account data
|
||||
const accountBefore = await accountService.getById(testAccountId);
|
||||
const initialBalance = accountBefore?.balance || 0;
|
||||
|
||||
const response = await request.delete(`/api/transactions/${testTransactionId}`);
|
||||
expect(response.status).toBe(204);
|
||||
|
||||
// Verify the transaction is gone
|
||||
const transactionCheck = await transactionService.getById(testTransactionId);
|
||||
expect(transactionCheck).toBeNull();
|
||||
|
||||
// Verify account balance was restored
|
||||
const accountAfter = await accountService.getById(testAccountId);
|
||||
expect(accountAfter?.balance).toBe(initialBalance + 75.5);
|
||||
|
||||
// Clear the testTransactionId since it's been deleted
|
||||
testTransactionId = '';
|
||||
});
|
||||
});
|
||||
|
||||
// Test error handling
|
||||
describe('Error Handling', () => {
|
||||
it('should handle invalid transaction creation', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
// Missing required fields
|
||||
const invalidData = {
|
||||
accountId: testAccountId,
|
||||
// Missing date, description, amount
|
||||
};
|
||||
|
||||
const response = await request
|
||||
.post('/api/transactions')
|
||||
.send(invalidData)
|
||||
.set('Content-Type', 'application/json');
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle non-existent account', async () => {
|
||||
if (shouldSkipTests) return;
|
||||
|
||||
const response = await request.get('/api/accounts/non-existent-id');
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(response.body.error).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user