committed by
GitHub
17 changed files with 1083 additions and 463 deletions
File diff suppressed because it is too large
@ -0,0 +1,152 @@ |
|||
import { MessageInput } from '@components/PageComponents/Messages/MessageInput.tsx'; |
|||
import { useDevice } from "@core/stores/deviceStore.ts"; |
|||
import { vi, describe, it, expect, beforeEach, Mock } from 'vitest'; |
|||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'; |
|||
import userEvent from '@testing-library/user-event'; |
|||
|
|||
vi.mock("@core/stores/deviceStore.ts", () => ({ |
|||
useDevice: vi.fn(), |
|||
})); |
|||
|
|||
vi.mock("@core/utils/debounce.ts", () => ({ |
|||
debounce: (fn: () => void) => fn, |
|||
})); |
|||
|
|||
vi.mock("@components/UI/Button.tsx", () => ({ |
|||
Button: ({ children, ...props }: { children: React.ReactNode }) => <button {...props}>{children}</button> |
|||
})); |
|||
|
|||
vi.mock("@components/UI/Input.tsx", () => ({ |
|||
Input: (props: any) => <input {...props} /> |
|||
})); |
|||
|
|||
vi.mock("lucide-react", () => ({ |
|||
SendIcon: () => <div data-testid="send-icon">Send</div> |
|||
})); |
|||
|
|||
// TODO: getting an error with this test
|
|||
describe('MessageInput Component', () => { |
|||
const mockProps = { |
|||
to: "broadcast" as const, |
|||
channel: 0 as const, |
|||
maxBytes: 100, |
|||
}; |
|||
|
|||
const mockSetMessageDraft = vi.fn(); |
|||
const mockSetMessageState = vi.fn(); |
|||
const mockSendText = vi.fn().mockResolvedValue(123); |
|||
|
|||
beforeEach(() => { |
|||
vi.clearAllMocks(); |
|||
|
|||
(useDevice as Mock).mockReturnValue({ |
|||
connection: { |
|||
sendText: mockSendText, |
|||
}, |
|||
setMessageState: mockSetMessageState, |
|||
messageDraft: "", |
|||
setMessageDraft: mockSetMessageDraft, |
|||
hardware: { |
|||
myNodeNum: 1234567890, |
|||
}, |
|||
}); |
|||
}); |
|||
|
|||
it('renders correctly with initial state', () => { |
|||
render(<MessageInput {...mockProps} />); |
|||
|
|||
expect(screen.getByPlaceholderText('Enter Message')).toBeInTheDocument(); |
|||
expect(screen.getByTestId('send-icon')).toBeInTheDocument(); |
|||
|
|||
expect(screen.getByText('0/100')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('updates local draft and byte count when typing', () => { |
|||
render(<MessageInput {...mockProps} />); |
|||
|
|||
const inputField = screen.getByPlaceholderText('Enter Message'); |
|||
fireEvent.change(inputField, { target: { value: 'Hello' } }) |
|||
|
|||
expect(screen.getByText('5/100')).toBeInTheDocument(); |
|||
expect(inputField).toHaveValue('Hello'); |
|||
expect(mockSetMessageDraft).toHaveBeenCalledWith('Hello'); |
|||
}); |
|||
|
|||
it.skip('does not allow input exceeding max bytes', () => { |
|||
render(<MessageInput {...mockProps} maxBytes={5} />); |
|||
|
|||
const inputField = screen.getByPlaceholderText('Enter Message'); |
|||
|
|||
expect(screen.getByText('0/100')).toBeInTheDocument(); |
|||
|
|||
userEvent.type(inputField, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis p') |
|||
|
|||
expect(screen.getByText('100/100')).toBeInTheDocument(); |
|||
expect(inputField).toHaveValue('Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean m'); |
|||
}); |
|||
|
|||
it('sends message and resets form when submitting', async () => { |
|||
try { |
|||
render(<MessageInput {...mockProps} />); |
|||
|
|||
const inputField = screen.getByPlaceholderText('Enter Message'); |
|||
const submitButton = screen.getByText('Send'); |
|||
|
|||
fireEvent.change(inputField, { target: { value: 'Test Message' } }); |
|||
fireEvent.click(submitButton); |
|||
|
|||
const form = screen.getByRole('form'); |
|||
fireEvent.submit(form); |
|||
|
|||
expect(mockSendText).toHaveBeenCalledWith('Test message', 'broadcast', true, 0); |
|||
|
|||
await waitFor(() => { |
|||
expect(mockSetMessageState).toHaveBeenCalledWith( |
|||
'broadcast', |
|||
0, |
|||
'broadcast', |
|||
1234567890, |
|||
123, |
|||
'ack' |
|||
); |
|||
|
|||
}); |
|||
|
|||
expect(inputField).toHaveValue(''); |
|||
expect(screen.getByText('0/100')).toBeInTheDocument(); |
|||
expect(mockSetMessageDraft).toHaveBeenCalledWith(''); |
|||
} catch (e) { |
|||
console.error(e); |
|||
} |
|||
}); |
|||
it('prevents sending empty messages', () => { |
|||
render(<MessageInput {...mockProps} />); |
|||
|
|||
const form = screen.getByPlaceholderText('Enter Message') |
|||
fireEvent.submit(form); |
|||
|
|||
expect(mockSendText).not.toHaveBeenCalled(); |
|||
}); |
|||
|
|||
it('initializes with existing message draft', () => { |
|||
(useDevice as Mock).mockReturnValue({ |
|||
connection: { |
|||
sendText: mockSendText, |
|||
}, |
|||
setMessageState: mockSetMessageState, |
|||
messageDraft: "Existing draft", |
|||
setMessageDraft: mockSetMessageDraft, |
|||
isQueueingMessages: false, |
|||
queueStatus: { free: 10 }, |
|||
hardware: { |
|||
myNodeNum: 1234567890, |
|||
}, |
|||
}); |
|||
|
|||
render(<MessageInput {...mockProps} />); |
|||
|
|||
const inputField = screen.getByRole('textbox'); |
|||
|
|||
expect(inputField).toHaveValue('Existing draft'); |
|||
}); |
|||
}); |
|||
@ -1,7 +1,18 @@ |
|||
import "@testing-library/jest-dom"; |
|||
// Try this import style instead
|
|||
import { expect, afterEach } from 'vitest'; |
|||
import { cleanup } from '@testing-library/react'; |
|||
import * as matchers from '@testing-library/jest-dom/matchers'; |
|||
|
|||
globalThis.ResizeObserver = class { |
|||
// Add the matchers (should work with * as import)
|
|||
expect.extend(matchers); |
|||
|
|||
// Mock ResizeObserver
|
|||
global.ResizeObserver = class { |
|||
observe() { } |
|||
unobserve() { } |
|||
disconnect() { } |
|||
}; |
|||
}; |
|||
|
|||
afterEach(() => { |
|||
cleanup(); |
|||
}); |
|||
@ -0,0 +1,24 @@ |
|||
import path from "node:path"; |
|||
import react from '@vitejs/plugin-react'; |
|||
import { defineConfig } from 'vitest/config' |
|||
|
|||
export default defineConfig({ |
|||
plugins: [ |
|||
react(), |
|||
], |
|||
resolve: { |
|||
alias: { |
|||
'@app': path.resolve(process.cwd(), './src'), |
|||
'@pages': path.resolve(process.cwd(), './src/pages'), |
|||
'@components': path.resolve(process.cwd(), './src/components'), |
|||
'@core': path.resolve(process.cwd(), './src/core'), |
|||
'@layouts': path.resolve(process.cwd(), './src/layouts'), |
|||
}, |
|||
}, |
|||
test: { |
|||
globals: true, |
|||
include: ['src/**/*.test.tsx', 'src/**/*.test.ts'], |
|||
setupFiles: ['src/tests/setupTests.ts'], |
|||
environment: 'happy-dom', |
|||
}, |
|||
}) |
|||
Loading…
Reference in new issue