mirror of https://github.com/buster-so/buster.git
714 lines
21 KiB
TypeScript
714 lines
21 KiB
TypeScript
import { randomUUID } from 'node:crypto';
|
|
import { dashboardFiles, db, inArray, metricFiles } from '@buster/database';
|
|
import { afterEach, beforeEach, describe } from 'vitest';
|
|
//import { modifyDashboardsFileTool } from '../../../src/tools/visualization-tools/modify-dashboards-file-tool';
|
|
|
|
describe('Modify Dashboards File Tool Integration Tests', () => {
|
|
let mockRuntimeContext: Record<string, unknown>;
|
|
let testDataSourceId: string;
|
|
let testUserId: string;
|
|
let testOrgId: string;
|
|
let createdMetricIds: string[] = [];
|
|
let createdDashboardIds: string[] = [];
|
|
|
|
beforeEach(() => {
|
|
// Use real test environment IDs
|
|
testDataSourceId = 'cc3ef3bc-44ec-4a43-8dc4-681cae5c996a';
|
|
testUserId = '1fe85021-e799-471b-8837-953e9ae06e4c';
|
|
testOrgId = 'bf58d19a-8bb9-4f1d-a257-2d2105e7f1ce';
|
|
|
|
mockRuntimeContext = {
|
|
get: (key: string) => {
|
|
const values: Record<string, string> = {
|
|
user_id: testUserId,
|
|
organization_id: testOrgId,
|
|
};
|
|
return values[key];
|
|
},
|
|
};
|
|
|
|
// Reset created IDs arrays
|
|
createdMetricIds = [];
|
|
createdDashboardIds = [];
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Clean up created dashboards and metrics
|
|
try {
|
|
if (createdDashboardIds.length > 0) {
|
|
await db
|
|
.delete(dashboardFiles)
|
|
.where(inArray(dashboardFiles.id, createdDashboardIds))
|
|
.execute();
|
|
}
|
|
|
|
if (createdMetricIds.length > 0) {
|
|
await db.delete(metricFiles).where(inArray(metricFiles.id, createdMetricIds)).execute();
|
|
}
|
|
} catch (error) {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
// Helper function to create test metrics for dashboard testing
|
|
async function createTestMetrics(count = 1): Promise<string[]> {
|
|
const metricIds: string[] = [];
|
|
|
|
for (let i = 1; i <= count; i++) {
|
|
const metricId = randomUUID();
|
|
const metricYml = {
|
|
name: `Test Metric ${i}`,
|
|
description: `A test metric ${i} for dashboard testing`,
|
|
timeFrame: 'Last 30 days',
|
|
sql: `SELECT COUNT(*) as count_${i} FROM test_table_${i}`,
|
|
chartConfig: {
|
|
selectedChartType: 'table',
|
|
columnLabelFormats: {
|
|
[`count_${i}`]: {
|
|
columnType: 'number',
|
|
style: 'number',
|
|
numberSeparatorStyle: ',',
|
|
replaceMissingDataWith: 0,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
await db
|
|
.insert(metricFiles)
|
|
.values({
|
|
id: metricId,
|
|
name: `Test Metric ${i}`,
|
|
fileName: `test-metric-${i}`,
|
|
content: metricYml,
|
|
verification: 'notRequested',
|
|
organizationId: testOrgId,
|
|
createdBy: testUserId,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
versionHistory: {
|
|
versions: [
|
|
{
|
|
versionNumber: 1,
|
|
content: metricYml,
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
],
|
|
},
|
|
dataSourceId: testDataSourceId,
|
|
})
|
|
.execute();
|
|
|
|
metricIds.push(metricId);
|
|
createdMetricIds.push(metricId);
|
|
}
|
|
|
|
return metricIds;
|
|
}
|
|
|
|
// Helper function to create test dashboard for modification testing
|
|
async function createTestDashboard(metricIds: string[]): Promise<string> {
|
|
const dashboardId = randomUUID();
|
|
const dashboardYml = {
|
|
name: 'Original Test Dashboard',
|
|
description: 'Original dashboard for modification testing',
|
|
rows: [
|
|
{
|
|
id: 1,
|
|
items: metricIds.slice(0, Math.min(metricIds.length, 2)).map((id) => ({ id })),
|
|
columnSizes: metricIds.length === 1 ? [12] : [6, 6],
|
|
},
|
|
],
|
|
};
|
|
|
|
await db
|
|
.insert(dashboardFiles)
|
|
.values({
|
|
id: dashboardId,
|
|
name: 'Original Test Dashboard',
|
|
fileName: 'original-test-dashboard',
|
|
content: dashboardYml,
|
|
filter: null,
|
|
organizationId: testOrgId,
|
|
createdBy: testUserId,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
deletedAt: null,
|
|
publiclyAccessible: false,
|
|
publiclyEnabledBy: null,
|
|
publicExpiryDate: null,
|
|
versionHistory: {
|
|
versions: [
|
|
{
|
|
versionNumber: 1,
|
|
content: dashboardYml,
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
],
|
|
},
|
|
publicPassword: null,
|
|
})
|
|
.execute();
|
|
|
|
createdDashboardIds.push(dashboardId);
|
|
return dashboardId;
|
|
}
|
|
/*
|
|
test('should have correct tool configuration', () => {
|
|
expect(modifyDashboardsFileTool.id).toBe('modify-dashboards-file');
|
|
expect(modifyDashboardsFileTool.description).toContain(
|
|
'Updates existing dashboard configuration files'
|
|
);
|
|
expect(modifyDashboardsFileTool.inputSchema).toBeDefined();
|
|
expect(modifyDashboardsFileTool.outputSchema).toBeDefined();
|
|
expect(modifyDashboardsFileTool.execute).toBeDefined();
|
|
});
|
|
|
|
test('should validate tool input schema', () => {
|
|
const validInput = {
|
|
files: [
|
|
{
|
|
id: randomUUID(),
|
|
yml_content: `
|
|
name: Updated Sales Dashboard
|
|
description: An updated comprehensive view of sales metrics
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: f47ac10b-58cc-4372-a567-0e02b2c3d479
|
|
columnSizes:
|
|
- 12
|
|
`,
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = modifyDashboardsFileTool.inputSchema.safeParse(validInput);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
test('should validate tool output schema', () => {
|
|
const validOutput = {
|
|
message: 'Successfully modified 1 dashboard file.',
|
|
duration: 1000,
|
|
files: [
|
|
{
|
|
id: randomUUID(),
|
|
name: 'Updated Test Dashboard',
|
|
file_type: 'dashboard',
|
|
yml_content: 'name: Updated Test Dashboard',
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString(),
|
|
version_number: 2,
|
|
},
|
|
],
|
|
failed_files: [],
|
|
};
|
|
|
|
const result = modifyDashboardsFileTool.outputSchema.safeParse(validOutput);
|
|
expect(result.success).toBe(true);
|
|
});
|
|
|
|
test('should handle runtime context requirements', async () => {
|
|
const contextWithoutUserId = {
|
|
get: (key: string) => {
|
|
if (key === 'user_id') return undefined;
|
|
return 'test-value';
|
|
},
|
|
};
|
|
|
|
const validYaml = `
|
|
name: Test Updated Dashboard
|
|
description: Test updated dashboard
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: f47ac10b-58cc-4372-a567-0e02b2c3d479
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: randomUUID(), yml_content: validYaml }],
|
|
runtimeContext: contextWithoutUserId,
|
|
};
|
|
|
|
await expect(modifyDashboardsFileTool.execute({ context: input })).rejects.toThrow(
|
|
'User ID not found in runtime context'
|
|
);
|
|
});
|
|
|
|
test('should reject modification of non-existent dashboard', async () => {
|
|
const nonExistentId = randomUUID();
|
|
const validYaml = `
|
|
name: Updated Dashboard
|
|
description: Updated dashboard
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: f47ac10b-58cc-4372-a567-0e02b2c3d479
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: nonExistentId, yml_content: validYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(0);
|
|
expect(result.failed_files).toHaveLength(1);
|
|
expect(result.failed_files[0].file_name).toBe(`Dashboard ${nonExistentId}`);
|
|
expect(result.failed_files[0].error).toContain('Dashboard file not found');
|
|
});
|
|
|
|
test('should reject dashboard modification with invalid YAML', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const invalidYaml = `
|
|
name: Invalid Dashboard
|
|
description: Invalid dashboard
|
|
# Missing rows
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: invalidYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(0);
|
|
expect(result.failed_files).toHaveLength(1);
|
|
expect(result.failed_files[0].error).toContain('Failed to validate modified YAML');
|
|
});
|
|
|
|
test('should reject dashboard modification with invalid column sizes', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const invalidColumnSizesYaml = `
|
|
name: Invalid Column Dashboard
|
|
description: Dashboard with invalid column sizes
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 10
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: invalidColumnSizesYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(0);
|
|
expect(result.failed_files).toHaveLength(1);
|
|
expect(result.failed_files[0].error).toContain('Column sizes must sum to exactly 12');
|
|
});
|
|
|
|
test('should reject dashboard modification with non-existent metric IDs', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const nonExistentMetricYaml = `
|
|
name: Non-existent Metric Dashboard
|
|
description: Dashboard referencing non-existent metrics
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: 00000000-0000-0000-0000-000000000000
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: nonExistentMetricYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(0);
|
|
expect(result.failed_files).toHaveLength(1);
|
|
expect(result.failed_files[0].error).toContain('Invalid metric references');
|
|
});
|
|
|
|
test('should successfully modify dashboard with valid changes', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(3);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const updatedDashboardYaml = `
|
|
name: Updated Valid Dashboard
|
|
description: An updated dashboard with valid changes
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
- id: ${metricIds[1]}
|
|
columnSizes:
|
|
- 6
|
|
- 6
|
|
- id: 2
|
|
items:
|
|
- id: ${metricIds[2]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: updatedDashboardYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(1);
|
|
expect(result.failed_files).toHaveLength(0);
|
|
expect(result.files[0].name).toBe('Updated Valid Dashboard');
|
|
expect(result.files[0].file_type).toBe('dashboard');
|
|
expect(result.files[0].version_number).toBe(2); // Should be incremented
|
|
expect(result.message).toBe('Successfully modified 1 dashboard file.');
|
|
|
|
// Verify database was updated
|
|
const updatedDashboard = await db
|
|
.select()
|
|
.from(dashboardFiles)
|
|
.where(eq(dashboardFiles.id, dashboardId))
|
|
.execute();
|
|
|
|
expect(updatedDashboard).toHaveLength(1);
|
|
expect(updatedDashboard[0].name).toBe('Updated Valid Dashboard');
|
|
expect(updatedDashboard[0].content.rows).toHaveLength(2);
|
|
|
|
// Verify version history
|
|
const versionHistory = updatedDashboard[0].versionHistory as never;
|
|
expect(versionHistory.versions).toHaveLength(2);
|
|
expect(versionHistory.versions[1].versionNumber).toBe(2);
|
|
expect(versionHistory.versions[1].content.name).toBe('Updated Valid Dashboard');
|
|
});
|
|
|
|
test('should handle mixed success and failure scenarios', async () => {
|
|
// Create test metrics and dashboards
|
|
const metricIds = await createTestMetrics(2);
|
|
const validDashboardId = await createTestDashboard(metricIds);
|
|
const invalidDashboardId = randomUUID(); // Non-existent dashboard
|
|
|
|
const validDashboardYaml = `
|
|
name: Valid Updated Dashboard
|
|
description: This should succeed
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const invalidDashboardYaml = `
|
|
name: Invalid Dashboard
|
|
description: This should fail because dashboard doesn't exist
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[1]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [
|
|
{ id: validDashboardId, yml_content: validDashboardYaml },
|
|
{ id: invalidDashboardId, yml_content: invalidDashboardYaml },
|
|
],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(1);
|
|
expect(result.failed_files).toHaveLength(1);
|
|
|
|
// The success should be the valid dashboard
|
|
expect(result.files[0].name).toBe('Valid Updated Dashboard');
|
|
|
|
// The failure should be due to non-existent dashboard
|
|
const failure = result.failed_files.find(
|
|
(f) => f.file_name === `Dashboard ${invalidDashboardId}`
|
|
);
|
|
expect(failure?.error).toContain('Dashboard file not found');
|
|
});
|
|
|
|
test('should properly handle version number increments', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
// First modification
|
|
const firstUpdateYaml = `
|
|
name: First Update
|
|
description: First update to the dashboard
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const firstInput = {
|
|
files: [{ id: dashboardId, yml_content: firstUpdateYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const firstResult = await modifyDashboardsFileTool.execute({ context: firstInput });
|
|
expect(firstResult.files[0].version_number).toBe(2);
|
|
|
|
// Second modification
|
|
const secondUpdateYaml = `
|
|
name: Second Update
|
|
description: Second update to the dashboard
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const secondInput = {
|
|
files: [{ id: dashboardId, yml_content: secondUpdateYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const secondResult = await modifyDashboardsFileTool.execute({ context: secondInput });
|
|
expect(secondResult.files[0].version_number).toBe(3);
|
|
|
|
// Verify final database state
|
|
const finalDashboard = await db
|
|
.select()
|
|
.from(dashboardFiles)
|
|
.where(eq(dashboardFiles.id, dashboardId))
|
|
.execute();
|
|
|
|
const versionHistory = finalDashboard[0].versionHistory as never;
|
|
expect(versionHistory.versions).toHaveLength(3);
|
|
expect(versionHistory.versions[0].versionNumber).toBe(1);
|
|
expect(versionHistory.versions[1].versionNumber).toBe(2);
|
|
expect(versionHistory.versions[2].versionNumber).toBe(3);
|
|
});
|
|
|
|
test('should properly format response timing', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const validYaml = `
|
|
name: Timing Test Dashboard
|
|
description: Test response timing
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: validYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.duration).toBeGreaterThan(0);
|
|
expect(typeof result.duration).toBe('number');
|
|
expect(result.duration).toBeLessThan(10000); // Should complete within 10 seconds
|
|
});
|
|
|
|
test('should handle bulk dashboard modifications correctly', async () => {
|
|
// Create test metrics and dashboards
|
|
const metricIds = await createTestMetrics(3);
|
|
const dashboardIds = await Promise.all([
|
|
createTestDashboard([metricIds[0]]),
|
|
createTestDashboard([metricIds[1]]),
|
|
createTestDashboard([metricIds[2]]),
|
|
]);
|
|
|
|
const createDashboardYaml = (index: number) => `
|
|
name: Bulk Updated Dashboard ${index}
|
|
description: Dashboard ${index} for bulk modification testing
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[index - 1]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const files = dashboardIds.map((id, i) => ({
|
|
id,
|
|
yml_content: createDashboardYaml(i + 1),
|
|
}));
|
|
|
|
const input = {
|
|
files,
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(3);
|
|
expect(result.failed_files).toHaveLength(0);
|
|
expect(result.message).toBe('Successfully modified 3 dashboard files.');
|
|
|
|
// Verify all files have proper structure
|
|
result.files.forEach((file, index) => {
|
|
expect(file.file_type).toBe('dashboard');
|
|
expect(file.version_number).toBe(2); // All should be version 2
|
|
expect(file.name).toContain('Bulk Updated Dashboard');
|
|
expect(file.yml_content).toContain(`Bulk Updated Dashboard ${index + 1}`);
|
|
});
|
|
});
|
|
|
|
test('should handle complex dashboard modifications with multiple rows', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(4);
|
|
const dashboardId = await createTestDashboard(metricIds.slice(0, 2));
|
|
|
|
const complexDashboardYaml = `
|
|
name: Complex Updated Dashboard
|
|
description: Dashboard with updated multiple rows and different layouts
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
- id: 2
|
|
items:
|
|
- id: ${metricIds[1]}
|
|
- id: ${metricIds[2]}
|
|
columnSizes:
|
|
- 6
|
|
- 6
|
|
- id: 3
|
|
items:
|
|
- id: ${metricIds[3]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: complexDashboardYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(1);
|
|
expect(result.failed_files).toHaveLength(0);
|
|
expect(result.files[0].name).toBe('Complex Updated Dashboard');
|
|
|
|
// Verify dashboard content in database
|
|
const updatedDashboard = await db
|
|
.select()
|
|
.from(dashboardFiles)
|
|
.where(eq(dashboardFiles.id, dashboardId))
|
|
.execute();
|
|
|
|
expect(updatedDashboard).toHaveLength(1);
|
|
expect(updatedDashboard[0].content.rows).toHaveLength(3);
|
|
expect(updatedDashboard[0].content.rows[0].items).toHaveLength(1);
|
|
expect(updatedDashboard[0].content.rows[1].items).toHaveLength(2);
|
|
expect(updatedDashboard[0].content.rows[2].items).toHaveLength(1);
|
|
});
|
|
|
|
test('should generate appropriate success and error messages', async () => {
|
|
// Test success message
|
|
const metricIds = await createTestMetrics(1);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const validYaml = `
|
|
name: Success Message Test
|
|
description: Test success message generation
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
columnSizes:
|
|
- 12
|
|
`;
|
|
|
|
const successInput = {
|
|
files: [{ id: dashboardId, yml_content: validYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const successResult = await modifyDashboardsFileTool.execute({ context: successInput });
|
|
expect(successResult.message).toBe('Successfully modified 1 dashboard file.');
|
|
|
|
// Test failure message
|
|
const nonExistentId = randomUUID();
|
|
const failureInput = {
|
|
files: [{ id: nonExistentId, yml_content: validYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const failureResult = await modifyDashboardsFileTool.execute({ context: failureInput });
|
|
expect(failureResult.message).toBe('Failed to modify 1 dashboard file.');
|
|
});
|
|
|
|
test('should preserve dashboard structure when modifying with same metric count', async () => {
|
|
// Create test metrics and dashboard
|
|
const metricIds = await createTestMetrics(2);
|
|
const dashboardId = await createTestDashboard(metricIds);
|
|
|
|
const preserveStructureYaml = `
|
|
name: Structure Preserved Dashboard
|
|
description: Dashboard with preserved structure but updated content
|
|
rows:
|
|
- id: 1
|
|
items:
|
|
- id: ${metricIds[0]}
|
|
- id: ${metricIds[1]}
|
|
columnSizes:
|
|
- 6
|
|
- 6
|
|
`;
|
|
|
|
const input = {
|
|
files: [{ id: dashboardId, yml_content: preserveStructureYaml }],
|
|
runtimeContext: mockRuntimeContext,
|
|
};
|
|
|
|
const result = await modifyDashboardsFileTool.execute({ context: input });
|
|
|
|
expect(result.files).toHaveLength(1);
|
|
expect(result.failed_files).toHaveLength(0);
|
|
expect(result.files[0].name).toBe('Structure Preserved Dashboard');
|
|
|
|
// Verify database content
|
|
const updatedDashboard = await db
|
|
.select()
|
|
.from(dashboardFiles)
|
|
.where(eq(dashboardFiles.id, dashboardId))
|
|
.execute();
|
|
|
|
expect(updatedDashboard[0].content.rows[0].items).toHaveLength(2);
|
|
expect(updatedDashboard[0].content.rows[0].columnSizes).toEqual([6, 6]);
|
|
});
|
|
|
|
*/
|
|
});
|