Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-drinks-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"jspsych": patch
---

parameter types will properly be checked in case of type mismatch, along with `ParameterType.SELECT` params properly using the `option` field to check if it is a valid parameter
1 change: 1 addition & 0 deletions packages/jspsych/src/modules/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export type ParameterInfo = (
array?: boolean;
pretty_name?: string;
default?: any;
options?: any;
};

export type ParameterInfos = Record<string, ParameterInfo>;
Expand Down
86 changes: 86 additions & 0 deletions packages/jspsych/src/timeline/Trial.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,92 @@ describe("Trial", () => {
});
});

describe("with parameter type mismatches", () => {
it("errors on non-boolean values for boolean parameters", async () => {
TestPlugin.setParameterInfos({
boolParameter: { type: ParameterType.BOOL },
});

// this should work:
await createTrial({ type: TestPlugin, boolParameter: true }).run();

// this shouldn't:
await expect(createTrial({ type: TestPlugin, boolParameter: "foo" }).run()).rejects.toThrow(
"A non-boolean value (`foo`) was provided for the boolean parameter \"boolParameter\" in the \"test\" plugin."
);
});

it("errors on non-string values for string parameters", async () => {
TestPlugin.setParameterInfos({
stringParameter: { type: ParameterType.STRING },
});

// this should work:
await createTrial({ type: TestPlugin, stringParameter: "foo" }).run();

// this shouldn't:
await expect(createTrial({ type: TestPlugin, stringParameter: 1 }).run()).rejects.toThrow(
"A non-string value (`1`) was provided for the parameter \"stringParameter\" in the \"test\" plugin."
);
});

it("errors on non-numeric values for numeric parameters", async () => {
TestPlugin.setParameterInfos({
intParameter: { type: ParameterType.INT },
floatParameter: { type: ParameterType.FLOAT },
});

// this should work:
await createTrial({ type: TestPlugin, intParameter: 1, floatParameter: 1.5 }).run();

// this shouldn't:
await expect(createTrial({ type: TestPlugin, intParameter: "foo", floatParameter: 1.5 }).run()).rejects.toThrow(
"A non-numeric value (`foo`) was provided for the numeric parameter \"intParameter\" in the \"test\" plugin."
);
await expect(createTrial({ type: TestPlugin, intParameter: 1, floatParameter: "foo" }).run()).rejects.toThrow(
"A non-numeric value (`foo`) was provided for the numeric parameter \"floatParameter\" in the \"test\" plugin."
);

// this should warn but not error:
const consoleSpy = jest.spyOn(console, "warn").mockImplementation();
await createTrial({ type: TestPlugin, intParameter: 1.5, floatParameter: 1.5 }).run();
expect(consoleSpy).toHaveBeenCalledWith(
`A float value (\`1.5\`) was provided for the integer parameter "intParameter" in the "test" plugin. The value will be truncated to an integer.`
);
});

it("errors on non-function values for function parameters", async () => {
TestPlugin.setParameterInfos({
functionParameter: { type: ParameterType.FUNCTION },
});

// this should work:
await createTrial({ type: TestPlugin, functionParameter: () => {} }).run();

// this shouldn't:
await expect(createTrial({ type: TestPlugin, functionParameter: "foo" }).run()).rejects.toThrow(
"A non-function value (`foo`) was provided for the function parameter \"functionParameter\" in the \"test\" plugin."
);
});

it("errors on select parameters with values not in the options", async () => {
TestPlugin.setParameterInfos({
selectParameter: {
type: ParameterType.SELECT,
options: ["foo", "bar"],
},
});

// this should work:
await createTrial({ type: TestPlugin, selectParameter: "foo" }).run();

// this shouldn't:
await expect(createTrial({ type: TestPlugin, selectParameter: "baz" }).run()).rejects.toThrow(
"The value \"baz\" is not a valid option for the parameter \"selectParameter\" in the \"test\" plugin. Valid options are: foo, bar."
);
});
});

it("respects `default_iti` and `post_trial_gap``", async () => {
dependencies.getDefaultIti.mockReturnValue(100);
TestPlugin.setManualFinishTrialMode();
Expand Down
78 changes: 78 additions & 0 deletions packages/jspsych/src/timeline/Trial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@
for (const [parameterName, parameterConfig] of Object.entries(parameterInfos)) {
const parameterPath = [...parentParameterPath, parameterName];

// evaluate parameter and validate required parameter
let parameterValue = this.getParameterValue(parameterPath, {
evaluateFunctions: parameterConfig.type !== ParameterType.FUNCTION,
replaceResult: (originalResult) => {
Expand All @@ -379,6 +380,83 @@
},
});

// major parameter type validation
if (!parameterConfig.array && parameterValue !== null) {
switch (parameterConfig.type) {
case ParameterType.BOOL:
if (typeof parameterValue !== "boolean") {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
`A non-boolean value (\`${parameterValue}\`) was provided for the boolean parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin.`
);
}
break;
// @ts-ignore falls through
case ParameterType.KEYS: // "ALL_KEYS", "NO_KEYS", and single key strings are checked here
if (Array.isArray(parameterValue))
break;
case ParameterType.STRING:
case ParameterType.HTML_STRING:
case ParameterType.KEY:
case ParameterType.AUDIO:
case ParameterType.VIDEO:
case ParameterType.IMAGE:
if (typeof parameterValue !== "string") {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
`A non-string value (\`${parameterValue}\`) was provided for the parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin.`
);
}
break;
case ParameterType.FLOAT:
case ParameterType.INT:
if (typeof parameterValue !== "number") {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-keyboard-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-keyboard-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-slider-response simulation › visual mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-slider-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-slider-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-slider-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-button-response simulation › visual mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-button-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

video-button-response › enable buttons during video playing

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-keyboard-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-keyboard-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-slider-response simulation › visual mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-slider-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-slider-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-slider-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-button-response simulation › visual mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-button-response simulation › data mode works

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25) at JsPsych.simulate (../jspsych/src/JsPsych.ts:167:5)

Check failure on line 415 in packages/jspsych/src/timeline/Trial.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 18

video-button-response › enable buttons during video playing

A non-numeric value (``) was provided for the numeric parameter "width" in the "video-button-response" plugin. at assignParameterValues (../jspsych/src/timeline/Trial.ts:415:23) at Trial.assignParameterValues [as processParameters] (../jspsych/src/timeline/Trial.ts:488:5) at Trial.processParameters [as run] (../jspsych/src/timeline/Trial.ts:65:10) at Timeline.run (../jspsych/src/timeline/Timeline.ts:87:31) at JsPsych.run (../jspsych/src/JsPsych.ts:150:25)
`A non-numeric value (\`${parameterValue}\`) was provided for the numeric parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin.`
);
}
break;
case ParameterType.FUNCTION:
if (typeof parameterValue !== "function") {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
`A non-function value (\`${parameterValue}\`) was provided for the function parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin.`
);
}
break;
case ParameterType.SELECT:
if (!parameterConfig.options) {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
`The "options" array is required for the "select" parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin.`
);
}
}

// truncate floats to integers if the parameter type is INT
if (parameterConfig.type === ParameterType.INT && parameterValue % 1 !== 0) {
const parameterPathString = parameterPathArrayToString(parameterPath);
console.warn(
`A float value (\`${parameterValue}\`) was provided for the integer parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin. The value will be truncated to an integer.`
);

parameterValue = Math.trunc(parameterValue);
}
}

if (parameterConfig.type === ParameterType.SELECT) {
if (!parameterConfig.options.includes(parameterValue)) {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
`The value "${parameterValue}" is not a valid option for the parameter "${parameterPathString}" in the "${this.pluginInfo.name}" plugin. Valid options are: ${parameterConfig.options.join(
", "
)}.`
);
}
}

// array validation
if (parameterConfig.array && !Array.isArray(parameterValue)) {
const parameterPathString = parameterPathArrayToString(parameterPath);
throw new Error(
Expand Down
Loading