66import { expect } from 'chai' ;
77import * as sinon from 'sinon' ;
88import * as vscode from 'vscode' ;
9+ import * as os from 'os' ;
910import * as fs from 'fs-extra' ;
11+ import path from 'path' ;
1012import { cloneSite } from '../../../../../power-pages/actions-hub/handlers/CloneSiteHandler' ;
1113import { Constants } from '../../../../../power-pages/actions-hub/Constants' ;
1214import { PacTerminal } from '../../../../../lib/PacTerminal' ;
@@ -29,20 +31,18 @@ describe('CloneSiteHandler', () => {
2931 uploadCodeSiteWithProgress : sinon . SinonStub ;
3032 } ;
3133 let executeCommandStub : sinon . SinonStub ;
32- let readdirSyncStub : sinon . SinonStub ;
33-
34- const mockDirEntry = ( name : string ) => ( {
35- name,
36- isDirectory : ( ) => true ,
37- isFile : ( ) => false ,
38- isBlockDevice : ( ) => false ,
39- isCharacterDevice : ( ) => false ,
40- isSymbolicLink : ( ) => false ,
41- isFIFO : ( ) => false ,
42- isSocket : ( ) => false ,
43- path : '' ,
44- parentPath : '' ,
45- } as unknown as fs . Dirent ) ;
34+
35+ /**
36+ * Simulates what the PAC CLI download/clone commands do:
37+ * create a site subfolder inside the target directory.
38+ */
39+ const simulateSiteSubfolderCreation = ( stub : sinon . SinonStub ) => {
40+ stub . callsFake ( ( ...args : string [ ] ) => {
41+ const targetDir = args [ 0 ] ;
42+ fs . ensureDirSync ( path . join ( targetDir , 'test-site' ) ) ;
43+ return Promise . resolve ( true ) ;
44+ } ) ;
45+ } ;
4646
4747 beforeEach ( ( ) => {
4848 sandbox = sinon . createSandbox ( ) ;
@@ -54,11 +54,6 @@ describe('CloneSiteHandler', () => {
5454
5555 executeCommandStub = sandbox . stub ( vscode . commands , 'executeCommand' ) . resolves ( ) ;
5656
57- // Stub fs-extra operations
58- sandbox . stub ( fs , 'ensureDirSync' ) ;
59- readdirSyncStub = sandbox . stub ( fs , 'readdirSync' ) . returns ( [ mockDirEntry ( 'test-site' ) ] ) ;
60- sandbox . stub ( fs , 'remove' ) . resolves ( ) ;
61-
6257 mockPacTerminal = sandbox . createStubInstance ( PacTerminal ) ;
6358
6459 mockPacWrapper = {
@@ -68,11 +63,27 @@ describe('CloneSiteHandler', () => {
6863 uploadSiteWithProgress : sandbox . stub ( ) . resolves ( true ) ,
6964 uploadCodeSiteWithProgress : sandbox . stub ( ) . resolves ( true ) ,
7065 } ;
66+
67+ // Simulate site subfolder creation for download and clone
68+ simulateSiteSubfolderCreation ( mockPacWrapper . downloadSiteWithProgress ) ;
69+ simulateSiteSubfolderCreation ( mockPacWrapper . downloadCodeSiteWithProgress ) ;
70+ mockPacWrapper . cloneSiteWithProgress . callsFake ( ( _src : string , outputDir : string ) => {
71+ fs . ensureDirSync ( path . join ( outputDir , 'test-site-clone' ) ) ;
72+ return Promise . resolve ( true ) ;
73+ } ) ;
74+
7175 mockPacTerminal . getWrapper . returns ( mockPacWrapper as unknown as ReturnType < PacTerminal [ 'getWrapper' ] > ) ;
7276 } ) ;
7377
7478 afterEach ( ( ) => {
7579 sandbox . restore ( ) ;
80+
81+ // Clean up any leftover temp dirs
82+ const tmpDir = os . tmpdir ( ) ;
83+ const entries = fs . readdirSync ( tmpDir ) . filter ( e => e . startsWith ( 'pp-clone-' ) ) ;
84+ for ( const entry of entries ) {
85+ fs . removeSync ( path . join ( tmpDir , entry ) ) ;
86+ }
7687 } ) ;
7788
7889 function createMockSiteTreeItem ( overrides : Partial < IWebsiteInfo > = { } ) : SiteTreeItem {
@@ -182,7 +193,7 @@ describe('CloneSiteHandler', () => {
182193 expect ( mockPacWrapper . uploadCodeSiteWithProgress . called ) . to . be . false ;
183194 } ) ;
184195
185- it ( 'should use temp directories and find site subfolder for clone and upload' , async ( ) => {
196+ it ( 'should pass discovered site subfolder paths to clone and upload' , async ( ) => {
186197 sandbox . stub ( vscode . window , 'showInputBox' ) . resolves ( 'Copy of Test Site' ) ;
187198
188199 const handler = cloneSite ( mockPacTerminal as unknown as PacTerminal ) ;
@@ -193,12 +204,10 @@ describe('CloneSiteHandler', () => {
193204 const cloneOutputPath = mockPacWrapper . cloneSiteWithProgress . firstCall . args [ 1 ] as string ;
194205 const uploadPath = mockPacWrapper . uploadSiteWithProgress . firstCall . args [ 0 ] as string ;
195206
196- // Clone source should be inside the download path (the site subfolder)
197- expect ( cloneSourcePath ) . to . include ( downloadPath ) ;
198- expect ( cloneSourcePath ) . to . include ( 'test-site' ) ;
199- // Upload path should be inside the clone output (the cloned site subfolder)
200- expect ( uploadPath ) . to . include ( cloneOutputPath ) ;
201- expect ( uploadPath ) . to . include ( 'test-site' ) ;
207+ // Clone source should point to the site subfolder inside the download dir
208+ expect ( cloneSourcePath ) . to . equal ( path . join ( downloadPath , 'test-site' ) ) ;
209+ // Upload path should point to the site subfolder inside the clone output dir
210+ expect ( uploadPath ) . to . equal ( path . join ( cloneOutputPath , 'test-site-clone' ) ) ;
202211 // Paths should be in temp directory
203212 expect ( downloadPath ) . to . include ( 'pp-clone-' ) ;
204213 } ) ;
@@ -227,8 +236,8 @@ describe('CloneSiteHandler', () => {
227236 sandbox . stub ( vscode . window , 'showInputBox' ) . resolves ( 'Clone Name' ) ;
228237 const mockShowErrorMessage = sandbox . stub ( vscode . window , 'showErrorMessage' ) ;
229238
230- // Return empty directory - no site subfolder
231- readdirSyncStub . returns ( [ ] ) ;
239+ // Override download to NOT create a subfolder
240+ mockPacWrapper . downloadSiteWithProgress . callsFake ( ( ) => Promise . resolve ( true ) ) ;
232241
233242 const handler = cloneSite ( mockPacTerminal as unknown as PacTerminal ) ;
234243 await handler ( createMockSiteTreeItem ( ) ) ;
@@ -246,7 +255,7 @@ describe('CloneSiteHandler', () => {
246255 sandbox . stub ( vscode . window , 'showInputBox' ) . resolves ( 'Clone Name' ) ;
247256 const mockShowErrorMessage = sandbox . stub ( vscode . window , 'showErrorMessage' ) ;
248257
249- mockPacWrapper . downloadSiteWithProgress . resolves ( false ) ;
258+ mockPacWrapper . downloadSiteWithProgress . callsFake ( ( ) => Promise . resolve ( false ) ) ;
250259
251260 const handler = cloneSite ( mockPacTerminal as unknown as PacTerminal ) ;
252261 await handler ( createMockSiteTreeItem ( ) ) ;
@@ -264,7 +273,7 @@ describe('CloneSiteHandler', () => {
264273 sandbox . stub ( vscode . window , 'showInputBox' ) . resolves ( 'Clone Name' ) ;
265274 const mockShowErrorMessage = sandbox . stub ( vscode . window , 'showErrorMessage' ) ;
266275
267- mockPacWrapper . cloneSiteWithProgress . resolves ( false ) ;
276+ mockPacWrapper . cloneSiteWithProgress . callsFake ( ( ) => Promise . resolve ( false ) ) ;
268277
269278 const handler = cloneSite ( mockPacTerminal as unknown as PacTerminal ) ;
270279 await handler ( createMockSiteTreeItem ( ) ) ;
@@ -300,7 +309,7 @@ describe('CloneSiteHandler', () => {
300309 it ( 'should catch the error and log telemetry' , async ( ) => {
301310 sandbox . stub ( vscode . window , 'showInputBox' ) . resolves ( 'Clone Name' ) ;
302311
303- mockPacWrapper . downloadSiteWithProgress . throws ( new Error ( 'Unexpected error' ) ) ;
312+ mockPacWrapper . downloadSiteWithProgress . callsFake ( ( ) => { throw new Error ( 'Unexpected error' ) ; } ) ;
304313
305314 const handler = cloneSite ( mockPacTerminal as unknown as PacTerminal ) ;
306315 await handler ( createMockSiteTreeItem ( ) ) ;
0 commit comments