Skip to content

Commit

Permalink
add tests for mime types
Browse files Browse the repository at this point in the history
  • Loading branch information
becky-gilbert committed Jan 16, 2025
1 parent c1918f3 commit 61de658
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 1 deletion.
98 changes: 97 additions & 1 deletion packages/record/src/recorder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jest.mock("jspsych", () => ({
pluginAPI: {
getCameraRecorder: jest.fn().mockReturnValue({
addEventListener: jest.fn(),
mimeType: "video/webm",
start: jest.fn(),
stop: jest.fn(),
stream: {
Expand Down Expand Up @@ -356,7 +357,7 @@ test("Recorder reset", () => {
expect(jsPsych.pluginAPI.initializeCameraRecorder).toHaveBeenCalledTimes(1);
expect(jsPsych.pluginAPI.initializeCameraRecorder).toHaveBeenCalledWith(
streamClone,
undefined,
{ mimeType: "video/webm" },
);
expect(rec["blobs"]).toStrictEqual([]);

Expand Down Expand Up @@ -506,3 +507,98 @@ test("Recorder createFileName constructs video file names correctly", () => {
// Restore Math.random
jest.spyOn(global.Math, "random").mockRestore();
});

test("Initializing a new recorder gets the mime type from the initialization", () => {
const jsPsych = initJsPsych();
const originalInitializeCameraRecorder =
jsPsych.pluginAPI.initializeCameraRecorder;

const stream = {
active: true,
clone: jest.fn(),
getTracks: jest.fn().mockReturnValue([{ stop: jest.fn() }]),
} as unknown as MediaStream;

jsPsych.pluginAPI.initializeCameraRecorder = jest
.fn()
.mockImplementation(
(stream: MediaStream, recorder_options: MediaRecorderOptions) => {
return {
addEventListener: jest.fn(),
mimeType: recorder_options.mimeType,
start: jest.fn(),
stop: jest.fn(),
stream: stream,
};
},
);

jsPsych.pluginAPI.getCameraRecorder = jest.fn().mockImplementation(() => {
return jsPsych.pluginAPI.initializeCameraRecorder(stream, recorder_options);
});

// Initialize with vp9
let recorder_options: MediaRecorderOptions = {
mimeType: "video/webm;codecs=vp9,opus",
};
jsPsych.pluginAPI.initializeCameraRecorder(stream, recorder_options);
const rec_1 = new Recorder(jsPsych);
// Called twice per construction - once for stream clone and once for mime type
expect(jsPsych.pluginAPI.getCameraRecorder).toHaveBeenCalledTimes(2);
expect(rec_1["mimeType"]).toBe("video/webm;codecs=vp9,opus");

// Initialize with vp8
recorder_options = {
mimeType: "video/webm;codecs=vp8,opus",
};
jsPsych.pluginAPI.initializeCameraRecorder(stream, recorder_options);
const rec_2 = new Recorder(jsPsych);
expect(jsPsych.pluginAPI.getCameraRecorder).toHaveBeenCalledTimes(4);
expect(rec_2["mimeType"]).toBe("video/webm;codecs=vp8,opus");

// Initialize with av1
recorder_options = {
mimeType: "video/webm;codecs=av1,opus",
};
jsPsych.pluginAPI.initializeCameraRecorder(stream, recorder_options);
const rec_3 = new Recorder(jsPsych);
expect(jsPsych.pluginAPI.getCameraRecorder).toHaveBeenCalledTimes(6);
expect(rec_3["mimeType"]).toBe("video/webm;codecs=av1,opus");

jsPsych.pluginAPI.initializeCameraRecorder = originalInitializeCameraRecorder;
});

test("New recorder uses a default mime type if none is set already", () => {
const jsPsych = initJsPsych();
const originalInitializeCameraRecorder =
jsPsych.pluginAPI.initializeCameraRecorder;

const stream = {
active: true,
clone: jest.fn(),
getTracks: jest.fn().mockReturnValue([{ stop: jest.fn() }]),
} as unknown as MediaStream;

jsPsych.pluginAPI.initializeCameraRecorder = jest
.fn()
.mockImplementation((stream: MediaStream) => {
return {
addEventListener: jest.fn(),
start: jest.fn(),
stop: jest.fn(),
stream: stream,
};
});

jsPsych.pluginAPI.getCameraRecorder = jest.fn().mockImplementation(() => {
return jsPsych.pluginAPI.initializeCameraRecorder(stream);
});

jsPsych.pluginAPI.initializeCameraRecorder(stream);
const rec = new Recorder(jsPsych);
// Called twice per construction - once for stream clone and once for mime type
expect(jsPsych.pluginAPI.getCameraRecorder).toHaveBeenCalledTimes(2);
expect(rec["mimeType"]).toBe("video/webm");

jsPsych.pluginAPI.initializeCameraRecorder = originalInitializeCameraRecorder;
});
140 changes: 140 additions & 0 deletions packages/record/src/videoConfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,30 @@ beforeEach(() => {
cameras: [devicesObj.cam1, devicesObj.cam2],
mics: [devicesObj.mic1, devicesObj.mic2],
};

// Global MediaRecorder.isTypeSupported
Object.defineProperty(global, "MediaRecorder", {
writable: true,
value: jest.fn().mockImplementation(() => ({
start: jest.fn(),
ondataavailable: jest.fn(),
onerror: jest.fn(),
state: "",
stop: jest.fn(),
pause: jest.fn(),
resume: jest.fn(),
})),
});

Object.defineProperty(MediaRecorder, "isTypeSupported", {
writable: true,
/**
* Placeholder for value
*
* @returns True
*/
value: () => true,
});
});

afterEach(() => {
Expand Down Expand Up @@ -1096,3 +1120,119 @@ test("Video config onMicActivityLevel", () => {
expect(video_config["micChecked"]).toBe(true);
expect(event_pass.resolve).toHaveBeenCalled();
});

test("Video config initializeAndCreateRecorder uses supported mime type", () => {
const getCompatibleMimeTypeSpy = jest.spyOn(
video_config,
"getCompatibleMimeType",
);

// getCameraRecorder is just a convenient way of grabbing the mock stream.
video_config["initializeAndCreateRecorder"](
jsPsych.pluginAPI.getCameraRecorder().stream,
);

expect(getCompatibleMimeTypeSpy).toHaveBeenCalled();
// isTypeSupported is already mocked to return true, so this should use the first mime type value in the list
expect(jsPsych.pluginAPI.initializeCameraRecorder).toHaveBeenCalledWith(
jsPsych.pluginAPI.getCameraRecorder().stream,
{ mimeType: "video/webm;codecs=vp9,opus" },
);
});

test("Video config initializeAndCreateRecorder uses default if no mime types are supported", () => {
const getCompatibleMimeTypeSpy = jest.spyOn(
video_config,
"getCompatibleMimeType",
);

// Override the isTypeSupported mock that is set in beforeEach
// No type is supported
jest.spyOn(MediaRecorder, "isTypeSupported").mockImplementation(() => {
return false;
});
expect(MediaRecorder.isTypeSupported("video/webm;codecs=vp9,opus")).toBe(
false,
);

// getCameraRecorder is just a convenient way of grabbing the mock stream.
video_config["initializeAndCreateRecorder"](
jsPsych.pluginAPI.getCameraRecorder().stream,
);

expect(getCompatibleMimeTypeSpy).toHaveBeenCalled();
// If there are no compatible mime types, then it should use the default "video/webm" for initialization.
expect(jsPsych.pluginAPI.initializeCameraRecorder).toHaveBeenCalledWith(
jsPsych.pluginAPI.getCameraRecorder().stream,
{ mimeType: "video/webm" },
);
});

test("Video config getCompatibleMimeType gets correct mime type or null", () => {
// Note - don't use 'mockImplementationOnce' for the isTypeSupported mock because isTypeSupported can be called multiple times by getCompatibleMimeType.

// Override the isTypeSupported mock that is set in beforeEach
// 1. only supports vp9,opus
const isTypeSupportedSpy = jest
.spyOn(MediaRecorder, "isTypeSupported")
.mockImplementation((type) => {
if (type == "video/webm;codecs=vp9,opus") {
return true;
} else {
return false;
}
});
const mime_type_1 = video_config["getCompatibleMimeType"]();
expect(mime_type_1).toBe("video/webm;codecs=vp9,opus");

// 2. only supports vp8,opus
isTypeSupportedSpy.mockImplementation((type) => {
if (type == "video/webm;codecs=vp8,opus") {
return true;
} else {
return false;
}
});
const mime_type_2 = video_config["getCompatibleMimeType"]();
expect(mime_type_2).toBe("video/webm;codecs=vp8,opus");

// 3. only supports av1,opus
isTypeSupportedSpy.mockImplementation((type) => {
if (type == "video/webm;codecs=av1,opus") {
return true;
} else {
return false;
}
});
const mime_type_3 = video_config["getCompatibleMimeType"]();
expect(mime_type_3).toBe("video/webm;codecs=av1,opus");

// 4. supports vp9,opus and av1,opus, should use the former
isTypeSupportedSpy.mockImplementation((type) => {
if (type == "video/webm;codecs=vp8,opus") {
return false;
} else {
return true;
}
});
const mime_type_4 = video_config["getCompatibleMimeType"]();
expect(mime_type_4).toBe("video/webm;codecs=vp9,opus");

// 5. supports vp8,opus and av1,opus, should use the former
isTypeSupportedSpy.mockImplementation((type) => {
if (type == "video/webm;codecs=vp9,opus") {
return false;
} else {
return true;
}
});
const mime_type_5 = video_config["getCompatibleMimeType"]();
expect(mime_type_5).toBe("video/webm;codecs=vp8,opus");

// 6. none supported, should return null
isTypeSupportedSpy.mockImplementation(() => {
return false;
});
const mime_type_6 = video_config["getCompatibleMimeType"]();
expect(mime_type_6).toBeNull();
});

0 comments on commit 61de658

Please sign in to comment.