Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test runs only with pattern: os != 'android'
- Manifest: browser/components/aiwindow/models/tests/xpcshell/xpcshell.toml
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
const { buildSessions } = ChromeUtils.importESModule(
"moz-src:///browser/components/aiwindow/models/memories/MemoriesSessions.sys.mjs"
);
const MS = 1_000;
const MICROS_PER_MS = 1_000;
function visit(timestampMs, extra = {}) {
return {
source: "history",
visitDateMicros: timestampMs * MICROS_PER_MS,
domain: "example.com",
title: "Example",
urlHash: 1,
totalViewTimeMs: 0,
...extra,
};
}
function search(timestampMs, extra = {}) {
return visit(timestampMs, { source: "search", title: "query", ...extra });
}
function chat(timestampMs, extra = {}) {
return {
role: "user",
content: "hello",
convId: extra.convId ?? "c1",
createdDate: timestampMs,
...extra,
};
}
add_task(function test_empty_inputs_return_empty_array() {
Assert.deepEqual(buildSessions(), [], "no args → []");
Assert.deepEqual(buildSessions([], []), [], "empty arrays → []");
});
add_task(function test_single_visit_makes_one_session() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[visit(t, { urlHash: 42, domain: "a.com", title: "A" })],
[]
);
Assert.equal(sessions.length, 1, "one session produced");
const s = sessions[0];
Assert.equal(s.visit_count, 1);
Assert.equal(s.search_count, 0);
Assert.equal(s.chat_count, 0);
Assert.equal(s.session_start_ms, t);
Assert.equal(s.session_end_ms, t);
Assert.deepEqual(s.history_source_ids, [42]);
Assert.deepEqual(s.conversation_source_ids, []);
Assert.deepEqual(s.domains, ["a.com"]);
Assert.deepEqual(s.titles, ["A"]);
});
add_task(function test_visits_within_gap_merge_into_one_session() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[
visit(t, { urlHash: 1, domain: "a.com", title: "A" }),
visit(t + 60 * MS, { urlHash: 2, domain: "b.com", title: "B" }),
visit(t + 120 * MS, { urlHash: 1, domain: "a.com", title: "A" }),
],
[],
{ gapSec: 900 }
);
Assert.equal(sessions.length, 1, "all within gap → 1 session");
const s = sessions[0];
Assert.equal(s.visit_count, 3, "raw event count, not dedup");
Assert.deepEqual(s.history_source_ids.sort(), [1, 2], "urlHashes deduped");
Assert.deepEqual(s.domains.sort(), ["a.com", "b.com"]);
});
add_task(function test_gap_exceeded_splits_into_two_sessions() {
const t = 1_700_000_000_000;
const sessions = buildSessions([visit(t), visit(t + 1000 * MS)], [], {
gapSec: 900,
});
Assert.equal(sessions.length, 2, "gap > 900s → 2 sessions");
Assert.equal(sessions[0].session_start_ms, t);
Assert.equal(sessions[1].session_start_ms, t + 1000 * MS);
});
add_task(function test_max_session_length_forces_split() {
const t = 1_700_000_000_000;
// Events 1s apart, but max session length = 5s → must split after 5s.
const history = [];
for (let i = 0; i < 10; i++) {
history.push(visit(t + i * MS));
}
const sessions = buildSessions(history, [], {
gapSec: 900,
maxSessionSec: 5,
});
Assert.equal(
sessions.length,
2,
"maxSessionSec forces a split even without a gap"
);
});
add_task(function test_history_and_chat_merge_in_time_order() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[visit(t), visit(t + 60 * MS)],
[chat(t + 30 * MS, { convId: "c-alpha" })],
{ gapSec: 900 }
);
Assert.equal(sessions.length, 1, "interleaved events → single session");
const s = sessions[0];
Assert.equal(s.visit_count, 2);
Assert.equal(s.chat_count, 1);
Assert.deepEqual(s.conversation_source_ids, ["c-alpha"]);
});
add_task(function test_source_ids_are_separated_and_deduped() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[visit(t, { urlHash: 7 }), visit(t + 10 * MS, { urlHash: 7 })],
[
chat(t + 5 * MS, { convId: "c1" }),
chat(t + 15 * MS, { convId: "c1" }),
chat(t + 20 * MS, { convId: "c2" }),
]
);
Assert.equal(sessions.length, 1);
const s = sessions[0];
Assert.deepEqual(s.history_source_ids, [7], "duplicate urlHash deduped");
Assert.deepEqual(
s.conversation_source_ids.sort(),
["c1", "c2"],
"duplicate convId deduped, both kept"
);
});
add_task(function test_search_rows_populate_search_queries() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[search(t, { title: "firefox release notes" }), visit(t + 5 * MS)],
[]
);
Assert.equal(sessions.length, 1);
const s = sessions[0];
Assert.equal(s.search_count, 1);
Assert.equal(s.visit_count, 1);
Assert.deepEqual(s.search_queries, ["firefox release notes"]);
});
add_task(function test_skips_rows_with_invalid_timestamps() {
const t = 1_700_000_000_000;
const sessions = buildSessions(
[
visit(t),
{ source: "history", visitDateMicros: NaN, urlHash: 99 },
{ source: "history", urlHash: 100 }, // missing visitDateMicros
],
[
chat(t + 5 * MS, { convId: "c1" }),
chat(NaN, { convId: "c2" }),
{ role: "user", content: "x", convId: null, createdDate: t + 6 * MS },
]
);
Assert.equal(sessions.length, 1);
const s = sessions[0];
Assert.equal(s.visit_count, 1, "rows with bad timestamps dropped");
Assert.equal(s.chat_count, 1, "chats missing convId or timestamp dropped");
});