mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-06-16 08:05:10 +02:00
133 lines
4.5 KiB
TypeScript
133 lines
4.5 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. 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('..');
|
|
});
|
|
});
|