rx-player
Version:
Canal+ HTML5 Video Player
375 lines (348 loc) • 11.2 kB
text/typescript
import { describe, beforeEach, afterEach, it, expect, vi } from "vitest";
import isNullOrUndefined from "../../../../../utils/is_null_or_undefined";
import probeDecodingInfos from "../../probers/decodingInfo";
import type { IMediaConfiguration } from "../../types";
import { ProberStatus } from "../../types";
const origDecodingInfo = navigator.mediaCapabilities;
const origMediaCapabilities = navigator.mediaCapabilities;
/**
* Stub decodingInfo API to resolve.
* @param {boolean} isSupported
* @param {undefined|boolean} mustReject
*/
function stubDecodingInfo(isSupported: boolean, mustReject?: boolean) {
const decodingInfoStub = vi.fn(() => {
if (mustReject === true) {
return Promise.reject();
} else {
return Promise.resolve({
supported: isSupported,
});
}
});
const mockMediaCapabilities = {
decodingInfo: decodingInfoStub,
};
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
navigator.mediaCapabilities = mockMediaCapabilities;
return decodingInfoStub;
}
/**
* Reset decodingInfo to native implementation.
*/
function resetDecodingInfos(): void {
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
navigator.mediaCapabilities = origDecodingInfo;
}
describe("MediaCapabilitiesProber probers - decodingInfo", () => {
beforeEach(() => {
vi.resetModules();
});
afterEach(() => {
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
navigator.mediaCapabilities = origMediaCapabilities;
});
it("should throw if no video and audio config", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration = {
type: "media-source" as const,
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(() => {
resetDecodingInfos();
})
.catch(({ message }: { message: string }) => {
expect(message).toEqual(
"MediaCapabilitiesProber >>> API_CALL: " +
"Not enough arguments for calling mediaCapabilites.",
);
expect(decodingInfoStub).not.toHaveBeenCalled();
resetDecodingInfos();
});
});
it("should throw if incomplete video config", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration = {
type: "media-source" as const,
video: {
contentType: "video/wmv",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(() => {
resetDecodingInfos();
})
.catch(({ message }: { message: string }) => {
expect(message).toEqual(
"MediaCapabilitiesProber >>> API_CALL: " +
"Not enough arguments for calling mediaCapabilites.",
);
expect(decodingInfoStub).not.toHaveBeenCalled();
resetDecodingInfos();
});
});
it("should throw if incomplete audio config", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration = {
type: "media-source" as const,
audio: {
contentType: "audio/wma",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(() => {
resetDecodingInfos();
})
.catch(({ message }: { message: string }) => {
expect(message).toEqual(
"MediaCapabilitiesProber >>> API_CALL: " +
"Not enough arguments for calling mediaCapabilites.",
);
expect(decodingInfoStub).not.toHaveBeenCalled();
resetDecodingInfos();
});
});
it("should throw if no type in config", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration = {
audio: {
contentType: "audio/wma",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(() => {
resetDecodingInfos();
})
.catch(({ message }: { message: string }) => {
expect(message).toEqual(
"MediaCapabilitiesProber >>> API_CALL: " +
"Not enough arguments for calling mediaCapabilites.",
);
expect(decodingInfoStub).not.toHaveBeenCalled();
resetDecodingInfos();
});
});
it("should throw if empty config", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration = {};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(() => {
resetDecodingInfos();
})
.catch(({ message }: { message: string }) => {
expect(message).toEqual(
"MediaCapabilitiesProber >>> API_CALL: " +
"Not enough arguments for calling mediaCapabilites.",
);
expect(decodingInfoStub).not.toHaveBeenCalled();
resetDecodingInfos();
});
});
it("should throw if API mediaCapabilities not available", async () => {
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
delete navigator.mediaCapabilities;
await expect(probeDecodingInfos({})).rejects.toThrowError(
"MediaCapabilitiesProber >>> API_CALL: MediaCapabilities API not available",
);
});
it("should throw if API decodingInfo not available", async () => {
if (!isNullOrUndefined(navigator.mediaCapabilities)) {
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
delete navigator.mediaCapabilities.decodingInfo;
} else {
// @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for
// now, we're going through JSDom through so that's OK.
navigator.mediaCapabilities = {};
}
await expect(probeDecodingInfos({})).rejects.toThrowError(
"MediaCapabilitiesProber >>> API_CALL: Decoding Info not available",
);
});
it("should resolve with `Supported` if decodingInfo supports (video only)", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration: IMediaConfiguration = {
type: "media-source",
video: {
contentType: "audio/wma",
bitrate: 5000,
framerate: "24",
height: 1080,
width: 1920,
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.Supported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should resolve with `Supported` if decodingInfo supports (audio only)", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration: IMediaConfiguration = {
type: "media-source",
audio: {
contentType: "audio/wma",
bitrate: 5000,
samplerate: 44100,
channels: "5.1",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.Supported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should resolve with `Supported` if decodingInfo supports video + audio", () => {
const decodingInfoStub = stubDecodingInfo(true);
const configuration: IMediaConfiguration = {
type: "media-source",
video: {
contentType: "audio/wma",
bitrate: 5000,
framerate: "24",
height: 1080,
width: 1920,
},
audio: {
contentType: "audio/wma",
bitrate: 5000,
samplerate: 44100,
channels: "5.1",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.Supported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should return `NotSupported` if no decodingInfo support (video only)", () => {
const decodingInfoStub = stubDecodingInfo(false);
const configuration: IMediaConfiguration = {
type: "media-source",
video: {
contentType: "audio/wma",
bitrate: 5000,
framerate: "24",
height: 1080,
width: 1920,
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.NotSupported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should return `NotSupported` if no decodingInfo support (audio only)", () => {
const decodingInfoStub = stubDecodingInfo(false);
const configuration: IMediaConfiguration = {
type: "media-source",
audio: {
contentType: "audio/wma",
bitrate: 5000,
samplerate: 44100,
channels: "5.1",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.NotSupported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should return `NotSupported` if no decodingInfo support", () => {
const decodingInfoStub = stubDecodingInfo(false);
const configuration: IMediaConfiguration = {
type: "media-source",
video: {
contentType: "audio/wma",
bitrate: 5000,
framerate: "24",
height: 1080,
width: 1920,
},
audio: {
contentType: "audio/wma",
bitrate: 5000,
samplerate: 44100,
channels: "5.1",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.NotSupported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
it("should resolve with `NotSupported` if decodingInfo throws", () => {
const decodingInfoStub = stubDecodingInfo(true, true);
const configuration: IMediaConfiguration = {
type: "media-source",
video: {
contentType: "audio/wma",
bitrate: 5000,
framerate: "24",
height: 1080,
width: 1920,
},
audio: {
contentType: "audio/wma",
bitrate: 5000,
samplerate: 44100,
channels: "5.1",
},
};
expect.assertions(2);
return probeDecodingInfos(configuration)
.then(([res]) => {
expect(res).toBe(ProberStatus.NotSupported);
expect(decodingInfoStub).toHaveBeenCalledTimes(1);
resetDecodingInfos();
})
.catch(() => {
resetDecodingInfos();
});
});
});