mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-05-18 07:16:17 +02:00
131 lines
4.3 KiB
TypeScript
131 lines
4.3 KiB
TypeScript
/**
|
|
* Tests for repeater-specific behavior.
|
|
*
|
|
* These tests verify edge cases in repeater interactions that could easily
|
|
* regress if the code is modified:
|
|
*
|
|
* 1. Repeater messages should NOT have sender parsed from text (colons are common in CLI output)
|
|
* 2. Empty password field = guest login, password field with text = password login
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { parseSenderFromText } from '../utils/messageParser';
|
|
import { CONTACT_TYPE_REPEATER } from '../types';
|
|
|
|
describe('Repeater message sender parsing', () => {
|
|
/**
|
|
* CLI responses from repeaters often contain colons (e.g., "clock: 12:30:00").
|
|
* If we parse these like normal channel messages, we'd incorrectly extract
|
|
* "clock" as a sender name, breaking the display.
|
|
*
|
|
* The fix in MessageList.tsx is to check if the contact is a repeater and
|
|
* skip parseSenderFromText entirely. These tests document the expected
|
|
* behavior pattern.
|
|
*/
|
|
|
|
it('parseSenderFromText would incorrectly parse CLI responses with colons', () => {
|
|
// This demonstrates WHY we skip parsing for repeaters
|
|
const cliResponse = 'clock: 2024-01-09 12:30:00';
|
|
const parsed = parseSenderFromText(cliResponse);
|
|
|
|
// Without the repeater check, we'd get this incorrect result:
|
|
expect(parsed.sender).toBe('clock');
|
|
expect(parsed.content).toBe('2024-01-09 12:30:00');
|
|
// This would display as "clock" sent "2024-01-09 12:30:00" - WRONG!
|
|
});
|
|
|
|
it('repeater messages should bypass parsing entirely', () => {
|
|
// This documents the correct behavior: skip parsing for repeaters
|
|
const cliResponse = 'clock: 2024-01-09 12:30:00';
|
|
const contactType = CONTACT_TYPE_REPEATER;
|
|
|
|
// The pattern used in MessageList.tsx:
|
|
const isRepeater = contactType === CONTACT_TYPE_REPEATER;
|
|
const { sender, content } = isRepeater
|
|
? { sender: null, content: cliResponse }
|
|
: parseSenderFromText(cliResponse);
|
|
|
|
// Correct: full text preserved, no sender extracted
|
|
expect(sender).toBeNull();
|
|
expect(content).toBe('clock: 2024-01-09 12:30:00');
|
|
});
|
|
|
|
it('non-repeater messages still get sender parsed', () => {
|
|
const channelMessage = 'Alice: Hello everyone!';
|
|
const contactType: number = 1; // client
|
|
|
|
const isRepeater = contactType === CONTACT_TYPE_REPEATER;
|
|
const { sender, content } = isRepeater
|
|
? { sender: null, content: channelMessage }
|
|
: parseSenderFromText(channelMessage);
|
|
|
|
// Normal behavior: sender extracted
|
|
expect(sender).toBe('Alice');
|
|
expect(content).toBe('Hello everyone!');
|
|
});
|
|
|
|
it('handles various CLI response formats that would be mis-parsed', () => {
|
|
const cliResponses = [
|
|
'ver: 1.2.3',
|
|
'tx: 20 dBm',
|
|
'name: MyRepeater',
|
|
'radio: 915.0,125,9,5',
|
|
'Error: command not found',
|
|
'uptime: 3d 12h 30m',
|
|
];
|
|
|
|
for (const response of cliResponses) {
|
|
// All of these would be incorrectly parsed without the repeater check
|
|
const parsed = parseSenderFromText(response);
|
|
expect(parsed.sender).not.toBeNull();
|
|
|
|
// But with repeater check, they're preserved
|
|
const isRepeater = true;
|
|
const { sender, content } = isRepeater
|
|
? { sender: null, content: response }
|
|
: parseSenderFromText(response);
|
|
|
|
expect(sender).toBeNull();
|
|
expect(content).toBe(response);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Repeater login behavior', () => {
|
|
/**
|
|
* Repeater login has two modes:
|
|
* - Empty password field = guest login (uses repeater's ACL permissions)
|
|
* - Password in field = admin login attempt
|
|
*/
|
|
|
|
it('empty input results in empty password (guest login)', () => {
|
|
// This is the logic in MessageInput.tsx handleSubmit
|
|
const text = '';
|
|
const trimmed = text.trim();
|
|
|
|
// Empty string is passed directly to onSend
|
|
expect(trimmed).toBe('');
|
|
});
|
|
|
|
it('password is passed through unchanged', () => {
|
|
const text = 'mySecretPassword';
|
|
const trimmed = text.trim();
|
|
|
|
expect(trimmed).toBe('mySecretPassword');
|
|
});
|
|
|
|
it('whitespace-only input is treated as empty (guest login)', () => {
|
|
const text = ' ';
|
|
const trimmed = text.trim();
|
|
|
|
expect(trimmed).toBe('');
|
|
});
|
|
|
|
it('password with surrounding whitespace is trimmed', () => {
|
|
const text = ' secret123 ';
|
|
const trimmed = text.trim();
|
|
|
|
expect(trimmed).toBe('secret123');
|
|
});
|
|
});
|