Files
boss/tests/android-chat-local-realtime-patch.test.ts

109 lines
4.5 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
async function readSource(path: string) {
return readFile(new URL(path, import.meta.url), "utf8");
}
test("events route enriches message events with a lightweight project chat payload", async () => {
const source = await readSource("../src/app/api/v1/events/route.ts");
assert.match(
source,
/projectMessagesPayload:\s*buildProjectMessagesRealtimePayload\(state,\s*String\(payload\.projectId \?\? ""\)\)/,
"expected realtime event route to include a lightweight project chat payload for message events",
);
});
test("ProjectDetailActivity applies lightweight realtime chat payloads before scheduling reloads", async () => {
const source = await readSource("../android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java");
assert.match(
source,
/if \(tryApplyRealtimeMessagesPatch\(event\)\) \{\s*return;\s*\}/,
"expected chat page to try a local realtime message patch before falling back to debounced reloads",
);
assert.match(
source,
/JSONObject projectMessagesPayload = event\.payload\.optJSONObject\("projectMessagesPayload"\);/,
"expected chat page to read the lightweight message payload from realtime events",
);
assert.match(
source,
/renderLoadedProjectSnapshot\(new ProjectSnapshot\(projectMessagesPayload,\s*null,\s*null\)\);/,
"expected chat page to render the local realtime payload without forcing a network request",
);
assert.match(
source,
/JSONArray executionWarnings = projectMessagesPayload\.optJSONArray\("executionWarnings"\);/,
"expected chat page to read executionWarnings from the lightweight realtime payload",
);
assert.match(
source,
/LinearLayout statusRow = BossUi\.buildMessageStatusRow\(this, message, conversationTask, messageWarnings, outgoing\);/,
"expected each rendered message to create a compact status row",
);
assert.match(
source,
/private List<JSONObject> buildMessageWarnings\(JSONObject payload, String messageId\)/,
"expected a helper returning grouped warnings per message",
);
assert.match(
source,
/if \(!TextUtils\.equals\(currentFingerprint,\s*nextFingerprint\)\) \{/,
"expected realtime warning patches to branch on fingerprint differences before replacing views",
);
assert.match(
source,
/replaceMessageViewById\(messageId,\s*buildMessageView\(message\)\);/,
"expected realtime warning patches to replace only the affected message after fingerprint differences",
);
const warningPatchMethod = source.match(
/private boolean tryPatchRealtimeExecutionWarnings\(JSONObject projectMessagesPayload\) \{[\s\S]*?\n \}/,
);
assert.ok(warningPatchMethod, "expected to locate the warning patch helper body");
const snapshotSwapCount =
warningPatchMethod[0].match(/currentRenderedProjectPayload = nextPayloadCopy;/g)?.length ?? 0;
assert.equal(
snapshotSwapCount,
1,
"expected warning patch helper to swap the rendered payload only once after all message diffs are processed",
);
});
test("BossUi keeps a detail-only message status row visible", async () => {
const source = await readSource("../android/app/src/main/java/com/hyzq/boss/BossUi.java");
assert.match(
source,
/boolean hasDetail = !TextUtils\.isEmpty\(detailText\);/,
"expected message status rows to detect detail-only status text",
);
assert.match(
source,
/if \(!hasTask && !hasWarnings && !hasDetail\) \{\s*row\.setVisibility\(View\.GONE\);\s*return row;\s*\}/,
"expected message status rows to stay visible whenever detail text exists",
);
assert.match(
source,
/if \(hasDetail\) \{\s*TextView detailView = new TextView\(context\);/,
"expected detail-only rows to still render their muted status text",
);
});
test("ProjectDetailActivity bypasses realtime message-only patching when group dispatch or repair state is active", async () => {
const source = await readSource("../android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java");
assert.match(
source,
/if \(shouldBypassRealtimeMessagesPatchForGroupState\(\)\) \{\s*return false;\s*\}/,
"expected realtime message patching to fall back to a full reload when group dispatch or repair state could be stale",
);
assert.match(
source,
/private boolean shouldBypassRealtimeMessagesPatchForGroupState\(\) \{/,
"expected a dedicated helper guarding the fast patch path for group-only state",
);
});