1+ /* eslint-disable max-lines-per-function */
12import { describe , it , expect , vi , beforeEach , afterEach } from "vitest" ;
23import {
34 generateUpgradeMessage ,
45 fetchLatestVersion ,
56 getPackageInfo ,
67 checkForUpdates ,
78} 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" ) ;
817
918describe ( "versionCheck" , ( ) => {
1019 describe ( "generateUpgradeMessage" , ( ) => {
1120 it ( "returns null when versions are the same" , ( ) => {
1221 expect ( generateUpgradeMessage ( "1.0.0" , "1.0.0" , "test-package" ) ) . toBe (
13- null ,
22+ null
1423 ) ;
1524 } ) ;
1625
@@ -19,6 +28,12 @@ describe("versionCheck", () => {
1928 expect ( message ) . toContain ( "Update available: 1.0.0 → 1.1.0" ) ;
2029 expect ( message ) . toContain ( "Run 'npm install -g test-package' to update" ) ;
2130 } ) ;
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+ } ) ;
2237 } ) ;
2338
2439 describe ( "fetchLatestVersion" , ( ) => {
@@ -43,18 +58,30 @@ describe("versionCheck", () => {
4358 const version = await fetchLatestVersion ( "test-package" ) ;
4459 expect ( version ) . toBe ( "1.1.0" ) ;
4560 expect ( mockFetch ) . toHaveBeenCalledWith (
46- "https://registry.npmjs.org/test-package/latest" ,
61+ "https://registry.npmjs.org/test-package/latest"
4762 ) ;
4863 } ) ;
4964
50- it ( "returns null when fetch fails" , async ( ) => {
65+ it ( "throws error when fetch fails" , async ( ) => {
5166 mockFetch . mockResolvedValueOnce ( {
5267 ok : false ,
5368 statusText : "Not Found" ,
5469 } ) ;
5570
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+ ) ;
5885 } ) ;
5986 } ) ;
6087
@@ -71,28 +98,69 @@ describe("versionCheck", () => {
7198 describe ( "checkForUpdates" , ( ) => {
7299 const mockFetch = vi . fn ( ) ;
73100 const originalFetch = global . fetch ;
74- const originalEnv = process . env ;
101+ const mockSettingsDir = "/mock/settings/dir" ;
102+ const versionFilePath = path . join ( mockSettingsDir , "lastVersionCheck" ) ;
75103
76104 beforeEach ( ( ) => {
77105 global . fetch = mockFetch ;
78- process . env = { ...originalEnv } ;
106+ vi . mocked ( getSettingsDir ) . mockReturnValue ( mockSettingsDir ) ;
107+ vi . mocked ( fs . existsSync ) . mockReturnValue ( false ) ;
79108 } ) ;
80109
81110 afterEach ( ( ) => {
82111 global . fetch = originalFetch ;
83- process . env = originalEnv ;
84112 vi . clearAllMocks ( ) ;
85113 } ) ;
86114
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 ) ;
89117 mockFetch . mockResolvedValueOnce ( {
90118 ok : true ,
91- json : ( ) => Promise . resolve ( { version : "999 .0.0" } ) , // Much higher version
119+ json : ( ) => Promise . resolve ( { version : "2 .0.0" } ) ,
92120 } ) ;
93121
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+
94140 const result = await checkForUpdates ( ) ;
95141 expect ( result ) . toContain ( "Update available" ) ;
96142 } ) ;
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+ } ) ;
97165 } ) ;
98166} ) ;
0 commit comments