Skip to content

Commit da4d467

Browse files
committed
Add comprehensive UX tests and fix test infrastructure
Added unit tests for UX components: - ASCII header and shimmer effects (40+ tests) - Progress indicators and spinners (50+ tests) - Messaging system (80+ tests) - Whoami command (8 tests) Fixed test infrastructure: - Re-enabled test suite in vitest.config.mts - Corrected import paths in test/utils.mts - Fixed esbuild config to execute build when run directly - Fixed local socket package paths in esbuild config (3 levels up) - Removed unused --src-only flag from package.json - Added yoga-sync.mjs to external/ for build dependency Tests validate animations are disabled in CI/VITEST modes and ensure no regression in CLI UX components.
1 parent f71de62 commit da4d467

File tree

9 files changed

+1417
-10
lines changed

9 files changed

+1417
-10
lines changed

packages/cli/.config/esbuild.cli.build.mjs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* esbuild is much faster than Rollup and doesn't have template literal corruption issues.
55
*/
66

7+
import { build } from 'esbuild'
78
import { execSync } from 'node:child_process'
89
import { randomUUID } from 'node:crypto'
910
import { existsSync, readFileSync } from 'node:fs'
@@ -46,17 +47,21 @@ const versionHash = `${packageJson.version}:${gitHash}:${randUuidSegment}${
4647

4748
// Get local Socket package paths.
4849
const socketPackages = {
49-
'@socketsecurity/lib': path.join(rootPath, '..', 'socket-lib'),
50+
'@socketsecurity/lib': path.join(rootPath, '..', '..', '..', 'socket-lib'),
5051
'@socketsecurity/registry': path.join(
5152
rootPath,
5253
'..',
54+
'..',
55+
'..',
5356
'socket-registry',
5457
'registry',
5558
),
56-
'@socketsecurity/sdk': path.join(rootPath, '..', 'socket-sdk-js'),
59+
'@socketsecurity/sdk': path.join(rootPath, '..', '..', '..', 'socket-sdk-js'),
5760
'@socketregistry/packageurl-js': path.join(
5861
rootPath,
5962
'..',
63+
'..',
64+
'..',
6065
'socket-packageurl-js',
6166
),
6267
}
@@ -101,7 +106,7 @@ function resolvePackageSubpath(packagePath, subpath) {
101106
return null
102107
}
103108

104-
export default {
109+
const config = {
105110
entryPoints: [path.join(rootPath, 'src/cli-dispatch.mts')],
106111
bundle: true,
107112
outfile: path.join(rootPath, 'dist/cli.js'),
@@ -208,7 +213,7 @@ export default {
208213
name: 'resolve-socket-lib-internals',
209214
setup(build) {
210215
// Resolve relative imports from socket-lib dist files.
211-
const socketLibPath = path.join(rootPath, '..', 'socket-lib')
216+
const socketLibPath = path.join(rootPath, '..', '..', '..', 'socket-lib')
212217
if (existsSync(socketLibPath)) {
213218
build.onResolve({ filter: /^\.\.\/constants\// }, args => {
214219
// Only handle imports from socket-lib's dist directory.
@@ -293,3 +298,13 @@ export default {
293298
},
294299
],
295300
}
301+
302+
// Run build if invoked directly.
303+
if (import.meta.url === `file://${process.argv[1]}`) {
304+
build(config).catch(error => {
305+
console.error('Build failed:', error)
306+
process.exitCode = 1
307+
})
308+
}
309+
310+
export default config

packages/cli/external/yoga-sync.mjs

Lines changed: 42 additions & 0 deletions
Large diffs are not rendered by default.

packages/cli/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"./data/command-api-requirements.json": "./data/command-api-requirements.json"
3232
},
3333
"scripts": {
34-
"build": "node --import=./scripts/load.mjs scripts/build.mjs --src-only",
34+
"build": "node --import=./scripts/load.mjs scripts/build.mjs",
3535
"build:sea:internal:bootstrap": "rollup -c .config/rollup.cli-sea.config.mjs",
3636
"build:js": "node scripts/extract-yoga-wasm.mjs && node .config/esbuild.cli.build.mjs",
3737
"build:watch": "node scripts/extract-yoga-wasm.mjs && node .config/esbuild.cli.build.mjs --watch",
@@ -53,7 +53,7 @@
5353
"lint-staged": "dotenvx -q run -f .env.local -- lint-staged",
5454
"precommit": "dotenvx -q run -f .env.local -- lint-staged",
5555
"prepare": "dotenvx -q run -f .env.local -- husky",
56-
"bs": "dotenvx -q run -f .env.local -- pnpm run build --src-only; pnpm exec socket --",
56+
"bs": "dotenvx -q run -f .env.local -- pnpm run build; pnpm exec socket --",
5757
"s": "dotenvx -q run -f .env.local -- pnpm exec socket --",
5858
"e2e-tests": "dotenvx -q run -f .env.test -- vitest run --config vitest.e2e.config.mts",
5959
"test": "run-s check test:*",
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* @fileoverview Tests for whoami command.
3+
* Validates authentication status display with various token sources.
4+
*/
5+
6+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
7+
8+
import { cmdit, spawnSocketCli } from '../../../test/utils.mts'
9+
import { FLAG_CONFIG, FLAG_HELP, FLAG_JSON } from '../../constants/cli.mts'
10+
import { getBinCliPath } from '../../constants/paths.mts'
11+
12+
const binCliPath = getBinCliPath()
13+
14+
describe('socket whoami', () => {
15+
let originalEnv: NodeJS.ProcessEnv
16+
17+
beforeEach(() => {
18+
// Save original environment.
19+
originalEnv = { ...process.env }
20+
})
21+
22+
afterEach(() => {
23+
// Restore original environment.
24+
process.env = originalEnv
25+
})
26+
27+
describe('help output', () => {
28+
cmdit(['whoami', FLAG_HELP], 'should show help', async cmd => {
29+
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd)
30+
31+
expect(code).toBe(0)
32+
expect(stderr).toContain('whoami')
33+
expect(stderr).toContain('Check if you are authenticated')
34+
expect(stderr).toContain('Examples')
35+
expect(stdout).toBe('')
36+
})
37+
})
38+
39+
describe('authenticated with API token', () => {
40+
// Test token - not a real API key.
41+
const testToken = 'sktsec_test123456789'
42+
43+
cmdit(
44+
['whoami', FLAG_CONFIG, `{"apiToken":"${testToken}"}`],
45+
'should show authenticated status',
46+
async cmd => {
47+
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd)
48+
49+
expect(code).toBe(0)
50+
expect(stderr).toContain('Authenticated with Socket')
51+
expect(stderr).toContain('Token: sktsec_')
52+
expect(stderr).toContain('Source:')
53+
expect(stdout).toBe('')
54+
},
55+
)
56+
57+
cmdit(
58+
['whoami', FLAG_JSON, FLAG_CONFIG, `{"apiToken":"${testToken}"}`],
59+
'should output JSON format',
60+
async cmd => {
61+
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd)
62+
63+
expect(code).toBe(0)
64+
expect(stdout).toContain('"authenticated":true')
65+
expect(stdout).toContain('"token":"sktsec_')
66+
expect(stdout).toContain('"location":')
67+
expect(stderr).toBe('')
68+
},
69+
)
70+
})
71+
72+
describe('not authenticated', () => {
73+
cmdit(
74+
['whoami', FLAG_CONFIG, '{}'],
75+
'should show not authenticated',
76+
async cmd => {
77+
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd, {
78+
env: {
79+
...process.env,
80+
// Explicitly unset any API token environment variables.
81+
SOCKET_SECURITY_API_KEY: '',
82+
SOCKET_CLI_API_TOKEN: '',
83+
},
84+
})
85+
86+
expect(code).toBe(0)
87+
expect(stderr).toContain('Not authenticated with Socket')
88+
expect(stderr).toContain('To authenticate')
89+
expect(stderr).toContain('socket login')
90+
expect(stdout).toBe('')
91+
},
92+
)
93+
94+
cmdit(
95+
['whoami', FLAG_JSON, FLAG_CONFIG, '{}'],
96+
'should output JSON format when not authenticated',
97+
async cmd => {
98+
const { code, stderr, stdout } = await spawnSocketCli(binCliPath, cmd, {
99+
env: {
100+
...process.env,
101+
SOCKET_SECURITY_API_KEY: '',
102+
SOCKET_CLI_API_TOKEN: '',
103+
},
104+
})
105+
106+
expect(code).toBe(0)
107+
expect(stdout).toContain('"authenticated":false')
108+
expect(stdout).toContain('"token":null')
109+
expect(stdout).toContain('"location":null')
110+
expect(stderr).toBe('')
111+
},
112+
)
113+
})
114+
115+
describe('token display', () => {
116+
cmdit(
117+
[
118+
'whoami',
119+
FLAG_CONFIG,
120+
'{"apiToken":"sktsec_abcdefghijklmnopqrstuvwxyz"}',
121+
],
122+
'should mask token after prefix',
123+
async cmd => {
124+
const { code, stderr } = await spawnSocketCli(binCliPath, cmd)
125+
126+
expect(code).toBe(0)
127+
expect(stderr).toContain('Token: sktsec_')
128+
expect(stderr).toContain('...')
129+
// Should not contain full token.
130+
expect(stderr).not.toContain('abcdefghijklmnopqrstuvwxyz')
131+
},
132+
)
133+
})
134+
135+
describe('token source detection', () => {
136+
cmdit(
137+
['whoami', FLAG_CONFIG, '{"apiToken":"sktsec_from_config"}'],
138+
'should detect config file source',
139+
async cmd => {
140+
const { code, stderr } = await spawnSocketCli(binCliPath, cmd)
141+
142+
expect(code).toBe(0)
143+
expect(stderr).toContain('Source:')
144+
expect(stderr).toContain('Config file')
145+
},
146+
)
147+
})
148+
149+
describe('error handling', () => {
150+
cmdit(
151+
['whoami', '--invalid-flag'],
152+
'should handle invalid flags',
153+
async cmd => {
154+
const { code, stderr } = await spawnSocketCli(binCliPath, cmd)
155+
156+
expect(code).not.toBe(0)
157+
expect(stderr).toContain('Unknown option')
158+
},
159+
)
160+
})
161+
})

0 commit comments

Comments
 (0)