From fefac9f756f68f19f68ec95c29f094946fc4c2d1 Mon Sep 17 00:00:00 2001 From: rudywaltz Date: Sun, 12 Jun 2022 00:08:06 +0200 Subject: [PATCH] #475@minor: Add playbackRate to HTMLMediaElement. --- .../html-media-element/HTMLMediaElement.ts | 60 +++++++++++++- .../html-media-element/IHTMLMediaElement.ts | 7 +- .../HTMLMediaElement.test.ts | 78 +++++++++++++++++++ 3 files changed, 140 insertions(+), 5 deletions(-) diff --git a/packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts b/packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts index 214d2b8f..4832ac2f 100644 --- a/packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts +++ b/packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts @@ -15,6 +15,8 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE #paused = true; #duration = NaN; #currentTime = 0; + #playbackRate = 1; + #defaultPlaybackRate = 1; /** * Returns autoplay. * @@ -222,8 +224,62 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE * * @param currentTime CurrentTime. */ - public set currentTime(currentTime: number) { - this.#currentTime = currentTime; + public set currentTime(currentTime: number | string) { + const parsedCurrentTime = Number(currentTime); + if (isNaN(parsedCurrentTime)) { + throw new TypeError( + `Failed to set the 'currentTime' property on 'HTMLMediaElement': The provided double value is non-finite.` + ); + } + this.#currentTime = parsedCurrentTime; + } + + /** + * Returns playbackRate. + * + * @returns playbackRate. + */ + public get playbackRate(): number { + return this.#playbackRate; + } + + /** + * Sets playbackRate. + * + * @param playbackRate playbackRate. + */ + public set playbackRate(playbackRate: number | string) { + const parsedPlaybackRate = Number(playbackRate); + if (isNaN(parsedPlaybackRate)) { + throw new TypeError( + `Failed to set the 'playbackRate' property on 'HTMLMediaElement': The provided double value is non-finite.` + ); + } + this.#playbackRate = parsedPlaybackRate; + } + + /** + * Returns defaultPlaybackRate. + * + * @returns defaultPlaybackRate. + */ + public get defaultPlaybackRate(): number { + return this.#defaultPlaybackRate; + } + + /** + * Sets defaultPlaybackRate. + * + * @param defaultPlaybackRate defaultPlaybackRate. + */ + public set defaultPlaybackRate(defaultPlaybackRate: number | string) { + const parsedDefaultPlaybackRate = Number(defaultPlaybackRate); + if (isNaN(parsedDefaultPlaybackRate)) { + throw new TypeError( + `Failed to set the 'defaultPlaybackRate' property on 'HTMLMediaElement': The provided double value is non-finite.` + ); + } + this.#defaultPlaybackRate = parsedDefaultPlaybackRate; } /** diff --git a/packages/happy-dom/src/nodes/html-media-element/IHTMLMediaElement.ts b/packages/happy-dom/src/nodes/html-media-element/IHTMLMediaElement.ts index 2c92b52a..48ae30b4 100644 --- a/packages/happy-dom/src/nodes/html-media-element/IHTMLMediaElement.ts +++ b/packages/happy-dom/src/nodes/html-media-element/IHTMLMediaElement.ts @@ -17,20 +17,21 @@ export default interface IHTMLMediaElement extends IHTMLElement { volume: number | string; src: string; crossOrigin: string; // Only anonymus and 'use-credentials' is valid - currentTime: number; + currentTime: number | string; + playbackRate: number | string; + defaultPlaybackRate: number | string; + // AddTextTrack; // Buffered; // TODO tameranges // CaptureStream; // TODO // ControlsList: string; // TODO // DefaultMuted: boolean; // TODO - // DefaultPlaybackRate; // TODO // DisableRemotePlayback: boolean; // TODO // Ended: boolean; // TODO readonly // Error; // TODO object // NetworkState; // TODO // Played: // TODO timeranges - // PlaybackRate: number; // TODO /** * The HTMLMediaElement.pause() method will pause playback of the media, if the media is already in a paused state this method will have no effect. diff --git a/packages/happy-dom/test/nodes/html-media-element/HTMLMediaElement.test.ts b/packages/happy-dom/test/nodes/html-media-element/HTMLMediaElement.test.ts index e59f54db..557f1e90 100644 --- a/packages/happy-dom/test/nodes/html-media-element/HTMLMediaElement.test.ts +++ b/packages/happy-dom/test/nodes/html-media-element/HTMLMediaElement.test.ts @@ -35,6 +35,12 @@ describe('HTMLMediaElement', () => { element[property] = true; expect(element.getAttribute(property)).toBe(''); }); + + it('Remove attribute value.', () => { + element.setAttribute(property, ''); + element[property] = false; + expect(element.getAttribute(property)).toBeNull(); + }); }); } @@ -70,6 +76,14 @@ describe('HTMLMediaElement', () => { }); }); + describe('currentSrc', () => { + it('Returns the current src', () => { + const src = 'https://src' + element.src = src; + expect(element.currentSrc).toBe(src); + }) + }) + describe('paused', () => { it('Default is true', () => { expect(element.paused).toBeTruthy(); @@ -137,12 +151,14 @@ describe('HTMLMediaElement', () => { it(`Set ${crossOrigin} as a valid crossOrigin`, () => { element.crossOrigin = crossOrigin; expect(element.getAttribute('crossorigin')).toBe(crossOrigin); + expect(element.crossOrigin).toBe(crossOrigin); }); } it(`Return 'anonymous' if crossOrigin is not valid`, () => { element.crossOrigin = 'randomString'; expect(element.getAttribute('crossorigin')).toBe('anonymous'); + expect(element.crossOrigin).toBe('anonymous'); }); }); @@ -160,5 +176,67 @@ describe('HTMLMediaElement', () => { element.currentTime = 42; expect(element.currentTime).toBe(42); }); + it('Set value as a string', () => { + element.currentTime = '42'; + expect(element.currentTime).toBe(42); + }); + + it('Throw type error if currentTime is not a number', () => { + expect(() => { + element.currentTime = 'zeropointfive'; + }).toThrowError( + new TypeError( + `Failed to set the 'currentTime' property on 'HTMLMediaElement': The provided double value is non-finite.` + ) + ); + }); + }); + + describe('playbackRate', () => { + it('Return default value', () => { + expect(element.playbackRate).toBe(1); + }); + it('Set value', () => { + element.playbackRate = 2.3; + expect(element.playbackRate).toBe(2.3); + }); + it('Set value as a string', () => { + element.playbackRate = '2.3'; + expect(element.playbackRate).toBe(2.3); + }); + + it('Throw type error if playbackRate is not a number', () => { + expect(() => { + element.playbackRate = 'zeropointfive'; + }).toThrowError( + new TypeError( + `Failed to set the 'playbackRate' property on 'HTMLMediaElement': The provided double value is non-finite.` + ) + ); + }); + }); + + describe('defaultPlaybackRate', () => { + it('Return default value', () => { + expect(element.defaultPlaybackRate).toBe(1); + }); + it('Set value', () => { + element.defaultPlaybackRate = 2.3; + expect(element.defaultPlaybackRate).toBe(2.3); + }); + it('Set value as a string', () => { + element.defaultPlaybackRate = '0.3'; + expect(element.defaultPlaybackRate).toBe(0.3); + }); + + it('Throw type error if defaultPlaybackRate is not a number', () => { + expect(() => { + element.defaultPlaybackRate = 'zeropointfive'; + }).toThrowError( + new TypeError( + `Failed to set the 'defaultPlaybackRate' property on 'HTMLMediaElement': The provided double value is non-finite.` + ) + ); + }); }); });