Skip to content

Commit a281077

Browse files
committed
test(integration): add comprehensive integration test suite
Add 3 integration test files covering end-to-end workflows: 1. full-package-scan.test.mts - Complete package scan workflow - Multi-package comparison - Organization and repository management 2. sbom-workflow.test.mts - SBOM upload and retrieval - SBOM comparison between versions - SBOM generation from package.json 3. batch-operations.test.mts - Batch package scanning - Concurrent API requests with throttling - Bulk dependency analysis - Paginated results handling Integration tests verify complete workflows and real-world SDK usage patterns, complementing existing unit tests.
1 parent 63bca7d commit a281077

File tree

3 files changed

+647
-0
lines changed

3 files changed

+647
-0
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/**
2+
* @fileoverview Integration test for batch operations and concurrent requests.
3+
* Tests bulk scanning, parallel API calls, and rate limiting.
4+
*/
5+
6+
import { describe, expect, it } from 'vitest'
7+
import nock from 'nock'
8+
9+
import {
10+
createTestClient,
11+
setupTestEnvironment,
12+
} from '../utils/environment.mts'
13+
14+
describe('Integration - Batch Operations', () => {
15+
setupTestEnvironment()
16+
17+
it('should handle batch package scanning', async () => {
18+
const client = createTestClient('test-api-token', { retries: 0 })
19+
20+
const packages = [
21+
{ name: 'react', version: '18.2.0' },
22+
{ name: 'vue', version: '3.3.4' },
23+
{ name: 'angular', version: '16.2.0' },
24+
{ name: 'svelte', version: '4.2.0' },
25+
]
26+
27+
// Mock batch scan endpoint
28+
nock('https://api.socket.dev')
29+
.post('/v0/npm/batch-scan', body => {
30+
return body.packages && body.packages.length === 4
31+
})
32+
.reply(200, {
33+
status: 'success',
34+
data: {
35+
batch_id: 'batch-456',
36+
total: 4,
37+
queued: 4,
38+
status: 'processing',
39+
},
40+
})
41+
42+
// Mock batch status check
43+
nock('https://api.socket.dev')
44+
.get('/v0/npm/batch-scan/batch-456/status')
45+
.reply(200, {
46+
status: 'success',
47+
data: {
48+
batch_id: 'batch-456',
49+
total: 4,
50+
completed: 4,
51+
failed: 0,
52+
status: 'completed',
53+
results: packages.map((pkg, index) => ({
54+
package: pkg.name,
55+
version: pkg.version,
56+
score: 80 + index * 2,
57+
issues: index,
58+
})),
59+
},
60+
})
61+
62+
const batchResult = await client.batchScanPackages(packages)
63+
expect(batchResult.batch_id).toBe('batch-456')
64+
expect(batchResult.total).toBe(4)
65+
66+
const status = await client.getBatchScanStatus('batch-456')
67+
expect(status.completed).toBe(4)
68+
expect(status.results).toHaveLength(4)
69+
expect(status.status).toBe('completed')
70+
})
71+
72+
it('should handle concurrent API requests with proper throttling', async () => {
73+
const client = createTestClient('test-api-token', { retries: 0 })
74+
75+
const packageNames = ['lodash', 'axios', 'express', 'react', 'vue']
76+
77+
// Mock multiple concurrent requests
78+
for (const name of packageNames) {
79+
nock('https://api.socket.dev')
80+
.get(`/v0/npm/package/${name}/latest`)
81+
.reply(200, {
82+
status: 'success',
83+
data: {
84+
name,
85+
version: '1.0.0',
86+
score: 85,
87+
},
88+
})
89+
}
90+
91+
const startTime = Date.now()
92+
93+
// Execute concurrent requests
94+
const results = await Promise.all(
95+
packageNames.map(name => client.getPackageLatest(name)),
96+
)
97+
98+
const duration = Date.now() - startTime
99+
100+
expect(results).toHaveLength(5)
101+
expect(results.every(r => r.score === 85)).toBe(true)
102+
103+
// With proper concurrency, should complete quickly (< 1 second for mock requests)
104+
expect(duration).toBeLessThan(1000)
105+
})
106+
107+
it('should handle bulk dependency analysis', async () => {
108+
const client = createTestClient('test-api-token', { retries: 0 })
109+
110+
const lockfileContent = `
111+
{
112+
"name": "test-project",
113+
"lockfileVersion": 3,
114+
"packages": {
115+
"node_modules/express": {
116+
"version": "4.18.2"
117+
},
118+
"node_modules/lodash": {
119+
"version": "4.17.21"
120+
},
121+
"node_modules/axios": {
122+
"version": "1.6.0"
123+
}
124+
}
125+
}
126+
`
127+
128+
// Mock bulk analysis
129+
nock('https://api.socket.dev')
130+
.post('/v0/dependencies/analyze', body => {
131+
return body.includes('lockfileVersion')
132+
})
133+
.reply(200, {
134+
status: 'success',
135+
data: {
136+
analysis_id: 'analysis-789',
137+
total_packages: 3,
138+
direct_dependencies: 3,
139+
transitive_dependencies: 0,
140+
vulnerabilities: {
141+
critical: 0,
142+
high: 0,
143+
medium: 1,
144+
low: 2,
145+
},
146+
supply_chain_risk: 'low',
147+
packages: [
148+
{
149+
name: 'express',
150+
version: '4.18.2',
151+
score: 90,
152+
issues: [],
153+
},
154+
{
155+
name: 'lodash',
156+
version: '4.17.21',
157+
score: 85,
158+
issues: [
159+
{
160+
type: 'deprecated',
161+
severity: 'medium',
162+
},
163+
],
164+
},
165+
{
166+
name: 'axios',
167+
version: '1.6.0',
168+
score: 92,
169+
issues: [],
170+
},
171+
],
172+
},
173+
})
174+
175+
const analysis = await client.analyzeDependencies(lockfileContent)
176+
177+
expect(analysis.analysis_id).toBe('analysis-789')
178+
expect(analysis.total_packages).toBe(3)
179+
expect(analysis.packages).toHaveLength(3)
180+
expect(analysis.vulnerabilities.medium).toBe(1)
181+
expect(analysis.supply_chain_risk).toBe('low')
182+
183+
const lodashPackage = analysis.packages.find(p => p.name === 'lodash')
184+
expect(lodashPackage?.issues).toHaveLength(1)
185+
expect(lodashPackage?.issues[0].type).toBe('deprecated')
186+
})
187+
188+
it('should handle paginated bulk results', async () => {
189+
const client = createTestClient('test-api-token', { retries: 0 })
190+
191+
// Mock first page
192+
nock('https://api.socket.dev')
193+
.get('/v0/repositories')
194+
.query({ limit: 10, offset: 0 })
195+
.reply(200, {
196+
status: 'success',
197+
data: {
198+
repositories: Array.from({ length: 10 }, (_, i) => ({
199+
id: `repo-${i}`,
200+
name: `repo-${i}`,
201+
})),
202+
total: 25,
203+
limit: 10,
204+
offset: 0,
205+
has_more: true,
206+
},
207+
})
208+
209+
// Mock second page
210+
nock('https://api.socket.dev')
211+
.get('/v0/repositories')
212+
.query({ limit: 10, offset: 10 })
213+
.reply(200, {
214+
status: 'success',
215+
data: {
216+
repositories: Array.from({ length: 10 }, (_, i) => ({
217+
id: `repo-${i + 10}`,
218+
name: `repo-${i + 10}`,
219+
})),
220+
total: 25,
221+
limit: 10,
222+
offset: 10,
223+
has_more: true,
224+
},
225+
})
226+
227+
// Mock third page
228+
nock('https://api.socket.dev')
229+
.get('/v0/repositories')
230+
.query({ limit: 10, offset: 20 })
231+
.reply(200, {
232+
status: 'success',
233+
data: {
234+
repositories: Array.from({ length: 5 }, (_, i) => ({
235+
id: `repo-${i + 20}`,
236+
name: `repo-${i + 20}`,
237+
})),
238+
total: 25,
239+
limit: 10,
240+
offset: 20,
241+
has_more: false,
242+
},
243+
})
244+
245+
// Fetch all pages
246+
const allRepos: Array<{ id: string; name: string }> = []
247+
let offset = 0
248+
let hasMore = true
249+
250+
while (hasMore) {
251+
const page = await client.getRepositories({ limit: 10, offset })
252+
allRepos.push(...page.repositories)
253+
hasMore = page.has_more
254+
offset += page.repositories.length
255+
}
256+
257+
expect(allRepos).toHaveLength(25)
258+
expect(allRepos[0].id).toBe('repo-0')
259+
expect(allRepos[24].id).toBe('repo-24')
260+
})
261+
})

0 commit comments

Comments
 (0)