@@ -15,20 +15,44 @@ describe('prepareOptions helpers - intensive tests', () => {
1515 let testLogger : logging . Logger ;
1616 let infoSpy : jest . SpyInstance ;
1717 let warnSpy : jest . SpyInstance ;
18+ const originalEnv = process . env ;
1819
1920 beforeEach ( ( ) => {
2021 testLogger = new logging . Logger ( 'test' ) ;
2122 infoSpy = jest . spyOn ( testLogger , 'info' ) ;
2223 warnSpy = jest . spyOn ( testLogger , 'warn' ) ;
23- // Reset environment for each test
24- process . env = { } ;
24+ // Create fresh copy of environment for each test
25+ // This preserves PATH, HOME, etc. needed by git
26+ process . env = { ...originalEnv } ;
27+ // Clear only CI-specific vars we're testing
28+ delete process . env . TRAVIS ;
29+ delete process . env . TRAVIS_COMMIT ;
30+ delete process . env . TRAVIS_COMMIT_MESSAGE ;
31+ delete process . env . TRAVIS_REPO_SLUG ;
32+ delete process . env . TRAVIS_BUILD_ID ;
33+ delete process . env . CIRCLECI ;
34+ delete process . env . CIRCLE_PROJECT_USERNAME ;
35+ delete process . env . CIRCLE_PROJECT_REPONAME ;
36+ delete process . env . CIRCLE_SHA1 ;
37+ delete process . env . CIRCLE_BUILD_URL ;
38+ delete process . env . GITHUB_ACTIONS ;
39+ delete process . env . GITHUB_REPOSITORY ;
40+ delete process . env . GITHUB_SHA ;
41+ delete process . env . GH_TOKEN ;
42+ delete process . env . PERSONAL_TOKEN ;
43+ delete process . env . GITHUB_TOKEN ;
2544 } ) ;
2645
2746 afterEach ( ( ) => {
2847 infoSpy . mockRestore ( ) ;
2948 warnSpy . mockRestore ( ) ;
3049 } ) ;
3150
51+ afterAll ( ( ) => {
52+ // Restore original environment for other test files
53+ process . env = originalEnv ;
54+ } ) ;
55+
3256 describe ( 'setupMonkeypatch' , ( ) => {
3357 let originalDebuglog : typeof import ( 'util' ) . debuglog ;
3458
@@ -280,7 +304,7 @@ describe('prepareOptions helpers - intensive tests', () => {
280304 describe ( 'appendCIMetadata' , ( ) => {
281305 const baseMessage = 'Deploy to gh-pages' ;
282306
283- it ( 'should append Travis CI metadata when TRAVIS env is set ' , ( ) => {
307+ it ( 'should append Travis CI metadata with exact format ' , ( ) => {
284308 process . env . TRAVIS = 'true' ;
285309 process . env . TRAVIS_COMMIT_MESSAGE = 'Fix bug in component' ;
286310 process . env . TRAVIS_REPO_SLUG = 'user/repo' ;
@@ -296,12 +320,15 @@ describe('prepareOptions helpers - intensive tests', () => {
296320
297321 helpers . appendCIMetadata ( options ) ;
298322
299- expect ( options . message ) . toContain ( ' -- Fix bug in component' ) ;
300- expect ( options . message ) . toContain ( 'Triggered by commit: https://github.com/user/repo/commit/abc123def456' ) ;
301- expect ( options . message ) . toContain ( 'Travis CI build: https://travis-ci.org/user/repo/builds/987654321' ) ;
323+ const expectedMessage =
324+ 'Deploy to gh-pages -- Fix bug in component \n\n' +
325+ 'Triggered by commit: https://github.com/user/repo/commit/abc123def456\n' +
326+ 'Travis CI build: https://travis-ci.org/user/repo/builds/987654321' ;
327+
328+ expect ( options . message ) . toBe ( expectedMessage ) ;
302329 } ) ;
303330
304- it ( 'should append CircleCI metadata when CIRCLECI env is set ' , ( ) => {
331+ it ( 'should append CircleCI metadata with exact format ' , ( ) => {
305332 process . env . CIRCLECI = 'true' ;
306333 process . env . CIRCLE_PROJECT_USERNAME = 'johndoe' ;
307334 process . env . CIRCLE_PROJECT_REPONAME = 'myproject' ;
@@ -317,11 +344,15 @@ describe('prepareOptions helpers - intensive tests', () => {
317344
318345 helpers . appendCIMetadata ( options ) ;
319346
320- expect ( options . message ) . toContain ( 'Triggered by commit: https://github.com/johndoe/myproject/commit/fedcba987654' ) ;
321- expect ( options . message ) . toContain ( 'CircleCI build: https://circleci.com/gh/johndoe/myproject/123' ) ;
347+ const expectedMessage =
348+ 'Deploy to gh-pages\n\n' +
349+ 'Triggered by commit: https://github.com/johndoe/myproject/commit/fedcba987654\n' +
350+ 'CircleCI build: https://circleci.com/gh/johndoe/myproject/123' ;
351+
352+ expect ( options . message ) . toBe ( expectedMessage ) ;
322353 } ) ;
323354
324- it ( 'should append GitHub Actions metadata when GITHUB_ACTIONS env is set ' , ( ) => {
355+ it ( 'should append GitHub Actions metadata with exact format ' , ( ) => {
325356 process . env . GITHUB_ACTIONS = 'true' ;
326357 process . env . GITHUB_REPOSITORY = 'angular-schule/angular-cli-ghpages' ;
327358 process . env . GITHUB_SHA = '1234567890abcdef' ;
@@ -335,7 +366,11 @@ describe('prepareOptions helpers - intensive tests', () => {
335366
336367 helpers . appendCIMetadata ( options ) ;
337368
338- expect ( options . message ) . toContain ( 'Triggered by commit: https://github.com/angular-schule/angular-cli-ghpages/commit/1234567890abcdef' ) ;
369+ const expectedMessage =
370+ 'Deploy to gh-pages\n\n' +
371+ 'Triggered by commit: https://github.com/angular-schule/angular-cli-ghpages/commit/1234567890abcdef' ;
372+
373+ expect ( options . message ) . toBe ( expectedMessage ) ;
339374 } ) ;
340375
341376 it ( 'should NOT modify message when no CI env is set' , ( ) => {
@@ -351,16 +386,23 @@ describe('prepareOptions helpers - intensive tests', () => {
351386 expect ( options . message ) . toBe ( baseMessage ) ;
352387 } ) ;
353388
354- it ( 'should append metadata from multiple CI environments if present' , ( ) => {
389+ it ( 'should append metadata from multiple CI environments in correct order' , ( ) => {
390+ // Set up multiple CI environments (Travis, CircleCI, GitHub Actions)
355391 process . env . TRAVIS = 'true' ;
356392 process . env . TRAVIS_COMMIT_MESSAGE = 'Update docs' ;
357393 process . env . TRAVIS_REPO_SLUG = 'org/repo' ;
358394 process . env . TRAVIS_COMMIT = 'abc123' ;
359395 process . env . TRAVIS_BUILD_ID = '111' ;
360396
397+ process . env . CIRCLECI = 'true' ;
398+ process . env . CIRCLE_PROJECT_USERNAME = 'org' ;
399+ process . env . CIRCLE_PROJECT_REPONAME = 'repo' ;
400+ process . env . CIRCLE_SHA1 = 'def456' ;
401+ process . env . CIRCLE_BUILD_URL = 'https://circleci.com/gh/org/repo/222' ;
402+
361403 process . env . GITHUB_ACTIONS = 'true' ;
362404 process . env . GITHUB_REPOSITORY = 'org/repo' ;
363- process . env . GITHUB_SHA = 'def456 ' ;
405+ process . env . GITHUB_SHA = 'ghi789 ' ;
364406
365407 const options : helpers . PreparedOptions = {
366408 message : baseMessage ,
@@ -371,8 +413,15 @@ describe('prepareOptions helpers - intensive tests', () => {
371413
372414 helpers . appendCIMetadata ( options ) ;
373415
374- expect ( options . message ) . toContain ( 'Travis CI build' ) ;
375- expect ( options . message ) . toContain ( 'Triggered by commit: https://github.com/org/repo/commit/def456' ) ;
416+ // Verify Travis appears first, then CircleCI, then GitHub Actions
417+ expect ( options . message ) . toBeDefined ( ) ;
418+ const travisIndex = options . message ! . indexOf ( 'Travis CI build' ) ;
419+ const circleIndex = options . message ! . indexOf ( 'CircleCI build' ) ;
420+ const ghActionsIndex = options . message ! . indexOf ( 'Triggered by commit: https://github.com/org/repo/commit/ghi789' ) ;
421+
422+ expect ( travisIndex ) . toBeGreaterThan ( - 1 ) ;
423+ expect ( circleIndex ) . toBeGreaterThan ( travisIndex ) ;
424+ expect ( ghActionsIndex ) . toBeGreaterThan ( circleIndex ) ;
376425 } ) ;
377426 } ) ;
378427
@@ -541,30 +590,33 @@ describe('prepareOptions helpers - intensive tests', () => {
541590 * comment in engine.prepare-options-helpers.ts for fallback options.
542591 */
543592
544- it ( 'should successfully call gh-pages/lib/git Git class and return URL ' , async ( ) => {
545- // This test verifies the internal API still exists and is callable
593+ it ( 'should return correct URL from git config and be consistent ' , async ( ) => {
594+ // This test verifies the internal API returns ACTUAL git config values
546595 const options = { remote : 'origin' } ;
547596
548- // Should successfully return the git remote URL
549- const result = await helpers . getRemoteUrl ( options ) ;
597+ // Get what git actually says
598+ const { execSync } = require ( 'child_process' ) ;
599+ const expectedUrl = execSync ( 'git config --get remote.origin.url' , { encoding : 'utf8' } ) . trim ( ) ;
550600
551- // Verify it returns a string URL
552- expect ( typeof result ) . toBe ( 'string' ) ;
553- expect ( result . length ) . toBeGreaterThan ( 0 ) ;
601+ // Verify getRemoteUrl returns the same value
602+ const result = await helpers . getRemoteUrl ( options ) ;
603+ expect ( result ) . toBe ( expectedUrl ) ;
554604
555- // Verify it looks like a git URL (either SSH or HTTPS)
556- const isGitUrl = result . includes ( 'github.com' ) || result . startsWith ( 'git@' ) || result . startsWith ( 'https://' ) ;
557- expect ( isGitUrl ) . toBe ( true ) ;
605+ // Verify consistency across multiple calls
606+ const result2 = await helpers . getRemoteUrl ( options ) ;
607+ expect ( result2 ) . toBe ( expectedUrl ) ;
608+ expect ( result ) . toBe ( result2 ) ;
558609 } ) ;
559610
560- it ( 'should pass remote option to getRemoteUrl method ' , async ( ) => {
611+ it ( 'should throw helpful error for non-existent remote ' , async ( ) => {
561612 const options = {
562613 remote : 'nonexistent-remote-12345' // Remote that definitely doesn't exist
563614 } ;
564615
565- // Should throw because this remote doesn't exist in our test repo
566- // This verifies the remote option is passed to getRemoteUrl method
567- await expect ( helpers . getRemoteUrl ( options ) ) . rejects . toThrow ( ) ;
616+ // Should throw with specific error message about the remote
617+ await expect ( helpers . getRemoteUrl ( options ) )
618+ . rejects
619+ . toThrow ( 'Failed to get remote.' ) ;
568620 } ) ;
569621
570622 it ( 'should throw helpful error when not in a git repository' , async ( ) => {
@@ -575,41 +627,15 @@ describe('prepareOptions helpers - intensive tests', () => {
575627
576628 try {
577629 process . chdir ( tempDir ) ;
578- const options = { } ;
630+ const options = { remote : 'origin' } ;
579631
580632 await expect ( helpers . getRemoteUrl ( options ) )
581633 . rejects
582- . toThrow ( ) ; // Will throw error about not being in a git repository
634+ . toThrow ( 'run in a git repository' ) ;
583635 } finally {
584636 process . chdir ( originalCwd ) ;
585637 await require ( 'fs-extra' ) . remove ( tempDir ) ;
586638 }
587639 } ) ;
588-
589- it ( 'should work when remote is provided from defaults' , async ( ) => {
590- // In real usage, options.remote is ALWAYS set because prepareOptions merges defaults
591- // Our defaults.ts has remote: 'origin', so options.remote is never undefined
592- const options = { remote : 'origin' } ;
593-
594- // Should successfully return the remote URL
595- const result = await helpers . getRemoteUrl ( options ) ;
596- expect ( typeof result ) . toBe ( 'string' ) ;
597- expect ( result . length ) . toBeGreaterThan ( 0 ) ;
598-
599- // Calling again with same remote should return same URL
600- const result2 = await helpers . getRemoteUrl ( options ) ;
601- expect ( result ) . toBe ( result2 ) ;
602- } ) ;
603-
604- it ( 'should return consistent URL for same remote' , async ( ) => {
605- const options1 = { remote : 'origin' } ;
606- const options2 = { remote : 'origin' } ;
607-
608- const result1 = await helpers . getRemoteUrl ( options1 ) ;
609- const result2 = await helpers . getRemoteUrl ( options2 ) ;
610-
611- // Same remote should return same URL
612- expect ( result1 ) . toBe ( result2 ) ;
613- } ) ;
614640 } ) ;
615641} ) ;
0 commit comments