Skip to content

Commit 6d1af69

Browse files
committed
test(desktop): run the desktop unit suite on Windows
Exclude the suites for subsystems Windows builds do not ship, keep POSIX mode-bit assertions to POSIX, and build expected paths with path.join.
1 parent 10146e4 commit 6d1af69

10 files changed

Lines changed: 69 additions & 45 deletions

File tree

‎apps/desktop/src/main/browser-agent/file-transfer.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { existsSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
22
import { open, rename, rm, truncate } from 'node:fs/promises'
33
import { tmpdir } from 'node:os'
4-
import { join } from 'node:path'
4+
import { basename, join } from 'node:path'
55
import { BROWSER_FILE_TRANSFER_MAX_BYTES } from '@sim/browser-protocol'
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
77

@@ -59,7 +59,7 @@ describe('stageUploadFiles', () => {
5959
body: JSON.stringify({ toolCallId: 'call-1', index: 0 }),
6060
signal,
6161
})
62-
expect(staged.map((path) => path.split('/').pop())).toEqual(['Q3 plan.pdf', 'granted.txt'])
62+
expect(staged.map((path) => basename(path))).toEqual(['Q3 plan.pdf', 'granted.txt'])
6363
expect(readFileSync(staged[0], 'utf8')).toBe('workspace bytes')
6464
expect(readFileSync(staged[1], 'utf8')).toBe('local bytes')
6565
expect(staged.every((path) => path.startsWith(join(temp, 'sim-browser-uploads')))).toBe(true)
@@ -83,7 +83,7 @@ describe('stageUploadFiles', () => {
8383
})
8484

8585
expect(staged.startsWith(join(temp, 'sim-browser-uploads'))).toBe(true)
86-
expect(staged.endsWith('/evil')).toBe(true)
86+
expect(basename(staged)).toBe('evil')
8787
})
8888

8989
it('refuses a workspace file over the transfer ceiling', async () => {

‎apps/desktop/src/main/browser-agent/keyboard.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ describe('dispatchKeyCombo', () => {
189189
.mockRejectedValueOnce(new Error('key-up response lost'))
190190
.mockRejectedValueOnce(new Error('cleanup unavailable'))
191191

192-
const dispatch = dispatchKeyCombo(contents, parseKeyCombo('Cmd+A'))
192+
const dispatch = dispatchKeyCombo(contents, parseKeyCombo('Cmd+A', 'darwin'))
193193

194194
await expect(dispatch).rejects.toEqual(
195195
expect.objectContaining({

‎apps/desktop/src/main/browser-credentials/vault.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('CredentialVault', () => {
8686
expect(JSON.parse(onDisk)).toMatchObject({ version: 1, ciphertext: expect.any(String) })
8787
})
8888

89-
it('writes the vault file owner-only', async () => {
89+
it.skipIf(process.platform === 'win32')('writes the vault file owner-only', async () => {
9090
const vault = new CredentialVault(vaultPath, encryption())
9191
await vault.importCredentials(CANDIDATES, 'keep-existing')
9292

‎apps/desktop/src/main/desktop-chat-session-store.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ describe('DesktopChatSessionStore', () => {
115115
expect(onDisk).not.toContain('report.csv')
116116
expect(JSON.parse(onDisk)).toEqual({ v: 1, ciphertext: expect.any(String) })
117117
expect(provider.encryptString).toHaveBeenCalledOnce()
118-
expect(statSync(filePath).mode & 0o077).toBe(0)
118+
// POSIX mode bits; on Windows the per-user %APPDATA% ACL keeps the file private.
119+
if (process.platform !== 'win32') expect(statSync(filePath).mode & 0o077).toBe(0)
119120
})
120121

121122
it('does not replace the durable store with an oversized encrypted envelope', () => {

‎apps/desktop/src/main/desktop-executor/runner.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ describe('local file calls', () => {
191191
})
192192
})
193193

194-
describe('background imports', () => {
194+
describe.skipIf(process.platform === 'win32')('background imports', () => {
195195
const roots: string[] = []
196196

197197
afterEach(async () => {

‎apps/desktop/src/main/desktop-executor/service.test.ts‎

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -337,20 +337,25 @@ describe('desktop executor registration', () => {
337337
}
338338
})
339339

340-
it('registers with no install id it could not save', async () => {
341-
const userData = await mkdtemp(join(tmpdir(), 'sim-executor-service-'))
342-
await chmod(userData, 0o500)
343-
try {
344-
const { sim, desktopExecutor } = await service(1, userData)
345-
346-
desktopExecutor.start()
347-
await sleep(200)
348-
349-
expect(sim.requests.filter((request) => request.includes('/api/desktop/devices'))).toEqual([])
350-
} finally {
351-
await chmod(userData, 0o700)
340+
it.skipIf(process.platform === 'win32')(
341+
'registers with no install id it could not save',
342+
async () => {
343+
const userData = await mkdtemp(join(tmpdir(), 'sim-executor-service-'))
344+
await chmod(userData, 0o500)
345+
try {
346+
const { sim, desktopExecutor } = await service(1, userData)
347+
348+
desktopExecutor.start()
349+
await sleep(200)
350+
351+
expect(sim.requests.filter((request) => request.includes('/api/desktop/devices'))).toEqual(
352+
[]
353+
)
354+
} finally {
355+
await chmod(userData, 0o700)
356+
}
352357
}
353-
})
358+
)
354359

355360
it('keeps its install id through a read failure instead of minting a new one', async () => {
356361
const userData = await mkdtemp(join(tmpdir(), 'sim-executor-service-'))

‎apps/desktop/src/main/downloads.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe('uniqueDownloadPath', () => {
4545
])
4646

4747
expect(new Set([first, second])).toEqual(
48-
new Set(['/Downloads/report.csv', '/Downloads/report (copy-1).csv'])
48+
new Set([join('/Downloads', 'report.csv'), join('/Downloads', 'report (copy-1).csv')])
4949
)
5050
})
5151
})

‎apps/desktop/src/main/ipc.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,9 @@ describe('registerIpcHandlers', () => {
418418

419419
expect(await handler?.(evilEvent)).toBe(false)
420420
expect(await handler?.(appEvent)).toBe(false)
421-
expect(await handler?.(activeAppEvent)).toBe(process.platform === 'darwin')
422-
expect(shell.openExternal).toHaveBeenCalledTimes(process.platform === 'darwin' ? 1 : 0)
421+
const hasPrivacySettings = process.platform === 'darwin' || process.platform === 'win32'
422+
expect(await handler?.(activeAppEvent)).toBe(hasPrivacySettings)
423+
expect(shell.openExternal).toHaveBeenCalledTimes(hasPrivacySettings ? 1 : 0)
423424
})
424425

425426
it('restricts the OAuth connect handoff to an activated app origin', async () => {

‎apps/desktop/src/main/observability.test.ts‎

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,37 @@ describe('scrubUrl', () => {
2626
})
2727

2828
describe('createEventLog', () => {
29-
it('creates its directory and log with private permissions', () => {
30-
const root = mkdtempSync(join(tmpdir(), 'sim-desktop-events-'))
31-
const dir = join(root, 'logs')
32-
const events = createEventLog(dir)
33-
events.record('app_launch')
29+
it.skipIf(process.platform === 'win32')(
30+
'creates its directory and log with private permissions',
31+
() => {
32+
const root = mkdtempSync(join(tmpdir(), 'sim-desktop-events-'))
33+
const dir = join(root, 'logs')
34+
const events = createEventLog(dir)
35+
events.record('app_launch')
3436

35-
expect(statSync(dir).mode & 0o777).toBe(0o700)
36-
expect(statSync(events.filePath).mode & 0o777).toBe(0o600)
37-
})
37+
expect(statSync(dir).mode & 0o777).toBe(0o700)
38+
expect(statSync(events.filePath).mode & 0o777).toBe(0o600)
39+
}
40+
)
3841

39-
it('reports permission failures without exposing local paths or OS errors', () => {
40-
const root = mkdtempSync(join(tmpdir(), 'sim-desktop-events-'))
41-
const overlongDir = join(root, 'x'.repeat(300))
42+
it.skipIf(process.platform === 'win32')(
43+
'reports permission failures without exposing local paths or OS errors',
44+
() => {
45+
const root = mkdtempSync(join(tmpdir(), 'sim-desktop-events-'))
46+
const overlongDir = join(root, 'x'.repeat(300))
4247

43-
const events = createEventLog(overlongDir)
44-
events.record('app_launch')
48+
const events = createEventLog(overlongDir)
49+
events.record('app_launch')
4550

46-
expect(mockLogger.warn.mock.calls).toEqual([
47-
['Could not apply private desktop event-log permissions', { target: 'directory' }],
48-
['Could not apply private desktop event-log permissions', { target: 'current-log' }],
49-
['Could not apply private desktop event-log permissions', { target: 'rotated-log' }],
50-
])
51-
expect(JSON.stringify(mockLogger.warn.mock.calls)).not.toContain(root)
52-
expect(JSON.stringify(mockLogger.warn.mock.calls)).not.toContain('ENAMETOOLONG')
53-
})
51+
expect(mockLogger.warn.mock.calls).toEqual([
52+
['Could not apply private desktop event-log permissions', { target: 'directory' }],
53+
['Could not apply private desktop event-log permissions', { target: 'current-log' }],
54+
['Could not apply private desktop event-log permissions', { target: 'rotated-log' }],
55+
])
56+
expect(JSON.stringify(mockLogger.warn.mock.calls)).not.toContain(root)
57+
expect(JSON.stringify(mockLogger.warn.mock.calls)).not.toContain('ENAMETOOLONG')
58+
}
59+
)
5460
})
5561

5662
describe('installMainProcessFailureObservers', () => {

‎apps/desktop/vitest.config.ts‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,18 @@ export default mergeConfig(
88
test: {
99
setupFiles: ['src/test/setup.ts'],
1010
include: ['src/**/*.test.ts'],
11-
exclude: ['**/e2e/**'],
11+
// These suites drive subsystems Windows builds do not ship (tmux, the macOS computer-use
12+
// helper, the POSIX native file module); see src/shared/platform-features.ts.
13+
exclude: [
14+
'**/e2e/**',
15+
...(process.platform === 'win32'
16+
? [
17+
'src/main/terminal/tmux.test.ts',
18+
'src/main/computer-use/native-client.test.ts',
19+
'src/main/local-files.test.ts',
20+
]
21+
: []),
22+
],
1223
pool: 'threads',
1324
testTimeout: 10000,
1425
},

0 commit comments

Comments
 (0)