mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-07 09:13:04 +02:00
Implement repeater CLI interface
This commit is contained in:
@@ -38,13 +38,6 @@ describe('parseSenderFromText', () => {
|
||||
expect(result.content).toBe('Note:this is not a sender');
|
||||
});
|
||||
|
||||
it('rejects sender containing square brackets', () => {
|
||||
const result = parseSenderFromText('[System]: Alert message');
|
||||
|
||||
expect(result.sender).toBeNull();
|
||||
expect(result.content).toBe('[System]: Alert message');
|
||||
});
|
||||
|
||||
it('rejects sender containing colon', () => {
|
||||
const result = parseSenderFromText('12:30: Time announcement');
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* 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. Password field "." should convert to empty string (for repeaters with no password)
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { parseSenderFromText } from '../utils/messageParser';
|
||||
import { CONTACT_TYPE_REPEATER, CONTACT_TYPE_CLIENT } 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 = CONTACT_TYPE_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 password handling', () => {
|
||||
/**
|
||||
* The "." password convention allows users to specify an empty password
|
||||
* for repeaters that don't require authentication. Without this, users
|
||||
* couldn't submit an empty password through the form.
|
||||
*/
|
||||
|
||||
it('"." converts to empty password', () => {
|
||||
// This is the logic in MessageInput.tsx handleSubmit
|
||||
const trimmed = '.';
|
||||
const password = trimmed === '.' ? '' : trimmed;
|
||||
|
||||
expect(password).toBe('');
|
||||
});
|
||||
|
||||
it('normal password is passed through unchanged', () => {
|
||||
const trimmed = 'mySecretPassword';
|
||||
const password = trimmed === '.' ? '' : trimmed;
|
||||
|
||||
expect(password).toBe('mySecretPassword');
|
||||
});
|
||||
|
||||
it('"." with surrounding whitespace still works after trim', () => {
|
||||
// In MessageInput, text.trim() is called before the check
|
||||
const text = ' . ';
|
||||
const trimmed = text.trim();
|
||||
const password = trimmed === '.' ? '' : trimmed;
|
||||
|
||||
expect(password).toBe('');
|
||||
});
|
||||
|
||||
it('".." is NOT converted (only single dot)', () => {
|
||||
const trimmed = '..';
|
||||
const password = trimmed === '.' ? '' : trimmed;
|
||||
|
||||
// Double dot is passed through as-is (it's a valid password)
|
||||
expect(password).toBe('..');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user