test_tabs_to_process.js (6400B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { SmartTabGroupingManager } = ChromeUtils.importESModule( 5 "moz-src:///browser/components/tabbrowser/SmartTabGrouping.sys.mjs" 6 ); 7 8 // Simple helper to construct tab-like objects for tests. 9 function makeTab(id, { pinned = false, hasURL = true } = {}) { 10 return { 11 id, 12 label: `Tab ${id}`, 13 pinned, 14 linkedBrowser: hasURL 15 ? { currentURI: { spec: `https://example.com/${id}` } } 16 : null, 17 }; 18 } 19 20 add_task( 21 function test_tabs_to_process_includes_group_first_and_respects_limit() { 22 const manager = new SmartTabGroupingManager(); 23 24 const groupTab1 = makeTab("group-1"); 25 const groupTab2 = makeTab("group-2"); 26 const other1 = makeTab("other-1"); 27 const other2 = makeTab("other-2"); 28 const other3 = makeTab("other-3"); 29 30 const tabsInGroup = [groupTab1, groupTab2]; 31 const allTabs = [groupTab1, other1, groupTab2, other2, other3]; 32 33 // Limit 4: should be [group tabs] first, then fill with window tabs. 34 let resultIds = manager 35 .getTabsToProcess(tabsInGroup, allTabs, 4) 36 .map(t => t.id); 37 38 Assert.deepEqual( 39 resultIds, 40 ["group-1", "group-2", "other-1", "other-2"], 41 "Group tabs should come first, then window tabs, up to the limit" 42 ); 43 44 // Limit 2: should only include the group tabs. 45 resultIds = manager 46 .getTabsToProcess(tabsInGroup, allTabs, 2) 47 .map(t => t.id); 48 49 Assert.deepEqual( 50 resultIds, 51 ["group-1", "group-2"], 52 "When limit equals number of group tabs, only group tabs are returned" 53 ); 54 } 55 ); 56 57 add_task( 58 function test_tabs_to_process_limits_anchor_tabs_to_max_nn_grouped_tabs() { 59 const manager = new SmartTabGroupingManager(); 60 61 // More than MAX_NN_GROUPED_TABS (4) tabs in the group. 62 const groupTabs = []; 63 for (let i = 0; i < 6; i++) { 64 groupTabs.push(makeTab(`group-${i}`)); 65 } 66 const extraTab = makeTab("other"); 67 const allTabs = [...groupTabs, extraTab]; 68 69 const resultIds = manager 70 .getTabsToProcess(groupTabs, allTabs, 10) 71 .map(t => t.id); 72 73 Assert.deepEqual( 74 resultIds, 75 ["group-0", "group-1", "group-2", "other"], 76 "Only the first MAX_NN_GROUPED_TABS group tabs should be kept, then window tabs" 77 ); 78 } 79 ); 80 81 add_task(function test_tabs_to_process_deduplicates_group_tabs_in_all_tabs() { 82 const manager = new SmartTabGroupingManager(); 83 84 const groupTab1 = makeTab("group-1"); 85 const groupTab2 = makeTab("group-2"); 86 const other1 = makeTab("other-1"); 87 88 // group tabs also appear in allTabs 89 const tabsInGroup = [groupTab1, groupTab2]; 90 const allTabs = [groupTab1, groupTab2, other1]; 91 92 const resultIds = manager 93 .getTabsToProcess(tabsInGroup, allTabs, 10) 94 .map(t => t.id); 95 96 Assert.deepEqual( 97 resultIds, 98 ["group-1", "group-2", "other-1"], 99 "Tabs already in the group should not be duplicated when iterating allTabs" 100 ); 101 }); 102 103 add_task(function test_tabs_to_process_more_non_group_tabs_than_limit() { 104 const manager = new SmartTabGroupingManager(); 105 106 const groupTab1 = makeTab("group-1"); 107 const groupTab2 = makeTab("group-2"); 108 109 const tabsInGroup = [groupTab1, groupTab2]; 110 111 // 10 non-group tabs 112 const nonGroupTabs = []; 113 for (let i = 0; i < 10; i++) { 114 nonGroupTabs.push(makeTab(`other-${i}`)); 115 } 116 117 const allTabs = [groupTab1, ...nonGroupTabs, groupTab2]; 118 119 // Limit 6 => 2 group tabs + first 4 non-group tabs (in allTabs order) 120 const resultIds = manager 121 .getTabsToProcess(tabsInGroup, allTabs, 6) 122 .map(t => t.id); 123 124 Assert.deepEqual( 125 resultIds, 126 ["group-1", "group-2", "other-0", "other-1", "other-2", "other-3"], 127 "When there are more non-group tabs than the limit, only the first ones (by window order) are included after the group tabs" 128 ); 129 }); 130 131 add_task(function test_tabs_to_process_with_no_group_tabs() { 132 const manager = new SmartTabGroupingManager(); 133 134 const allTabs = []; 135 for (let i = 0; i < 8; i++) { 136 allTabs.push(makeTab(`tab-${i}`)); 137 } 138 139 const tabsInGroup = []; 140 141 const resultIds = manager 142 .getTabsToProcess(tabsInGroup, allTabs, 5) 143 .map(t => t.id); 144 145 Assert.deepEqual( 146 resultIds, 147 ["tab-0", "tab-1", "tab-2", "tab-3", "tab-4"], 148 "When there are no group tabs, we should just take up to the limit from window tabs" 149 ); 150 }); 151 152 add_task(function test_tabs_to_process_uses_default_max_limit() { 153 const manager = new SmartTabGroupingManager(); 154 155 // 350 non-group tabs, all valid 156 const allTabs = []; 157 for (let i = 0; i < 350; i++) { 158 allTabs.push(makeTab(`tab-${i}`)); 159 } 160 161 const tabsInGroup = []; 162 163 // Use default max_limit_to_process (should be 100) 164 const result = manager.getTabsToProcess(tabsInGroup, allTabs); 165 const resultIds = result.map(t => t.id); 166 167 Assert.equal( 168 resultIds.length, 169 300, 170 "Default max limit should cap the number of processed tabs to 300" 171 ); 172 173 Assert.deepEqual( 174 resultIds.slice(0, 5), 175 ["tab-0", "tab-1", "tab-2", "tab-3", "tab-4"], 176 "Default behavior should preserve window order for the first tabs" 177 ); 178 }); 179 180 add_task(function test_tabs_to_process_all_tabs_filtered_out() { 181 const manager = new SmartTabGroupingManager(); 182 183 // All pinned 184 const pinned1 = makeTab("pinned-1", { pinned: true }); 185 const pinned2 = makeTab("pinned-2", { pinned: true }); 186 187 // All missing URL 188 const noUrl1 = makeTab("no-url-1", { hasURL: false }); 189 const noUrl2 = makeTab("no-url-2", { hasURL: false }); 190 191 const tabsInGroup = [pinned1]; 192 const allTabs = [pinned1, pinned2, noUrl1, noUrl2]; 193 194 const result = manager.getTabsToProcess(tabsInGroup, allTabs, 10); 195 196 Assert.deepEqual( 197 result, 198 [], 199 "If all tabs are filtered out (pinned or no URL), we should return an empty list" 200 ); 201 }); 202 203 add_task(function test_tabs_to_process_group_tabs_not_in_allTabs() { 204 const manager = new SmartTabGroupingManager(); 205 206 const externalGroupTab = makeTab("external-group"); // not in allTabs 207 const other1 = makeTab("other-1"); 208 const other2 = makeTab("other-2"); 209 210 const tabsInGroup = [externalGroupTab]; 211 const allTabs = [other1, other2]; 212 213 const resultIds = manager 214 .getTabsToProcess(tabsInGroup, allTabs, 3) 215 .map(t => t.id); 216 217 Assert.deepEqual( 218 resultIds, 219 ["external-group", "other-1", "other-2"], 220 "Tabs in the group should still be included even if they don't appear in allTabs" 221 ); 222 });