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);