Skip to content

Commit 390ca90

Browse files
committed
test: add comprehensive regression tests for dependency constraint preservation
- Add regression tests for zip/unzip cross-contamination bug - Test real-world scenario with mixed package updates - Cover edge cases like packages with shared substrings (react/react-dom) - Test packages with special characters in YAML format - Validates that word boundary fix prevents package name confusion - All 4 regression tests pass, ensuring the fix is working correctly These tests will catch any future regressions in constraint preservation logic.
1 parent a53810f commit 390ca90

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import type { PackageUpdate } from '../src/types'
2+
import { describe, expect, it } from 'bun:test'
3+
import { updateDependencyFile } from '../src/utils/dependency-file-parser'
4+
5+
describe('Regression Test - Dependency Constraint Preservation', () => {
6+
describe('zip/unzip cross-contamination bug', () => {
7+
it('should preserve correct constraints for zip and unzip packages', async () => {
8+
// This is the exact content from the stacks deps.yaml file
9+
const content = `# Please note, this file is auto-generated based on your ./config & local environment.
10+
# It's recommended to keep it in your project's root directory, and to commit it.
11+
#
12+
# The framework understands your project's dependencies, knows which ones are
13+
# already installed in your environment, and which aren't — prompting
14+
# to automatically install missing dependencies when needed.
15+
#
16+
# To learn more, please visit:
17+
# https://stacksjs.org/docs/dependency-management
18+
19+
dependencies:
20+
aws/cli: ^2.22.26
21+
bun: ^1.2.13
22+
gh: ^2.69.0
23+
zip: ^3.0
24+
unzip: ^6.0
25+
sqlite3: ^3.47.2
26+
node: ^22.12.0 # only temporarily needed until bun & vue-tsc issue is resolved
27+
# mailpit: ^1.21.8
28+
# redis: ^7.4.1
29+
# rust: ^1.74.1
30+
# openjdk.org: ^21.0.3.6`
31+
32+
// These are the actual updates that would be generated by dependency resolution
33+
const updates: PackageUpdate[] = [
34+
{
35+
name: 'zip',
36+
currentVersion: '^3.0',
37+
newVersion: '3.0.0',
38+
updateType: 'patch',
39+
dependencyType: 'dependencies',
40+
file: 'deps.yaml',
41+
metadata: undefined,
42+
},
43+
{
44+
name: 'unzip',
45+
currentVersion: '^6.0',
46+
newVersion: '6.0.0',
47+
updateType: 'patch',
48+
dependencyType: 'dependencies',
49+
file: 'deps.yaml',
50+
metadata: undefined,
51+
},
52+
]
53+
54+
const result = await updateDependencyFile('deps.yaml', content, updates)
55+
56+
// CRITICAL: These are the exact assertions that must pass to prevent regression
57+
expect(result).toContain('zip: ^3.0.0') // zip should be updated to ^3.0.0
58+
expect(result).toContain('unzip: ^6.0.0') // unzip should be updated to ^6.0.0 (NOT ^3.0.0!)
59+
60+
// Ensure no cross-contamination happened
61+
expect(result).not.toContain('unzip: ^3.0.0') // This was the bug - unzip getting zip's version
62+
expect(result).not.toMatch(/^\s*zip: \^6\.0\.0/m) // zip should not get unzip's version
63+
64+
// Verify other packages remain unchanged
65+
expect(result).toContain('aws/cli: ^2.22.26')
66+
expect(result).toContain('bun: ^1.2.13')
67+
expect(result).toContain('gh: ^2.69.0')
68+
expect(result).toContain('sqlite3: ^3.47.2')
69+
expect(result).toContain('node: ^22.12.0')
70+
})
71+
72+
it('should handle mixed updates in real-world scenario', async () => {
73+
const content = `dependencies:
74+
aws/cli: ^2.22.26
75+
bun: ^1.2.19
76+
gh: ^2.76.1
77+
zip: ^3.0
78+
unzip: ^6.0
79+
sqlite3: ^3.50.3
80+
node: ^22.17.1`
81+
82+
// Simulate what happens when multiple packages get updated at once
83+
const updates: PackageUpdate[] = [
84+
{
85+
name: 'aws/cli',
86+
currentVersion: '^2.22.26',
87+
newVersion: '2.27.60',
88+
updateType: 'minor',
89+
dependencyType: 'dependencies',
90+
file: 'deps.yaml',
91+
metadata: undefined,
92+
},
93+
{
94+
name: 'bun',
95+
currentVersion: '^1.2.19',
96+
newVersion: '1.2.19',
97+
updateType: 'patch',
98+
dependencyType: 'dependencies',
99+
file: 'deps.yaml',
100+
metadata: undefined,
101+
},
102+
{
103+
name: 'zip',
104+
currentVersion: '^3.0',
105+
newVersion: '3.0.0',
106+
updateType: 'patch',
107+
dependencyType: 'dependencies',
108+
file: 'deps.yaml',
109+
metadata: undefined,
110+
},
111+
{
112+
name: 'unzip',
113+
currentVersion: '^6.0',
114+
newVersion: '6.0.0',
115+
updateType: 'patch',
116+
dependencyType: 'dependencies',
117+
file: 'deps.yaml',
118+
metadata: undefined,
119+
},
120+
]
121+
122+
const result = await updateDependencyFile('deps.yaml', content, updates)
123+
124+
// This reproduces the exact scenario from the user's reported issue
125+
expect(result).toContain('aws/cli: ^2.27.60')
126+
expect(result).toContain('bun: ^1.2.19')
127+
expect(result).toContain('zip: ^3.0.0')
128+
expect(result).toContain('unzip: ^6.0.0') // MUST be ^6.0.0, not ^3.0.0!
129+
130+
// Log the result for debugging if the test fails
131+
if (result.includes('unzip: ^3.0.0')) {
132+
console.log('REGRESSION: unzip got wrong version!')
133+
console.log('Full result:')
134+
console.log(result)
135+
}
136+
})
137+
})
138+
139+
describe('similar package name edge cases', () => {
140+
it('should handle packages that are substrings of each other', async () => {
141+
const content = `dependencies:
142+
react: ^18.0.0
143+
react-dom: ^18.0.0
144+
react-router: ^6.0.0
145+
react-router-dom: ^6.0.0`
146+
147+
const updates: PackageUpdate[] = [
148+
{
149+
name: 'react',
150+
currentVersion: '^18.0.0',
151+
newVersion: '18.2.0',
152+
updateType: 'minor',
153+
dependencyType: 'dependencies',
154+
file: 'deps.yaml',
155+
metadata: undefined,
156+
},
157+
]
158+
159+
const result = await updateDependencyFile('deps.yaml', content, updates)
160+
161+
expect(result).toContain('react: ^18.2.0')
162+
expect(result).toContain('react-dom: ^18.0.0')
163+
expect(result).toContain('react-router: ^6.0.0')
164+
expect(result).toContain('react-router-dom: ^6.0.0')
165+
})
166+
167+
it('should handle packages with special characters in YAML format', async () => {
168+
const content = `dependencies:
169+
"@types/node": ^20.0.0
170+
"@types/node-fetch": ^2.0.0
171+
node: ^20.0.0`
172+
173+
const updates: PackageUpdate[] = [
174+
{
175+
name: 'node',
176+
currentVersion: '^20.0.0',
177+
newVersion: '20.5.0',
178+
updateType: 'minor',
179+
dependencyType: 'dependencies',
180+
file: 'deps.yaml',
181+
metadata: undefined,
182+
},
183+
]
184+
185+
const result = await updateDependencyFile('deps.yaml', content, updates)
186+
187+
// Should only update unquoted 'node', not '@types/node' or '@types/node-fetch'
188+
expect(result).toContain('node: ^20.5.0')
189+
expect(result).toContain('"@types/node": ^20.0.0')
190+
expect(result).toContain('"@types/node-fetch": ^2.0.0')
191+
})
192+
})
193+
})

0 commit comments

Comments
 (0)