@lookit/record 0.0.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -85
- package/dist/consentVideo.d.ts +10 -8
- package/dist/index.browser.js +86 -354
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.min.js +2 -2
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +85 -353
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +85 -353
- package/dist/index.js.map +1 -1
- package/dist/stop.d.ts +15 -4
- package/dist/{video_config.d.ts → videoConfig.d.ts} +36 -20
- package/package.json +3 -8
- package/src/consentVideo.ts +5 -4
- package/src/index.spec.ts +6 -2
- package/src/index.ts +1 -1
- package/src/stop.ts +11 -6
- package/src/{video_config.spec.ts → videoConfig.spec.ts} +70 -85
- package/src/{video_config.ts → videoConfig.ts} +70 -72
- package/src/{video_config_mic_check.spec.ts → videoConfig_mic_check.spec.ts} +1 -1
package/dist/stop.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { JsPsych, JsPsychPlugin } from "jspsych";
|
|
1
|
+
import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
|
|
2
2
|
declare const info: {
|
|
3
3
|
readonly name: "stop-record-plugin";
|
|
4
|
-
readonly parameters: {
|
|
4
|
+
readonly parameters: {
|
|
5
|
+
readonly locale: {
|
|
6
|
+
readonly type: ParameterType.STRING;
|
|
7
|
+
readonly default: "en-us";
|
|
8
|
+
};
|
|
9
|
+
};
|
|
5
10
|
};
|
|
6
11
|
type Info = typeof info;
|
|
7
12
|
/** Stop recording. Used by researchers who want to record across trials. */
|
|
@@ -9,7 +14,12 @@ export default class StopRecordPlugin implements JsPsychPlugin<Info> {
|
|
|
9
14
|
private jsPsych;
|
|
10
15
|
static readonly info: {
|
|
11
16
|
readonly name: "stop-record-plugin";
|
|
12
|
-
readonly parameters: {
|
|
17
|
+
readonly parameters: {
|
|
18
|
+
readonly locale: {
|
|
19
|
+
readonly type: ParameterType.STRING;
|
|
20
|
+
readonly default: "en-us";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
13
23
|
};
|
|
14
24
|
private recorder;
|
|
15
25
|
/**
|
|
@@ -24,7 +34,8 @@ export default class StopRecordPlugin implements JsPsychPlugin<Info> {
|
|
|
24
34
|
* @param display_element - DOM element where jsPsych content is being
|
|
25
35
|
* rendered (set in initJsPsych and automatically made available to a
|
|
26
36
|
* plugin's trial method via jsPsych core).
|
|
37
|
+
* @param trial - Trial object with parameters/values.
|
|
27
38
|
*/
|
|
28
|
-
trial(display_element: HTMLElement): void;
|
|
39
|
+
trial(display_element: HTMLElement, trial: TrialType<Info>): void;
|
|
29
40
|
}
|
|
30
41
|
export {};
|
|
@@ -3,6 +3,10 @@ declare const info: {
|
|
|
3
3
|
readonly name: "video-config-plugin";
|
|
4
4
|
readonly version: string;
|
|
5
5
|
readonly parameters: {
|
|
6
|
+
readonly locale: {
|
|
7
|
+
readonly type: ParameterType.STRING;
|
|
8
|
+
readonly default: "en-us";
|
|
9
|
+
};
|
|
6
10
|
readonly troubleshooting_intro: {
|
|
7
11
|
/**
|
|
8
12
|
* Optional string to appear at the start of the "Setup tips and
|
|
@@ -27,6 +31,30 @@ declare const info: {
|
|
|
27
31
|
};
|
|
28
32
|
type Info = typeof info;
|
|
29
33
|
export type VideoConsentTrialType = TrialType<Info>;
|
|
34
|
+
export declare const html_params: {
|
|
35
|
+
webcam_container_id: string;
|
|
36
|
+
reload_button_id_text: string;
|
|
37
|
+
reload_button_id_cam: string;
|
|
38
|
+
camera_selection_id: string;
|
|
39
|
+
mic_selection_id: string;
|
|
40
|
+
next_button_id: string;
|
|
41
|
+
error_msg_div_id: string;
|
|
42
|
+
step1_id: string;
|
|
43
|
+
step2_id: string;
|
|
44
|
+
step3_id: string;
|
|
45
|
+
step_complete_class: string;
|
|
46
|
+
waiting_for_access_msg_id: string;
|
|
47
|
+
checking_mic_msg_id: string;
|
|
48
|
+
access_problem_msg_id: string;
|
|
49
|
+
setup_problem_msg_id: string;
|
|
50
|
+
chromeInitialPrompt: any;
|
|
51
|
+
chromeAlwaysAllow: any;
|
|
52
|
+
chromePermissions: any;
|
|
53
|
+
firefoxInitialPrompt: any;
|
|
54
|
+
firefoxChooseDevice: any;
|
|
55
|
+
firefoxDevicesBlocked: any;
|
|
56
|
+
checkmarkIcon: any;
|
|
57
|
+
};
|
|
30
58
|
/**
|
|
31
59
|
* **Video Config**.
|
|
32
60
|
*
|
|
@@ -44,6 +72,10 @@ export default class VideoConfigPlugin implements JsPsychPlugin<Info> {
|
|
|
44
72
|
readonly name: "video-config-plugin";
|
|
45
73
|
readonly version: string;
|
|
46
74
|
readonly parameters: {
|
|
75
|
+
readonly locale: {
|
|
76
|
+
readonly type: ParameterType.STRING;
|
|
77
|
+
readonly default: "en-us";
|
|
78
|
+
};
|
|
47
79
|
readonly troubleshooting_intro: {
|
|
48
80
|
/**
|
|
49
81
|
* Optional string to appear at the start of the "Setup tips and
|
|
@@ -76,22 +108,6 @@ export default class VideoConfigPlugin implements JsPsychPlugin<Info> {
|
|
|
76
108
|
private minVolume;
|
|
77
109
|
private micChecked;
|
|
78
110
|
private processorNode;
|
|
79
|
-
private webcam_container_id;
|
|
80
|
-
private reload_button_id_text;
|
|
81
|
-
private reload_button_id_cam;
|
|
82
|
-
private camera_selection_id;
|
|
83
|
-
private mic_selection_id;
|
|
84
|
-
private next_button_id;
|
|
85
|
-
private error_msg_div_id;
|
|
86
|
-
private step1_id;
|
|
87
|
-
private step2_id;
|
|
88
|
-
private step3_id;
|
|
89
|
-
private step_complete_class;
|
|
90
|
-
private step_complete_text;
|
|
91
|
-
private waiting_for_access_msg;
|
|
92
|
-
private checking_mic_msg;
|
|
93
|
-
private access_problem_msg;
|
|
94
|
-
private setup_problem_msg;
|
|
95
111
|
/**
|
|
96
112
|
* Constructor for video config plugin.
|
|
97
113
|
*
|
|
@@ -108,8 +124,7 @@ export default class VideoConfigPlugin implements JsPsychPlugin<Info> {
|
|
|
108
124
|
/**
|
|
109
125
|
* Add HTML content to the page.
|
|
110
126
|
*
|
|
111
|
-
* @param
|
|
112
|
-
* Trial object.
|
|
127
|
+
* @param trial - Trial object.
|
|
113
128
|
*/
|
|
114
129
|
private addHtmlContent;
|
|
115
130
|
/** Add event listeners to elements after they've been added to the page. */
|
|
@@ -264,8 +279,9 @@ export default class VideoConfigPlugin implements JsPsychPlugin<Info> {
|
|
|
264
279
|
* Update the errors/messages div with information for the user about the
|
|
265
280
|
* camera/mic checks.
|
|
266
281
|
*
|
|
267
|
-
* @param
|
|
268
|
-
*
|
|
282
|
+
* @param errorMsgId - Span element ID containing the message to display in
|
|
283
|
+
* the error message div. Call the function without an errorMsgId to clear
|
|
284
|
+
* the errors.
|
|
269
285
|
*/
|
|
270
286
|
private updateErrors;
|
|
271
287
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lookit/record",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Recording extensions and plugins for CHS studies.",
|
|
5
5
|
"homepage": "https://github.com/lookit/lookit-jspsych#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -34,20 +34,15 @@
|
|
|
34
34
|
"@rollup/plugin-image": "^3.0.3",
|
|
35
35
|
"@rollup/plugin-replace": "^6.0.1",
|
|
36
36
|
"@types/audioworklet": "^0.0.60",
|
|
37
|
-
"@types/js-yaml": "^4.0.9",
|
|
38
|
-
"@types/node-polyglot": "^2.5.0",
|
|
39
37
|
"handlebars": "^4.7.8",
|
|
40
|
-
"i18next": "^23.15.1",
|
|
41
|
-
"i18next-icu": "^2.3.0",
|
|
42
|
-
"js-yaml": "^4.1.0",
|
|
43
38
|
"rollup-plugin-dotenv": "^0.5.1",
|
|
44
39
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
|
45
40
|
"rollup-plugin-string-import": "^1.2.4",
|
|
46
41
|
"typescript": "^5.6.2"
|
|
47
42
|
},
|
|
48
43
|
"peerDependencies": {
|
|
49
|
-
"@lookit/data": "^0.0
|
|
50
|
-
"@lookit/templates": "^
|
|
44
|
+
"@lookit/data": "^0.1.0",
|
|
45
|
+
"@lookit/templates": "^1.1.0",
|
|
51
46
|
"jspsych": "^8.0.2"
|
|
52
47
|
}
|
|
53
48
|
}
|
package/src/consentVideo.ts
CHANGED
|
@@ -46,15 +46,16 @@ const info = <const>{
|
|
|
46
46
|
additional_segments: {
|
|
47
47
|
type: ParameterType.COMPLEX,
|
|
48
48
|
array: true,
|
|
49
|
+
default: [],
|
|
49
50
|
nested: {
|
|
50
51
|
title: {
|
|
51
52
|
type: ParameterType.STRING,
|
|
52
53
|
default: "",
|
|
53
54
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
text: {
|
|
56
|
+
type: ParameterType.STRING,
|
|
57
|
+
default: "",
|
|
58
|
+
},
|
|
58
59
|
},
|
|
59
60
|
},
|
|
60
61
|
prompt_all_adults: { type: ParameterType.BOOL, default: false },
|
package/src/index.spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LookitWindow } from "@lookit/data/dist/types";
|
|
2
|
-
import { initJsPsych } from "jspsych";
|
|
2
|
+
import { initJsPsych, PluginInfo, TrialType } from "jspsych";
|
|
3
3
|
import { ExistingRecordingError, NoSessionRecordingError } from "./errors";
|
|
4
4
|
import Rec from "./index";
|
|
5
5
|
import Recorder from "./recorder";
|
|
@@ -96,7 +96,11 @@ test("Stop Recording", async () => {
|
|
|
96
96
|
|
|
97
97
|
mockRecStop.mockImplementation(jest.fn().mockReturnValue(Promise.resolve()));
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const trial = {
|
|
100
|
+
locale: "en-us",
|
|
101
|
+
} as unknown as TrialType<PluginInfo>;
|
|
102
|
+
|
|
103
|
+
await stopRec.trial(display_element, trial);
|
|
100
104
|
|
|
101
105
|
expect(jsPsych.finishTrial).toHaveBeenCalledTimes(1);
|
|
102
106
|
expect(window.chs.sessionRecorder).toBeNull();
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { VideoConsentPlugin } from "./consentVideo";
|
|
|
2
2
|
import StartRecordPlugin from "./start";
|
|
3
3
|
import StopRecordPlugin from "./stop";
|
|
4
4
|
import TrialRecordExtension from "./trial";
|
|
5
|
-
import VideoConfigPlugin from "./
|
|
5
|
+
import VideoConfigPlugin from "./videoConfig";
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
TrialRecordExtension,
|
package/src/stop.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { LookitWindow } from "@lookit/data/dist/types";
|
|
2
|
-
import
|
|
3
|
-
import { JsPsych, JsPsychPlugin } from "jspsych";
|
|
4
|
-
import uploadingVideo from "../hbs/uploading-video.hbs";
|
|
2
|
+
import chsTemplates from "@lookit/templates";
|
|
3
|
+
import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
|
|
5
4
|
import { NoSessionRecordingError } from "./errors";
|
|
6
5
|
import Recorder from "./recorder";
|
|
7
6
|
|
|
8
7
|
declare let window: LookitWindow;
|
|
9
8
|
|
|
10
|
-
const info = <const>{
|
|
9
|
+
const info = <const>{
|
|
10
|
+
name: "stop-record-plugin",
|
|
11
|
+
parameters: {
|
|
12
|
+
locale: { type: ParameterType.STRING, default: "en-us" },
|
|
13
|
+
},
|
|
14
|
+
};
|
|
11
15
|
type Info = typeof info;
|
|
12
16
|
|
|
13
17
|
/** Stop recording. Used by researchers who want to record across trials. */
|
|
@@ -34,9 +38,10 @@ export default class StopRecordPlugin implements JsPsychPlugin<Info> {
|
|
|
34
38
|
* @param display_element - DOM element where jsPsych content is being
|
|
35
39
|
* rendered (set in initJsPsych and automatically made available to a
|
|
36
40
|
* plugin's trial method via jsPsych core).
|
|
41
|
+
* @param trial - Trial object with parameters/values.
|
|
37
42
|
*/
|
|
38
|
-
public trial(display_element: HTMLElement): void {
|
|
39
|
-
display_element.innerHTML =
|
|
43
|
+
public trial(display_element: HTMLElement, trial: TrialType<Info>): void {
|
|
44
|
+
display_element.innerHTML = chsTemplates.uploadingVideo(trial);
|
|
40
45
|
this.recorder.stop().then(() => {
|
|
41
46
|
window.chs.sessionRecorder = null;
|
|
42
47
|
display_element.innerHTML = "";
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { clickTarget } from "@jspsych/test-utils";
|
|
2
|
-
import
|
|
2
|
+
import chsTemplates from "@lookit/templates";
|
|
3
3
|
import { initJsPsych, JsPsych } from "jspsych";
|
|
4
|
-
import videoConfig from "../hbs/video-config.hbs";
|
|
5
4
|
import { NoStreamError } from "./errors";
|
|
6
|
-
import chromeInitialPrompt from "./img/chrome_initialprompt.png";
|
|
7
|
-
import chromeAlwaysAllow from "./img/chrome_step1_alwaysallow.png";
|
|
8
|
-
import chromePermissions from "./img/chrome_step1_permissions.png";
|
|
9
|
-
import firefoxInitialPrompt from "./img/firefox_initialprompt.png";
|
|
10
|
-
import firefoxChooseDevice from "./img/firefox_prompt_choose_device.png";
|
|
11
|
-
import firefoxDevicesBlocked from "./img/firefox_prompt_devices_blocked.png";
|
|
12
5
|
import Recorder from "./recorder";
|
|
13
|
-
import VideoConfigPlugin, {
|
|
6
|
+
import VideoConfigPlugin, {
|
|
7
|
+
html_params,
|
|
8
|
+
VideoConsentTrialType,
|
|
9
|
+
} from "./videoConfig";
|
|
14
10
|
|
|
15
11
|
jest.mock("./recorder");
|
|
16
12
|
jest.mock("@lookit/data");
|
|
@@ -42,7 +38,6 @@ jest.mock("jspsych", () => ({
|
|
|
42
38
|
let display_el: HTMLBodyElement;
|
|
43
39
|
let jsPsych: JsPsych;
|
|
44
40
|
let video_config: VideoConfigPlugin;
|
|
45
|
-
let html_params: object;
|
|
46
41
|
let devices: MediaDeviceInfo[];
|
|
47
42
|
let devicesObj: {
|
|
48
43
|
cam1: MediaDeviceInfo;
|
|
@@ -55,6 +50,12 @@ let returnedDeviceLists: {
|
|
|
55
50
|
mics: MediaDeviceInfo[];
|
|
56
51
|
};
|
|
57
52
|
|
|
53
|
+
// Video consent trial object with defaults
|
|
54
|
+
const trial_info = {
|
|
55
|
+
locale: "en-us",
|
|
56
|
+
troubleshooting_intro: "",
|
|
57
|
+
} as VideoConsentTrialType;
|
|
58
|
+
|
|
58
59
|
/**
|
|
59
60
|
* Clean rendered html to be compared with DOM.
|
|
60
61
|
*
|
|
@@ -70,6 +71,10 @@ const cleanHTML = (html: string) => {
|
|
|
70
71
|
.replace(/\s*\/*>/gm, ">")
|
|
71
72
|
// equals empty string
|
|
72
73
|
.replace(/(="")/gm, "")
|
|
74
|
+
// convert " to double quote
|
|
75
|
+
.replace(/(")/gm, '"')
|
|
76
|
+
// convert ' to single quote
|
|
77
|
+
.replace(/(')/gm, "'")
|
|
73
78
|
);
|
|
74
79
|
};
|
|
75
80
|
|
|
@@ -79,28 +84,6 @@ beforeEach(() => {
|
|
|
79
84
|
video_config = new VideoConfigPlugin(jsPsych);
|
|
80
85
|
video_config["display_el"] = display_el;
|
|
81
86
|
|
|
82
|
-
// Set up parameters for rendering HTML template
|
|
83
|
-
html_params = {
|
|
84
|
-
webcam_container_id: video_config["webcam_container_id"],
|
|
85
|
-
reload_button_id_cam: video_config["reload_button_id_cam"],
|
|
86
|
-
camera_selection_id: video_config["camera_selection_id"],
|
|
87
|
-
mic_selection_id: video_config["mic_selection_id"],
|
|
88
|
-
step1_id: video_config["step1_id"],
|
|
89
|
-
step2_id: video_config["step2_id"],
|
|
90
|
-
step3_id: video_config["step3_id"],
|
|
91
|
-
step_complete_class: video_config["step_complete_class"],
|
|
92
|
-
step_complete_text: video_config["step_complete_text"],
|
|
93
|
-
reload_button_id_text: video_config["reload_button_id_text"],
|
|
94
|
-
next_button_id: video_config["next_button_id"],
|
|
95
|
-
chromeInitialPrompt: chromeInitialPrompt,
|
|
96
|
-
chromeAlwaysAllow: chromeAlwaysAllow,
|
|
97
|
-
chromePermissions: chromePermissions,
|
|
98
|
-
firefoxInitialPrompt: firefoxInitialPrompt,
|
|
99
|
-
firefoxChooseDevice: firefoxChooseDevice,
|
|
100
|
-
firefoxDevicesBlocked: firefoxDevicesBlocked,
|
|
101
|
-
troubleshooting_intro: "",
|
|
102
|
-
};
|
|
103
|
-
|
|
104
87
|
// Mocks for handling media streams and devices
|
|
105
88
|
const mic1 = {
|
|
106
89
|
deviceId: "mic1",
|
|
@@ -158,10 +141,6 @@ afterEach(() => {
|
|
|
158
141
|
});
|
|
159
142
|
|
|
160
143
|
test("Video config trial method sets up trial", () => {
|
|
161
|
-
const trial_info = {
|
|
162
|
-
troubleshooting_intro: "",
|
|
163
|
-
} as unknown as VideoConsentTrialType;
|
|
164
|
-
|
|
165
144
|
// Set up mocks for upstream functions called in trial method.
|
|
166
145
|
const addHtmlMock = jest
|
|
167
146
|
.spyOn(video_config, "addHtmlContent")
|
|
@@ -195,11 +174,11 @@ test("Video config addHtmlContent loads template", () => {
|
|
|
195
174
|
|
|
196
175
|
// Render the template with the HTML parameters.
|
|
197
176
|
const rendered_trial_html = cleanHTML(
|
|
198
|
-
|
|
177
|
+
chsTemplates.videoConfig(trial_info, html_params),
|
|
199
178
|
);
|
|
200
179
|
|
|
201
180
|
// Run addHtmlContent to get the actual trial HTML.
|
|
202
|
-
video_config["addHtmlContent"](
|
|
181
|
+
video_config["addHtmlContent"](trial_info);
|
|
203
182
|
const displayed_html = cleanHTML(document.body.innerHTML);
|
|
204
183
|
|
|
205
184
|
expect(displayed_html).toStrictEqual(rendered_trial_html);
|
|
@@ -209,19 +188,18 @@ test("Video config addHtmlContent loads template with custom troubleshooting tex
|
|
|
209
188
|
expect(video_config["display_el"]?.innerHTML).toBe("");
|
|
210
189
|
|
|
211
190
|
// Render the template with a custom trial parameter.
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
};
|
|
191
|
+
const trial_info_custom_troubleshoot = {
|
|
192
|
+
locale: "en-us",
|
|
193
|
+
troubleshooting_intro: "Custom text.",
|
|
194
|
+
} as VideoConsentTrialType;
|
|
217
195
|
|
|
218
196
|
// Remove new lines, indents (tabs or spaces), and empty HTML property values.
|
|
219
197
|
const rendered_trial_html = cleanHTML(
|
|
220
|
-
|
|
198
|
+
chsTemplates.videoConfig(trial_info_custom_troubleshoot, html_params),
|
|
221
199
|
);
|
|
222
200
|
|
|
223
201
|
// Get the actual trial HTML
|
|
224
|
-
video_config["addHtmlContent"](
|
|
202
|
+
video_config["addHtmlContent"](trial_info_custom_troubleshoot);
|
|
225
203
|
const displayed_html = cleanHTML(document.body.innerHTML);
|
|
226
204
|
|
|
227
205
|
expect(displayed_html).toStrictEqual(rendered_trial_html);
|
|
@@ -229,14 +207,14 @@ test("Video config addHtmlContent loads template with custom troubleshooting tex
|
|
|
229
207
|
|
|
230
208
|
test("Video config add event listeners", async () => {
|
|
231
209
|
expect(video_config["display_el"]?.innerHTML).toBe("");
|
|
232
|
-
video_config["addHtmlContent"](
|
|
210
|
+
video_config["addHtmlContent"](trial_info);
|
|
233
211
|
|
|
234
212
|
// Get relevant elements (device selection elements tested separately)
|
|
235
213
|
const next_button_el = video_config["display_el"]?.querySelector(
|
|
236
|
-
`#${
|
|
214
|
+
`#${html_params["next_button_id"]}`,
|
|
237
215
|
) as HTMLButtonElement;
|
|
238
216
|
const reload_button_els = video_config["display_el"]?.querySelectorAll(
|
|
239
|
-
`#${
|
|
217
|
+
`#${html_params["reload_button_id_cam"]}, #${html_params["reload_button_id_text"]}`,
|
|
240
218
|
) as NodeListOf<HTMLButtonElement>;
|
|
241
219
|
const acc_button_els = document.getElementsByClassName(
|
|
242
220
|
"lookit-jspsych-accordion",
|
|
@@ -291,41 +269,41 @@ test("Video config add event listeners", async () => {
|
|
|
291
269
|
test("Video config enable next", () => {
|
|
292
270
|
expect(video_config["display_el"]?.innerHTML).toBe("");
|
|
293
271
|
|
|
294
|
-
video_config["addHtmlContent"](
|
|
272
|
+
video_config["addHtmlContent"](trial_info);
|
|
295
273
|
const next_button_el = video_config["display_el"]?.querySelector(
|
|
296
|
-
`#${
|
|
274
|
+
`#${html_params["next_button_id"]}`,
|
|
297
275
|
) as HTMLButtonElement;
|
|
298
276
|
|
|
299
277
|
// When trial first loads, next button should exist but be disabled and no 'step_complete_class'
|
|
300
278
|
expect(next_button_el).toBeTruthy();
|
|
301
279
|
expect(
|
|
302
|
-
next_button_el.classList.contains(
|
|
280
|
+
next_button_el.classList.contains(html_params["step_complete_class"]),
|
|
303
281
|
).toBe(false);
|
|
304
282
|
expect(next_button_el.disabled).toBe(true);
|
|
305
283
|
|
|
306
284
|
// Calling with 'true' enables the button and adds the class.
|
|
307
285
|
video_config["enableNext"](true);
|
|
308
286
|
expect(
|
|
309
|
-
next_button_el.classList.contains(
|
|
287
|
+
next_button_el.classList.contains(html_params["step_complete_class"]),
|
|
310
288
|
).toBe(true);
|
|
311
289
|
expect(next_button_el.disabled).toBe(false);
|
|
312
290
|
|
|
313
291
|
// Calling with 'false' sets everything back.
|
|
314
292
|
video_config["enableNext"](false);
|
|
315
293
|
expect(
|
|
316
|
-
next_button_el.classList.contains(
|
|
294
|
+
next_button_el.classList.contains(html_params["step_complete_class"]),
|
|
317
295
|
).toBe(false);
|
|
318
296
|
expect(next_button_el.disabled).toBe(true);
|
|
319
297
|
});
|
|
320
298
|
|
|
321
299
|
test("Video config update instructions", () => {
|
|
322
300
|
expect(video_config["display_el"]?.innerHTML).toBe("");
|
|
323
|
-
video_config["addHtmlContent"](
|
|
301
|
+
video_config["addHtmlContent"](trial_info);
|
|
324
302
|
|
|
325
303
|
// Get the relevant elements from the instructions section.
|
|
326
|
-
const step1_id =
|
|
327
|
-
const step2_id =
|
|
328
|
-
const step3_id =
|
|
304
|
+
const step1_id = html_params["step1_id"];
|
|
305
|
+
const step2_id = html_params["step2_id"];
|
|
306
|
+
const step3_id = html_params["step3_id"];
|
|
329
307
|
const step1_span = video_config["display_el"]?.querySelector(
|
|
330
308
|
`#${step1_id}-span`,
|
|
331
309
|
) as HTMLSpanElement;
|
|
@@ -376,27 +354,34 @@ test("Video config update instructions", () => {
|
|
|
376
354
|
|
|
377
355
|
test("Video config update errors", () => {
|
|
378
356
|
expect(video_config["display_el"]?.innerHTML).toBe("");
|
|
379
|
-
video_config["addHtmlContent"](
|
|
357
|
+
video_config["addHtmlContent"](trial_info);
|
|
380
358
|
const error_msg_div = video_config["display_el"]?.querySelector(
|
|
381
|
-
`#${
|
|
359
|
+
`#${html_params["error_msg_div_id"]}`,
|
|
382
360
|
) as HTMLDivElement;
|
|
383
361
|
|
|
384
|
-
// Error/info
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
362
|
+
// Error/info messages are all hidden when the page first loads.
|
|
363
|
+
const error_msg_elements = error_msg_div.querySelectorAll(
|
|
364
|
+
"span.error_msg",
|
|
365
|
+
) as NodeListOf<HTMLSpanElement>;
|
|
366
|
+
error_msg_elements.forEach((span) => {
|
|
367
|
+
expect(span.style.display).toBe("none");
|
|
368
|
+
});
|
|
389
369
|
|
|
390
|
-
|
|
370
|
+
// Calling with an error message ID displays the message element
|
|
371
|
+
video_config["updateErrors"](html_params["waiting_for_access_msg_id"]);
|
|
372
|
+
const waiting_for_access_msg_el = error_msg_div.querySelector(
|
|
373
|
+
`span#${html_params["waiting_for_access_msg_id"]}`,
|
|
374
|
+
) as HTMLSpanElement;
|
|
375
|
+
expect(waiting_for_access_msg_el?.style.display).toBe("block");
|
|
391
376
|
});
|
|
392
377
|
|
|
393
378
|
test("Video config reload button click", async () => {
|
|
394
379
|
expect(video_config["hasReloaded"]).toBe(false);
|
|
395
380
|
|
|
396
|
-
video_config["addHtmlContent"](
|
|
381
|
+
video_config["addHtmlContent"](trial_info);
|
|
397
382
|
|
|
398
383
|
const reload_button_els = video_config["display_el"]?.querySelectorAll(
|
|
399
|
-
`#${
|
|
384
|
+
`#${html_params["reload_button_id_cam"]}, #${html_params["reload_button_id_text"]}`,
|
|
400
385
|
) as NodeListOf<HTMLButtonElement>;
|
|
401
386
|
|
|
402
387
|
// Mock upstream function calls.
|
|
@@ -432,12 +417,12 @@ test("Video config reload button click", async () => {
|
|
|
432
417
|
});
|
|
433
418
|
|
|
434
419
|
test("Video config updateDeviceSelection", () => {
|
|
435
|
-
video_config["addHtmlContent"](
|
|
420
|
+
video_config["addHtmlContent"](trial_info);
|
|
436
421
|
const cam_selection_el = video_config["display_el"]?.querySelector(
|
|
437
|
-
`#${
|
|
422
|
+
`#${html_params["camera_selection_id"]}`,
|
|
438
423
|
) as HTMLSelectElement;
|
|
439
424
|
const mic_selection_el = video_config["display_el"]?.querySelector(
|
|
440
|
-
`#${
|
|
425
|
+
`#${html_params["mic_selection_id"]}`,
|
|
441
426
|
) as HTMLSelectElement;
|
|
442
427
|
|
|
443
428
|
expect(cam_selection_el).not.toBeUndefined();
|
|
@@ -583,9 +568,9 @@ test("Video config setupRecorder", async () => {
|
|
|
583
568
|
// Adds error message when waiting for stream access, then clears the message after access is granted.
|
|
584
569
|
expect(updateErrorsMock).toHaveBeenCalledTimes(2);
|
|
585
570
|
expect(updateErrorsMock.mock.calls[0]).toStrictEqual([
|
|
586
|
-
|
|
571
|
+
html_params["waiting_for_access_msg_id"],
|
|
587
572
|
]);
|
|
588
|
-
expect(updateErrorsMock.mock.calls[1]).toStrictEqual([
|
|
573
|
+
expect(updateErrorsMock.mock.calls[1]).toStrictEqual([]);
|
|
589
574
|
// Needs to request permissions before it can get device lists.
|
|
590
575
|
expect(requestPermissionMock).toHaveBeenCalledWith({
|
|
591
576
|
video: true,
|
|
@@ -603,15 +588,15 @@ test("Video config setupRecorder", async () => {
|
|
|
603
588
|
});
|
|
604
589
|
|
|
605
590
|
test("Video config setDevices", async () => {
|
|
606
|
-
video_config["addHtmlContent"](
|
|
591
|
+
video_config["addHtmlContent"](trial_info);
|
|
607
592
|
const cam_selection_el = video_config["display_el"]?.querySelector(
|
|
608
|
-
`#${
|
|
593
|
+
`#${html_params["camera_selection_id"]}`,
|
|
609
594
|
) as HTMLSelectElement;
|
|
610
595
|
const mic_selection_el = video_config["display_el"]?.querySelector(
|
|
611
|
-
`#${
|
|
596
|
+
`#${html_params["mic_selection_id"]}`,
|
|
612
597
|
) as HTMLSelectElement;
|
|
613
598
|
const next_button_el = video_config["display_el"]?.querySelector(
|
|
614
|
-
`#${
|
|
599
|
+
`#${html_params["next_button_id"]}`,
|
|
615
600
|
) as HTMLButtonElement;
|
|
616
601
|
video_config["recorder"] = new Recorder(jsPsych);
|
|
617
602
|
|
|
@@ -683,7 +668,7 @@ test("Video config setDevices", async () => {
|
|
|
683
668
|
});
|
|
684
669
|
|
|
685
670
|
test("Video config runStreamChecks throws NoStreamAccess", () => {
|
|
686
|
-
video_config["addHtmlContent"](
|
|
671
|
+
video_config["addHtmlContent"](trial_info);
|
|
687
672
|
video_config["recorder"] = new Recorder(initJsPsych());
|
|
688
673
|
jest
|
|
689
674
|
.spyOn(jsPsych.pluginAPI, "getCameraRecorder")
|
|
@@ -704,7 +689,7 @@ test("Video config runStreamChecks throws NoStreamAccess", () => {
|
|
|
704
689
|
});
|
|
705
690
|
|
|
706
691
|
test("Video config runStreamChecks throws Mic Check error", async () => {
|
|
707
|
-
video_config["addHtmlContent"](
|
|
692
|
+
video_config["addHtmlContent"](trial_info);
|
|
708
693
|
video_config["recorder"] = new Recorder(jsPsych);
|
|
709
694
|
|
|
710
695
|
// Setup upstream mocks.
|
|
@@ -730,15 +715,15 @@ test("Video config runStreamChecks throws Mic Check error", async () => {
|
|
|
730
715
|
// If the recorder mic check throws an error, then the plugin should update the error message and throw the error.
|
|
731
716
|
expect(updateErrorsMock).toHaveBeenCalledTimes(2);
|
|
732
717
|
expect(updateErrorsMock.mock.calls[0]).toStrictEqual([
|
|
733
|
-
|
|
718
|
+
html_params["checking_mic_msg_id"],
|
|
734
719
|
]);
|
|
735
720
|
expect(updateErrorsMock.mock.calls[1]).toStrictEqual([
|
|
736
|
-
|
|
721
|
+
html_params["setup_problem_msg_id"],
|
|
737
722
|
]);
|
|
738
723
|
});
|
|
739
724
|
|
|
740
725
|
test("Video config runStreamChecks", async () => {
|
|
741
|
-
video_config["addHtmlContent"](
|
|
726
|
+
video_config["addHtmlContent"](trial_info);
|
|
742
727
|
video_config["recorder"] = new Recorder(jsPsych);
|
|
743
728
|
|
|
744
729
|
// Setup upstream mocks.
|
|
@@ -765,14 +750,14 @@ test("Video config runStreamChecks", async () => {
|
|
|
765
750
|
// Called twice: first with "checking mic" message, then to clear that message.
|
|
766
751
|
expect(updateErrorsMock).toHaveBeenCalledTimes(2);
|
|
767
752
|
expect(updateErrorsMock.mock.calls[0]).toStrictEqual([
|
|
768
|
-
|
|
753
|
+
html_params["checking_mic_msg_id"],
|
|
769
754
|
]);
|
|
770
|
-
expect(updateErrorsMock.mock.calls[1]).toStrictEqual([
|
|
755
|
+
expect(updateErrorsMock.mock.calls[1]).toStrictEqual([]);
|
|
771
756
|
expect(checkMicMock).toHaveBeenCalledTimes(1);
|
|
772
757
|
});
|
|
773
758
|
|
|
774
759
|
test("Video config runStreamChecks enables next button when all checks have passed", async () => {
|
|
775
|
-
video_config["addHtmlContent"](
|
|
760
|
+
video_config["addHtmlContent"](trial_info);
|
|
776
761
|
video_config["recorder"] = new Recorder(jsPsych);
|
|
777
762
|
|
|
778
763
|
// Setup upstream mocks.
|
|
@@ -840,7 +825,7 @@ test("Video config onDeviceChange event listener", async () => {
|
|
|
840
825
|
});
|
|
841
826
|
|
|
842
827
|
test("Video config device selection element on change event listener", async () => {
|
|
843
|
-
video_config["addHtmlContent"](
|
|
828
|
+
video_config["addHtmlContent"](trial_info);
|
|
844
829
|
|
|
845
830
|
// Mock upstream functions called by device selection change event listener.
|
|
846
831
|
const setDevicesMock = jest
|