* fix: resolve lint warnings/errors and apply formatting Fix 10 oxlint issues (2 errors, 8 warnings): - Remove unused catch parameters in Security.tsx and ImportDialog.tsx - Remove stray expression in Generator.tsx - Add eslint-disable for debounced useCallback in FilterControl.tsx - Remove unnecessary deps (resolveDB, store) in bindStoreToDevice.ts - Prefix unused variant param in AppSidebar.tsx - Memoize tabs arrays in DeviceConfig, RadioConfig, ModuleConfig - Fix channels type in RadioConfig TabItem Also applies oxfmt formatting across all files. * updating lock file * update protobuf package * fix: regenerate pnpm-lock.yaml and exclude jsr protobufs from minimumReleaseAge * prevented http card from always being polled * updated pnpm config fiile * updated actions * removed biome config and lint system leftovers * updating protobuf package
119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
import { Types } from "@meshtastic/core";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
export interface TransportContract {
|
|
name: string;
|
|
create: () => Promise<Types.Transport>;
|
|
setup?: () => void | Promise<void>;
|
|
teardown?: () => void | Promise<void>;
|
|
pushIncoming?: (bytes: Uint8Array) => void | Promise<void>;
|
|
assertLastWritten?: (bytes: Uint8Array) => void;
|
|
triggerDisconnect?: () => void | Promise<void>;
|
|
}
|
|
|
|
async function readUntilType(
|
|
reader: ReadableStreamDefaultReader<Types.DeviceOutput>,
|
|
expectedType: Types.DeviceOutput["type"],
|
|
maxReads = 20,
|
|
): Promise<Types.DeviceOutput> {
|
|
for (let i = 0; i < maxReads; i++) {
|
|
const { value, done } = await reader.read();
|
|
if (done) {
|
|
break;
|
|
}
|
|
if (value && value.type === expectedType) {
|
|
return value;
|
|
}
|
|
}
|
|
throw new Error(`Did not receive a '${expectedType}' event within ${maxReads} reads`);
|
|
}
|
|
|
|
export function runTransportContract(contract: TransportContract) {
|
|
describe(contract.name, () => {
|
|
it("reads packets from fromDevice", async () => {
|
|
await contract.setup?.();
|
|
const transport = await contract.create();
|
|
|
|
const reader = transport.fromDevice.getReader();
|
|
const sampleBytes = new Uint8Array([0x01, 0x02, 0x03]);
|
|
|
|
await contract.pushIncoming?.(sampleBytes);
|
|
|
|
const packetEvent = await readUntilType(reader, "packet");
|
|
expect("data" in packetEvent ? packetEvent.data : undefined).toEqual(sampleBytes);
|
|
|
|
reader.releaseLock();
|
|
await contract.teardown?.();
|
|
});
|
|
|
|
it("writes bytes to toDevice", async () => {
|
|
await contract.setup?.();
|
|
const transport = await contract.create();
|
|
|
|
const writer = transport.toDevice.getWriter();
|
|
const outgoingBytes = new Uint8Array([0xaa, 0xbb]);
|
|
await writer.write(outgoingBytes);
|
|
await writer.close();
|
|
|
|
contract.assertLastWritten?.(outgoingBytes);
|
|
await contract.teardown?.();
|
|
});
|
|
|
|
it("disconnect() emits DeviceDisconnected('user')", async () => {
|
|
await contract.setup?.();
|
|
const transport = await contract.create();
|
|
|
|
const reader = transport.fromDevice.getReader();
|
|
|
|
// Trigger user disconnect
|
|
await transport.disconnect();
|
|
|
|
// Read a few events and assert we eventually see the user disconnect.
|
|
let sawUser = false;
|
|
for (let i = 0; i < 10; i++) {
|
|
const { value } = await reader.read();
|
|
if (
|
|
value &&
|
|
value.type === "status" &&
|
|
value.data.status === Types.DeviceStatusEnum.DeviceDisconnected &&
|
|
value.data.reason === "user"
|
|
) {
|
|
sawUser = true;
|
|
break;
|
|
}
|
|
}
|
|
expect(sawUser).toBe(true);
|
|
|
|
reader.releaseLock();
|
|
await contract.teardown?.();
|
|
});
|
|
|
|
it("emits DeviceDisconnected when the underlying link drops", async () => {
|
|
await contract.setup?.();
|
|
const transport = await contract.create();
|
|
|
|
const reader = transport.fromDevice.getReader();
|
|
|
|
await contract.triggerDisconnect?.();
|
|
|
|
// As above, read a few events and assert we eventually see "disconnected"
|
|
let sawDrop = false;
|
|
for (let i = 0; i < 10; i++) {
|
|
const { value } = await reader.read();
|
|
if (
|
|
value &&
|
|
value.type === "status" &&
|
|
value.data.status === Types.DeviceStatusEnum.DeviceDisconnected
|
|
) {
|
|
sawDrop = true;
|
|
break;
|
|
}
|
|
}
|
|
expect(sawDrop).toBe(true);
|
|
|
|
reader.releaseLock();
|
|
await contract.teardown?.();
|
|
});
|
|
});
|
|
}
|