tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_ChatStore.js (20333B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 do_get_profile();
      5 
      6 const lazy = {};
      7 
      8 ChromeUtils.defineESModuleGetters(lazy, {
      9  sinon: "resource://testing-common/Sinon.sys.mjs",
     10 });
     11 
     12 const { ChatStore, ChatConversation, ChatMessage } = ChromeUtils.importESModule(
     13  "moz-src:///browser/components/aiwindow/ui/modules/ChatStore.sys.mjs"
     14 );
     15 
     16 async function addBasicConvoTestData(date, title, updated = null) {
     17  const link = "https://www.firefox.com";
     18  const updatedDate = updated || date;
     19 
     20  return addConvoWithSpecificTestData(
     21    new Date(date),
     22    link,
     23    link,
     24    title,
     25    "test content",
     26    new Date(updatedDate)
     27  );
     28 }
     29 
     30 async function addBasicConvoWithSpecificUpdatedTestData(updatedDate, title) {
     31  const link = "https://www.firefox.com";
     32  return addConvoWithSpecificTestData(
     33    new Date("1/1/2023"),
     34    link,
     35    link,
     36    title,
     37    "test content",
     38    new Date(updatedDate)
     39  );
     40 }
     41 
     42 async function addConvoWithSpecificTestData(
     43  createdDate,
     44  mainLink,
     45  messageLink,
     46  title,
     47  message = "the message body",
     48  updatedDate = false
     49 ) {
     50  const conversation = new ChatConversation({
     51    createdDate: createdDate.getTime(),
     52    updatedDate: updatedDate ? updatedDate.getTime() : createdDate.getTime(),
     53    pageUrl: mainLink,
     54  });
     55  conversation.title = title;
     56  conversation.addUserMessage(message, messageLink, 0);
     57  await gChatStore.updateConversation(conversation);
     58 }
     59 
     60 async function addConvoWithSpecificCustomContentTestData(
     61  createdDate,
     62  mainLink,
     63  messageLink,
     64  title,
     65  content,
     66  role
     67 ) {
     68  const conversation = new ChatConversation({
     69    createdDate: createdDate.getTime(),
     70    updatedDate: createdDate.getTime(),
     71    pageUrl: mainLink,
     72  });
     73  conversation.title = title;
     74  conversation.addMessage(role, content, messageLink, 0);
     75  await gChatStore.updateConversation(conversation);
     76 }
     77 
     78 /**
     79 * Runs a test atomically so that the clean up code
     80 * runs after each test intead of after the entire
     81 * list of tasks in the file are done.
     82 *
     83 * @todo Bug 2005408
     84 * Replace add_atomic_task usage when this Bug 1656557 lands
     85 *
     86 * @param {Function} func - The test function to run
     87 */
     88 function add_atomic_task(func) {
     89  return add_task(async function () {
     90    await test_ChatStorage_setup();
     91 
     92    try {
     93      await func();
     94    } finally {
     95      await test_cleanUp();
     96    }
     97  });
     98 }
     99 
    100 let gChatStore, gSandbox;
    101 
    102 async function cleanUpDatabase() {
    103  if (gChatStore) {
    104    await gChatStore.destroyDatabase();
    105    gChatStore = null;
    106  }
    107 }
    108 
    109 async function test_ChatStorage_setup() {
    110  Services.prefs.setBoolPref("browser.aiwindow.removeDatabaseOnStartup", true);
    111 
    112  gChatStore = new ChatStore();
    113  await gChatStore.destroyDatabase();
    114 
    115  gSandbox = lazy.sinon.createSandbox();
    116 }
    117 
    118 async function test_cleanUp() {
    119  Services.prefs.clearUserPref("browser.aiwindow.removeDatabaseOnStartup");
    120 
    121  await cleanUpDatabase();
    122  gSandbox.restore();
    123 }
    124 
    125 add_atomic_task(async function task_ChatStorage_constructor() {
    126  gChatStore = new ChatStore();
    127 
    128  Assert.ok(gChatStore, "Should return a ChatStorage instance");
    129 });
    130 
    131 add_atomic_task(async function test_ChatStorage_updateConversation() {
    132  let success = true;
    133  let errorMessage = "";
    134 
    135  try {
    136    gChatStore = new ChatStore();
    137    const conversation = new ChatConversation({});
    138 
    139    conversation.addUserMessage("test content", "https://www.firefox.com", 0);
    140 
    141    await gChatStore.updateConversation(conversation);
    142  } catch (e) {
    143    success = false;
    144    errorMessage = e.message;
    145  }
    146 
    147  Assert.ok(success, errorMessage);
    148 });
    149 
    150 add_atomic_task(async function test_ChatStorage_findRecentConversations() {
    151  gChatStore = new ChatStore();
    152 
    153  await addBasicConvoTestData("1/1/2025", "conversation 1");
    154  await addBasicConvoTestData("1/2/2025", "conversation 2");
    155  await addBasicConvoTestData("1/3/2025", "conversation 3");
    156 
    157  const recentConversations = await gChatStore.findRecentConversations(2);
    158 
    159  Assert.withSoftAssertions(function (soft) {
    160    soft.equal(recentConversations[0].title, "conversation 3");
    161    soft.equal(recentConversations[1].title, "conversation 2");
    162  });
    163 });
    164 
    165 add_atomic_task(async function test_ChatStorage_findConversationById() {
    166  gChatStore = new ChatStore();
    167 
    168  let conversation = new ChatConversation({});
    169  conversation.title = "conversation 1";
    170  conversation.addUserMessage("test content", "https://www.firefox.com", 0);
    171  await gChatStore.updateConversation(conversation);
    172 
    173  const conversationId = conversation.id;
    174 
    175  conversation = await gChatStore.findConversationById(conversationId);
    176 
    177  Assert.withSoftAssertions(function (soft) {
    178    soft.equal(conversation.id, conversationId);
    179    soft.equal(conversation.title, "conversation 1");
    180  });
    181 });
    182 
    183 add_atomic_task(async function test_ChatStorage_findConversationsByDate() {
    184  gChatStore = new ChatStore();
    185 
    186  await addBasicConvoWithSpecificUpdatedTestData("1/1/2025", "conversation 1");
    187  await addBasicConvoWithSpecificUpdatedTestData("6/1/2025", "conversation 2");
    188  await addBasicConvoWithSpecificUpdatedTestData("12/1/2025", "conversation 3");
    189 
    190  const startDate = new Date("5/1/2025").getTime();
    191  const endDate = new Date("1/1/2026").getTime();
    192  const conversations = await gChatStore.findConversationsByDate(
    193    startDate,
    194    endDate
    195  );
    196 
    197  const errorMessage = `Incorrect message sorting: ${JSON.stringify(conversations)}`;
    198 
    199  Assert.withSoftAssertions(function (soft) {
    200    soft.equal(
    201      conversations.length,
    202      2,
    203      "Incorrect number of conversations received"
    204    );
    205    soft.equal(conversations[0].title, "conversation 3", errorMessage);
    206    soft.equal(conversations[1].title, "conversation 2", errorMessage);
    207  });
    208 });
    209 
    210 add_atomic_task(async function test_ChatStorage_findConversationsByURL() {
    211  async function addTestData() {
    212    await addConvoWithSpecificTestData(
    213      new Date("1/1/2025"),
    214      new URL("https://www.firefox.com"),
    215      new URL("https://www.mozilla.com"),
    216      "conversation 1"
    217    );
    218 
    219    await addConvoWithSpecificTestData(
    220      new Date("1/2/2025"),
    221      new URL("https://www.firefox.com"),
    222      new URL("https://www.mozilla.org"),
    223      "Mozilla.org conversation 1"
    224    );
    225 
    226    await addConvoWithSpecificTestData(
    227      new Date("1/3/2025"),
    228      new URL("https://www.firefox.com"),
    229      new URL("https://www.mozilla.org"),
    230      "Mozilla.org conversation 2"
    231    );
    232  }
    233 
    234  gChatStore = new ChatStore();
    235 
    236  await addTestData();
    237 
    238  const conversations = await gChatStore.findConversationsByURL(
    239    new URL("https://www.mozilla.org")
    240  );
    241 
    242  Assert.withSoftAssertions(function (soft) {
    243    soft.equal(conversations.length, 2, "Chat conversations not found");
    244    soft.equal(conversations[0].title, "Mozilla.org conversation 2");
    245    soft.equal(conversations[1].title, "Mozilla.org conversation 1");
    246  });
    247 });
    248 
    249 async function addTestDataForFindMessageByDate() {
    250  await gChatStore.updateConversation(
    251    new ChatConversation({
    252      title: "convo 1",
    253      description: "",
    254      pageUrl: new URL("https://www.firefox.com"),
    255      pageMeta: {},
    256      messages: [
    257        new ChatMessage({
    258          createdDate: new Date("1/1/2025").getTime(),
    259          ordinal: 0,
    260          role: 0,
    261          content: { type: "text", content: "a message" },
    262          pageUrl: new URL("https://www.mozilla.com"),
    263        }),
    264      ],
    265    })
    266  );
    267 
    268  await gChatStore.updateConversation(
    269    new ChatConversation({
    270      title: "convo 2",
    271      description: "",
    272      pageUrl: new URL("https://www.firefox.com"),
    273      pageMeta: {},
    274      messages: [
    275        new ChatMessage({
    276          createdDate: new Date("7/1/2025").getTime(),
    277          ordinal: 0,
    278          role: 0,
    279          content: { type: "text", content: "a message in july" },
    280          pageUrl: new URL("https://www.mozilla.com"),
    281        }),
    282      ],
    283    })
    284  );
    285 
    286  await gChatStore.updateConversation(
    287    new ChatConversation({
    288      title: "convo 3",
    289      description: "",
    290      pageUrl: new URL("https://www.firefox.com"),
    291      pageMeta: {},
    292      messages: [
    293        new ChatMessage({
    294          createdDate: new Date("8/1/2025").getTime(),
    295          ordinal: 0,
    296          role: 1,
    297          content: { type: "text", content: "a message in august" },
    298          pageUrl: new URL("https://www.mozilla.com"),
    299        }),
    300      ],
    301    })
    302  );
    303 }
    304 
    305 add_atomic_task(
    306  async function test_withoutSpecifiedRole_ChatStorage_findMessagesByDate() {
    307    gChatStore = new ChatStore();
    308 
    309    await addTestDataForFindMessageByDate();
    310 
    311    const startDate = new Date("6/1/2025");
    312    const endDate = new Date("1/1/2026");
    313    const messages = await gChatStore.findMessagesByDate(startDate, endDate);
    314 
    315    Assert.withSoftAssertions(function (soft) {
    316      soft.equal(messages.length, 2, "Chat messages not found");
    317      soft.equal(messages?.[0]?.content?.content, "a message in august");
    318      soft.equal(messages?.[1]?.content?.content, "a message in july");
    319    });
    320  }
    321 );
    322 
    323 add_atomic_task(async function test_limit_ChatStorage_findMessagesByDate() {
    324  gChatStore = new ChatStore();
    325 
    326  await addTestDataForFindMessageByDate();
    327 
    328  const startDate = new Date("6/1/2025");
    329  const endDate = new Date("1/1/2026");
    330  const messages = await gChatStore.findMessagesByDate(
    331    startDate,
    332    endDate,
    333    -1,
    334    1
    335  );
    336 
    337  Assert.withSoftAssertions(function (soft) {
    338    soft.equal(messages.length, 1, "Chat messages not found");
    339    soft.equal(messages?.[0]?.content?.content, "a message in august");
    340  });
    341 });
    342 
    343 add_atomic_task(async function test_skip_ChatStorage_findMessagesByDate() {
    344  gChatStore = new ChatStore();
    345 
    346  await addTestDataForFindMessageByDate();
    347 
    348  const startDate = new Date("6/1/2025");
    349  const endDate = new Date("1/1/2026");
    350  const messages = await gChatStore.findMessagesByDate(
    351    startDate,
    352    endDate,
    353    -1,
    354    -1,
    355    1
    356  );
    357 
    358  Assert.withSoftAssertions(function (soft) {
    359    soft.equal(messages.length, 1, "Chat messages not found");
    360    soft.equal(messages?.[0]?.content?.content, "a message in july");
    361  });
    362 });
    363 
    364 add_atomic_task(
    365  async function test_withSpecifiedRole_ChatStorage_findMessagesByDate() {
    366    gChatStore = new ChatStore();
    367 
    368    await addTestDataForFindMessageByDate();
    369 
    370    const startDate = new Date("6/1/2025");
    371    const endDate = new Date("1/1/2026");
    372    const messages = await gChatStore.findMessagesByDate(startDate, endDate, 0);
    373 
    374    Assert.withSoftAssertions(function (soft) {
    375      soft.equal(messages.length, 1, "Chat messages not found");
    376      soft.equal(messages?.[0]?.content?.content, "a message in july");
    377    });
    378  }
    379 );
    380 
    381 add_atomic_task(async function test_ChatStorage_searchContent() {
    382  await addConvoWithSpecificTestData(
    383    new Date("1/2/2025"),
    384    new URL("https://www.firefox.com"),
    385    new URL("https://www.mozilla.org"),
    386    "Mozilla.org conversation 1",
    387    "a random message"
    388  );
    389 
    390  await addConvoWithSpecificTestData(
    391    new Date("1/2/2025"),
    392    new URL("https://www.firefox.com"),
    393    new URL("https://www.mozilla.org"),
    394    "Mozilla.org conversation 2",
    395    "a random message again"
    396  );
    397 
    398  await addConvoWithSpecificTestData(
    399    new Date("1/2/2025"),
    400    new URL("https://www.firefox.com"),
    401    new URL("https://www.mozilla.org"),
    402    "Mozilla.org conversation 3",
    403    "the interesting message"
    404  );
    405 
    406  const conversations = await gChatStore.searchContent("body");
    407 
    408  Assert.equal(conversations.length, 3);
    409 });
    410 
    411 add_atomic_task(async function test_deepPath_ChatStorage_searchContent() {
    412  async function addTestData() {
    413    await addConvoWithSpecificCustomContentTestData(
    414      new Date("1/2/2025"),
    415      new URL("https://www.firefox.com"),
    416      new URL("https://www.mozilla.org"),
    417      "Mozilla.org conversation 1",
    418      { type: "text", content: "a random message" },
    419      0 // MessageRole.USER
    420    );
    421 
    422    await addConvoWithSpecificCustomContentTestData(
    423      new Date("1/2/2025"),
    424      new URL("https://www.firefox.com"),
    425      new URL("https://www.mozilla.org"),
    426      "Mozilla.org conversation 2",
    427      { type: "text", content: "a random message again" },
    428      0 // MessageRole.USER
    429    );
    430 
    431    await addConvoWithSpecificCustomContentTestData(
    432      new Date("1/2/2025"),
    433      new URL("https://www.firefox.com"),
    434      new URL("https://www.mozilla.org"),
    435      "Mozilla.org conversation 3",
    436      {
    437        type: "text",
    438        someKey: {
    439          deeper: {
    440            keyToLookIn: "the interesting message",
    441          },
    442        },
    443      },
    444      0 // MessageRole.USER
    445    );
    446  }
    447 
    448  await addTestData();
    449 
    450  const conversations = await gChatStore.searchContent(
    451    "someKey.deeper.keyToLookIn"
    452  );
    453 
    454  const foundConvo = conversations[0];
    455  const firstMessage = foundConvo?.messages?.[0];
    456  const contentJson = firstMessage?.content;
    457 
    458  Assert.withSoftAssertions(function (soft) {
    459    soft.equal(conversations.length, 1);
    460    soft.equal(
    461      contentJson?.someKey?.deeper?.keyToLookIn,
    462      "the interesting message"
    463    );
    464  });
    465 });
    466 
    467 add_atomic_task(async function test_ChatStorage_search() {
    468  async function addTestData() {
    469    await addConvoWithSpecificTestData(
    470      new Date("1/2/2025"),
    471      new URL("https://www.firefox.com"),
    472      new URL("https://www.mozilla.org"),
    473      "Mozilla.org conversation 1",
    474      "a random message"
    475    );
    476 
    477    await addConvoWithSpecificTestData(
    478      new Date("1/2/2025"),
    479      new URL("https://www.firefox.com"),
    480      new URL("https://www.mozilla.org"),
    481      "Mozilla.org interesting conversation 2",
    482      "a random message again"
    483    );
    484 
    485    await addConvoWithSpecificTestData(
    486      new Date("1/2/2025"),
    487      new URL("https://www.firefox.com"),
    488      new URL("https://www.mozilla.org"),
    489      "Mozilla.org conversation 3",
    490      "some other message"
    491    );
    492  }
    493 
    494  await addTestData();
    495 
    496  const conversations = await gChatStore.search("interesting");
    497 
    498  Assert.withSoftAssertions(function (soft) {
    499    soft.equal(conversations.length, 1);
    500    soft.equal(
    501      conversations[0].title,
    502      "Mozilla.org interesting conversation 2"
    503    );
    504 
    505    const message = conversations[0].messages[0];
    506    soft.equal(message.content.body, "a random message again");
    507  });
    508 });
    509 
    510 add_atomic_task(async function test_ChatStorage_deleteConversationById() {
    511  await addBasicConvoTestData("1/1/2025", "a conversation");
    512 
    513  let conversations = await gChatStore.findRecentConversations(10);
    514 
    515  Assert.equal(
    516    conversations.length,
    517    1,
    518    "Test conversation for deleteConversationById() did not save."
    519  );
    520 
    521  const conversation = conversations[0];
    522 
    523  await gChatStore.deleteConversationById(conversation.id);
    524  conversations = await gChatStore.findRecentConversations(10);
    525  Assert.equal(conversations.length, 0, "Test conversation was not deleted");
    526 });
    527 
    528 // TODO: Disabled this test. pruneDatabase() needs some work to switch
    529 // db file size to be checked via dbstat. Additionally, after switching
    530 // the last line to `PRAGMA incremental_vacuum;` the disk storage is
    531 // not immediately freed, so this test is now failing. Will need to
    532 // revisit this test when pruneDatabase() is updated.
    533 //
    534 // add_atomic_task(async function test_ChatStorage_pruneDatabase() {
    535 //   const initialDbSize = await gChatStore.getDatabaseSize();
    536 //
    537 //   // NOTE: Add enough conversations to increase the SQLite file
    538 //   // by a measurable size
    539 //   for (let i = 0; i < 1000; i++) {
    540 //     await addBasicConvoTestData("1/1/2025", "a conversation");
    541 //   }
    542 //
    543 //   const dbSizeWithTestData = await gChatStore.getDatabaseSize();
    544 //
    545 //   Assert.greater(
    546 //     dbSizeWithTestData,
    547 //     initialDbSize,
    548 //     "Test conversations not saved for pruneDatabase() test"
    549 //   );
    550 //
    551 //   await gChatStore.pruneDatabase(0.5, 100000);
    552 //
    553 //   const dbSizeAfterPrune = await gChatStore.getDatabaseSize();
    554 //
    555 //   const proximityToInitialSize = dbSizeAfterPrune - initialDbSize;
    556 //   const proximityToTestDataSize = dbSizeWithTestData - initialDbSize;
    557 //
    558 //   Assert.less(
    559 //     proximityToInitialSize,
    560 //     proximityToTestDataSize,
    561 //     "The pruned size is not closer to the initial db size than it is to the size with test data in it"
    562 //   );
    563 // });
    564 
    565 add_atomic_task(async function test_applyMigrations_notCalledOnInitialSetup() {
    566  lazy.sinon.stub(gChatStore, "CURRENT_SCHEMA_VERSION").returns(0);
    567  lazy.sinon.spy(gChatStore, "applyMigrations");
    568 
    569  // Trigger connection to db so file creates and migrations applied
    570  await gChatStore.getDatabaseSize();
    571 
    572  Assert.ok(gChatStore.applyMigrations.notCalled);
    573 });
    574 
    575 add_atomic_task(
    576  async function test_applyMigrations_calledOnceIfSchemaIsGreaterThanDb() {
    577    lazy.sinon.stub(gChatStore, "CURRENT_SCHEMA_VERSION").get(() => 2);
    578    lazy.sinon.stub(gChatStore, "getDatabaseSchemaVersion").resolves(1);
    579    lazy.sinon.stub(gChatStore, "applyMigrations");
    580    lazy.sinon.stub(gChatStore, "setSchemaVersion");
    581 
    582    // Trigger connection to db so file creates and migrations applied
    583    await gChatStore.getDatabaseSize();
    584 
    585    Assert.withSoftAssertions(function (soft) {
    586      soft.ok(gChatStore.applyMigrations.calledOnce);
    587      soft.ok(gChatStore.setSchemaVersion.calledWith(2));
    588    });
    589  }
    590 );
    591 
    592 add_atomic_task(
    593  async function test_applyMigrations_notCalledIfCurrentSchemaIsLessThanDbSchema_dbDowngrades() {
    594    lazy.sinon.stub(gChatStore, "CURRENT_SCHEMA_VERSION").get(() => 1);
    595    lazy.sinon.stub(gChatStore, "getDatabaseSchemaVersion").resolves(2);
    596    lazy.sinon.stub(gChatStore, "applyMigrations");
    597    lazy.sinon.stub(gChatStore, "setSchemaVersion");
    598 
    599    // Trigger connection to db so file creates and migrations applied
    600    await gChatStore.getDatabaseSize();
    601 
    602    Assert.withSoftAssertions(function (soft) {
    603      soft.ok(
    604        gChatStore.applyMigrations.notCalled,
    605        "applyMigrations was called"
    606      );
    607      soft.ok(
    608        gChatStore.setSchemaVersion.calledWith(1),
    609        "setSchemaVersion was not called with 1"
    610      );
    611    });
    612  }
    613 );
    614 
    615 async function addChatHistoryTestData() {
    616  await addConvoWithSpecificTestData(
    617    new Date("1/2/2025"),
    618    new URL("https://www.firefox.com"),
    619    new URL("https://www.mozilla.org"),
    620    "Mozilla.org conversation 1",
    621    "a random message"
    622  );
    623 
    624  await addConvoWithSpecificTestData(
    625    new Date("1/3/2025"),
    626    new URL("https://www.firefox.com"),
    627    new URL("https://www.mozilla.org"),
    628    "Mozilla.org interesting conversation 2",
    629    "a random message again"
    630  );
    631 
    632  await addConvoWithSpecificTestData(
    633    new Date("1/4/2025"),
    634    new URL("https://www.firefox.com"),
    635    new URL("https://www.mozilla.org"),
    636    "Mozilla.org conversation 3",
    637    "some other message"
    638  );
    639 }
    640 
    641 add_atomic_task(async function test_chatHistoryView() {
    642  await addChatHistoryTestData();
    643 
    644  const entries = await gChatStore.chatHistoryView();
    645 
    646  Assert.withSoftAssertions(function (soft) {
    647    soft.equal(entries.length, 3);
    648    soft.equal(entries[0].title, "Mozilla.org conversation 3");
    649    soft.equal(entries[1].title, "Mozilla.org interesting conversation 2");
    650    soft.equal(entries[2].title, "Mozilla.org conversation 1");
    651  });
    652 });
    653 
    654 add_atomic_task(async function test_chatHistoryView_sorting_desc() {
    655  await addChatHistoryTestData();
    656 
    657  const entries = await gChatStore.chatHistoryView(1, 20, "desc");
    658 
    659  Assert.withSoftAssertions(function (soft) {
    660    soft.equal(entries.length, 3);
    661    soft.equal(entries[0].title, "Mozilla.org conversation 3");
    662    soft.equal(entries[1].title, "Mozilla.org interesting conversation 2");
    663    soft.equal(entries[2].title, "Mozilla.org conversation 1");
    664  });
    665 });
    666 
    667 add_atomic_task(async function test_chatHistoryView_sorting_asc() {
    668  await addChatHistoryTestData();
    669 
    670  const entries = await gChatStore.chatHistoryView(1, 20, "asc");
    671 
    672  Assert.withSoftAssertions(function (soft) {
    673    soft.equal(entries.length, 3);
    674    soft.equal(entries[0].title, "Mozilla.org conversation 1");
    675    soft.equal(entries[1].title, "Mozilla.org interesting conversation 2");
    676    soft.equal(entries[2].title, "Mozilla.org conversation 3");
    677  });
    678 });
    679 
    680 add_atomic_task(async function test_chatHistoryView_pageSize() {
    681  await addChatHistoryTestData();
    682 
    683  const entries = await gChatStore.chatHistoryView(1, 2, "asc");
    684 
    685  Assert.equal(entries.length, 2);
    686 });
    687 
    688 add_atomic_task(async function test_chatHistoryView_pageNumber() {
    689  await addChatHistoryTestData();
    690 
    691  const entries = await gChatStore.chatHistoryView(3, 1, "asc");
    692 
    693  Assert.withSoftAssertions(function (soft) {
    694    soft.equal(entries.length, 1);
    695    soft.equal(entries[0].title, "Mozilla.org conversation 3");
    696  });
    697 });