Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"autoprefixer": "^10.5.2",
"gzipper": "^8.3.0",
"happy-dom": "^20.10.6",
"oxfmt": "^0.58.0",
"oxfmt": "^0.59.0",
"oxlint": "^1.73.0",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4.3.2",
Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/pages/Connections/useConnections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ export function useConnections() {
// Read from the live store, not the memoized `connections` closure: callers
// such as addConnectionAndConnect() add a connection and connect to it in the
// same tick, before this hook re-renders, so the closure would be stale.
const conn = useDeviceStore.getState().savedConnections.find((c) => c.id === id);
const conn = useDeviceStore
.getState()
.savedConnections.find((c) => c.id === id);
if (!conn) {
log.warn("connect: unknown connection id", { id });
return false;
Expand Down
12 changes: 9 additions & 3 deletions e2e/fixtures/peer.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import path from "node:path";
* that talks to the non-browser node over the TCP phone API. It sends text,
* blocks until a specific text is received, or reports the node's number.
*/
const PYTHON = process.env.E2E_PEER_PYTHON ?? path.resolve("e2e/peer/.venv/bin/python");
const PYTHON =
process.env.E2E_PEER_PYTHON ?? path.resolve("e2e/peer/.venv/bin/python");
const SCRIPT = path.resolve("e2e/peer/peer.py");
const HOST = process.env.E2E_PEER_HOST ?? "127.0.0.1";
const PORT = process.env.E2E_PEER_PORT ?? "14404";
Expand All @@ -16,7 +17,10 @@ function spawnPeer(args: string[]): ChildProcess {
}

/** Invoke `onLine` for each complete stdout line. */
function onStdoutLines(child: ChildProcess, onLine: (line: string) => void): void {
function onStdoutLines(
child: ChildProcess,
onLine: (line: string) => void,
): void {
let buf = "";
child.stdout?.on("data", (chunk: Buffer) => {
buf += chunk.toString();
Expand Down Expand Up @@ -44,7 +48,9 @@ export function peerSend(
});
return new Promise<void>((resolve, reject) => {
child.on("exit", (code) =>
code === 0 ? resolve() : reject(new Error(`peer send exited ${code}: ${stderr.trim()}`)),
code === 0
? resolve()
: reject(new Error(`peer send exited ${code}: ${stderr.trim()}`)),
);
child.on("error", reject);
});
Expand Down
14 changes: 11 additions & 3 deletions e2e/global-setup.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,17 @@ async function waitForHttps(url: string, timeoutMs: number): Promise<void> {
if (ok) return;
await sleep(1000);
}
throw new Error(`device webserver not ready at ${url} within ${timeoutMs}ms (last: ${lastErr})`);
throw new Error(
`device webserver not ready at ${url} within ${timeoutMs}ms (last: ${lastErr})`,
);
}

/** Poll a TCP port until it accepts a connection. */
async function waitForTcp(host: string, port: number, timeoutMs: number): Promise<void> {
async function waitForTcp(
host: string,
port: number,
timeoutMs: number,
): Promise<void> {
const deadline = Date.now() + timeoutMs;
let lastErr = "connection refused";
while (Date.now() < deadline) {
Expand Down Expand Up @@ -83,7 +89,9 @@ export default async function globalSetup(): Promise<void> {
console.log("[e2e] bringing up meshtasticd two-node mesh ...");
execSync(`docker compose -f ${COMPOSE_FILE} up -d`, { stdio: "inherit" });
} else {
console.log(`[e2e] hardware mode: device=${NODE_A_URL} peer=${PEER_HOST}:${PEER_PORT}`);
console.log(
`[e2e] hardware mode: device=${NODE_A_URL} peer=${PEER_HOST}:${PEER_PORT}`,
);
}

console.log(`[e2e] waiting for device webserver ${NODE_A_URL} ...`);
Expand Down
4 changes: 3 additions & 1 deletion e2e/global-teardown.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default async function globalTeardown(): Promise<void> {
console.log("[e2e] tearing down meshtasticd mesh ...");
execSync(`docker compose -f ${COMPOSE_FILE} down -v`, { stdio: "inherit" });
} else {
console.log("[e2e] leaving meshtasticd mesh running (set E2E_DOCKER_DOWN=1 to stop).");
console.log(
"[e2e] leaving meshtasticd mesh running (set E2E_DOCKER_DOWN=1 to stop).",
);
}
}
18 changes: 14 additions & 4 deletions e2e/pages/ConnectionPage.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { expect, type Page } from "@playwright/test";
export class ConnectionPage {
constructor(private readonly page: Page) {}

async connectHttp(opts: { host: string; tls: boolean; name?: string }): Promise<void> {
async connectHttp(opts: {
host: string;
tls: boolean;
name?: string;
}): Promise<void> {
const { host, tls, name = "E2E Device" } = opts;
const page = this.page;

Expand All @@ -25,19 +29,25 @@ export class ConnectionPage {
await dialog.locator("#url").fill(host);

const httpsSwitch = dialog.getByRole("switch");
const isChecked = (await httpsSwitch.getAttribute("aria-checked")) === "true";
const isChecked =
(await httpsSwitch.getAttribute("aria-checked")) === "true";
if (tls !== isChecked) {
await httpsSwitch.click();
}

await dialog.getByRole("button", { name: "Test connection" }).click();

const save = dialog.getByRole("button", { name: "Save connection" });
await expect(save, "Save enables only after the device is reachable").toBeEnabled({
await expect(
save,
"Save enables only after the device is reachable",
).toBeEnabled({
timeout: 20_000,
});
await save.click();

await expect(page).toHaveURL(/\/messages\/broadcast\/0/, { timeout: 60_000 });
await expect(page).toHaveURL(/\/messages\/broadcast\/0/, {
timeout: 60_000,
});
}
}
4 changes: 3 additions & 1 deletion e2e/pages/MessagesPage.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export class MessagesPage {
await expect(this.input()).toBeEnabled();
// The SDK chat client lags the composer (device handshake + sqlocal init), so
// an immediate send is silently dropped. Gate on the "Connected" status.
await expect(this.page.getByText("Connected", { exact: true }).first()).toBeVisible({
await expect(
this.page.getByText("Connected", { exact: true }).first(),
).toBeVisible({
timeout: 30_000,
});
}
Expand Down
8 changes: 6 additions & 2 deletions e2e/tests/messaging.broadcast.spec.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ test.describe("broadcast messaging over a real two-node mesh", () => {
await messagesPage.waitReady();
});

test("renders a broadcast received from a mesh peer (mesh -> web)", async ({ messagesPage }) => {
test("renders a broadcast received from a mesh peer (mesh -> web)", async ({
messagesPage,
}) => {
const nonce = `pong-${Date.now()}`;
await peerSend(nonce);
await messagesPage.expectMessage(nonce);
});

test("delivers a typed broadcast to the mesh (web -> mesh)", async ({ messagesPage }) => {
test("delivers a typed broadcast to the mesh (web -> mesh)", async ({
messagesPage,
}) => {
const nonce = `ping-${Date.now()}`;
// Listen on the peer node before sending, then type+send from the browser.
const recv = await startPeerRecv(nonce, { timeout: 60 });
Expand Down
23 changes: 11 additions & 12 deletions e2e/tests/messaging.direct.spec.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change

Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ test.describe("direct messaging over a real two-node mesh", () => {
await messagesPage.waitReady();
});

test.fixme(
"delivers a direct message from the browser to the peer node (web -> mesh)",
async ({ messagesPage }) => {
const peerNum = await peerNodeNum();
const nonce = `dm-${Date.now()}`;
const recv = await startPeerRecv(nonce, { timeout: 60 });
await messagesPage.openDirectMessageByNodeNum(peerNum);
await messagesPage.send(nonce);
const from = await recv.received;
expect(from).toBeGreaterThan(0);
},
);
test.fixme("delivers a direct message from the browser to the peer node (web -> mesh)", async ({
messagesPage,
}) => {
const peerNum = await peerNodeNum();
const nonce = `dm-${Date.now()}`;
const recv = await startPeerRecv(nonce, { timeout: 60 });
await messagesPage.openDirectMessageByNodeNum(peerNum);
await messagesPage.send(nonce);
const from = await recv.received;
expect(from).toBeGreaterThan(0);
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@types/node": "^26.1.0",
"husky": "^9.1.0",
"lint-staged": "^17.0.8",
"oxfmt": "^0.58.0",
"oxfmt": "^0.59.0",
"oxlint": "^1.73.0",
"tsdown": "^0.22.7",
"typescript": "^7.0.2",
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/src/features/nodes/NodesClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ describe("NodesClient", () => {
const { transport } = createFakeTransport();
const client = new MeshClient({ transport });

client.events.onNodeInfoPacket.dispatch(create(Protobuf.Mesh.NodeInfoSchema, { num: 100 }));
client.events.onNodeInfoPacket.dispatch(
create(Protobuf.Mesh.NodeInfoSchema, { num: 100 }),
);
client.events.onTelemetryPacket.dispatch({
id: 1,
from: 100,
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/vitest.config.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a new PR

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineProject } from "vitest/config";

export default defineProject({
test: {
name: "@meshtastic/ui",
environment: "happy-dom",
include: ["src/**/*.test.ts", "src/**/*.test.tsx"],
},
});
5 changes: 4 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export default defineConfig({
timeout: 90_000,
expect: { timeout: 15_000 },

reporter: [["list"], ["html", { outputFolder: "e2e/.report", open: "never" }]],
reporter: [
["list"],
["html", { outputFolder: "e2e/.report", open: "never" }],
],

use: {
baseURL: `http://localhost:${WEB_PORT}`,
Expand Down
Loading
Loading