Skip to content

Commit 9f79653

Browse files
committed
Add unit tests for requestAllSpaces() in background.js
1 parent 54e426d commit 9f79653

File tree

4 files changed

+151
-48
lines changed

4 files changed

+151
-48
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
88

99
- Fixed [issue #16](https://github.com/codedread/spaces/issues/16): Stop duplicating tabs of a closed Space when tab is clicked from the Spaces window.
1010
- Fixed [issue #14](https://github.com/codedread/spaces/issues/14): Open Spaces windows on the currently-active display.
11-
- Increased unit test coverage from 8.11% to 9.32%.
11+
- Increased unit test coverage from 8.11% to 10.12%.
1212

1313

1414
## [1.1.5] - 2025-09-08

js/background/background.js

Lines changed: 41 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -791,47 +791,6 @@ async function requestSpaceFromSessionId(sessionId) {
791791
};
792792
}
793793

794-
/**
795-
* Requests all spaces (sessions) from the database.
796-
*
797-
* @returns {Promise<Space[]>} Promise that resolves to an array of Space objects
798-
*/
799-
async function requestAllSpaces() {
800-
// Get all sessions from spacesService (includes both saved and temporary open window sessions)
801-
const allSessions = await spacesService.getAllSessions();
802-
/** @type {Space[]} */
803-
const allSpaces = allSessions
804-
.map(session => {
805-
return { sessionId: session.id, ...session };
806-
})
807-
.filter(session => {
808-
return session && session.tabs && session.tabs.length > 0;
809-
});
810-
811-
// sort results
812-
allSpaces.sort(spaceDateCompare);
813-
814-
return allSpaces;
815-
}
816-
817-
function spaceDateCompare(a, b) {
818-
// order open sessions first
819-
if (a.windowId && !b.windowId) {
820-
return -1;
821-
}
822-
if (!a.windowId && b.windowId) {
823-
return 1;
824-
}
825-
// then order by last access date
826-
if (a.lastAccess > b.lastAccess) {
827-
return -1;
828-
}
829-
if (a.lastAccess < b.lastAccess) {
830-
return 1;
831-
}
832-
return 0;
833-
}
834-
835794
async function handleLoadSession(sessionId, tabUrl) {
836795
const session = await dbService.fetchSessionById(sessionId);
837796

@@ -896,7 +855,7 @@ async function handleLoadSession(sessionId, tabUrl) {
896855
async function handleLoadWindow(windowId, tabUrl) {
897856
// assume window is already open, give it focus
898857
if (windowId) {
899-
await focusWindow(windowId);
858+
await chrome.windows.update(windowId, { focused: true })
900859
}
901860

902861
// if tabUrl is defined, then focus this tab
@@ -906,10 +865,6 @@ async function handleLoadWindow(windowId, tabUrl) {
906865
}
907866
}
908867

909-
async function focusWindow(windowId) {
910-
await chrome.windows.update(windowId, { focused: true });
911-
}
912-
913868
/**
914869
* Saves a new session from the specified window.
915870
*
@@ -1306,10 +1261,50 @@ async function getTargetDisplayWorkArea() {
13061261
return targetDisplay.workArea;
13071262
}
13081263

1264+
/**
1265+
* Requests all spaces (sessions) from the database.
1266+
*
1267+
* @returns {Promise<Space[]>} Promise that resolves to an array of Space objects
1268+
*/
1269+
async function requestAllSpaces() {
1270+
// Get all sessions from spacesService (includes both saved and temporary open window sessions)
1271+
const allSessions = await spacesService.getAllSessions();
1272+
/** @type {Space[]} */
1273+
const allSpaces = allSessions
1274+
.map(session => {
1275+
return { sessionId: session.id, ...session };
1276+
})
1277+
.filter(session => {
1278+
return session && session.tabs && session.tabs.length > 0;
1279+
});
1280+
1281+
// sort results
1282+
allSpaces.sort((a, b) => {
1283+
// order open sessions first
1284+
if (a.windowId && !b.windowId) {
1285+
return -1;
1286+
}
1287+
if (!a.windowId && b.windowId) {
1288+
return 1;
1289+
}
1290+
// then order by last access date
1291+
if (a.lastAccess > b.lastAccess) {
1292+
return -1;
1293+
}
1294+
if (a.lastAccess < b.lastAccess) {
1295+
return 1;
1296+
}
1297+
return 0;
1298+
});
1299+
1300+
return allSpaces;
1301+
}
1302+
13091303
// Exports for testing.
13101304
export {
13111305
cleanParameter,
13121306
focusOrLoadTabInWindow,
13131307
getEffectiveTabUrl,
13141308
getTargetDisplayWorkArea,
1309+
requestAllSpaces,
13151310
};

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Spaces",
33
"description": "Intuitive tab management",
4-
"version": "1.1.6.1",
4+
"version": "1.1.6.2",
55
"permissions": [
66
"contextMenus",
77
"favicon",

tests/requestAllSpaces.test.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { jest, describe, test, expect, beforeEach, afterEach } from '@jest/globals';
2+
import { requestAllSpaces } from '../js/background/background.js';
3+
import { spacesService } from '../js/background/spacesService.js';
4+
5+
describe('requestAllSpaces', () => {
6+
let getAllSessionsSpy;
7+
8+
beforeEach(() => {
9+
// Spy on the method and provide a mock implementation for each test
10+
getAllSessionsSpy = jest.spyOn(spacesService, 'getAllSessions');
11+
});
12+
13+
afterEach(() => {
14+
// Restore the original implementation after each test
15+
getAllSessionsSpy.mockRestore();
16+
});
17+
18+
test('should return sorted spaces with open windows first, then by last access time', async () => {
19+
const mockSessions = [
20+
{ id: 1, name: 'Saved Space 1', windowId: null, tabs: [{ url: 'http://a.com' }], lastAccess: new Date('2023-01-01T12:00:00Z') },
21+
{ id: 2, name: 'Open Window 1', windowId: 101, tabs: [{ url: 'http://b.com' }], lastAccess: new Date('2023-01-02T12:00:00Z') },
22+
{ id: 3, name: 'Saved Space 2', windowId: null, tabs: [{ url: 'http://c.com' }], lastAccess: new Date('2023-01-03T12:00:00Z') },
23+
{ id: 4, name: 'Open Window 2', windowId: 102, tabs: [{ url: 'http://d.com' }], lastAccess: new Date('2023-01-01T10:00:00Z') },
24+
{ id: 5, name: 'Empty Space', windowId: null, tabs: [], lastAccess: new Date('2023-01-05T12:00:00Z') }, // Should be filtered out
25+
];
26+
27+
getAllSessionsSpy.mockResolvedValue(mockSessions);
28+
29+
const spaces = await requestAllSpaces();
30+
31+
// Verify that getAllSessions was called
32+
expect(getAllSessionsSpy).toHaveBeenCalledTimes(1);
33+
34+
// Check the length of the returned spaces (should exclude the empty one)
35+
expect(spaces.length).toBe(4);
36+
37+
// Check the sorting order
38+
// 1. Open Window 1 (id: 2) - open
39+
// 2. Open Window 2 (id: 4) - open
40+
// 3. Saved Space 2 (id: 3) - most recent lastAccess
41+
// 4. Saved Space 1 (id: 1) - older lastAccess
42+
expect(spaces[0].id).toBe(2); // Open Window 1
43+
expect(spaces[1].id).toBe(4); // Open Window 2
44+
expect(spaces[2].id).toBe(3); // Saved Space 2
45+
expect(spaces[3].id).toBe(1); // Saved Space 1
46+
47+
// Check that the mapping from session to space is correct
48+
expect(spaces[0]).toEqual(expect.objectContaining({ sessionId: 2, name: 'Open Window 1' }));
49+
});
50+
51+
test('should return an empty array when no sessions are available', async () => {
52+
getAllSessionsSpy.mockResolvedValue([]);
53+
54+
const spaces = await requestAllSpaces();
55+
56+
expect(getAllSessionsSpy).toHaveBeenCalledTimes(1);
57+
expect(spaces).toEqual([]);
58+
});
59+
60+
test('should filter out sessions that have no tabs', async () => {
61+
const mockSessions = [
62+
{ id: 1, name: 'Valid Space', windowId: null, tabs: [{ url: 'http://a.com' }], lastAccess: new Date() },
63+
{ id: 2, name: 'Empty Space', windowId: 101, tabs: [], lastAccess: new Date() },
64+
{ id: 3, name: 'Null Tabs Space', windowId: null, tabs: null, lastAccess: new Date() },
65+
];
66+
67+
getAllSessionsSpy.mockResolvedValue(mockSessions);
68+
69+
const spaces = await requestAllSpaces();
70+
71+
expect(spaces.length).toBe(1);
72+
expect(spaces[0].id).toBe(1);
73+
});
74+
75+
test('should handle sessions with only open windows', async () => {
76+
const mockSessions = [
77+
{ id: 1, name: 'Open Window 1', windowId: 101, tabs: [{ url: 'http://a.com' }], lastAccess: new Date('2023-01-01T12:00:00Z') },
78+
{ id: 2, name: 'Open Window 2', windowId: 102, tabs: [{ url: 'http://b.com' }], lastAccess: new Date('2023-01-02T12:00:00Z') },
79+
];
80+
81+
getAllSessionsSpy.mockResolvedValue(mockSessions);
82+
83+
const spaces = await requestAllSpaces();
84+
85+
expect(spaces.length).toBe(2);
86+
// The order between two open windows doesn't have a secondary sort key in the original function,
87+
// so we just check that both are present.
88+
expect(spaces.map(s => s.id)).toContain(1);
89+
expect(spaces.map(s => s.id)).toContain(2);
90+
});
91+
92+
test('should correctly sort saved spaces by lastAccess date', async () => {
93+
const mockSessions = [
94+
{ id: 1, name: 'Oldest', windowId: null, tabs: [{ url: 'http://a.com' }], lastAccess: new Date('2023-01-01T12:00:00Z') },
95+
{ id: 2, name: 'Newest', windowId: null, tabs: [{ url: 'http://b.com' }], lastAccess: new Date('2023-01-03T12:00:00Z') },
96+
{ id: 3, name: 'Middle', windowId: null, tabs: [{ url: 'http://c.com' }], lastAccess: new Date('2023-01-02T12:00:00Z') },
97+
];
98+
99+
getAllSessionsSpy.mockResolvedValue(mockSessions);
100+
101+
const spaces = await requestAllSpaces();
102+
103+
expect(spaces.length).toBe(3);
104+
expect(spaces[0].id).toBe(2); // Newest
105+
expect(spaces[1].id).toBe(3); // Middle
106+
expect(spaces[2].id).toBe(1); // Oldest
107+
});
108+
});

0 commit comments

Comments
 (0)