From 86a8fee73f10a85d806ea8c2d7c48a01568a770c Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 18 Oct 2019 18:53:22 +0200 Subject: [PATCH] fix(snack-bar): handle large numbers passed in as duration (#17239) Handles very large numbers being passed in as a snack bar duration (e.g. `Infinity`). We need to cap the duration, otherwise the browser will revert it back to 1 if it's too large. Fixes #17234. --- src/material/snack-bar/snack-bar-ref.ts | 7 ++++++- src/material/snack-bar/snack-bar.spec.ts | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/material/snack-bar/snack-bar-ref.ts b/src/material/snack-bar/snack-bar-ref.ts index e8f8d800c4f7..adc03a7c267d 100644 --- a/src/material/snack-bar/snack-bar-ref.ts +++ b/src/material/snack-bar/snack-bar-ref.ts @@ -17,6 +17,9 @@ export interface MatSnackBarDismiss { dismissedByAction: boolean; } +/** Maximum amount of milliseconds that can be passed into setTimeout. */ +const MAX_TIMEOUT = Math.pow(2, 31) - 1; + /** * Reference to a snack bar dispatched from the snack bar service. */ @@ -85,7 +88,9 @@ export class MatSnackBarRef { /** Dismisses the snack bar after some duration */ _dismissAfter(duration: number): void { - this._durationTimeoutId = setTimeout(() => this.dismiss(), duration); + // Note that we need to cap the duration to the maximum value for setTimeout, because + // it'll revert to 1 if somebody passes in something greater (e.g. `Infinity`). See #17234. + this._durationTimeoutId = setTimeout(() => this.dismiss(), Math.min(duration, MAX_TIMEOUT)); } /** Marks the snackbar as opened */ diff --git a/src/material/snack-bar/snack-bar.spec.ts b/src/material/snack-bar/snack-bar.spec.ts index 1faf57d95bab..4435dd0ed0b9 100644 --- a/src/material/snack-bar/snack-bar.spec.ts +++ b/src/material/snack-bar/snack-bar.spec.ts @@ -496,6 +496,19 @@ describe('MatSnackBar', () => { expect(overlayContainerElement.childElementCount).toBe(0); })); + it('should cap the timeout to the maximum accepted delay in setTimeout', fakeAsync(() => { + const config = new MatSnackBarConfig(); + config.duration = Infinity; + snackBar.open('content', 'test', config); + viewContainerFixture.detectChanges(); + spyOn(window, 'setTimeout').and.callThrough(); + tick(100); + + expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), Math.pow(2, 31) - 1); + + flush(); + })); + describe('with custom component', () => { it('should open a custom component', () => { const snackBarRef = snackBar.openFromComponent(BurritosNotification);