Skip to content

Commit 128c52f

Browse files
committed
Add comprehensive tests for DisplayManager functionality
1 parent a049efe commit 128c52f

1 file changed

Lines changed: 251 additions & 0 deletions

File tree

test/displayManager.js

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import { vi, describe, it, beforeEach, expect } from 'vitest'
2+
import 'chai/register-should'
3+
import { screen } from 'electron'
4+
import DisplayManager from '../app/utils/displayManager.js'
5+
6+
vi.mock('electron', () => {
7+
const mockScreen = {
8+
getAllDisplays: vi.fn(() => [
9+
{ id: 0, bounds: { x: 0, y: 0, width: 1920, height: 1080 } },
10+
{ id: 1, bounds: { x: 1920, y: 0, width: 1440, height: 900 } }
11+
]),
12+
getPrimaryDisplay: vi.fn(() => ({ id: 0, bounds: { x: 0, y: 0, width: 1920, height: 1080 } })),
13+
getDisplayNearestPoint: vi.fn(() => ({ id: 0, bounds: { x: 0, y: 0, width: 1920, height: 1080 } })),
14+
getCursorScreenPoint: vi.fn(() => ({ x: 960, y: 540 }))
15+
}
16+
return { screen: mockScreen }
17+
})
18+
19+
describe('DisplayManager', function () {
20+
let displayManager
21+
let mockSettings
22+
let mockLog
23+
24+
beforeEach(function () {
25+
vi.clearAllMocks()
26+
mockSettings = {
27+
get: vi.fn()
28+
}
29+
mockLog = {
30+
warn: vi.fn()
31+
}
32+
})
33+
34+
describe('Mathematical Calculations', function () {
35+
beforeEach(function () {
36+
mockSettings.get.mockImplementation((key) => {
37+
if (key === 'allScreens') return true
38+
return null
39+
})
40+
displayManager = new DisplayManager(mockSettings, mockLog)
41+
})
42+
43+
it('centers window horizontally correctly', function () {
44+
const result = displayManager.getDisplayX(0, 800, false)
45+
result.should.equal(560)
46+
})
47+
48+
it('centers window vertically correctly', function () {
49+
const result = displayManager.getDisplayY(0, 600, false)
50+
result.should.equal(240)
51+
})
52+
53+
it('returns display origin for fullscreen X', function () {
54+
const result = displayManager.getDisplayX(1, 800, true)
55+
result.should.equal(1920)
56+
})
57+
58+
it('returns display origin for fullscreen Y', function () {
59+
const result = displayManager.getDisplayY(1, 600, true)
60+
result.should.equal(0)
61+
})
62+
63+
it('handles small windows correctly', function () {
64+
const result = displayManager.getDisplayX(0, 100, false)
65+
result.should.equal(910)
66+
})
67+
68+
it('handles large windows correctly', function () {
69+
const result = displayManager.getDisplayX(0, 2000, false)
70+
result.should.equal(-40)
71+
})
72+
73+
it('returns floored display width', function () {
74+
const result = displayManager.getDisplayWidth(0)
75+
result.should.equal(1920)
76+
})
77+
78+
it('returns floored display height', function () {
79+
const result = displayManager.getDisplayHeight(0)
80+
result.should.equal(1080)
81+
})
82+
83+
it('handles secondary display positioning', function () {
84+
const x = displayManager.getDisplayX(1, 800, false)
85+
const y = displayManager.getDisplayY(1, 600, false)
86+
x.should.equal(2240)
87+
y.should.equal(150)
88+
})
89+
})
90+
91+
describe('Method Integration', function () {
92+
beforeEach(function () {
93+
mockSettings.get.mockImplementation((key) => {
94+
if (key === 'allScreens') return true
95+
return null
96+
})
97+
displayManager = new DisplayManager(mockSettings, mockLog)
98+
})
99+
100+
it('getWindowPosition returns consistent windowed positioning', function () {
101+
const position = displayManager.getWindowPosition(0, { width: 800, height: 600, fullscreen: false })
102+
position.should.have.property('x', 560)
103+
position.should.have.property('y', 240)
104+
position.should.have.property('width', 800)
105+
position.should.have.property('height', 600)
106+
})
107+
108+
it('getWindowPosition returns consistent fullscreen positioning', function () {
109+
const position = displayManager.getWindowPosition(0, { width: 800, height: 600, fullscreen: true })
110+
111+
position.should.have.property('x', 0)
112+
position.should.have.property('y', 0)
113+
position.should.have.property('width', 1920)
114+
position.should.have.property('height', 1080)
115+
})
116+
117+
it('uses default parameters correctly', function () {
118+
const position = displayManager.getWindowPosition()
119+
120+
position.should.have.property('x', 560)
121+
position.should.have.property('y', 240)
122+
position.should.have.property('width', 800)
123+
position.should.have.property('height', 600)
124+
})
125+
126+
it('individual methods match getWindowPosition results', function () {
127+
const width = 1000
128+
const height = 700
129+
const displayID = 0
130+
131+
const position = displayManager.getWindowPosition(displayID, { width, height, fullscreen: false })
132+
const x = displayManager.getDisplayX(displayID, width, false)
133+
const y = displayManager.getDisplayY(displayID, height, false)
134+
135+
position.x.should.equal(x)
136+
position.y.should.equal(y)
137+
position.width.should.equal(width)
138+
position.height.should.equal(height)
139+
})
140+
141+
it('all methods return valid numbers', function () {
142+
const x = displayManager.getDisplayX()
143+
const y = displayManager.getDisplayY()
144+
const width = displayManager.getDisplayWidth()
145+
const height = displayManager.getDisplayHeight()
146+
const position = displayManager.getWindowPosition()
147+
148+
x.should.be.a('number')
149+
y.should.be.a('number')
150+
width.should.be.a('number')
151+
height.should.be.a('number')
152+
position.x.should.be.a('number')
153+
position.y.should.be.a('number')
154+
position.width.should.be.a('number')
155+
position.height.should.be.a('number')
156+
157+
Number.isNaN(x).should.equal(false)
158+
Number.isNaN(y).should.equal(false)
159+
Number.isNaN(width).should.equal(false)
160+
Number.isNaN(height).should.equal(false)
161+
})
162+
})
163+
164+
describe('Settings Integration', function () {
165+
beforeEach(function () {
166+
displayManager = new DisplayManager(mockSettings, mockLog)
167+
})
168+
169+
it('uses cursor position when allScreens is true', function () {
170+
mockSettings.get.mockImplementation((key) => {
171+
if (key === 'allScreens') return true
172+
return null
173+
})
174+
displayManager.getTargetDisplay()
175+
expect(screen.getDisplayNearestPoint).toHaveBeenCalled()
176+
})
177+
178+
it('uses primary display when screen preference is "primary"', function () {
179+
mockSettings.get.mockImplementation((key) => {
180+
if (key === 'allScreens') return false
181+
if (key === 'screen') return 'primary'
182+
return null
183+
})
184+
displayManager.getTargetDisplay()
185+
expect(screen.getPrimaryDisplay).toHaveBeenCalled()
186+
})
187+
188+
it('uses cursor display when screen preference is "cursor"', function () {
189+
mockSettings.get.mockImplementation((key) => {
190+
if (key === 'allScreens') return false
191+
if (key === 'screen') return 'cursor'
192+
return null
193+
})
194+
displayManager.getTargetDisplay()
195+
expect(screen.getDisplayNearestPoint).toHaveBeenCalled()
196+
})
197+
198+
it('uses correct display with numeric screen setting', function () {
199+
mockSettings.get.mockImplementation((key) => {
200+
if (key === 'allScreens') return false
201+
if (key === 'screen') return '1'
202+
return null
203+
})
204+
const target = displayManager.getTargetDisplay()
205+
expect(screen.getAllDisplays).toHaveBeenCalled()
206+
target.id.should.equal(1)
207+
})
208+
})
209+
210+
describe('Error Handling', function () {
211+
beforeEach(function () {
212+
mockSettings.get.mockImplementation((key) => {
213+
if (key === 'allScreens') return true
214+
return null
215+
})
216+
displayManager = new DisplayManager(mockSettings, mockLog)
217+
})
218+
219+
it('handles invalid displayID by falling back and logging a warning', () => {
220+
const target = displayManager.getTargetDisplay(5)
221+
expect(mockLog.warn).toHaveBeenCalledWith('Stretchly: invalid displayID 5, falling back to cursor display')
222+
expect(screen.getDisplayNearestPoint).toHaveBeenCalled()
223+
target.id.should.equal(0)
224+
})
225+
226+
it('handles boundary displayID values', function () {
227+
const target1 = displayManager.getTargetDisplay(0)
228+
const target2 = displayManager.getTargetDisplay(1)
229+
target1.id.should.equal(0)
230+
target2.id.should.equal(1)
231+
})
232+
233+
it('handles extreme window sizes', function () {
234+
const verySmall = displayManager.getDisplayX(0, 1, false)
235+
const veryLarge = displayManager.getDisplayX(0, 5000, false)
236+
237+
verySmall.should.be.a('number')
238+
veryLarge.should.be.a('number')
239+
Number.isNaN(verySmall).should.equal(false)
240+
Number.isNaN(veryLarge).should.equal(false)
241+
})
242+
243+
it('handles zero dimensions gracefully', function () {
244+
const zeroWidth = displayManager.getDisplayX(0, 0, false)
245+
const zeroHeight = displayManager.getDisplayY(0, 0, false)
246+
247+
zeroWidth.should.equal(960)
248+
zeroHeight.should.equal(540)
249+
})
250+
})
251+
})

0 commit comments

Comments
 (0)