1
+ /* eslint-disable max-lines-per-function */
1
2
import { describe , it , expect , vi , beforeEach , afterEach } from "vitest" ;
2
3
import {
3
4
generateUpgradeMessage ,
4
5
fetchLatestVersion ,
5
6
getPackageInfo ,
6
7
checkForUpdates ,
7
8
} from "./versionCheck.js" ;
9
+ import * as fs from "fs" ;
10
+ import * as fsPromises from "fs/promises" ;
11
+ import * as path from "path" ;
12
+ import { getSettingsDir } from "../settings/settings.js" ;
13
+
14
+ vi . mock ( "fs" ) ;
15
+ vi . mock ( "fs/promises" ) ;
16
+ vi . mock ( "../settings/settings.js" ) ;
8
17
9
18
describe ( "versionCheck" , ( ) => {
10
19
describe ( "generateUpgradeMessage" , ( ) => {
11
20
it ( "returns null when versions are the same" , ( ) => {
12
21
expect ( generateUpgradeMessage ( "1.0.0" , "1.0.0" , "test-package" ) ) . toBe (
13
- null ,
22
+ null
14
23
) ;
15
24
} ) ;
16
25
@@ -19,6 +28,12 @@ describe("versionCheck", () => {
19
28
expect ( message ) . toContain ( "Update available: 1.0.0 → 1.1.0" ) ;
20
29
expect ( message ) . toContain ( "Run 'npm install -g test-package' to update" ) ;
21
30
} ) ;
31
+
32
+ it ( "returns null when current version is higher" , ( ) => {
33
+ expect ( generateUpgradeMessage ( "2.0.0" , "1.0.0" , "test-package" ) ) . toBe (
34
+ null
35
+ ) ;
36
+ } ) ;
22
37
} ) ;
23
38
24
39
describe ( "fetchLatestVersion" , ( ) => {
@@ -43,18 +58,30 @@ describe("versionCheck", () => {
43
58
const version = await fetchLatestVersion ( "test-package" ) ;
44
59
expect ( version ) . toBe ( "1.1.0" ) ;
45
60
expect ( mockFetch ) . toHaveBeenCalledWith (
46
- "https://registry.npmjs.org/test-package/latest" ,
61
+ "https://registry.npmjs.org/test-package/latest"
47
62
) ;
48
63
} ) ;
49
64
50
- it ( "returns null when fetch fails" , async ( ) => {
65
+ it ( "throws error when fetch fails" , async ( ) => {
51
66
mockFetch . mockResolvedValueOnce ( {
52
67
ok : false ,
53
68
statusText : "Not Found" ,
54
69
} ) ;
55
70
56
- const version = await fetchLatestVersion ( "test-package" ) ;
57
- expect ( version ) . toBe ( null ) ;
71
+ await expect ( fetchLatestVersion ( "test-package" ) ) . rejects . toThrow (
72
+ "Failed to fetch version info: Not Found"
73
+ ) ;
74
+ } ) ;
75
+
76
+ it ( "throws error when version is missing from response" , async ( ) => {
77
+ mockFetch . mockResolvedValueOnce ( {
78
+ ok : true ,
79
+ json : ( ) => Promise . resolve ( { } ) ,
80
+ } ) ;
81
+
82
+ await expect ( fetchLatestVersion ( "test-package" ) ) . rejects . toThrow (
83
+ "Version info not found in response"
84
+ ) ;
58
85
} ) ;
59
86
} ) ;
60
87
@@ -71,28 +98,69 @@ describe("versionCheck", () => {
71
98
describe ( "checkForUpdates" , ( ) => {
72
99
const mockFetch = vi . fn ( ) ;
73
100
const originalFetch = global . fetch ;
74
- const originalEnv = process . env ;
101
+ const mockSettingsDir = "/mock/settings/dir" ;
102
+ const versionFilePath = path . join ( mockSettingsDir , "lastVersionCheck" ) ;
75
103
76
104
beforeEach ( ( ) => {
77
105
global . fetch = mockFetch ;
78
- process . env = { ...originalEnv } ;
106
+ vi . mocked ( getSettingsDir ) . mockReturnValue ( mockSettingsDir ) ;
107
+ vi . mocked ( fs . existsSync ) . mockReturnValue ( false ) ;
79
108
} ) ;
80
109
81
110
afterEach ( ( ) => {
82
111
global . fetch = originalFetch ;
83
- process . env = originalEnv ;
84
112
vi . clearAllMocks ( ) ;
85
113
} ) ;
86
114
87
- it ( "returns upgrade message when update available " , async ( ) => {
88
- process . env . npm_config_global = "true" ;
115
+ it ( "returns null and initiates background check when no cached version " , async ( ) => {
116
+ vi . mocked ( fs . existsSync ) . mockReturnValue ( false ) ;
89
117
mockFetch . mockResolvedValueOnce ( {
90
118
ok : true ,
91
- json : ( ) => Promise . resolve ( { version : "999 .0.0" } ) , // Much higher version
119
+ json : ( ) => Promise . resolve ( { version : "2 .0.0" } ) ,
92
120
} ) ;
93
121
122
+ const result = await checkForUpdates ( ) ;
123
+ expect ( result ) . toBe ( null ) ;
124
+
125
+ // Wait for setImmediate to complete
126
+ await new Promise ( ( resolve ) => setImmediate ( resolve ) ) ;
127
+
128
+ expect ( mockFetch ) . toHaveBeenCalled ( ) ;
129
+ expect ( fsPromises . writeFile ) . toHaveBeenCalledWith (
130
+ versionFilePath ,
131
+ "2.0.0" ,
132
+ "utf8"
133
+ ) ;
134
+ } ) ;
135
+
136
+ it ( "returns upgrade message when cached version is newer" , async ( ) => {
137
+ vi . mocked ( fs . existsSync ) . mockReturnValue ( true ) ;
138
+ vi . mocked ( fsPromises . readFile ) . mockResolvedValue ( "2.0.0" ) ;
139
+
94
140
const result = await checkForUpdates ( ) ;
95
141
expect ( result ) . toContain ( "Update available" ) ;
96
142
} ) ;
143
+
144
+ it ( "handles errors gracefully during version check" , async ( ) => {
145
+ vi . mocked ( fs . existsSync ) . mockReturnValue ( true ) ;
146
+ vi . mocked ( fsPromises . readFile ) . mockRejectedValue ( new Error ( "Test error" ) ) ;
147
+
148
+ const result = await checkForUpdates ( ) ;
149
+ expect ( result ) . toBe ( null ) ;
150
+ } ) ;
151
+
152
+ it ( "handles errors gracefully during background update" , async ( ) => {
153
+ vi . mocked ( fs . existsSync ) . mockReturnValue ( false ) ;
154
+ mockFetch . mockRejectedValue ( new Error ( "Network error" ) ) ;
155
+
156
+ const result = await checkForUpdates ( ) ;
157
+ expect ( result ) . toBe ( null ) ;
158
+
159
+ // Wait for setImmediate to complete
160
+ await new Promise ( ( resolve ) => setImmediate ( resolve ) ) ;
161
+
162
+ // Verify the error was handled
163
+ expect ( fsPromises . writeFile ) . not . toHaveBeenCalled ( ) ;
164
+ } ) ;
97
165
} ) ;
98
166
} ) ;
0 commit comments