- Removed manual refresh button from frontend (kept auto-refresh functionality) - Fixed WebKit 'object cannot be found' error by replacing absolute positioning with flexbox - Added lazy loading to images to prevent preload warnings - Cleaned up unused imports and variables: - Removed unused useRef import - Removed unused colors state variable and colorService - Removed unused ColorSwatch import from FilamentTableV2 - Removed unused getModifierIcon function from MaterialBadge - Updated tests to match current implementation - Improved layout stability for better cross-browser compatibility - Removed temporary migration scripts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
229 lines
6.4 KiB
TypeScript
229 lines
6.4 KiB
TypeScript
import { Filament } from '../src/types/filament';
|
|
import { Pool } from 'pg';
|
|
|
|
describe('Data Structure Consistency Tests', () => {
|
|
const connectionString = "postgresql://filamenteka_admin:onrBjiAjHKQXBAJSVWU2t2kQ7HDil9re@filamenteka.ci7fsdlbzmag.eu-central-1.rds.amazonaws.com:5432/filamenteka";
|
|
|
|
// Admin panel expected structure (source of truth)
|
|
const ADMIN_STRUCTURE = {
|
|
fields: [
|
|
'id',
|
|
'tip',
|
|
'finish',
|
|
'boja',
|
|
'boja_hex', // Now using snake_case consistently
|
|
'refill',
|
|
'spulna', // Frontend still uses spulna
|
|
'kolicina',
|
|
'cena',
|
|
'created_at',
|
|
'updated_at'
|
|
],
|
|
requiredFields: ['tip', 'finish', 'boja'],
|
|
excludedFields: ['brand'], // Should NOT exist
|
|
fieldTypes: {
|
|
tip: 'string',
|
|
finish: 'string',
|
|
boja: 'string',
|
|
boja_hex: 'string',
|
|
refill: 'number',
|
|
spulna: 'number',
|
|
kolicina: 'number',
|
|
cena: 'string'
|
|
}
|
|
};
|
|
|
|
// Database expected structure
|
|
const DB_STRUCTURE = {
|
|
columns: [
|
|
'id',
|
|
'tip',
|
|
'finish',
|
|
'boja',
|
|
'boja_hex', // Database uses snake_case
|
|
'refill',
|
|
'spulna',
|
|
'kolicina',
|
|
'cena',
|
|
'created_at',
|
|
'updated_at'
|
|
],
|
|
excludedColumns: ['brand'],
|
|
columnTypes: {
|
|
id: 'uuid',
|
|
tip: 'character varying',
|
|
finish: 'character varying',
|
|
boja: 'character varying',
|
|
boja_hex: 'character varying',
|
|
refill: 'integer',
|
|
spulna: 'integer',
|
|
kolicina: 'integer',
|
|
cena: 'character varying',
|
|
created_at: 'timestamp with time zone',
|
|
updated_at: 'timestamp with time zone'
|
|
}
|
|
};
|
|
|
|
describe('Admin Panel Structure', () => {
|
|
it('should have correct TypeScript interface', () => {
|
|
// Check Filament interface matches admin structure
|
|
const filamentKeys: (keyof Filament)[] = [
|
|
'id', 'tip', 'finish', 'boja', 'boja_hex',
|
|
'refill', 'spulna', 'kolicina', 'cena',
|
|
'status', 'createdAt', 'updatedAt'
|
|
];
|
|
|
|
// Should not have brand
|
|
expect(filamentKeys).not.toContain('brand');
|
|
|
|
// Should have all required fields
|
|
ADMIN_STRUCTURE.requiredFields.forEach(field => {
|
|
expect(filamentKeys).toContain(field);
|
|
});
|
|
});
|
|
|
|
it('should have consistent form fields in admin dashboard', () => {
|
|
const formFields = [
|
|
'tip', 'finish', 'boja', 'boja_hex',
|
|
'refill', 'spulna', 'kolicina', 'cena'
|
|
];
|
|
|
|
// Check all form fields are in admin structure
|
|
formFields.forEach(field => {
|
|
expect(ADMIN_STRUCTURE.fields).toContain(field);
|
|
});
|
|
|
|
// Should not have brand in form
|
|
expect(formFields).not.toContain('brand');
|
|
});
|
|
});
|
|
|
|
describe('Database Schema Consistency', () => {
|
|
let pool: Pool;
|
|
|
|
beforeAll(() => {
|
|
pool = new Pool({
|
|
connectionString,
|
|
ssl: { rejectUnauthorized: false }
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await pool.end();
|
|
});
|
|
|
|
it('should have correct columns in database', async () => {
|
|
const result = await pool.query(`
|
|
SELECT column_name, data_type
|
|
FROM information_schema.columns
|
|
WHERE table_name = 'filaments'
|
|
ORDER BY ordinal_position
|
|
`);
|
|
|
|
const columns = result.rows.map(row => row.column_name);
|
|
const columnTypes = result.rows.reduce((acc, row) => {
|
|
acc[row.column_name] = row.data_type;
|
|
return acc;
|
|
}, {} as Record<string, string>);
|
|
|
|
// Check all expected columns exist
|
|
DB_STRUCTURE.columns.forEach(col => {
|
|
expect(columns).toContain(col);
|
|
});
|
|
|
|
// Check no excluded columns exist
|
|
DB_STRUCTURE.excludedColumns.forEach(col => {
|
|
expect(columns).not.toContain(col);
|
|
});
|
|
|
|
// Check column types match
|
|
Object.entries(DB_STRUCTURE.columnTypes).forEach(([col, type]) => {
|
|
expect(columnTypes[col]).toBe(type);
|
|
});
|
|
});
|
|
|
|
it('should not have brand column', async () => {
|
|
const result = await pool.query(`
|
|
SELECT COUNT(*) as count
|
|
FROM information_schema.columns
|
|
WHERE table_name = 'filaments' AND column_name = 'brand'
|
|
`);
|
|
|
|
expect(parseInt(result.rows[0].count)).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('Frontend Consistency', () => {
|
|
it('should transform fields correctly between admin and database', () => {
|
|
// All fields now use snake_case consistently
|
|
const snakeCaseFields = {
|
|
'boja_hex': 'boja_hex',
|
|
'created_at': 'created_at',
|
|
'updated_at': 'updated_at'
|
|
};
|
|
|
|
Object.entries(snakeCaseFields).forEach(([adminField, dbField]) => {
|
|
expect(ADMIN_STRUCTURE.fields).toContain(adminField);
|
|
expect(DB_STRUCTURE.columns).toContain(dbField);
|
|
});
|
|
});
|
|
|
|
it('should handle quantity fields correctly', () => {
|
|
// Admin form shows refill, spulna as numbers
|
|
// Database stores them as strings like "2", "1 spulna"
|
|
const quantityFields = ['refill', 'spulna'];
|
|
|
|
quantityFields.forEach(field => {
|
|
expect(ADMIN_STRUCTURE.fieldTypes[field]).toBe('number');
|
|
expect(DB_STRUCTURE.columnTypes[field]).toBe('integer');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('API Consistency', () => {
|
|
it('should handle requests without brand field', () => {
|
|
const validRequest = {
|
|
tip: 'PLA',
|
|
finish: 'Basic',
|
|
boja: 'Black',
|
|
boja_hex: '#000000',
|
|
refill: '2',
|
|
spulna: '1 spulna',
|
|
kolicina: '3',
|
|
cena: '3999'
|
|
};
|
|
|
|
// Should not have brand
|
|
expect(validRequest).not.toHaveProperty('brand');
|
|
|
|
// Should have all required fields
|
|
expect(validRequest).toHaveProperty('tip');
|
|
expect(validRequest).toHaveProperty('finish');
|
|
expect(validRequest).toHaveProperty('boja');
|
|
});
|
|
});
|
|
|
|
describe('Data Flow Consistency', () => {
|
|
it('should maintain consistent data flow: Admin → API → Database', () => {
|
|
// Admin form data
|
|
const adminData = {
|
|
tip: 'PLA',
|
|
finish: 'Basic',
|
|
boja: 'Black',
|
|
boja_hex: '#000000',
|
|
refill: '2',
|
|
spulna: '1 spulna',
|
|
kolicina: '3',
|
|
cena: '3999'
|
|
};
|
|
|
|
// No transformation needed - using boja_hex consistently
|
|
const apiData = adminData;
|
|
|
|
// Database expected data
|
|
expect(apiData).toHaveProperty('boja_hex');
|
|
// No longer have bojaHex field
|
|
expect(apiData).not.toHaveProperty('brand');
|
|
});
|
|
});
|
|
}); |