2026-05-20 20:18:29 +00:00
import { afterAll , beforeEach , expect , jest , test } from "@jest/globals" ;
2026-05-20 19:31:39 +00:00
// Mock @actions/core
jest . unstable_mockModule ( "@actions/core" , () => ({
getInput : jest.fn (( name : string , options ?: { required? : boolean }) => {
const val =
process . env [ `INPUT_ ${ name . replace ( / /g , "_" ). toUpperCase () } ` ] || "" ;
if ( options && options . required && ! val ) {
throw new Error ( `Input required and not supplied: ${ name } ` );
}
return val . trim ();
}),
setOutput : jest.fn (),
setFailed : jest.fn (),
info : jest.fn (),
warning : jest.fn (),
debug : jest.fn (),
error : jest.fn (),
saveState : jest.fn (),
getState : jest.fn (() => "" ),
isDebug : jest.fn (() => false ),
exportVariable : jest.fn (),
addPath : jest.fn (),
group : jest.fn (( name : string , fn : () => Promise < unknown >) => fn ()),
startGroup : jest.fn (),
endGroup : jest.fn ()
}));
// Mock @actions/cache
jest . unstable_mockModule ( "@actions/cache" , () => ({
restoreCache : jest.fn (),
saveCache : jest.fn (),
isFeatureAvailable : jest.fn (() => true ),
ReserveCacheError : class ReserveCacheError extends Error {
constructor ( message : string ) {
super ( message );
this . name = "ReserveCacheError" ;
}
}
}));
2019-11-13 16:13:00 -05:00
2026-05-20 19:31:39 +00:00
const core = await import ( "@actions/core" );
const cache = await import ( "@actions/cache" );
const { Events , RefKey } = await import ( "../src/constants" );
const actionUtils = await import ( "../src/utils/actionUtils" );
const testUtils = await import ( "../src/utils/testUtils" );
2020-03-20 13:02:11 -07:00
2024-10-18 17:22:08 +00:00
let pristineEnv : NodeJS.ProcessEnv ;
beforeEach (() => {
2026-05-20 19:31:39 +00:00
pristineEnv = { ... process . env };
jest . clearAllMocks ();
2026-06-11 14:46:05 +00:00
jest . mocked ( core . getInput ). mockImplementation (
2026-05-20 19:31:39 +00:00
( name : string , options ?: { required? : boolean }) => {
const val =
2026-05-20 20:18:29 +00:00
process . env [ `INPUT_ ${ name . replace ( / /g , "_" ). toUpperCase () } ` ] ||
"" ;
2026-05-20 19:31:39 +00:00
if ( options && options . required && ! val ) {
2026-05-20 20:18:29 +00:00
throw new Error ( `Input required and not supplied: ${ name } ` );
2026-05-20 19:31:39 +00:00
}
return val . trim ();
}
);
2019-11-13 16:13:00 -05:00
delete process . env [ Events . Key ];
2020-04-17 15:46:46 -04:00
delete process . env [ RefKey ];
2019-11-13 16:13:00 -05:00
});
2024-10-18 17:22:08 +00:00
afterAll (() => {
process . env = pristineEnv ;
});
2020-09-29 12:36:19 -05:00
test ( "isGhes returns true if server url is not github.com" , () => {
try {
process . env [ "GITHUB_SERVER_URL" ] = "http://example.com" ;
expect ( actionUtils . isGhes ()). toBe ( true );
} finally {
process . env [ "GITHUB_SERVER_URL" ] = undefined ;
}
});
2022-02-07 14:20:40 +09:00
test ( "isGhes returns false when server url is github.com" , () => {
2020-09-29 12:36:19 -05:00
try {
process . env [ "GITHUB_SERVER_URL" ] = "http://github.com" ;
expect ( actionUtils . isGhes ()). toBe ( false );
} finally {
process . env [ "GITHUB_SERVER_URL" ] = undefined ;
}
});
2020-05-14 17:27:38 -04:00
test ( "isExactKeyMatch with undefined cache key returns false" , () => {
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-rust" , undefined )). toBe ( false );
2019-11-13 16:13:00 -05:00
});
2020-05-14 17:27:38 -04:00
test ( "isExactKeyMatch with empty cache key returns false" , () => {
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-rust" , "" )). toBe ( false );
2019-11-13 16:13:00 -05:00
});
test ( "isExactKeyMatch with different keys returns false" , () => {
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-rust" , "linux-" )). toBe ( false );
2019-11-13 16:13:00 -05:00
});
test ( "isExactKeyMatch with different key accents returns false" , () => {
2026-05-20 20:18:29 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-áccent" , "linux-accent" )). toBe (
false
);
2019-11-13 16:13:00 -05:00
});
test ( "isExactKeyMatch with same key returns true" , () => {
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-rust" , "linux-rust" )). toBe ( true );
2019-11-13 16:13:00 -05:00
});
test ( "isExactKeyMatch with same key and different casing returns true" , () => {
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isExactKeyMatch ( "linux-rust" , "LINUX-RUST" )). toBe ( true );
2019-11-13 16:13:00 -05:00
});
2019-11-21 14:37:54 -05:00
test ( "logWarning logs a message with a warning prefix" , () => {
const message = "A warning occurred." ;
actionUtils . logWarning ( message );
2026-05-20 19:31:39 +00:00
expect ( core . info ). toHaveBeenCalledWith ( `[warning] ${ message } ` );
2019-11-21 14:37:54 -05:00
});
2020-04-17 15:46:46 -04:00
test ( "isValidEvent returns false for event that does not have a branch or tag" , () => {
2026-05-20 19:31:39 +00:00
process . env [ Events . Key ] = "foo" ;
expect ( actionUtils . isValidEvent ()). toBe ( false );
2019-11-13 16:13:00 -05:00
});
2020-04-17 15:46:46 -04:00
test ( "isValidEvent returns true for event that has a ref" , () => {
2026-05-20 19:31:39 +00:00
process . env [ Events . Key ] = Events . Push ;
2020-04-17 15:46:46 -04:00
process . env [ RefKey ] = "ref/heads/feature" ;
2026-05-20 19:31:39 +00:00
expect ( actionUtils . isValidEvent ()). toBe ( true );
2019-11-13 16:13:00 -05:00
});
2020-06-02 10:21:03 -05:00
test ( "getInputAsArray returns empty array if not required and missing" , () => {
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([]);
});
test ( "getInputAsArray throws error if required and missing" , () => {
expect (() =>
actionUtils . getInputAsArray ( "foo" , { required : true })
2026-05-20 19:31:39 +00:00
). toThrow ();
2020-06-02 10:21:03 -05:00
});
test ( "getInputAsArray handles single line correctly" , () => {
testUtils . setInput ( "foo" , "bar" );
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([ "bar" ]);
});
test ( "getInputAsArray handles multiple lines correctly" , () => {
testUtils . setInput ( "foo" , "bar\nbaz" );
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([ "bar" , "baz" ]);
});
test ( "getInputAsArray handles different new lines correctly" , () => {
testUtils . setInput ( "foo" , "bar\r\nbaz" );
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([ "bar" , "baz" ]);
});
test ( "getInputAsArray handles empty lines correctly" , () => {
testUtils . setInput ( "foo" , "\n\nbar\n\nbaz\n\n" );
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([ "bar" , "baz" ]);
});
2020-10-02 09:59:55 -05:00
2020-11-28 20:34:06 +01:00
test ( "getInputAsArray removes spaces after ! at the beginning" , () => {
testUtils . setInput (
"foo" ,
"! bar\n! baz\n! qux\n!quux\ncorge\ngrault! garply\n!\r\t waldo"
);
expect ( actionUtils . getInputAsArray ( "foo" )). toEqual ([
"!bar" ,
"!baz" ,
"!qux" ,
2022-10-03 06:39:10 +00:00
"!quux" ,
2020-11-28 20:34:06 +01:00
"corge" ,
2022-10-03 06:39:10 +00:00
"grault! garply" ,
"!waldo"
2020-11-28 20:34:06 +01:00
]);
});
2020-10-02 09:59:55 -05:00
test ( "getInputAsInt returns undefined if input not set" , () => {
2020-10-02 10:55:30 -05:00
expect ( actionUtils . getInputAsInt ( "undefined" )). toBeUndefined ();
2020-10-02 09:59:55 -05:00
});
test ( "getInputAsInt returns value if input is valid" , () => {
testUtils . setInput ( "foo" , "8" );
expect ( actionUtils . getInputAsInt ( "foo" )). toBe ( 8 );
});
test ( "getInputAsInt returns undefined if input is invalid or NaN" , () => {
testUtils . setInput ( "foo" , "bar" );
expect ( actionUtils . getInputAsInt ( "foo" )). toBeUndefined ();
});
2020-10-02 10:55:30 -05:00
test ( "getInputAsInt throws if required and value missing" , () => {
expect (() =>
actionUtils . getInputAsInt ( "undefined" , { required : true })
2026-05-20 19:31:39 +00:00
). toThrow ();
2020-10-02 10:55:30 -05:00
});
2022-03-30 15:46:49 +05:30
2023-01-05 16:49:13 +05:30
test ( "getInputAsBool returns false if input not set" , () => {
expect ( actionUtils . getInputAsBool ( "undefined" )). toBe ( false );
});
test ( "getInputAsBool returns value if input is valid" , () => {
testUtils . setInput ( "foo" , "true" );
expect ( actionUtils . getInputAsBool ( "foo" )). toBe ( true );
});
test ( "getInputAsBool returns false if input is invalid or NaN" , () => {
testUtils . setInput ( "foo" , "bar" );
expect ( actionUtils . getInputAsBool ( "foo" )). toBe ( false );
});
test ( "getInputAsBool throws if required and value missing" , () => {
expect (() =>
actionUtils . getInputAsBool ( "undefined2" , { required : true })
2026-05-20 19:31:39 +00:00
). toThrow ();
2023-01-05 16:49:13 +05:30
});
2022-03-30 15:46:49 +05:30
test ( "isCacheFeatureAvailable for ac enabled" , () => {
2026-06-11 14:46:05 +00:00
jest . mocked ( cache . isFeatureAvailable ). mockReturnValue ( true );
2022-03-30 15:46:49 +05:30
expect ( actionUtils . isCacheFeatureAvailable ()). toBe ( true );
});
test ( "isCacheFeatureAvailable for ac disabled on GHES" , () => {
2026-06-11 14:46:05 +00:00
jest . mocked ( cache . isFeatureAvailable ). mockReturnValue ( false );
2022-03-30 15:46:49 +05:30
2022-09-20 10:47:27 +05:30
const message = `Cache action is only supported on GHES version >= 3.5. If you are on version >=3.5 Please check with GHES admin if Actions cache service is enabled or not.
Otherwise please upgrade to GHES version >= 3.5 and If you are also using Github Connect, please unretire the actions/cache namespace before upgrade (see https://docs.github.com/en/enterprise-server@3.5/admin/github-actions/managing-access-to-actions-from-githubcom/enabling-automatic-access-to-githubcom-actions-using-github-connect#automatic-retirement-of-namespaces-for-actions-accessed-on-githubcom)` ;
2022-03-30 15:46:49 +05:30
try {
process . env [ "GITHUB_SERVER_URL" ] = "http://example.com" ;
expect ( actionUtils . isCacheFeatureAvailable ()). toBe ( false );
2026-05-20 19:31:39 +00:00
expect ( core . info ). toHaveBeenCalledWith ( `[warning] ${ message } ` );
2022-03-30 15:46:49 +05:30
} finally {
delete process . env [ "GITHUB_SERVER_URL" ];
}
});
test ( "isCacheFeatureAvailable for ac disabled on dotcom" , () => {
2026-06-11 14:46:05 +00:00
jest . mocked ( cache . isFeatureAvailable ). mockReturnValue ( false );
2022-03-30 15:46:49 +05:30
const message =
"An internal error has occurred in cache backend. Please check https://www.githubstatus.com/ for any ongoing issue in actions." ;
try {
process . env [ "GITHUB_SERVER_URL" ] = "http://github.com" ;
expect ( actionUtils . isCacheFeatureAvailable ()). toBe ( false );
2026-05-20 19:31:39 +00:00
expect ( core . info ). toHaveBeenCalledWith ( `[warning] ${ message } ` );
2022-03-30 15:46:49 +05:30
} finally {
delete process . env [ "GITHUB_SERVER_URL" ];
}
});
2024-10-18 17:22:08 +00:00
2026-05-20 19:31:39 +00:00
test ( "isGhes returns false when the GITHUB_SERVER_URL environment variable is not defined" , () => {
2024-10-18 17:22:08 +00:00
delete process . env [ "GITHUB_SERVER_URL" ];
expect ( actionUtils . isGhes ()). toBeFalsy ();
});
2026-05-20 19:31:39 +00:00
test ( "isGhes returns false when the GITHUB_SERVER_URL environment variable is set to github.com" , () => {
2024-10-18 17:22:08 +00:00
process . env [ "GITHUB_SERVER_URL" ] = "https://github.com" ;
expect ( actionUtils . isGhes ()). toBeFalsy ();
});
2026-05-20 19:31:39 +00:00
test ( "isGhes returns false when the GITHUB_SERVER_URL environment variable is set to a GitHub Enterprise Cloud-style URL" , () => {
2024-10-18 17:22:08 +00:00
process . env [ "GITHUB_SERVER_URL" ] = "https://contoso.ghe.com" ;
expect ( actionUtils . isGhes ()). toBeFalsy ();
});
2026-05-20 19:31:39 +00:00
test ( "isGhes returns false when the GITHUB_SERVER_URL environment variable has a .localhost suffix" , () => {
2024-10-18 17:22:08 +00:00
process . env [ "GITHUB_SERVER_URL" ] = "https://mock-github.localhost" ;
expect ( actionUtils . isGhes ()). toBeFalsy ();
});
2026-05-20 19:31:39 +00:00
test ( "isGhes returns true when the GITHUB_SERVER_URL environment variable is set to some other URL" , () => {
2024-10-18 17:22:08 +00:00
process . env [ "GITHUB_SERVER_URL" ] = "https://src.onpremise.fabrikam.com" ;
expect ( actionUtils . isGhes ()). toBeTruthy ();
});