|
@@ -1,680 +0,0 @@
|
|
|
-/**
|
|
|
|
|
- * Tests for the VirtualPrinterSettings component.
|
|
|
|
|
- *
|
|
|
|
|
- * Tests the virtual printer configuration UI including:
|
|
|
|
|
- * - Enable/disable toggle
|
|
|
|
|
- * - Access code management
|
|
|
|
|
- * - Archive mode selection
|
|
|
|
|
- * - Status display
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
-import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
|
|
-import { screen, waitFor } from '@testing-library/react';
|
|
|
|
|
-import userEvent from '@testing-library/user-event';
|
|
|
|
|
-import { render } from '../utils';
|
|
|
|
|
-import { VirtualPrinterSettings } from '../../components/VirtualPrinterSettings';
|
|
|
|
|
-
|
|
|
|
|
-// Mock the API client
|
|
|
|
|
-vi.mock('../../api/client', () => ({
|
|
|
|
|
- api: {
|
|
|
|
|
- getSettings: vi.fn().mockResolvedValue({}),
|
|
|
|
|
- updateSettings: vi.fn().mockResolvedValue({}),
|
|
|
|
|
- getPrinters: vi.fn().mockResolvedValue([]),
|
|
|
|
|
- getNetworkInterfaces: vi.fn().mockResolvedValue({ interfaces: [] }),
|
|
|
|
|
- },
|
|
|
|
|
- virtualPrinterApi: {
|
|
|
|
|
- getSettings: vi.fn(),
|
|
|
|
|
- updateSettings: vi.fn(),
|
|
|
|
|
- getModels: vi.fn().mockResolvedValue({
|
|
|
|
|
- models: {
|
|
|
|
|
- 'BL-P001': 'X1C',
|
|
|
|
|
- 'C12': 'P1S',
|
|
|
|
|
- 'N7': 'P2S',
|
|
|
|
|
- },
|
|
|
|
|
- }),
|
|
|
|
|
- },
|
|
|
|
|
-}));
|
|
|
|
|
-
|
|
|
|
|
-// Import mocked module
|
|
|
|
|
-import { virtualPrinterApi } from '../../api/client';
|
|
|
|
|
-
|
|
|
|
|
-// Mock data factory
|
|
|
|
|
-const createMockSettings = (overrides = {}) => ({
|
|
|
|
|
- enabled: false,
|
|
|
|
|
- access_code_set: false,
|
|
|
|
|
- mode: 'archive' as const,
|
|
|
|
|
- model: 'BL-P001',
|
|
|
|
|
- target_printer_id: null as number | null,
|
|
|
|
|
- remote_interface_ip: null as string | null,
|
|
|
|
|
- status: {
|
|
|
|
|
- enabled: false,
|
|
|
|
|
- running: false,
|
|
|
|
|
- mode: 'archive',
|
|
|
|
|
- name: 'Bambuddy',
|
|
|
|
|
- serial: '00M00A391800001',
|
|
|
|
|
- model: 'BL-P001',
|
|
|
|
|
- model_name: 'X1C',
|
|
|
|
|
- pending_files: 0,
|
|
|
|
|
- },
|
|
|
|
|
- ...overrides,
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-describe('VirtualPrinterSettings', () => {
|
|
|
|
|
- beforeEach(() => {
|
|
|
|
|
- vi.clearAllMocks();
|
|
|
|
|
- // Default mock implementation
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(createMockSettings());
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(createMockSettings());
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('rendering', () => {
|
|
|
|
|
- it('renders loading state initially', () => {
|
|
|
|
|
- // Delay the API response to catch loading state
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockImplementation(
|
|
|
|
|
- () => new Promise(() => {}) // Never resolves
|
|
|
|
|
- );
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- // Should show loading spinner
|
|
|
|
|
- expect(document.querySelector('.animate-spin')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders component title', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Virtual Printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders enable toggle', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders access code section', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Access Code')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders mode section', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Mode')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders how it works info', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('How it works:')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('status indicator', () => {
|
|
|
|
|
- it('shows Stopped when not running', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ status: { ...createMockSettings().status, running: false } })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Stopped')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows Running when active', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- status: { ...createMockSettings().status, enabled: true, running: true },
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Running')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows status details when running', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- status: {
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- running: true,
|
|
|
|
|
- mode: 'archive',
|
|
|
|
|
- name: 'Bambuddy',
|
|
|
|
|
- serial: '00M00A391800001',
|
|
|
|
|
- model: 'BL-P001',
|
|
|
|
|
- model_name: 'X1C',
|
|
|
|
|
- pending_files: 0,
|
|
|
|
|
- },
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Status Details')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Bambuddy')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('00M00A391800001')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('access code', () => {
|
|
|
|
|
- it('shows warning when access code not set', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ access_code_set: false })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('No access code set - required to enable')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows success when access code is set', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Access code is set')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows character count while typing', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Access Code')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const input = screen.getByPlaceholderText('Enter 8-char code');
|
|
|
|
|
- await user.type(input, '1234');
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.getByText('(4/8)')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('saves access code on button click', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Access Code')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const input = screen.getByPlaceholderText('Enter 8-char code');
|
|
|
|
|
- await user.type(input, '12345678');
|
|
|
|
|
-
|
|
|
|
|
- const saveButton = screen.getByRole('button', { name: 'Save' });
|
|
|
|
|
- await user.click(saveButton);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({
|
|
|
|
|
- access_code: '12345678',
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('toggles password visibility', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Access Code')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const input = screen.getByPlaceholderText('Enter 8-char code');
|
|
|
|
|
- expect(input).toHaveAttribute('type', 'password');
|
|
|
|
|
-
|
|
|
|
|
- // Find and click the visibility toggle (eye icon button)
|
|
|
|
|
- const toggleButtons = screen.getAllByRole('button');
|
|
|
|
|
- const visibilityToggle = toggleButtons.find(
|
|
|
|
|
- (btn) => btn.querySelector('svg') && btn.className.includes('absolute')
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- if (visibilityToggle) {
|
|
|
|
|
- await user.click(visibilityToggle);
|
|
|
|
|
- expect(input).toHaveAttribute('type', 'text');
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('mode selection', () => {
|
|
|
|
|
- it('renders Archive mode option', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Archive')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Archive files immediately')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders Review mode option', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Review')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Review before archiving')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('renders Queue mode option', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Queue')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Archive and add to queue')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('highlights current mode (review)', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'review' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- const reviewButton = screen.getByText('Review').closest('button');
|
|
|
|
|
- expect(reviewButton?.className).toContain('border-bambu-green');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('highlights current mode (legacy immediate maps to archive button)', async () => {
|
|
|
|
|
- // Pre-#1429 the wire value was `immediate` but the UI button was
|
|
|
|
|
- // labeled "Archive". Backend migration rewrites stored rows, but a
|
|
|
|
|
- // stale-cached settings payload may still carry the legacy value —
|
|
|
|
|
- // the component normalises it client-side so the right button lights up.
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'immediate' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- const archiveButton = screen.getByText('Archive').closest('button');
|
|
|
|
|
- expect(archiveButton?.className).toContain('border-bambu-green');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('highlights current mode (legacy print_queue maps to queue button)', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'print_queue' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- const queueButton = screen.getByText('Queue').closest('button');
|
|
|
|
|
- expect(queueButton?.className).toContain('border-bambu-green');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('changes mode to review on click', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'review' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Review')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const reviewButton = screen.getByText('Review').closest('button');
|
|
|
|
|
- if (reviewButton) {
|
|
|
|
|
- await user.click(reviewButton);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'review' });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('changes mode to queue on click', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'queue' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Queue')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const queueButton = screen.getByText('Queue').closest('button');
|
|
|
|
|
- if (queueButton) {
|
|
|
|
|
- await user.click(queueButton);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'queue' });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('enable/disable toggle', () => {
|
|
|
|
|
- it('cannot enable without access code', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: false, access_code_set: false })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // Find the toggle switch (it's a button with relative class containing the slider)
|
|
|
|
|
- const allButtons = screen.getAllByRole('button');
|
|
|
|
|
- const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));
|
|
|
|
|
-
|
|
|
|
|
- if (toggle) {
|
|
|
|
|
- await user.click(toggle);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Should not call update API (no access code set)
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).not.toHaveBeenCalled();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('can enable when access code is set', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: false, access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // Find the toggle switch (it's a button with rounded-full and w-12 classes)
|
|
|
|
|
- const allButtons = screen.getAllByRole('button');
|
|
|
|
|
- const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));
|
|
|
|
|
-
|
|
|
|
|
- expect(toggle).toBeDefined();
|
|
|
|
|
- if (toggle) {
|
|
|
|
|
- await user.click(toggle);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith(
|
|
|
|
|
- expect.objectContaining({ enabled: true })
|
|
|
|
|
- );
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('can disable when enabled', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: false, access_code_set: true })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // Find the toggle switch
|
|
|
|
|
- const allButtons = screen.getAllByRole('button');
|
|
|
|
|
- const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));
|
|
|
|
|
-
|
|
|
|
|
- expect(toggle).toBeDefined();
|
|
|
|
|
- if (toggle) {
|
|
|
|
|
- await user.click(toggle);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith(
|
|
|
|
|
- expect.objectContaining({ enabled: false })
|
|
|
|
|
- );
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('info section', () => {
|
|
|
|
|
- it('shows setup required warning', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Setup Required')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows link to setup guide', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Read the setup guide before enabling')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows how it works section', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('How it works:')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText(/virtual printers appear in your slicer/)).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('proxy mode', () => {
|
|
|
|
|
- it('renders Proxy mode option', async () => {
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Proxy')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Relay to real printer')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('highlights proxy mode when selected', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'proxy', target_printer_id: 1 })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- const proxyButton = screen.getByText('Proxy').closest('button');
|
|
|
|
|
- expect(proxyButton?.className).toContain('border-blue-500');
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows proxy status details when running in proxy mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- mode: 'proxy',
|
|
|
|
|
- target_printer_id: 1,
|
|
|
|
|
- status: {
|
|
|
|
|
- enabled: true,
|
|
|
|
|
- running: true,
|
|
|
|
|
- mode: 'proxy',
|
|
|
|
|
- name: 'Bambuddy (Proxy)',
|
|
|
|
|
- serial: '00M00A391800001',
|
|
|
|
|
- model: 'BL-P001',
|
|
|
|
|
- model_name: 'X1C',
|
|
|
|
|
- pending_files: 0,
|
|
|
|
|
- proxy: {
|
|
|
|
|
- running: true,
|
|
|
|
|
- target_host: '192.168.1.100',
|
|
|
|
|
- ftp_port: 990, // Privileged port for Bambu Studio compatibility
|
|
|
|
|
- mqtt_port: 8883,
|
|
|
|
|
- ftp_connections: 1,
|
|
|
|
|
- mqtt_connections: 2,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Running')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Status Details')).toBeInTheDocument();
|
|
|
|
|
- // IP address appears in multiple places (target printer and status details)
|
|
|
|
|
- expect(screen.getAllByText('192.168.1.100').length).toBeGreaterThan(0);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows target printer dropdown in proxy mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'proxy' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Target Printer')).toBeInTheDocument();
|
|
|
|
|
- expect(screen.getByText('Select a printer...')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('changes mode to proxy on click', async () => {
|
|
|
|
|
- const user = userEvent.setup();
|
|
|
|
|
- vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ mode: 'proxy' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Proxy')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const proxyButton = screen.getByText('Proxy').closest('button');
|
|
|
|
|
- if (proxyButton) {
|
|
|
|
|
- await user.click(proxyButton);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'proxy' });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('network interface override', () => {
|
|
|
|
|
- it('shows interface dropdown when enabled in immediate mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'archive' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows interface dropdown when enabled in review mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'review' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows interface dropdown when enabled in print_queue mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'queue' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows interface dropdown when enabled in proxy mode', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'proxy', target_printer_id: 1 })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('hides interface dropdown when disabled', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: false, mode: 'archive' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Mode')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- expect(screen.queryByText('Network Interface Override')).not.toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows configured status when interface is set', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'archive', remote_interface_ip: '10.0.0.50' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText('Interface override active')).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- it('shows optional hint when no interface is set', async () => {
|
|
|
|
|
- vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
|
|
|
|
|
- createMockSettings({ enabled: true, mode: 'archive', remote_interface_ip: '' })
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- render(<VirtualPrinterSettings />);
|
|
|
|
|
-
|
|
|
|
|
- await waitFor(() => {
|
|
|
|
|
- expect(screen.getByText(/Optional.*auto-detected IP/)).toBeInTheDocument();
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-});
|
|
|