Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
303 lines
12 KiB
JavaScript
303 lines
12 KiB
JavaScript
/**
|
|
* Tests for Docker Section JavaScript
|
|
*/
|
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { JSDOM } from 'jsdom';
|
|
|
|
// Mock fetch
|
|
global.fetch = vi.fn();
|
|
|
|
const createTestDom = () => {
|
|
const dom = new JSDOM(`
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<body>
|
|
<div id="docker-hosts-grid"></div>
|
|
<div id="docker-stat-hosts">0</div>
|
|
<div id="docker-stat-containers">0</div>
|
|
<div id="docker-stat-images">0</div>
|
|
<div id="docker-stat-alerts">0</div>
|
|
<div id="docker-alerts-badge" class="hidden">0</div>
|
|
<input id="docker-search" type="text" />
|
|
<div id="docker-detail-modal" class="hidden"></div>
|
|
<div id="docker-containers-list"></div>
|
|
<div id="docker-images-list"></div>
|
|
<div id="docker-volumes-list"></div>
|
|
<div id="docker-host-alerts-list"></div>
|
|
<div id="docker-logs-modal" class="hidden"></div>
|
|
<div id="docker-logs-content"></div>
|
|
</body>
|
|
</html>
|
|
`);
|
|
|
|
global.window = dom.window;
|
|
global.document = dom.window.document;
|
|
global.localStorage = {
|
|
getItem: vi.fn(),
|
|
setItem: vi.fn(),
|
|
removeItem: vi.fn(),
|
|
};
|
|
};
|
|
|
|
// Import docker section after DOM setup
|
|
const dockerSection = {
|
|
hosts: [],
|
|
stats: {},
|
|
|
|
formatRelativeTime(dateStr) {
|
|
if (!dateStr) return 'N/A';
|
|
const date = new Date(dateStr);
|
|
const now = new Date();
|
|
const diffMs = now - date;
|
|
const diffMins = Math.floor(diffMs / 60000);
|
|
const diffHours = Math.floor(diffMins / 60);
|
|
const diffDays = Math.floor(diffHours / 24);
|
|
|
|
if (diffMins < 1) return 'À l\'instant';
|
|
if (diffMins < 60) return `Il y a ${diffMins}min`;
|
|
if (diffHours < 24) return `Il y a ${diffHours}h`;
|
|
return `Il y a ${diffDays}j`;
|
|
},
|
|
|
|
formatBytes(bytes) {
|
|
if (!bytes) return '0 B';
|
|
const k = 1024;
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
},
|
|
|
|
renderHostCard(host) {
|
|
const statusColor = host.docker_status === 'online' ? 'green' :
|
|
host.docker_status === 'offline' ? 'red' : 'yellow';
|
|
return `<div class="glass-card" data-host-id="${host.host_id}">
|
|
<h3>${host.host_name}</h3>
|
|
<span class="status-${statusColor}">${host.docker_status}</span>
|
|
<div>${host.containers_running}/${host.containers_total} containers</div>
|
|
</div>`;
|
|
},
|
|
|
|
renderHostsGrid() {
|
|
const grid = document.getElementById('docker-hosts-grid');
|
|
if (!grid) return;
|
|
|
|
if (this.hosts.length === 0) {
|
|
grid.innerHTML = '<div class="empty">Aucun host Docker</div>';
|
|
return;
|
|
}
|
|
|
|
grid.innerHTML = this.hosts.map(host => this.renderHostCard(host)).join('');
|
|
},
|
|
|
|
updateStatsDisplay() {
|
|
const el = (id, value) => {
|
|
const elem = document.getElementById(id);
|
|
if (elem) elem.textContent = value;
|
|
};
|
|
|
|
el('docker-stat-hosts', this.stats.enabled_hosts || 0);
|
|
el('docker-stat-containers', this.stats.running_containers || 0);
|
|
el('docker-stat-images', this.stats.total_images || 0);
|
|
el('docker-stat-alerts', this.stats.open_alerts || 0);
|
|
},
|
|
|
|
filterHosts(query) {
|
|
const cards = document.querySelectorAll('#docker-hosts-grid > div[data-host-id]');
|
|
const lowerQuery = query.toLowerCase();
|
|
|
|
cards.forEach(card => {
|
|
const hostId = card.dataset.hostId;
|
|
const host = this.hosts.find(h => h.host_id === hostId);
|
|
if (host) {
|
|
const matches = host.host_name.toLowerCase().includes(lowerQuery) ||
|
|
host.host_ip.toLowerCase().includes(lowerQuery);
|
|
card.style.display = matches ? '' : 'none';
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
describe('Docker Section', () => {
|
|
beforeEach(() => {
|
|
createTestDom();
|
|
vi.clearAllMocks();
|
|
dockerSection.hosts = [];
|
|
dockerSection.stats = {};
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Cleanup between tests
|
|
if (global.document) {
|
|
global.document.body.innerHTML = '';
|
|
}
|
|
});
|
|
|
|
describe('formatRelativeTime', () => {
|
|
it('returns N/A for null input', () => {
|
|
expect(dockerSection.formatRelativeTime(null)).toBe('N/A');
|
|
});
|
|
|
|
it('returns "À l\'instant" for recent times', () => {
|
|
const now = new Date().toISOString();
|
|
expect(dockerSection.formatRelativeTime(now)).toBe('À l\'instant');
|
|
});
|
|
|
|
it('returns minutes for times less than an hour ago', () => {
|
|
const thirtyMinsAgo = new Date(Date.now() - 30 * 60 * 1000).toISOString();
|
|
expect(dockerSection.formatRelativeTime(thirtyMinsAgo)).toBe('Il y a 30min');
|
|
});
|
|
|
|
it('returns hours for times less than a day ago', () => {
|
|
const fiveHoursAgo = new Date(Date.now() - 5 * 60 * 60 * 1000).toISOString();
|
|
expect(dockerSection.formatRelativeTime(fiveHoursAgo)).toBe('Il y a 5h');
|
|
});
|
|
|
|
it('returns days for older times', () => {
|
|
const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
|
|
expect(dockerSection.formatRelativeTime(twoDaysAgo)).toBe('Il y a 2j');
|
|
});
|
|
});
|
|
|
|
describe('formatBytes', () => {
|
|
it('returns "0 B" for falsy input', () => {
|
|
expect(dockerSection.formatBytes(0)).toBe('0 B');
|
|
expect(dockerSection.formatBytes(null)).toBe('0 B');
|
|
expect(dockerSection.formatBytes(undefined)).toBe('0 B');
|
|
});
|
|
|
|
it('formats bytes correctly', () => {
|
|
expect(dockerSection.formatBytes(500)).toBe('500 B');
|
|
});
|
|
|
|
it('formats kilobytes correctly', () => {
|
|
expect(dockerSection.formatBytes(1024)).toBe('1 KB');
|
|
expect(dockerSection.formatBytes(2048)).toBe('2 KB');
|
|
});
|
|
|
|
it('formats megabytes correctly', () => {
|
|
expect(dockerSection.formatBytes(1024 * 1024)).toBe('1 MB');
|
|
expect(dockerSection.formatBytes(150 * 1024 * 1024)).toBe('150 MB');
|
|
});
|
|
|
|
it('formats gigabytes correctly', () => {
|
|
expect(dockerSection.formatBytes(1024 * 1024 * 1024)).toBe('1 GB');
|
|
expect(dockerSection.formatBytes(2.5 * 1024 * 1024 * 1024)).toBe('2.5 GB');
|
|
});
|
|
});
|
|
|
|
describe('renderHostsGrid', () => {
|
|
it('shows empty message when no hosts', () => {
|
|
dockerSection.hosts = [];
|
|
dockerSection.renderHostsGrid();
|
|
|
|
const grid = document.getElementById('docker-hosts-grid');
|
|
expect(grid.innerHTML).toContain('Aucun host Docker');
|
|
});
|
|
|
|
it('renders host cards for each host', () => {
|
|
dockerSection.hosts = [
|
|
{ host_id: 'h1', host_name: 'server1', host_ip: '192.168.1.10', docker_status: 'online', containers_total: 5, containers_running: 3 },
|
|
{ host_id: 'h2', host_name: 'server2', host_ip: '192.168.1.11', docker_status: 'offline', containers_total: 2, containers_running: 0 }
|
|
];
|
|
dockerSection.renderHostsGrid();
|
|
|
|
const grid = document.getElementById('docker-hosts-grid');
|
|
expect(grid.querySelectorAll('[data-host-id]').length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('renderHostCard', () => {
|
|
it('includes host name', () => {
|
|
const host = { host_id: 'h1', host_name: 'myserver', host_ip: '192.168.1.10', docker_status: 'online', containers_total: 5, containers_running: 3 };
|
|
const html = dockerSection.renderHostCard(host);
|
|
expect(html).toContain('myserver');
|
|
});
|
|
|
|
it('shows green status for online hosts', () => {
|
|
const host = { host_id: 'h1', host_name: 'myserver', host_ip: '192.168.1.10', docker_status: 'online', containers_total: 5, containers_running: 3 };
|
|
const html = dockerSection.renderHostCard(host);
|
|
expect(html).toContain('status-green');
|
|
});
|
|
|
|
it('shows red status for offline hosts', () => {
|
|
const host = { host_id: 'h1', host_name: 'myserver', host_ip: '192.168.1.10', docker_status: 'offline', containers_total: 5, containers_running: 0 };
|
|
const html = dockerSection.renderHostCard(host);
|
|
expect(html).toContain('status-red');
|
|
});
|
|
|
|
it('shows container counts', () => {
|
|
const host = { host_id: 'h1', host_name: 'myserver', host_ip: '192.168.1.10', docker_status: 'online', containers_total: 10, containers_running: 7 };
|
|
const html = dockerSection.renderHostCard(host);
|
|
expect(html).toContain('7/10 containers');
|
|
});
|
|
});
|
|
|
|
describe('updateStatsDisplay', () => {
|
|
it('updates stat elements with values', () => {
|
|
dockerSection.stats = {
|
|
enabled_hosts: 5,
|
|
running_containers: 25,
|
|
total_images: 100,
|
|
open_alerts: 3
|
|
};
|
|
dockerSection.updateStatsDisplay();
|
|
|
|
expect(document.getElementById('docker-stat-hosts').textContent).toBe('5');
|
|
expect(document.getElementById('docker-stat-containers').textContent).toBe('25');
|
|
expect(document.getElementById('docker-stat-images').textContent).toBe('100');
|
|
expect(document.getElementById('docker-stat-alerts').textContent).toBe('3');
|
|
});
|
|
|
|
it('shows 0 for missing stats', () => {
|
|
dockerSection.stats = {};
|
|
dockerSection.updateStatsDisplay();
|
|
|
|
expect(document.getElementById('docker-stat-hosts').textContent).toBe('0');
|
|
expect(document.getElementById('docker-stat-containers').textContent).toBe('0');
|
|
});
|
|
});
|
|
|
|
describe('filterHosts', () => {
|
|
beforeEach(() => {
|
|
dockerSection.hosts = [
|
|
{ host_id: 'h1', host_name: 'production-server', host_ip: '192.168.1.10', docker_status: 'online', containers_total: 5, containers_running: 3 },
|
|
{ host_id: 'h2', host_name: 'staging-server', host_ip: '192.168.1.11', docker_status: 'online', containers_total: 2, containers_running: 2 },
|
|
{ host_id: 'h3', host_name: 'dev-server', host_ip: '10.0.0.5', docker_status: 'offline', containers_total: 1, containers_running: 0 }
|
|
];
|
|
dockerSection.renderHostsGrid();
|
|
});
|
|
|
|
it('filters hosts by name', () => {
|
|
dockerSection.filterHosts('production');
|
|
|
|
const cards = document.querySelectorAll('#docker-hosts-grid > div[data-host-id]');
|
|
const visibleCards = Array.from(cards).filter(c => c.style.display !== 'none');
|
|
expect(visibleCards.length).toBe(1);
|
|
});
|
|
|
|
it('filters hosts by IP', () => {
|
|
dockerSection.filterHosts('10.0.0');
|
|
|
|
const cards = document.querySelectorAll('#docker-hosts-grid > div[data-host-id]');
|
|
const visibleCards = Array.from(cards).filter(c => c.style.display !== 'none');
|
|
expect(visibleCards.length).toBe(1);
|
|
});
|
|
|
|
it('shows all hosts with empty query', () => {
|
|
dockerSection.filterHosts('');
|
|
|
|
const cards = document.querySelectorAll('#docker-hosts-grid > div[data-host-id]');
|
|
const visibleCards = Array.from(cards).filter(c => c.style.display !== 'none');
|
|
expect(visibleCards.length).toBe(3);
|
|
});
|
|
|
|
it('is case insensitive', () => {
|
|
dockerSection.filterHosts('STAGING');
|
|
|
|
const cards = document.querySelectorAll('#docker-hosts-grid > div[data-host-id]');
|
|
const visibleCards = Array.from(cards).filter(c => c.style.display !== 'none');
|
|
expect(visibleCards.length).toBe(1);
|
|
});
|
|
});
|
|
});
|