1+ import * as action from '../commands/update/action.js' ;
2+ import * as constants from '../constants.js' ;
13import { type UpdateCheckResult , checkForUpdate , printUpdateNotification } from '../update-notifier.js' ;
2- import { rmSync } from 'fs' ;
3- import { mkdir , readFile , writeFile } from 'fs/promises' ;
4+ import { mkdtempSync , rmSync } from 'fs' ;
5+ import { chmod , mkdir , readFile , writeFile } from 'fs/promises' ;
6+ import { tmpdir } from 'os' ;
47import { join } from 'path' ;
58import { afterAll , afterEach , beforeEach , describe , expect , it , vi } from 'vitest' ;
69
7- const tmpDir = vi . hoisted ( ( ) => {
8- /* eslint-disable @typescript-eslint/no-require-imports */
9- const fs = require ( 'fs' ) ;
10- const os = require ( 'os' ) ;
11- const path = require ( 'path' ) ;
12- /* eslint-enable @typescript-eslint/no-require-imports */
13- return fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'update-notifier-test-' ) ) ;
14- } ) ;
15-
16- vi . mock ( '../../lib/schemas/io/global-config.js' , ( ) => ( {
17- GLOBAL_CONFIG_DIR : tmpDir ,
18- } ) ) ;
19-
20- vi . mock ( '../constants.js' , async importOriginal => {
21- const actual = await importOriginal < typeof import ( '../constants.js' ) > ( ) ;
22- return { ...actual , PACKAGE_VERSION : '1.0.0' } ;
23- } ) ;
24-
25- const { mockFetchLatestVersion } = vi . hoisted ( ( ) => ( {
26- mockFetchLatestVersion : vi . fn ( ) ,
27- } ) ) ;
28-
29- vi . mock ( '../commands/update/action.js' , async importOriginal => {
30- const actual = await importOriginal < typeof import ( '../commands/update/action.js' ) > ( ) ;
31- return { ...actual , fetchLatestVersion : mockFetchLatestVersion } ;
32- } ) ;
33-
34- const CACHE_DIR = tmpDir ;
10+ const tmpDir = mkdtempSync ( join ( tmpdir ( ) , 'update-notifier-test-' ) ) ;
3511const CACHE_FILE = join ( tmpDir , 'update-check.json' ) ;
3612
3713describe ( 'checkForUpdate' , ( ) => {
14+ let originalConfigDir : string | undefined ;
15+
3816 beforeEach ( ( ) => {
17+ originalConfigDir = process . env . AGENTCORE_CONFIG_DIR ;
18+ process . env . AGENTCORE_CONFIG_DIR = tmpDir ;
3919 vi . spyOn ( Date , 'now' ) . mockReturnValue ( 1708646400000 ) ;
40- try {
41- rmSync ( CACHE_DIR , { recursive : true } ) ;
42- } catch { }
20+ vi . spyOn ( constants , 'PACKAGE_VERSION' , 'get' ) . mockReturnValue ( '1.0.0' ) ;
21+ rmSync ( tmpDir , { recursive : true , force : true } ) ;
4322 } ) ;
4423
4524 afterEach ( ( ) => {
4625 vi . restoreAllMocks ( ) ;
47- mockFetchLatestVersion . mockReset ( ) ;
26+ if ( originalConfigDir === undefined ) {
27+ delete process . env . AGENTCORE_CONFIG_DIR ;
28+ } else {
29+ process . env . AGENTCORE_CONFIG_DIR = originalConfigDir ;
30+ }
4831 } ) ;
4932
5033 afterAll ( ( ) => {
51- rmSync ( tmpDir , { recursive : true } ) ;
34+ rmSync ( tmpDir , { recursive : true , force : true } ) ;
5235 } ) ;
5336
5437 it ( 'fetches from registry when no cache exists' , async ( ) => {
55- mockFetchLatestVersion . mockResolvedValue ( '2.0.0' ) ;
38+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '2.0.0' ) ;
5639
5740 const result = await checkForUpdate ( ) ;
5841
5942 expect ( result ) . toEqual ( { updateAvailable : true , latestVersion : '2.0.0' } ) ;
60- expect ( mockFetchLatestVersion ) . toHaveBeenCalled ( ) ;
6143 } ) ;
6244
6345 it ( 'uses cache when last check was less than 24 hours ago' , async ( ) => {
64- await mkdir ( CACHE_DIR , { recursive : true } ) ;
46+ await mkdir ( tmpDir , { recursive : true } ) ;
6547 await writeFile ( CACHE_FILE , JSON . stringify ( { lastCheck : 1708646400000 - 1000 , latestVersion : '2.0.0' } ) , 'utf-8' ) ;
6648
6749 const result = await checkForUpdate ( ) ;
6850
6951 expect ( result ) . toEqual ( { updateAvailable : true , latestVersion : '2.0.0' } ) ;
70- expect ( mockFetchLatestVersion ) . not . toHaveBeenCalled ( ) ;
7152 } ) ;
7253
7354 it ( 'fetches from registry when cache is expired' , async ( ) => {
74- await mkdir ( CACHE_DIR , { recursive : true } ) ;
55+ await mkdir ( tmpDir , { recursive : true } ) ;
7556 await writeFile (
7657 CACHE_FILE ,
7758 JSON . stringify ( { lastCheck : 1708646400000 - 25 * 60 * 60 * 1000 , latestVersion : '1.5.0' } ) ,
7859 'utf-8'
7960 ) ;
80- mockFetchLatestVersion . mockResolvedValue ( '2.0.0' ) ;
61+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '2.0.0' ) ;
8162
8263 const result = await checkForUpdate ( ) ;
8364
8465 expect ( result ) . toEqual ( { updateAvailable : true , latestVersion : '2.0.0' } ) ;
85- expect ( mockFetchLatestVersion ) . toHaveBeenCalled ( ) ;
8666 } ) ;
8767
8868 it ( 'writes cache after fetching' , async ( ) => {
89- mockFetchLatestVersion . mockResolvedValue ( '2.0.0' ) ;
69+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '2.0.0' ) ;
9070
9171 await checkForUpdate ( ) ;
9272
@@ -95,52 +75,52 @@ describe('checkForUpdate', () => {
9575 } ) ;
9676
9777 it ( 'returns updateAvailable: false when versions match' , async ( ) => {
98- mockFetchLatestVersion . mockResolvedValue ( '1.0.0' ) ;
78+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '1.0.0' ) ;
9979
10080 const result = await checkForUpdate ( ) ;
10181
10282 expect ( result ) . toEqual ( { updateAvailable : false , latestVersion : '1.0.0' } ) ;
10383 } ) ;
10484
10585 it ( 'returns updateAvailable: false when current is newer' , async ( ) => {
106- mockFetchLatestVersion . mockResolvedValue ( '0.9.0' ) ;
86+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '0.9.0' ) ;
10787
10888 const result = await checkForUpdate ( ) ;
10989
11090 expect ( result ) . toEqual ( { updateAvailable : false , latestVersion : '0.9.0' } ) ;
11191 } ) ;
11292
11393 it ( 'returns null on fetch error' , async ( ) => {
114- mockFetchLatestVersion . mockRejectedValue ( new Error ( 'network error' ) ) ;
94+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockRejectedValue ( new Error ( 'network error' ) ) ;
11595
11696 const result = await checkForUpdate ( ) ;
11797
11898 expect ( result ) . toBeNull ( ) ;
11999 } ) ;
120100
121101 it ( 'returns null on cache parse error and fetch error' , async ( ) => {
122- await mkdir ( CACHE_DIR , { recursive : true } ) ;
102+ await mkdir ( tmpDir , { recursive : true } ) ;
123103 await writeFile ( CACHE_FILE , 'invalid json' , 'utf-8' ) ;
124- mockFetchLatestVersion . mockRejectedValue ( new Error ( 'network error' ) ) ;
104+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockRejectedValue ( new Error ( 'network error' ) ) ;
125105
126106 const result = await checkForUpdate ( ) ;
127107
128108 expect ( result ) . toBeNull ( ) ;
129109 } ) ;
130110
131111 it ( 'succeeds even when cache write fails' , async ( ) => {
132- await mkdir ( CACHE_DIR , { recursive : true } ) ;
133- await writeFile ( CACHE_FILE , '' , 'utf-8' ) ;
134- const { chmod } = await import ( 'fs/promises' ) ;
135- await chmod ( CACHE_DIR , 0o444 ) ;
136-
137- mockFetchLatestVersion . mockResolvedValue ( '2.0.0' ) ;
112+ await mkdir ( tmpDir , { recursive : true } ) ;
113+ await chmod ( tmpDir , 0o444 ) ;
138114
139- const result = await checkForUpdate ( ) ;
115+ try {
116+ vi . spyOn ( action , 'fetchLatestVersion' ) . mockResolvedValue ( '2.0.0' ) ;
140117
141- expect ( result ) . toEqual ( { updateAvailable : true , latestVersion : '2.0.0' } ) ;
118+ const result = await checkForUpdate ( ) ;
142119
143- await chmod ( CACHE_DIR , 0o755 ) ;
120+ expect ( result ) . toEqual ( { updateAvailable : true , latestVersion : '2.0.0' } ) ;
121+ } finally {
122+ await chmod ( tmpDir , 0o755 ) ;
123+ }
144124 } ) ;
145125} ) ;
146126
@@ -153,9 +133,7 @@ describe('printUpdateNotification', () => {
153133
154134 const output = stderrSpy . mock . calls . map ( c => c [ 0 ] ) . join ( '' ) ;
155135 expect ( output ) . toContain ( 'Update available:' ) ;
156- expect ( output ) . toContain ( '1.0.0' ) ;
157136 expect ( output ) . toContain ( '2.0.0' ) ;
158- expect ( output ) . toContain ( 'npm install -g @aws/agentcore@latest' ) ;
159137
160138 stderrSpy . mockRestore ( ) ;
161139 } ) ;
0 commit comments