fix(engine): disarm popup lifecycle callbacks
- commit
- 82824aca0c59776e63a70d50c15cc325e9382a85
- author
- brice · · 2026-07-25 08:26 UTC
- committer
- brice · · 2026-07-26 16:42 UTC
- parent
- 9a38c58
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +107 -20
M internal/infrastructure/cef/webview.go +13 -2
| @@ -172,6 +172,7 @@ type WebView struct { | |||
| 172 | 172 | // Programmatic popup lifecycle callbacks used for OAuth auto-close and | |
| 173 | 173 | // synthetic window.open() proxy support on CEF. | |
| 174 | 174 | closeCallbacks []func() | |
| 175 | + | popupLifecycleClose func() | |
| 175 | 176 | navigationCallbacks []func(string) | |
| 176 | 177 | openerMessageCallbacks []func() | |
| 177 | 178 | openerNavigationCallbacks []func(string) | |
| @@ -653,9 +654,15 @@ func (wv *WebView) SetOnReadyToShow(fn func()) { | |||
| 653 | 654 | } | |
| 654 | 655 | } | |
| 655 | 656 | ||
| 656 | - | // SetOnClose implements port.PopupLifecycleCapable. | |
| 657 | + | // SetOnClose replaces the coordinator-owned popup lifecycle callback without | |
| 658 | + | // disturbing OAuth and other additive close callbacks. | |
| 657 | 659 | func (wv *WebView) SetOnClose(fn func()) { | |
| 658 | - | wv.AddCloseCallback(fn) | |
| 660 | + | if wv == nil { | |
| 661 | + | return | |
| 662 | + | } | |
| 663 | + | wv.mu.Lock() | |
| 664 | + | wv.popupLifecycleClose = fn | |
| 665 | + | wv.mu.Unlock() | |
| 659 | 666 | } | |
| 660 | 667 | ||
| 661 | 668 | // Show implements port.PopupLifecycleCapable. | |
| @@ -2299,6 +2306,10 @@ func (wv *WebView) runCloseCallbacks() { | |||
| 2299 | 2306 | wv.mu.Lock() | |
| 2300 | 2307 | callbacks := append([]func(){}, wv.closeCallbacks...) | |
| 2301 | 2308 | wv.closeCallbacks = nil | |
| 2309 | + | if wv.popupLifecycleClose != nil { | |
| 2310 | + | callbacks = append(callbacks, wv.popupLifecycleClose) | |
| 2311 | + | wv.popupLifecycleClose = nil | |
| 2312 | + | } | |
| 2302 | 2313 | wv.mu.Unlock() | |
| 2303 | 2314 | if len(callbacks) == 0 { | |
| 2304 | 2315 | return | |
| @@ -172,6 +172,7 @@ type WebView struct { | |||||
| 172 | // Programmatic popup lifecycle callbacks used for OAuth auto-close and | 172 | // Programmatic popup lifecycle callbacks used for OAuth auto-close and | ||
| 173 | // synthetic window.open() proxy support on CEF. | 173 | // synthetic window.open() proxy support on CEF. | ||
| 174 | closeCallbacks []func() | 174 | closeCallbacks []func() | ||
| 175 | + | popupLifecycleClose func() | |||
| 175 | navigationCallbacks []func(string) | 176 | navigationCallbacks []func(string) | ||
| 176 | openerMessageCallbacks []func() | 177 | openerMessageCallbacks []func() | ||
| 177 | openerNavigationCallbacks []func(string) | 178 | openerNavigationCallbacks []func(string) | ||
| @@ -653,9 +654,15 @@ func (wv *WebView) SetOnReadyToShow(fn func()) { | |||||
| 653 | } | 654 | } | ||
| 654 | } | 655 | } | ||
| 655 | 656 | ||||
| 656 | - | // SetOnClose implements port.PopupLifecycleCapable. | 657 | + | // SetOnClose replaces the coordinator-owned popup lifecycle callback without |
| 658 | + | // disturbing OAuth and other additive close callbacks. | |||
| 657 | func (wv *WebView) SetOnClose(fn func()) { | 659 | func (wv *WebView) SetOnClose(fn func()) { | ||
| 658 | - | wv.AddCloseCallback(fn) | 660 | + | if wv == nil { |
| 661 | + | return | |||
| 662 | + | } | |||
| 663 | + | wv.mu.Lock() | |||
| 664 | + | wv.popupLifecycleClose = fn | |||
| 665 | + | wv.mu.Unlock() | |||
| 659 | } | 666 | } | ||
| 660 | 667 | ||||
| 661 | // Show implements port.PopupLifecycleCapable. | 668 | // Show implements port.PopupLifecycleCapable. | ||
| @@ -2299,6 +2306,10 @@ func (wv *WebView) runCloseCallbacks() { | |||||
| 2299 | wv.mu.Lock() | 2306 | wv.mu.Lock() | ||
| 2300 | callbacks := append([]func(){}, wv.closeCallbacks...) | 2307 | callbacks := append([]func(){}, wv.closeCallbacks...) | ||
| 2301 | wv.closeCallbacks = nil | 2308 | wv.closeCallbacks = nil | ||
| 2309 | + | if wv.popupLifecycleClose != nil { | |||
| 2310 | + | callbacks = append(callbacks, wv.popupLifecycleClose) | |||
| 2311 | + | wv.popupLifecycleClose = nil | |||
| 2312 | + | } | |||
| 2302 | wv.mu.Unlock() | 2313 | wv.mu.Unlock() | ||
| 2303 | if len(callbacks) == 0 { | 2314 | if len(callbacks) == 0 { | ||
| 2304 | return | 2315 | return | ||
A internal/infrastructure/cef/webview_popup_lifecycle_test.go +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | ||
| 6 | + | "github.com/stretchr/testify/assert" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | func TestPopupLifecycleCallbacksCanBeDisarmed(t *testing.T) { | |
| 10 | + | wv := &WebView{inputAttached: true} | |
| 11 | + | readyCalls := 0 | |
| 12 | + | lifecycleCloseCalls := 0 | |
| 13 | + | oauthCloseCalls := 0 | |
| 14 | + | wv.SetOnReadyToShow(func() { readyCalls++ }) | |
| 15 | + | wv.SetOnClose(func() { lifecycleCloseCalls++ }) | |
| 16 | + | wv.AddCloseCallback(func() { oauthCloseCalls++ }) | |
| 17 | + | ||
| 18 | + | wv.SetOnReadyToShow(nil) | |
| 19 | + | wv.SetOnClose(nil) | |
| 20 | + | wv.fireReadyToShow() | |
| 21 | + | wv.runCloseCallbacks() | |
| 22 | + | ||
| 23 | + | assert.Zero(t, readyCalls) | |
| 24 | + | assert.Zero(t, lifecycleCloseCalls) | |
| 25 | + | assert.Equal(t, 1, oauthCloseCalls) | |
| 26 | + | } | |
| @@ -0,0 +1,26 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "testing" | |||
| 5 | + | ||||
| 6 | + | "github.com/stretchr/testify/assert" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | func TestPopupLifecycleCallbacksCanBeDisarmed(t *testing.T) { | |||
| 10 | + | wv := &WebView{inputAttached: true} | |||
| 11 | + | readyCalls := 0 | |||
| 12 | + | lifecycleCloseCalls := 0 | |||
| 13 | + | oauthCloseCalls := 0 | |||
| 14 | + | wv.SetOnReadyToShow(func() { readyCalls++ }) | |||
| 15 | + | wv.SetOnClose(func() { lifecycleCloseCalls++ }) | |||
| 16 | + | wv.AddCloseCallback(func() { oauthCloseCalls++ }) | |||
| 17 | + | ||||
| 18 | + | wv.SetOnReadyToShow(nil) | |||
| 19 | + | wv.SetOnClose(nil) | |||
| 20 | + | wv.fireReadyToShow() | |||
| 21 | + | wv.runCloseCallbacks() | |||
| 22 | + | ||||
| 23 | + | assert.Zero(t, readyCalls) | |||
| 24 | + | assert.Zero(t, lifecycleCloseCalls) | |||
| 25 | + | assert.Equal(t, 1, oauthCloseCalls) | |||
| 26 | + | } | |||
M internal/infrastructure/webkit/webview.go +42 -18
| @@ -155,6 +155,7 @@ type WebView struct { | |||
| 155 | 155 | OnProgressChanged func(float64) | |
| 156 | 156 | OnFaviconChanged func(*gdk.Texture) // Called when page favicon changes | |
| 157 | 157 | OnClose func() | |
| 158 | + | popupLifecycleClose func() | |
| 158 | 159 | OnCreate func(PopupRequest) *WebView // Return new WebView or nil to block popup | |
| 159 | 160 | OnReadyToShow func() // Called when popup is ready to display | |
| 160 | 161 | OnLinkMiddleClick func(uri string) bool // Return true if handled (blocks navigation) | |
| @@ -515,9 +516,7 @@ func (wv *WebView) connectWebProcessResponsiveSignal() { | |||
| 515 | 516 | ||
| 516 | 517 | func (wv *WebView) connectCloseSignal() { | |
| 517 | 518 | closeCb := func(_ webkit.WebView) { | |
| 518 | - | if wv.OnClose != nil { | |
| 519 | - | wv.OnClose() | |
| 520 | - | } | |
| 519 | + | wv.runCloseCallbacks() | |
| 521 | 520 | } | |
| 522 | 521 | sigID := wv.inner.ConnectClose(&closeCb) | |
| 523 | 522 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | |
| @@ -633,9 +632,7 @@ func (wv *WebView) connectCreateSignal() { | |||
| 633 | 632 | ||
| 634 | 633 | func (wv *WebView) connectReadyToShowSignal() { | |
| 635 | 634 | readyToShowCb := func(_ webkit.WebView) { | |
| 636 | - | if wv.OnReadyToShow != nil { | |
| 637 | - | wv.OnReadyToShow() | |
| 638 | - | } | |
| 635 | + | wv.fireReadyToShow() | |
| 639 | 636 | } | |
| 640 | 637 | sigID := wv.inner.ConnectReadyToShow(&readyToShowCb) | |
| 641 | 638 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | |
| @@ -1663,27 +1660,54 @@ func (*WebView) PrimePopupNavigation(string) {} | |||
| 1663 | 1660 | // SetOnReadyToShow sets the callback invoked when the popup WebView is ready to display. | |
| 1664 | 1661 | // It implements port.PopupLifecycleCapable. | |
| 1665 | 1662 | func (wv *WebView) SetOnReadyToShow(fn func()) { | |
| 1663 | + | if wv == nil { | |
| 1664 | + | return | |
| 1665 | + | } | |
| 1666 | + | wv.mu.Lock() | |
| 1666 | 1667 | wv.OnReadyToShow = fn | |
| 1668 | + | wv.mu.Unlock() | |
| 1667 | 1669 | } | |
| 1668 | 1670 | ||
| 1669 | - | // SetOnClose composes fn with any existing OnClose handler so multiple callers | |
| 1670 | - | // can each register a close callback without overwriting one another. | |
| 1671 | - | // It implements port.PopupLifecycleCapable. | |
| 1671 | + | // SetOnClose replaces the coordinator-owned popup lifecycle callback without | |
| 1672 | + | // disturbing WebView callbacks or additive OAuth close callbacks. | |
| 1672 | 1673 | func (wv *WebView) SetOnClose(fn func()) { | |
| 1673 | - | existing := wv.OnClose | |
| 1674 | - | if existing == nil { | |
| 1675 | - | wv.OnClose = fn | |
| 1674 | + | if wv == nil { | |
| 1676 | 1675 | return | |
| 1677 | 1676 | } | |
| 1678 | - | if fn == nil { | |
| 1677 | + | wv.mu.Lock() | |
| 1678 | + | wv.popupLifecycleClose = fn | |
| 1679 | + | wv.mu.Unlock() | |
| 1680 | + | } | |
| 1681 | + | ||
| 1682 | + | func (wv *WebView) fireReadyToShow() { | |
| 1683 | + | if wv == nil { | |
| 1679 | 1684 | return | |
| 1680 | 1685 | } | |
| 1681 | - | wv.OnClose = func() { | |
| 1682 | - | existing() | |
| 1686 | + | wv.mu.RLock() | |
| 1687 | + | fn := wv.OnReadyToShow | |
| 1688 | + | wv.mu.RUnlock() | |
| 1689 | + | if fn != nil { | |
| 1683 | 1690 | fn() | |
| 1684 | 1691 | } | |
| 1685 | 1692 | } | |
| 1686 | 1693 | ||
| 1694 | + | func (wv *WebView) runCloseCallbacks() { | |
| 1695 | + | if wv == nil { | |
| 1696 | + | return | |
| 1697 | + | } | |
| 1698 | + | wv.mu.Lock() | |
| 1699 | + | base := wv.OnClose | |
| 1700 | + | lifecycle := wv.popupLifecycleClose | |
| 1701 | + | wv.popupLifecycleClose = nil | |
| 1702 | + | wv.mu.Unlock() | |
| 1703 | + | if base != nil { | |
| 1704 | + | base() | |
| 1705 | + | } | |
| 1706 | + | if lifecycle != nil { | |
| 1707 | + | lifecycle() | |
| 1708 | + | } | |
| 1709 | + | } | |
| 1710 | + | ||
| 1687 | 1711 | // State returns the current WebView state as a snapshot. | |
| 1688 | 1712 | func (wv *WebView) State() port.WebViewState { | |
| 1689 | 1713 | return port.WebViewState{ | |
| @@ -1842,9 +1866,7 @@ func (wv *WebView) Close() { | |||
| 1842 | 1866 | if wv.destroyed.Load() { | |
| 1843 | 1867 | return | |
| 1844 | 1868 | } | |
| 1845 | - | if wv.OnClose != nil { | |
| 1846 | - | wv.OnClose() | |
| 1847 | - | } | |
| 1869 | + | wv.runCloseCallbacks() | |
| 1848 | 1870 | } | |
| 1849 | 1871 | ||
| 1850 | 1872 | // AddCloseCallback implements port.OAuthCallbackCapable. | |
| @@ -1980,6 +2002,7 @@ func (wv *WebView) DestroyWithPolicy(policy string) { | |||
| 1980 | 2002 | wv.browsingContextDecision = dto.HostDecision{} | |
| 1981 | 2003 | wv.hasBrowsingContextDecision = false | |
| 1982 | 2004 | wv.nativePopupHostAbort = nil | |
| 2005 | + | wv.popupLifecycleClose = nil | |
| 1983 | 2006 | wv.mu.Unlock() | |
| 1984 | 2007 | ||
| 1985 | 2008 | // 4. Unparent from GTK hierarchy (must happen before process termination) | |
| @@ -2050,6 +2073,7 @@ func (wv *WebView) ResetForPoolReuse() { | |||
| 2050 | 2073 | wv.browsingContextDecision = dto.HostDecision{} | |
| 2051 | 2074 | wv.hasBrowsingContextDecision = false | |
| 2052 | 2075 | wv.nativePopupHostAbort = nil | |
| 2076 | + | wv.popupLifecycleClose = nil | |
| 2053 | 2077 | wv.lastProgressUpdate.Store(0) | |
| 2054 | 2078 | wv.mu.Unlock() | |
| 2055 | 2079 | ||
| @@ -155,6 +155,7 @@ type WebView struct { | |||||
| 155 | OnProgressChanged func(float64) | 155 | OnProgressChanged func(float64) | ||
| 156 | OnFaviconChanged func(*gdk.Texture) // Called when page favicon changes | 156 | OnFaviconChanged func(*gdk.Texture) // Called when page favicon changes | ||
| 157 | OnClose func() | 157 | OnClose func() | ||
| 158 | + | popupLifecycleClose func() | |||
| 158 | OnCreate func(PopupRequest) *WebView // Return new WebView or nil to block popup | 159 | OnCreate func(PopupRequest) *WebView // Return new WebView or nil to block popup | ||
| 159 | OnReadyToShow func() // Called when popup is ready to display | 160 | OnReadyToShow func() // Called when popup is ready to display | ||
| 160 | OnLinkMiddleClick func(uri string) bool // Return true if handled (blocks navigation) | 161 | OnLinkMiddleClick func(uri string) bool // Return true if handled (blocks navigation) | ||
| @@ -515,9 +516,7 @@ func (wv *WebView) connectWebProcessResponsiveSignal() { | |||||
| 515 | 516 | ||||
| 516 | func (wv *WebView) connectCloseSignal() { | 517 | func (wv *WebView) connectCloseSignal() { | ||
| 517 | closeCb := func(_ webkit.WebView) { | 518 | closeCb := func(_ webkit.WebView) { | ||
| 518 | - | if wv.OnClose != nil { | 519 | + | wv.runCloseCallbacks() |
| 519 | - | wv.OnClose() | |||
| 520 | - | } | |||
| 521 | } | 520 | } | ||
| 522 | sigID := wv.inner.ConnectClose(&closeCb) | 521 | sigID := wv.inner.ConnectClose(&closeCb) | ||
| 523 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | 522 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | ||
| @@ -633,9 +632,7 @@ func (wv *WebView) connectCreateSignal() { | |||||
| 633 | 632 | ||||
| 634 | func (wv *WebView) connectReadyToShowSignal() { | 633 | func (wv *WebView) connectReadyToShowSignal() { | ||
| 635 | readyToShowCb := func(_ webkit.WebView) { | 634 | readyToShowCb := func(_ webkit.WebView) { | ||
| 636 | - | if wv.OnReadyToShow != nil { | 635 | + | wv.fireReadyToShow() |
| 637 | - | wv.OnReadyToShow() | |||
| 638 | - | } | |||
| 639 | } | 636 | } | ||
| 640 | sigID := wv.inner.ConnectReadyToShow(&readyToShowCb) | 637 | sigID := wv.inner.ConnectReadyToShow(&readyToShowCb) | ||
| 641 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | 638 | wv.signalIDs = append(wv.signalIDs, uintptr(sigID)) | ||
| @@ -1663,27 +1660,54 @@ func (*WebView) PrimePopupNavigation(string) {} | |||||
| 1663 | // SetOnReadyToShow sets the callback invoked when the popup WebView is ready to display. | 1660 | // SetOnReadyToShow sets the callback invoked when the popup WebView is ready to display. | ||
| 1664 | // It implements port.PopupLifecycleCapable. | 1661 | // It implements port.PopupLifecycleCapable. | ||
| 1665 | func (wv *WebView) SetOnReadyToShow(fn func()) { | 1662 | func (wv *WebView) SetOnReadyToShow(fn func()) { | ||
| 1663 | + | if wv == nil { | |||
| 1664 | + | return | |||
| 1665 | + | } | |||
| 1666 | + | wv.mu.Lock() | |||
| 1666 | wv.OnReadyToShow = fn | 1667 | wv.OnReadyToShow = fn | ||
| 1668 | + | wv.mu.Unlock() | |||
| 1667 | } | 1669 | } | ||
| 1668 | 1670 | ||||
| 1669 | - | // SetOnClose composes fn with any existing OnClose handler so multiple callers | 1671 | + | // SetOnClose replaces the coordinator-owned popup lifecycle callback without |
| 1670 | - | // can each register a close callback without overwriting one another. | 1672 | + | // disturbing WebView callbacks or additive OAuth close callbacks. |
| 1671 | - | // It implements port.PopupLifecycleCapable. | |||
| 1672 | func (wv *WebView) SetOnClose(fn func()) { | 1673 | func (wv *WebView) SetOnClose(fn func()) { | ||
| 1673 | - | existing := wv.OnClose | 1674 | + | if wv == nil { |
| 1674 | - | if existing == nil { | |||
| 1675 | - | wv.OnClose = fn | |||
| 1676 | return | 1675 | return | ||
| 1677 | } | 1676 | } | ||
| 1678 | - | if fn == nil { | 1677 | + | wv.mu.Lock() |
| 1678 | + | wv.popupLifecycleClose = fn | |||
| 1679 | + | wv.mu.Unlock() | |||
| 1680 | + | } | |||
| 1681 | + | ||||
| 1682 | + | func (wv *WebView) fireReadyToShow() { | |||
| 1683 | + | if wv == nil { | |||
| 1679 | return | 1684 | return | ||
| 1680 | } | 1685 | } | ||
| 1681 | - | wv.OnClose = func() { | 1686 | + | wv.mu.RLock() |
| 1682 | - | existing() | 1687 | + | fn := wv.OnReadyToShow |
| 1688 | + | wv.mu.RUnlock() | |||
| 1689 | + | if fn != nil { | |||
| 1683 | fn() | 1690 | fn() | ||
| 1684 | } | 1691 | } | ||
| 1685 | } | 1692 | } | ||
| 1686 | 1693 | ||||
| 1694 | + | func (wv *WebView) runCloseCallbacks() { | |||
| 1695 | + | if wv == nil { | |||
| 1696 | + | return | |||
| 1697 | + | } | |||
| 1698 | + | wv.mu.Lock() | |||
| 1699 | + | base := wv.OnClose | |||
| 1700 | + | lifecycle := wv.popupLifecycleClose | |||
| 1701 | + | wv.popupLifecycleClose = nil | |||
| 1702 | + | wv.mu.Unlock() | |||
| 1703 | + | if base != nil { | |||
| 1704 | + | base() | |||
| 1705 | + | } | |||
| 1706 | + | if lifecycle != nil { | |||
| 1707 | + | lifecycle() | |||
| 1708 | + | } | |||
| 1709 | + | } | |||
| 1710 | + | ||||
| 1687 | // State returns the current WebView state as a snapshot. | 1711 | // State returns the current WebView state as a snapshot. | ||
| 1688 | func (wv *WebView) State() port.WebViewState { | 1712 | func (wv *WebView) State() port.WebViewState { | ||
| 1689 | return port.WebViewState{ | 1713 | return port.WebViewState{ | ||
| @@ -1842,9 +1866,7 @@ func (wv *WebView) Close() { | |||||
| 1842 | if wv.destroyed.Load() { | 1866 | if wv.destroyed.Load() { | ||
| 1843 | return | 1867 | return | ||
| 1844 | } | 1868 | } | ||
| 1845 | - | if wv.OnClose != nil { | 1869 | + | wv.runCloseCallbacks() |
| 1846 | - | wv.OnClose() | |||
| 1847 | - | } | |||
| 1848 | } | 1870 | } | ||
| 1849 | 1871 | ||||
| 1850 | // AddCloseCallback implements port.OAuthCallbackCapable. | 1872 | // AddCloseCallback implements port.OAuthCallbackCapable. | ||
| @@ -1980,6 +2002,7 @@ func (wv *WebView) DestroyWithPolicy(policy string) { | |||||
| 1980 | wv.browsingContextDecision = dto.HostDecision{} | 2002 | wv.browsingContextDecision = dto.HostDecision{} | ||
| 1981 | wv.hasBrowsingContextDecision = false | 2003 | wv.hasBrowsingContextDecision = false | ||
| 1982 | wv.nativePopupHostAbort = nil | 2004 | wv.nativePopupHostAbort = nil | ||
| 2005 | + | wv.popupLifecycleClose = nil | |||
| 1983 | wv.mu.Unlock() | 2006 | wv.mu.Unlock() | ||
| 1984 | 2007 | ||||
| 1985 | // 4. Unparent from GTK hierarchy (must happen before process termination) | 2008 | // 4. Unparent from GTK hierarchy (must happen before process termination) | ||
| @@ -2050,6 +2073,7 @@ func (wv *WebView) ResetForPoolReuse() { | |||||
| 2050 | wv.browsingContextDecision = dto.HostDecision{} | 2073 | wv.browsingContextDecision = dto.HostDecision{} | ||
| 2051 | wv.hasBrowsingContextDecision = false | 2074 | wv.hasBrowsingContextDecision = false | ||
| 2052 | wv.nativePopupHostAbort = nil | 2075 | wv.nativePopupHostAbort = nil | ||
| 2076 | + | wv.popupLifecycleClose = nil | |||
| 2053 | wv.lastProgressUpdate.Store(0) | 2077 | wv.lastProgressUpdate.Store(0) | ||
| 2054 | wv.mu.Unlock() | 2078 | wv.mu.Unlock() | ||
| 2055 | 2079 | ||||
A internal/infrastructure/webkit/webview_popup_lifecycle_test.go +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | package webkit | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "testing" | |
| 5 | + | ||
| 6 | + | "github.com/stretchr/testify/assert" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | func TestPopupLifecycleCallbacksCanBeDisarmed(t *testing.T) { | |
| 10 | + | wv := &WebView{} | |
| 11 | + | readyCalls := 0 | |
| 12 | + | lifecycleCloseCalls := 0 | |
| 13 | + | oauthCloseCalls := 0 | |
| 14 | + | wv.SetOnReadyToShow(func() { readyCalls++ }) | |
| 15 | + | wv.SetOnClose(func() { lifecycleCloseCalls++ }) | |
| 16 | + | wv.AddCloseCallback(func() { oauthCloseCalls++ }) | |
| 17 | + | ||
| 18 | + | wv.SetOnReadyToShow(nil) | |
| 19 | + | wv.SetOnClose(nil) | |
| 20 | + | wv.fireReadyToShow() | |
| 21 | + | wv.runCloseCallbacks() | |
| 22 | + | ||
| 23 | + | assert.Zero(t, readyCalls) | |
| 24 | + | assert.Zero(t, lifecycleCloseCalls) | |
| 25 | + | assert.Equal(t, 1, oauthCloseCalls) | |
| 26 | + | } | |
| @@ -0,0 +1,26 @@ | |||||
| 1 | + | package webkit | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "testing" | |||
| 5 | + | ||||
| 6 | + | "github.com/stretchr/testify/assert" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | func TestPopupLifecycleCallbacksCanBeDisarmed(t *testing.T) { | |||
| 10 | + | wv := &WebView{} | |||
| 11 | + | readyCalls := 0 | |||
| 12 | + | lifecycleCloseCalls := 0 | |||
| 13 | + | oauthCloseCalls := 0 | |||
| 14 | + | wv.SetOnReadyToShow(func() { readyCalls++ }) | |||
| 15 | + | wv.SetOnClose(func() { lifecycleCloseCalls++ }) | |||
| 16 | + | wv.AddCloseCallback(func() { oauthCloseCalls++ }) | |||
| 17 | + | ||||
| 18 | + | wv.SetOnReadyToShow(nil) | |||
| 19 | + | wv.SetOnClose(nil) | |||
| 20 | + | wv.fireReadyToShow() | |||
| 21 | + | wv.runCloseCallbacks() | |||
| 22 | + | ||||
| 23 | + | assert.Zero(t, readyCalls) | |||
| 24 | + | assert.Zero(t, lifecycleCloseCalls) | |||
| 25 | + | assert.Equal(t, 1, oauthCloseCalls) | |||
| 26 | + | } | |||