@@ -2428,50 +2428,6 @@ describe('Unit test case for ts embed', () => {
24282428 } ) ;
24292429 } ) ;
24302430
2431- describe ( 'When destroyed' , ( ) => {
2432- it ( 'should remove the iframe' , async ( ) => {
2433- const appEmbed = new AppEmbed ( getRootEl ( ) , {
2434- frameParams : {
2435- width : '100%' ,
2436- height : '100%' ,
2437- } ,
2438- } ) ;
2439- await appEmbed . render ( ) ;
2440- expect ( getIFrameEl ( ) ) . toBeTruthy ( ) ;
2441- appEmbed . destroy ( ) ;
2442- expect ( getIFrameEl ( ) ) . toBeFalsy ( ) ;
2443- } ) ;
2444-
2445- it ( 'should remove the iframe when insertAsSibling is true' , async ( ) => {
2446- const appEmbed = new AppEmbed ( getRootEl ( ) , {
2447- frameParams : {
2448- width : '100%' ,
2449- height : '100%' ,
2450- } ,
2451- insertAsSibling : true ,
2452- } ) ;
2453- await appEmbed . render ( ) ;
2454- expect ( getIFrameEl ( ) ) . toBeTruthy ( ) ;
2455- appEmbed . destroy ( ) ;
2456- expect ( getIFrameEl ( ) ) . toBeFalsy ( ) ;
2457- } ) ;
2458-
2459- it ( "Should remove the error message on destroy if it's present" , async ( ) => {
2460- jest . spyOn ( baseInstance , 'getAuthPromise' ) . mockResolvedValueOnce ( false ) ;
2461- const appEmbed = new AppEmbed ( getRootEl ( ) , {
2462- frameParams : {
2463- width : '100%' ,
2464- height : '100%' ,
2465- } ,
2466- insertAsSibling : true ,
2467- } ) ;
2468- await appEmbed . render ( ) ;
2469- expect ( getRootEl ( ) . nextElementSibling . innerHTML ) . toContain ( 'Not logged in' ) ;
2470- appEmbed . destroy ( ) ;
2471- expect ( getRootEl ( ) . nextElementSibling . innerHTML ) . toBe ( '' ) ;
2472- } ) ;
2473- } ) ;
2474-
24752431 describe ( 'validate getThoughtSpotPostUrlParams' , ( ) => {
24762432 const { location } = window ;
24772433
@@ -3456,4 +3412,172 @@ describe('Unit test case for ts embed', () => {
34563412 triggerSpy . mockReset ( ) ;
34573413 } ) ;
34583414 } ) ;
3415+
3416+ describe ( 'When destroyed' , ( ) => {
3417+ it ( 'should remove the iframe' , async ( ) => {
3418+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3419+ frameParams : {
3420+ width : '100%' ,
3421+ height : '100%' ,
3422+ } ,
3423+ } ) ;
3424+ await appEmbed . render ( ) ;
3425+ expect ( getIFrameEl ( ) ) . toBeTruthy ( ) ;
3426+ appEmbed . destroy ( ) ;
3427+ expect ( getIFrameEl ( ) ) . toBeFalsy ( ) ;
3428+ } ) ;
3429+
3430+ it ( 'should remove the iframe when insertAsSibling is true' , async ( ) => {
3431+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3432+ frameParams : {
3433+ width : '100%' ,
3434+ height : '100%' ,
3435+ } ,
3436+ insertAsSibling : true ,
3437+ } ) ;
3438+ await appEmbed . render ( ) ;
3439+ expect ( getIFrameEl ( ) ) . toBeTruthy ( ) ;
3440+ appEmbed . destroy ( ) ;
3441+ expect ( getIFrameEl ( ) ) . toBeFalsy ( ) ;
3442+ } ) ;
3443+
3444+ it ( "Should remove the error message on destroy if it's present" , async ( ) => {
3445+ jest . spyOn ( baseInstance , 'getAuthPromise' ) . mockResolvedValueOnce ( false ) ;
3446+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3447+ frameParams : {
3448+ width : '100%' ,
3449+ height : '100%' ,
3450+ } ,
3451+ insertAsSibling : true ,
3452+ } ) ;
3453+ await appEmbed . render ( ) ;
3454+ expect ( getRootEl ( ) . nextElementSibling . innerHTML ) . toContain ( 'Not logged in' ) ;
3455+ appEmbed . destroy ( ) ;
3456+ expect ( getRootEl ( ) . nextElementSibling . innerHTML ) . toBe ( '' ) ;
3457+ } ) ;
3458+
3459+ describe ( 'with waitForCleanupOnDestroy configuration' , ( ) => {
3460+ let originalEmbedConfig : any ;
3461+
3462+ beforeEach ( ( ) => {
3463+ originalEmbedConfig = embedConfig . getEmbedConfig ( ) ;
3464+ } ) ;
3465+
3466+ afterEach ( ( ) => {
3467+ embedConfig . setEmbedConfig ( originalEmbedConfig ) ;
3468+ } ) ;
3469+
3470+ it ( 'should trigger DestroyEmbed event immediately when waitForCleanupOnDestroy is false' , async ( ) => {
3471+ embedConfig . setEmbedConfig ( {
3472+ ...originalEmbedConfig ,
3473+ waitForCleanupOnDestroy : false ,
3474+ } ) ;
3475+
3476+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3477+ frameParams : {
3478+ width : '100%' ,
3479+ height : '100%' ,
3480+ } ,
3481+ } ) ;
3482+ await appEmbed . render ( ) ;
3483+
3484+ const triggerSpy = jest . spyOn ( appEmbed , 'trigger' ) . mockResolvedValue ( null ) ;
3485+ const removeChildSpy = jest . spyOn ( Node . prototype , 'removeChild' ) . mockImplementation ( ( ) => getRootEl ( ) ) ;
3486+
3487+ appEmbed . destroy ( ) ;
3488+
3489+ expect ( triggerSpy ) . toHaveBeenCalledWith ( HostEvent . DestroyEmbed ) ;
3490+ expect ( removeChildSpy ) . toHaveBeenCalled ( ) ;
3491+ } ) ;
3492+
3493+ it ( 'should trigger DestroyEmbed event and wait for cleanup when waitForCleanupOnDestroy is true' , async ( ) => {
3494+ embedConfig . setEmbedConfig ( {
3495+ ...originalEmbedConfig ,
3496+ waitForCleanupOnDestroy : true ,
3497+ cleanupTimeout : 1000 ,
3498+ } ) ;
3499+
3500+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3501+ frameParams : {
3502+ width : '100%' ,
3503+ height : '100%' ,
3504+ } ,
3505+ } ) ;
3506+ await appEmbed . render ( ) ;
3507+
3508+ const triggerSpy = jest . spyOn ( appEmbed , 'trigger' ) . mockResolvedValue ( null ) ;
3509+ const removeChildSpy = jest . spyOn ( Node . prototype , 'removeChild' ) . mockImplementation ( ( ) => getRootEl ( ) ) ;
3510+
3511+ appEmbed . destroy ( ) ;
3512+
3513+ // Should be called immediately when waitForCleanupOnDestroy is true
3514+ expect ( triggerSpy ) . toHaveBeenCalledWith ( HostEvent . DestroyEmbed ) ;
3515+
3516+ // Wait for the timeout to complete
3517+ await new Promise ( resolve => setTimeout ( resolve , 1100 ) ) ;
3518+
3519+ expect ( removeChildSpy ) . toHaveBeenCalled ( ) ;
3520+ } ) ;
3521+
3522+ it ( 'should handle Promise.race with successful cleanup completion' , async ( ) => {
3523+ embedConfig . setEmbedConfig ( {
3524+ ...originalEmbedConfig ,
3525+ waitForCleanupOnDestroy : true ,
3526+ cleanupTimeout : 2000 ,
3527+ } ) ;
3528+
3529+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3530+ frameParams : {
3531+ width : '100%' ,
3532+ height : '100%' ,
3533+ } ,
3534+ } ) ;
3535+ await appEmbed . render ( ) ;
3536+
3537+ // Mock trigger to resolve quickly (before timeout)
3538+ const triggerSpy = jest . spyOn ( appEmbed , 'trigger' ) . mockImplementation ( ( ) =>
3539+ new Promise ( resolve => setTimeout ( ( ) => resolve ( null ) , 100 ) )
3540+ ) ;
3541+ const removeChildSpy = jest . spyOn ( Node . prototype , 'removeChild' ) . mockImplementation ( ( ) => getRootEl ( ) ) ;
3542+
3543+ appEmbed . destroy ( ) ;
3544+
3545+ // Wait for the trigger to complete
3546+ await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
3547+
3548+ expect ( triggerSpy ) . toHaveBeenCalledWith ( HostEvent . DestroyEmbed ) ;
3549+ expect ( removeChildSpy ) . toHaveBeenCalled ( ) ;
3550+ } ) ;
3551+
3552+ it ( 'should handle Promise.race with timeout when cleanup takes too long' , async ( ) => {
3553+ embedConfig . setEmbedConfig ( {
3554+ ...originalEmbedConfig ,
3555+ waitForCleanupOnDestroy : true ,
3556+ cleanupTimeout : 100 ,
3557+ } ) ;
3558+
3559+ const appEmbed = new AppEmbed ( getRootEl ( ) , {
3560+ frameParams : {
3561+ width : '100%' ,
3562+ height : '100%' ,
3563+ } ,
3564+ } ) ;
3565+ await appEmbed . render ( ) ;
3566+
3567+ // Mock trigger to take longer than timeout
3568+ const triggerSpy = jest . spyOn ( appEmbed , 'trigger' ) . mockImplementation ( ( ) =>
3569+ new Promise ( resolve => setTimeout ( ( ) => resolve ( null ) , 500 ) )
3570+ ) ;
3571+ const removeChildSpy = jest . spyOn ( Node . prototype , 'removeChild' ) . mockImplementation ( ( ) => getRootEl ( ) ) ;
3572+
3573+ appEmbed . destroy ( ) ;
3574+
3575+ // Wait for the timeout to complete
3576+ await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
3577+
3578+ expect ( triggerSpy ) . toHaveBeenCalledWith ( HostEvent . DestroyEmbed ) ;
3579+ expect ( removeChildSpy ) . toHaveBeenCalled ( ) ;
3580+ } ) ;
3581+ } ) ;
3582+ } ) ;
34593583} ) ;
0 commit comments