import { flushPromises } from "@jspsych/test-utils"; import { JsPsych, JsPsychPlugin, TrialType } from "jspsych"; import { ParameterInfos } from "../src/modules/plugins"; import { SimulationMode, SimulationOptions, TrialResult } from "../src/timeline"; import { PromiseWrapper } from "../src/timeline/util"; export const testPluginInfo = { name: "test", parameters: {}, }; class TestPlugin implements JsPsychPlugin { static info = testPluginInfo; static setParameterInfos(parameters: ParameterInfos) { TestPlugin.info = { ...testPluginInfo, parameters }; } static resetPluginInfo() { TestPlugin.info = testPluginInfo; } private static defaultTrialResult: Record = { my: "result" }; static setDefaultTrialResult(defaultTrialResult: Record = { my: "result" }) { TestPlugin.defaultTrialResult = defaultTrialResult; } private static finishTrialMode: "immediate" | "manual" = "immediate"; /** * Disables immediate finishing of the `trial` method of all `TestPlugin` instances. Instead, any * running trial can be finished by invoking `TestPlugin.finishTrial()`. */ static setManualFinishTrialMode() { TestPlugin.finishTrialMode = "manual"; } /** * Makes the `trial` method of all instances of `TestPlugin` finish immediately and allows to manually finish the trial by * invoking `TestPlugin.finishTrial()` instead. */ static setImmediateFinishTrialMode() { TestPlugin.finishTrialMode = "immediate"; } private static trialPromise = new PromiseWrapper>(); /** * Resolves the promise returned by `trial()` with the provided `result` object or `{ my: "result" * }` if no `result` object was provided. **/ static async finishTrial(result?: Record) { TestPlugin.trialPromise.resolve(result ?? TestPlugin.defaultTrialResult); await flushPromises(); } /** Resets all static properties including the `trial` function mock */ static reset() { TestPlugin.prototype.trial .mockReset() .mockImplementation(TestPlugin.prototype.defaultTrialImplementation); TestPlugin.prototype.simulate .mockReset() .mockImplementation(TestPlugin.prototype.defaultSimulateImplementation); this.resetPluginInfo(); this.setDefaultTrialResult(); this.setImmediateFinishTrialMode(); } constructor(private jsPsych: JsPsych) {} // For convenience, `trial` is set to a `jest.fn` below using `TestPlugin.prototype` and // `defaultTrialImplementation` trial: jest.Mock | void>; simulate: jest.Mock | void>; defaultTrialImplementation( display_element: HTMLElement, trial: TrialType, on_load: () => void ) { on_load(); if (TestPlugin.finishTrialMode === "immediate") { return Promise.resolve(TestPlugin.defaultTrialResult); } return TestPlugin.trialPromise.get(); } defaultSimulateImplementation( trial: TrialType, simulation_mode: SimulationMode, simulation_options: SimulationOptions, on_load?: () => void ): void | Promise { return this.defaultTrialImplementation(document.createElement("div"), trial, on_load); } } TestPlugin.prototype.trial = jest.fn(TestPlugin.prototype.defaultTrialImplementation); TestPlugin.prototype.simulate = jest.fn(TestPlugin.prototype.defaultTrialImplementation); export default TestPlugin;