()
| 755 | } |
| 756 | |
| 757 | async _afterSuite() { |
| 758 | // Reset leftover test-level cleanup state (e.g. screenshot failures) |
| 759 | // so only errors from this suite teardown are evaluated below. |
| 760 | this.hasCleanupError = false |
| 761 | this.testFailures = [] |
| 762 | |
| 763 | // Stop browser after suite completes |
| 764 | // For restart strategies: stop after each suite |
| 765 | // For session mode (restart:false): stop after the last suite |
| 766 | if (this.isRunning) { |
| 767 | try { |
| 768 | // Add timeout protection to prevent hanging |
| 769 | await Promise.race([this._stopBrowser(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in afterSuite')), 10000))]) |
| 770 | } catch (e) { |
| 771 | console.warn('Warning during suite cleanup:', e.message) |
| 772 | // Track suite cleanup failures |
| 773 | this.hasCleanupError = true |
| 774 | this.testFailures.push(`Suite cleanup failed: ${e.message}`) |
| 775 | // Force cleanup on timeout |
| 776 | this.browser = null |
| 777 | this.browserContext = null |
| 778 | this.isRunning = false |
| 779 | } finally { |
| 780 | this.isRunning = false |
| 781 | } |
| 782 | } |
| 783 | |
| 784 | // Force cleanup of any remaining browser processes |
| 785 | try { |
| 786 | if (this.browser && (!this.browser.isConnected || this.browser)) { |
| 787 | await Promise.race([Promise.resolve(), new Promise(resolve => setTimeout(resolve, 1000))]) |
| 788 | } |
| 789 | } catch (e) { |
| 790 | console.warn('Final cleanup warning:', e.message) |
| 791 | this.hasCleanupError = true |
| 792 | this.testFailures.push(`Final cleanup failed: ${e.message}`) |
| 793 | } |
| 794 | |
| 795 | // Clean up session pages explicitly to prevent hanging references |
| 796 | try { |
| 797 | if (this.sessionPages && Object.keys(this.sessionPages).length > 0) { |
| 798 | for (const sessionName in this.sessionPages) { |
| 799 | const sessionPage = this.sessionPages[sessionName] |
| 800 | if (sessionPage && !sessionPage.isClosed()) { |
| 801 | try { |
| 802 | // Remove any remaining event listeners from session pages |
| 803 | sessionPage.removeAllListeners('dialog') |
| 804 | sessionPage.removeAllListeners('crash') |
| 805 | sessionPage.removeAllListeners('close') |
| 806 | sessionPage.removeAllListeners('error') |
| 807 | await sessionPage.close() |
| 808 | } catch (e) { |
| 809 | console.warn(`Warning closing session page ${sessionName}:`, e.message) |
| 810 | } |
| 811 | } |
| 812 | } |
| 813 | this.sessionPages = {} // Clear the session pages object |
| 814 | this.activeSessionName = '' // Reset active session name |
nothing calls this directly
no test coverage detected