Skip to content

Commit

Permalink
capricorn86#475@minor: Add timeranges.
Browse files Browse the repository at this point in the history
  • Loading branch information
rudywaltz committed Jul 9, 2022
1 parent 054c907 commit 20c576c
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 45 deletions.
95 changes: 77 additions & 18 deletions packages/happy-dom/src/nodes/html-media-element/HTMLMediaElement.ts
Expand Up @@ -5,6 +5,23 @@ import DOMExceptionNameEnum from '../../exception/DOMExceptionNameEnum';
import HTMLElement from '../html-element/HTMLElement';
import IHTMLMediaElement, { IMediaError } from './IHTMLMediaElement';

/**
*
* This implementation coming from jsdom
* https://github.com/jsdom/jsdom/blob/master/lib/jsdom/living/nodes/HTMLMediaElement-impl.js#L7
*
*/
function getTimeRangeDummy(): object {
return {
length: 0,
start() {
return 0;
},
end() {
return 0;
}
};
}
/**
* HTML Base Element.
*
Expand All @@ -13,15 +30,27 @@ import IHTMLMediaElement, { IMediaError } from './IHTMLMediaElement';
*/
export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaElement {
// Public Properties
public readonly readyState = 0;
public readonly networkState = 0;
public readonly buffered = getTimeRangeDummy();
public readonly duration = NaN;
public readonly error: IMediaError = null;
public readonly ended = false;
public readonly duration = NaN;
public readonly networkState = 0;
public readonly readyState = 0;
public readonly textTracks = [];
public readonly videoTracks = [];
public readonly seeking = false;
public readonly seekable = getTimeRangeDummy();
public readonly played = getTimeRangeDummy();

// Events
public onabort: (event: Event) => void = null;
public oncanplay: (event: Event) => void = null;
public oncanplaythrough: (event: Event) => void = null;
public ondurationchange: (event: Event) => void = null;
public onemptied: (event: Event) => void = null;
public onended: (event: Event) => void = null;
public onerror: (event: ErrorEvent) => void = null;
public onloadeddata: (event: Event) => void = null;

#volume = 1;
#paused = true;
Expand Down Expand Up @@ -102,7 +131,15 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
* @returns Muted.
*/
public get muted(): boolean {
return this.#muted;
if (this.#muted) {
return this.#muted;
}

if (!this.#defaultMuted) {
return this.getAttributeNS(null, 'muted') !== null;
}

return false;
}

/**
Expand All @@ -111,7 +148,7 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
* @param muted Muted.
*/
public set muted(muted: boolean) {
this.muted = Boolean(muted);
this.#muted = !!muted;
if (!muted && !this.#defaultMuted) {
this.removeAttributeNS(null, 'muted');
} else {
Expand All @@ -134,7 +171,7 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
* @param defaultMuted DefaultMuted.
*/
public set defaultMuted(defaultMuted: boolean) {
this.#defaultMuted = Boolean(defaultMuted);
this.#defaultMuted = !!defaultMuted;
if (!this.#defaultMuted && !this.#muted) {
this.removeAttributeNS(null, 'muted');
} else {
Expand All @@ -160,6 +197,7 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
this.setAttributeNS(null, 'src', src);
if (Boolean(src)) {
this.dispatchEvent(new Event('canplay', { bubbles: false, cancelable: false }));
this.dispatchEvent(new Event('durationchange', { bubbles: false, cancelable: false }));
}
}

Expand Down Expand Up @@ -230,15 +268,6 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
}
}

/**
* Returns paused.
*
* @returns Paused.
*/
public get paused(): boolean {
return this.#paused;
}

/**
* Returns currentTime.
*
Expand Down Expand Up @@ -330,14 +359,42 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
}

/**
* Returns preload.
*
* @returns preload.
*/
public get preload(): string {
return this.getAttributeNS(null, 'preload') || 'auto';
}

/**
* Sets preload.
*
* @param preload preload.
*/
public set preload(preload: string) {
this.setAttributeNS(null, 'preload', preload);
}

/**
* Returns paused.
*
* @returns Paused.
*/
public get paused(): boolean {
return this.#paused;
}

/**
* Pause played media
*/
public pause(): void {
this.#paused = true;
this.dispatchEvent(new Event('pause', { bubbles: false, cancelable: false }));
}

/**
*
* Start playing media
*/
public async play(): Promise<void> {
this.#paused = false;
Expand All @@ -353,9 +410,11 @@ export default class HTMLMediaElement extends HTMLElement implements IHTMLMediaE
}

/**
*
* Load media
*/
public load(): void {}
public load(): void {
this.dispatchEvent(new Event('emptied', { bubbles: false, cancelable: false }));
}

/**
*
Expand Down
Expand Up @@ -17,40 +17,34 @@ export default interface IHTMLMediaElement extends IHTMLElement {
readonly ended: boolean;
readonly error: IMediaError | null;
readonly networkState: number;
readonly played: object; // TimeRanges https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
readonly readyState: number;
readonly seekable: object; // TimeRanges https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
readonly seeking: boolean;
readonly textTracks: object[];
readonly videoTracks: object[];
readonly buffered: object; // TimeRanges https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
autoplay: boolean;
controls: boolean;
crossOrigin: string; // Only anonymus and 'use-credentials' is valid
currentTime: number | string;
defaultMuted: boolean;
defaultPlaybackRate: number | string;
loop: boolean;
muted: boolean;
paused: boolean;
volume: number | string;
src: string;
currentTime: number | string;
playbackRate: number | string;
defaultPlaybackRate: number | string;
defaultMuted: boolean;
preload: string;
preservesPitch: boolean;

// Buffered; // TODO tameranges
// Played: // TODO timeranges
// Seekable: // TODO timeranges

// CaptureStream; // TODO https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream

/**
* 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.
*/

pause(): void;
src: string;
volume: number | string;

/**
* The HTMLMediaElement play() method attempts to begin playback of the media. It returns a Promise
* which is resolved when playback has been successfully started.
* A MediaStream object which can be used as a source for audio and/or video data by other media processing code,
* or as a source for WebRTC.
* Https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream
*/
play(): Promise<void>;
captureStream(): object;

/**
* The HTMLMediaElement method canPlayType() reports how likely it is that the current browser will be able to play
Expand All @@ -68,12 +62,16 @@ export default interface IHTMLMediaElement extends IHTMLElement {
load(): void;

/**
* A MediaStream object which can be used as a source for audio and/or video data by other media processing code,
* or as a source for WebRTC.
* Https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream.
* 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.
*/
pause(): void;

captureStream(): object;
/**
* The HTMLMediaElement play() method attempts to begin playback of the media. It returns a Promise
* which is resolved when playback has been successfully started.
*/
play(): Promise<void>;

/**
* Clones a node.
Expand Down
Expand Up @@ -21,7 +21,7 @@ describe('HTMLMediaElement', () => {
jest.restoreAllMocks();
});

for (const property of ['autoplay', 'controls', 'loop', 'muted']) {
for (const property of ['autoplay', 'controls', 'loop']) {
describe(`get ${property}()`, () => {
it('Returns attribute value.', () => {
expect(element[property]).toBe(false);
Expand All @@ -44,7 +44,7 @@ describe('HTMLMediaElement', () => {
});
}

for (const property of ['src']) {
for (const property of ['src', 'preload']) {
describe(`get ${property}()`, () => {
it(`Returns the "${property}" attribute.`, () => {
element.setAttribute(property, 'test');
Expand Down Expand Up @@ -81,6 +81,38 @@ describe('HTMLMediaElement', () => {
});
});

describe(`get muted()`, () => {
it('Returns value.', () => {
element.setAttribute('muted', '');
expect(element.muted).toBe(true);
});
it('Returns setter value.', () => {
element.muted = true;
expect(element.muted).toBe(true);
});
});

describe(`set muted()`, () => {
it('Sets attribute value.', () => {
element.muted = true;
expect(element.getAttribute('muted')).toBe('');
});

it('Remove attribute value.', () => {
element.setAttribute('muted', '');
element.muted = false;
expect(element.getAttribute('muted')).toBeNull();
});

it('Keep attribute value, if default muted true', () => {
element.setAttribute('muted', '');
element.defaultMuted = true;
element.muted = false;
expect(element.getAttribute('muted')).toBe('');
expect(element.muted).toBe(false);
});
});

describe('canplay event', () => {
it('Should dispatch after src set', () => {
let dispatchedEvent: Event = null;
Expand Down Expand Up @@ -297,4 +329,16 @@ describe('HTMLMediaElement', () => {
expect(element.readyState).toBe(0);
});
});

describe('load', () => {
it('Dispatch emptied event', () => {
let dispatchedEvent: Event = null;
element.addEventListener('emptied', (event: Event) => (dispatchedEvent = event));

element.load();

expect(dispatchedEvent.cancelable).toBe(false);
expect(dispatchedEvent.bubbles).toBe(false);
});
});
});

0 comments on commit 20c576c

Please sign in to comment.