mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
Remove JsPsych
dependency from timeline nodes
This commit is contained in:
parent
f23fb33a53
commit
771ee6671e
2
package-lock.json
generated
2
package-lock.json
generated
@ -24644,7 +24644,7 @@
|
||||
"@jspsych/test-utils": "^1.1.1",
|
||||
"@types/dom-mediacapture-record": "^1.0.11",
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@types/lodash.has": "*",
|
||||
"@types/lodash.has": "^4.5.7",
|
||||
"@types/lodash.set": "^4.3.7",
|
||||
"auto-bind": "^4.0.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
|
@ -1,15 +1,17 @@
|
||||
import autoBind from "auto-bind";
|
||||
import { Class } from "type-fest";
|
||||
|
||||
import { version } from "../package.json";
|
||||
import { JsPsychData } from "./modules/data";
|
||||
import { PluginAPI, createJointPluginAPIObject } from "./modules/plugin-api";
|
||||
import { JsPsychPlugin, PluginInfo } from "./modules/plugins";
|
||||
import * as randomization from "./modules/randomization";
|
||||
import * as turk from "./modules/turk";
|
||||
import * as utils from "./modules/utils";
|
||||
import {
|
||||
GlobalTimelineNodeCallbacks,
|
||||
TimelineArray,
|
||||
TimelineDescription,
|
||||
TimelineNodeDependencies,
|
||||
TimelineVariable,
|
||||
TrialResult,
|
||||
} from "./timeline";
|
||||
@ -67,7 +69,7 @@ export class JsPsych {
|
||||
*/
|
||||
private simulation_options;
|
||||
|
||||
private timelineNodeCallbacks = new (class implements GlobalTimelineNodeCallbacks {
|
||||
private timelineDependencies = new (class implements TimelineNodeDependencies {
|
||||
constructor(private jsPsych: JsPsych) {
|
||||
autoBind(this);
|
||||
}
|
||||
@ -101,6 +103,16 @@ export class JsPsych {
|
||||
this.jsPsych.removeCssClasses(cssClasses);
|
||||
}
|
||||
}
|
||||
|
||||
instantiatePlugin<Info extends PluginInfo>(pluginClass: Class<JsPsychPlugin<Info>>) {
|
||||
return new pluginClass(this.jsPsych);
|
||||
}
|
||||
|
||||
defaultIti = this.jsPsych.options.default_iti;
|
||||
|
||||
displayElement = this.jsPsych.getDisplayElement();
|
||||
|
||||
finishTrialPromise = this.jsPsych.finishTrialPromise;
|
||||
})(this);
|
||||
|
||||
constructor(options?) {
|
||||
@ -175,7 +187,7 @@ export class JsPsych {
|
||||
}
|
||||
|
||||
// create experiment timeline
|
||||
this.timeline = new Timeline(this, this.timelineNodeCallbacks, timeline);
|
||||
this.timeline = new Timeline(this.timelineDependencies, timeline);
|
||||
|
||||
await this.prepareDom();
|
||||
await this.loadExtensions(this.options.extensions);
|
||||
@ -416,7 +428,7 @@ export class JsPsych {
|
||||
|
||||
// New stuff as replacements for old methods:
|
||||
|
||||
finishTrialPromise = new PromiseWrapper<TrialResult>();
|
||||
private finishTrialPromise = new PromiseWrapper<TrialResult | void>();
|
||||
finishTrial(data?: TrialResult) {
|
||||
this.finishTrialPromise.resolve(data);
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { GlobalTimelineNodeCallbacks } from "src/timeline";
|
||||
|
||||
import { JsPsych } from "../../JsPsych";
|
||||
import { DataCollection } from "./DataCollection";
|
||||
import { getQueryString } from "./utils";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SetRequired } from "type-fest";
|
||||
|
||||
import { TrialDescription } from "../timeline";
|
||||
import { TrialDescription, TrialResult } from "../timeline";
|
||||
|
||||
/**
|
||||
* Parameter types for plugins
|
||||
@ -136,8 +136,6 @@ export const universalPluginParameters = <const>{
|
||||
|
||||
export type UniversalPluginParameters = InferredParameters<typeof universalPluginParameters>;
|
||||
|
||||
type test = undefined extends null ? "a" : "b";
|
||||
|
||||
export interface PluginInfo {
|
||||
name: string;
|
||||
parameters: ParameterInfos;
|
||||
@ -148,7 +146,7 @@ export interface JsPsychPlugin<I extends PluginInfo> {
|
||||
display_element: HTMLElement,
|
||||
trial: TrialType<I>,
|
||||
on_load?: () => void
|
||||
): void | Promise<any>;
|
||||
): void | Promise<TrialResult | void>;
|
||||
}
|
||||
|
||||
export type TrialType<I extends PluginInfo> = InferredParameters<I["parameters"]> &
|
||||
|
@ -1,13 +1,12 @@
|
||||
import get from "lodash.get";
|
||||
import has from "lodash.has";
|
||||
|
||||
import { JsPsych } from "../JsPsych";
|
||||
import { Timeline } from "./Timeline";
|
||||
import {
|
||||
GetParameterValueOptions,
|
||||
GlobalTimelineNodeCallbacks,
|
||||
TimelineDescription,
|
||||
TimelineNode,
|
||||
TimelineNodeDependencies,
|
||||
TimelineNodeStatus,
|
||||
TimelineVariable,
|
||||
TrialDescription,
|
||||
@ -24,10 +23,7 @@ export abstract class BaseTimelineNode implements TimelineNode {
|
||||
|
||||
protected status = TimelineNodeStatus.PENDING;
|
||||
|
||||
constructor(
|
||||
protected readonly jsPsych: JsPsych,
|
||||
protected readonly globalCallbacks: GlobalTimelineNodeCallbacks
|
||||
) {}
|
||||
constructor(protected readonly dependencies: TimelineNodeDependencies) {}
|
||||
|
||||
getStatus() {
|
||||
return this.status;
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { flushPromises } from "@jspsych/test-utils";
|
||||
import { JsPsych, initJsPsych } from "jspsych";
|
||||
import { mocked } from "ts-jest/utils";
|
||||
|
||||
import { GlobalCallbacks, mockDomRelatedJsPsychMethods } from "../../tests/test-utils";
|
||||
import { MockTimelineNodeDependencies } from "../../tests/test-utils";
|
||||
import TestPlugin from "../../tests/TestPlugin";
|
||||
import {
|
||||
repeat,
|
||||
@ -30,19 +29,15 @@ const exampleTimeline: TimelineDescription = {
|
||||
timeline: [{ type: TestPlugin }, { type: TestPlugin }, { timeline: [{ type: TestPlugin }] }],
|
||||
};
|
||||
|
||||
const globalCallbacks = new GlobalCallbacks();
|
||||
const dependencies = new MockTimelineNodeDependencies();
|
||||
|
||||
describe("Timeline", () => {
|
||||
let jsPsych: JsPsych;
|
||||
|
||||
const createTimeline = (description: TimelineDescription | TimelineArray, parent?: Timeline) =>
|
||||
new Timeline(jsPsych, globalCallbacks, description, parent);
|
||||
new Timeline(dependencies, description, parent);
|
||||
|
||||
beforeEach(() => {
|
||||
globalCallbacks.reset();
|
||||
dependencies.reset();
|
||||
TestPlugin.reset();
|
||||
jsPsych = initJsPsych();
|
||||
mockDomRelatedJsPsychMethods(jsPsych);
|
||||
});
|
||||
|
||||
describe("run()", () => {
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { JsPsych } from "../JsPsych";
|
||||
import {
|
||||
repeat,
|
||||
sampleWithReplacement,
|
||||
@ -11,10 +10,10 @@ import { Trial } from "./Trial";
|
||||
import { PromiseWrapper } from "./util";
|
||||
import {
|
||||
GetParameterValueOptions,
|
||||
GlobalTimelineNodeCallbacks,
|
||||
TimelineArray,
|
||||
TimelineDescription,
|
||||
TimelineNode,
|
||||
TimelineNodeDependencies,
|
||||
TimelineNodeStatus,
|
||||
TimelineVariable,
|
||||
TrialDescription,
|
||||
@ -28,13 +27,12 @@ export class Timeline extends BaseTimelineNode {
|
||||
public readonly description: TimelineDescription;
|
||||
|
||||
constructor(
|
||||
jsPsych: JsPsych,
|
||||
globalCallbacks: GlobalTimelineNodeCallbacks,
|
||||
dependencies: TimelineNodeDependencies,
|
||||
description: TimelineDescription | TimelineArray,
|
||||
protected readonly parent?: Timeline,
|
||||
public readonly index = 0
|
||||
) {
|
||||
super(jsPsych, globalCallbacks);
|
||||
super(dependencies);
|
||||
this.description = Array.isArray(description) ? { timeline: description } : description;
|
||||
this.nextChildNodeIndex = index;
|
||||
}
|
||||
@ -143,8 +141,8 @@ export class Timeline extends BaseTimelineNode {
|
||||
const newChildNodes = this.description.timeline.map((childDescription) => {
|
||||
const childNodeIndex = this.nextChildNodeIndex++;
|
||||
return isTimelineDescription(childDescription)
|
||||
? new Timeline(this.jsPsych, this.globalCallbacks, childDescription, this, childNodeIndex)
|
||||
: new Trial(this.jsPsych, this.globalCallbacks, childDescription, this, childNodeIndex);
|
||||
? new Timeline(this.dependencies, childDescription, this, childNodeIndex)
|
||||
: new Trial(this.dependencies, childDescription, this, childNodeIndex);
|
||||
});
|
||||
this.children.push(...newChildNodes);
|
||||
return newChildNodes;
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { flushPromises } from "@jspsych/test-utils";
|
||||
import { JsPsych, initJsPsych } from "jspsych";
|
||||
import { mocked } from "ts-jest/utils";
|
||||
|
||||
import { GlobalCallbacks, mockDomRelatedJsPsychMethods } from "../../tests/test-utils";
|
||||
import { MockTimelineNodeDependencies } from "../../tests/test-utils";
|
||||
import TestPlugin from "../../tests/TestPlugin";
|
||||
import { ParameterType } from "../modules/plugins";
|
||||
import { Timeline } from "./Timeline";
|
||||
@ -14,23 +13,20 @@ jest.useFakeTimers();
|
||||
|
||||
jest.mock("./Timeline");
|
||||
|
||||
const globalCallbacks = new GlobalCallbacks();
|
||||
const dependencies = new MockTimelineNodeDependencies();
|
||||
|
||||
describe("Trial", () => {
|
||||
let jsPsych: JsPsych;
|
||||
let timeline: Timeline;
|
||||
|
||||
beforeEach(() => {
|
||||
globalCallbacks.reset();
|
||||
dependencies.reset();
|
||||
TestPlugin.reset();
|
||||
|
||||
jsPsych = initJsPsych();
|
||||
mockDomRelatedJsPsychMethods(jsPsych);
|
||||
timeline = new Timeline(jsPsych, globalCallbacks, { timeline: [] });
|
||||
timeline = new Timeline(dependencies, { timeline: [] });
|
||||
});
|
||||
|
||||
const createTrial = (description: TrialDescription) =>
|
||||
new Trial(jsPsych, globalCallbacks, description, timeline, 0);
|
||||
new Trial(dependencies, description, timeline, 0);
|
||||
|
||||
describe("run()", () => {
|
||||
it("instantiates the corresponding plugin", async () => {
|
||||
@ -49,8 +45,8 @@ describe("Trial", () => {
|
||||
|
||||
expect(onStartCallback).toHaveBeenCalledTimes(1);
|
||||
expect(onStartCallback).toHaveBeenCalledWith(description);
|
||||
expect(globalCallbacks.onTrialStart).toHaveBeenCalledTimes(1);
|
||||
expect(globalCallbacks.onTrialStart).toHaveBeenCalledWith(trial);
|
||||
expect(dependencies.onTrialStart).toHaveBeenCalledTimes(1);
|
||||
expect(dependencies.onTrialStart).toHaveBeenCalledWith(trial);
|
||||
});
|
||||
|
||||
it("properly invokes the plugin's `trial` method", async () => {
|
||||
@ -107,7 +103,7 @@ describe("Trial", () => {
|
||||
.spyOn(TestPlugin.prototype, "trial")
|
||||
.mockImplementation(async (display_element, trial, on_load) => {
|
||||
on_load();
|
||||
jsPsych.finishTrial({ finishTrial: "result" });
|
||||
dependencies.finishTrialPromise.resolve({ finishTrial: "result" });
|
||||
return { my: "result" };
|
||||
});
|
||||
|
||||
@ -120,7 +116,7 @@ describe("Trial", () => {
|
||||
describe("if `trial` returns no promise", () => {
|
||||
beforeAll(() => {
|
||||
TestPlugin.prototype.trial.mockImplementation(() => {
|
||||
jsPsych.finishTrial({ my: "result" });
|
||||
dependencies.finishTrialPromise.resolve({ my: "result" });
|
||||
});
|
||||
});
|
||||
|
||||
@ -130,7 +126,7 @@ describe("Trial", () => {
|
||||
await trial.run();
|
||||
|
||||
expect(onLoadCallback).toHaveBeenCalledTimes(1);
|
||||
expect(globalCallbacks.onTrialLoaded).toHaveBeenCalledTimes(1);
|
||||
expect(dependencies.onTrialLoaded).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("picks up the result data from the `finishTrial()` function", async () => {
|
||||
@ -154,8 +150,8 @@ describe("Trial", () => {
|
||||
const trial = createTrial({ type: TestPlugin });
|
||||
await trial.run();
|
||||
|
||||
expect(globalCallbacks.onTrialFinished).toHaveBeenCalledTimes(1);
|
||||
expect(globalCallbacks.onTrialFinished).toHaveBeenCalledWith(trial);
|
||||
expect(dependencies.onTrialFinished).toHaveBeenCalledTimes(1);
|
||||
expect(dependencies.onTrialFinished).toHaveBeenCalledWith(trial);
|
||||
});
|
||||
|
||||
it("includes result data from the `data` property", async () => {
|
||||
@ -417,7 +413,7 @@ describe("Trial", () => {
|
||||
});
|
||||
|
||||
it("respects `default_iti` and `post_trial_gap``", async () => {
|
||||
jest.spyOn(jsPsych, "getInitSettings").mockReturnValue({ default_iti: 100 });
|
||||
dependencies.defaultIti = 100;
|
||||
TestPlugin.setManualFinishTrialMode();
|
||||
|
||||
const trial1 = createTrial({ type: TestPlugin });
|
||||
@ -456,10 +452,10 @@ describe("Trial", () => {
|
||||
|
||||
describe("evaluateTimelineVariable()", () => {
|
||||
it("defers to the parent node", () => {
|
||||
const timeline = new Timeline(jsPsych, globalCallbacks, { timeline: [] });
|
||||
const timeline = new Timeline(dependencies, { timeline: [] });
|
||||
mocked(timeline).evaluateTimelineVariable.mockReturnValue(1);
|
||||
|
||||
const trial = new Trial(jsPsych, globalCallbacks, { type: TestPlugin }, timeline, 0);
|
||||
const trial = new Trial(dependencies, { type: TestPlugin }, timeline, 0);
|
||||
|
||||
const variable = new TimelineVariable("x");
|
||||
expect(trial.evaluateTimelineVariable(variable)).toEqual(1);
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { JsPsych, JsPsychPlugin, ParameterType, PluginInfo } from "jspsych";
|
||||
import get from "lodash.get";
|
||||
import set from "lodash.set";
|
||||
import { ParameterInfos } from "src/modules/plugins";
|
||||
import { Class } from "type-fest";
|
||||
|
||||
import { JsPsychPlugin, ParameterType, PluginInfo } from "../";
|
||||
import { deepCopy } from "../modules/utils";
|
||||
import { BaseTimelineNode } from "./BaseTimelineNode";
|
||||
import { Timeline } from "./Timeline";
|
||||
import { delay, parameterPathArrayToString } from "./util";
|
||||
import {
|
||||
GetParameterValueOptions,
|
||||
GlobalTimelineNodeCallbacks,
|
||||
TimelineNodeDependencies,
|
||||
TimelineNodeStatus,
|
||||
TimelineVariable,
|
||||
TrialDescription,
|
||||
@ -25,16 +25,14 @@ export class Trial extends BaseTimelineNode {
|
||||
|
||||
private result: TrialResult;
|
||||
private readonly pluginInfo: PluginInfo;
|
||||
private cssClasses?: string[];
|
||||
|
||||
constructor(
|
||||
jsPsych: JsPsych,
|
||||
globalCallbacks: GlobalTimelineNodeCallbacks,
|
||||
dependencies: TimelineNodeDependencies,
|
||||
public readonly description: TrialDescription,
|
||||
protected readonly parent: Timeline,
|
||||
public readonly index: number
|
||||
) {
|
||||
super(jsPsych, globalCallbacks);
|
||||
super(dependencies);
|
||||
this.trialObject = deepCopy(description);
|
||||
this.pluginClass = this.getParameterValue("type", { evaluateFunctions: false });
|
||||
this.pluginInfo = this.pluginClass["info"];
|
||||
@ -46,7 +44,7 @@ export class Trial extends BaseTimelineNode {
|
||||
|
||||
this.onStart();
|
||||
|
||||
this.pluginInstance = new this.pluginClass(this.jsPsych);
|
||||
this.pluginInstance = this.dependencies.instantiatePlugin(this.pluginClass);
|
||||
|
||||
const result = await this.executeTrial();
|
||||
|
||||
@ -59,8 +57,7 @@ export class Trial extends BaseTimelineNode {
|
||||
|
||||
this.onFinish();
|
||||
|
||||
const gap =
|
||||
this.getParameterValue("post_trial_gap") ?? this.jsPsych.getInitSettings().default_iti;
|
||||
const gap = this.getParameterValue("post_trial_gap") ?? this.dependencies.defaultIti;
|
||||
if (gap !== 0) {
|
||||
await delay(gap);
|
||||
}
|
||||
@ -69,7 +66,7 @@ export class Trial extends BaseTimelineNode {
|
||||
}
|
||||
|
||||
private async executeTrial() {
|
||||
let trialPromise = this.jsPsych.finishTrialPromise.get();
|
||||
const trialPromise = this.dependencies.finishTrialPromise.get();
|
||||
|
||||
/** Used as a way to figure out if `finishTrial()` has ben called without awaiting `trialPromise` */
|
||||
let hasTrialPromiseBeenResolved = false;
|
||||
@ -78,13 +75,13 @@ export class Trial extends BaseTimelineNode {
|
||||
});
|
||||
|
||||
const trialReturnValue = this.pluginInstance.trial(
|
||||
this.jsPsych.getDisplayElement(),
|
||||
this.dependencies.displayElement,
|
||||
this.trialObject,
|
||||
this.onLoad
|
||||
);
|
||||
|
||||
// Wait until the trial has completed and grab result data
|
||||
let result: TrialResult;
|
||||
let result: TrialResult | void;
|
||||
if (isPromise(trialReturnValue)) {
|
||||
result = await Promise.race([trialReturnValue, trialPromise]);
|
||||
|
||||
@ -115,18 +112,18 @@ export class Trial extends BaseTimelineNode {
|
||||
}
|
||||
|
||||
private onStart() {
|
||||
this.globalCallbacks.onTrialStart(this);
|
||||
this.dependencies.onTrialStart(this);
|
||||
this.runParameterCallback("on_start", this.trialObject);
|
||||
}
|
||||
|
||||
private onLoad = () => {
|
||||
this.globalCallbacks.onTrialLoaded(this);
|
||||
this.dependencies.onTrialLoaded(this);
|
||||
this.runParameterCallback("on_load");
|
||||
};
|
||||
|
||||
private onFinish() {
|
||||
this.runParameterCallback("on_finish", this.getResult());
|
||||
this.globalCallbacks.onTrialFinished(this);
|
||||
this.dependencies.onTrialFinished(this);
|
||||
}
|
||||
|
||||
public evaluateTimelineVariable(variable: TimelineVariable) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Class } from "type-fest";
|
||||
|
||||
import { JsPsychPlugin } from "../modules/plugins";
|
||||
import { JsPsychPlugin, PluginInfo } from "../modules/plugins";
|
||||
import { Trial } from "./Trial";
|
||||
import { PromiseWrapper } from "./util";
|
||||
|
||||
export function isPromise(value: any): value is Promise<any> {
|
||||
return value && typeof value["then"] === "function";
|
||||
@ -112,12 +113,11 @@ export enum TimelineNodeStatus {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callbacks that get invoked by `TimelineNode`s. The callbacks are provided by the `JsPsych` class
|
||||
* itself to avoid numerous `JsPsych` instance method calls from within timeline nodes, and to keep
|
||||
* the public `JsPsych` API slim. This approach helps to decouple the `JsPsych` and timeline node
|
||||
* classes and thus simplifies unit testing.
|
||||
* Functions and options needed by `TimelineNode`s, provided by the `JsPsych` instance. This
|
||||
* approach allows to keep the public `JsPsych` API slim and decouples the `JsPsych` and timeline
|
||||
* node classes, simplifying unit testing.
|
||||
*/
|
||||
export interface GlobalTimelineNodeCallbacks {
|
||||
export interface TimelineNodeDependencies {
|
||||
/**
|
||||
* Called at the start of a trial, prior to invoking the plugin's trial method.
|
||||
*/
|
||||
@ -132,6 +132,29 @@ export interface GlobalTimelineNodeCallbacks {
|
||||
* Called after a trial has finished.
|
||||
*/
|
||||
onTrialFinished: (trial: Trial) => void;
|
||||
|
||||
/**
|
||||
* Given a plugin class, creates a new instance of it and returns it.
|
||||
*/
|
||||
instantiatePlugin: <Info extends PluginInfo>(
|
||||
pluginClass: Class<JsPsychPlugin<Info>>
|
||||
) => JsPsychPlugin<Info>;
|
||||
|
||||
/**
|
||||
* The default inter-trial interval as provided to `initJsPsych`
|
||||
*/
|
||||
defaultIti: number;
|
||||
|
||||
/**
|
||||
* JsPsych's display element which is provided to plugins
|
||||
*/
|
||||
displayElement: HTMLElement;
|
||||
|
||||
/**
|
||||
* A `PromiseWrapper` whose promise is resolved with result data whenever `jsPsych.finishTrial()`
|
||||
* is called.
|
||||
*/
|
||||
finishTrialPromise: PromiseWrapper<TrialResult | void>;
|
||||
}
|
||||
|
||||
export type GetParameterValueOptions = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { flushPromises } from "@jspsych/test-utils";
|
||||
import { JsPsych, JsPsychPlugin, TrialType } from "jspsych";
|
||||
import { TrialResult } from "src/timeline";
|
||||
|
||||
import { ParameterInfos } from "../src/modules/plugins";
|
||||
import { PromiseWrapper } from "../src/timeline/util";
|
||||
@ -69,7 +70,7 @@ class TestPlugin implements JsPsychPlugin<typeof testPluginInfo> {
|
||||
|
||||
// For convenience, `trial` is set to a `jest.fn` below using `TestPlugin.prototype` and
|
||||
// `defaultTrialImplementation`
|
||||
trial: jest.Mock<Promise<Record<string, any> | void> | void>;
|
||||
trial: jest.Mock<Promise<TrialResult | void> | void>;
|
||||
|
||||
defaultTrialImplementation(
|
||||
display_element: HTMLElement,
|
||||
|
@ -1,28 +1,46 @@
|
||||
import { JsPsych } from "../src";
|
||||
import { GlobalTimelineNodeCallbacks } from "../src/timeline";
|
||||
import { Class } from "type-fest";
|
||||
|
||||
export function mockDomRelatedJsPsychMethods(jsPsychInstance: JsPsych) {
|
||||
const displayElement = document.createElement("div");
|
||||
const displayContainerElement = document.createElement("div");
|
||||
jest.spyOn(jsPsychInstance, "getDisplayElement").mockImplementation(() => displayElement);
|
||||
jest
|
||||
.spyOn(jsPsychInstance, "getDisplayContainerElement")
|
||||
.mockImplementation(() => displayContainerElement);
|
||||
}
|
||||
import { JsPsych, JsPsychPlugin } from "../src";
|
||||
import { TimelineNodeDependencies, TrialResult } from "../src/timeline";
|
||||
import { PromiseWrapper } from "../src/timeline/util";
|
||||
|
||||
jest.mock("../src/JsPsych");
|
||||
|
||||
/**
|
||||
* A class to instantiate mocked `GlobalTimelineNodeCallbacks` objects that have additional
|
||||
* A class to instantiate mocked `TimelineNodeDependencies` objects that have additional
|
||||
* testing-related functions.
|
||||
*/
|
||||
export class GlobalCallbacks implements GlobalTimelineNodeCallbacks {
|
||||
export class MockTimelineNodeDependencies implements TimelineNodeDependencies {
|
||||
onTrialStart = jest.fn();
|
||||
onTrialLoaded = jest.fn();
|
||||
onTrialFinished = jest.fn();
|
||||
|
||||
instantiatePlugin = jest.fn(
|
||||
(pluginClass: Class<JsPsychPlugin<any>>) => new pluginClass(this.jsPsych)
|
||||
);
|
||||
|
||||
defaultIti: number;
|
||||
displayElement: HTMLDivElement;
|
||||
finishTrialPromise: PromiseWrapper<TrialResult>;
|
||||
jsPsych: JsPsych; // So we have something for plugins in `instantiatePlugin`
|
||||
|
||||
constructor() {
|
||||
this.initializeProperties();
|
||||
}
|
||||
|
||||
private initializeProperties() {
|
||||
this.defaultIti = 0;
|
||||
this.displayElement = document.createElement("div");
|
||||
this.finishTrialPromise = new PromiseWrapper<TrialResult>();
|
||||
this.jsPsych = new JsPsych();
|
||||
}
|
||||
|
||||
// Test utility functions
|
||||
reset() {
|
||||
this.onTrialStart.mockReset();
|
||||
this.onTrialLoaded.mockReset();
|
||||
this.onTrialFinished.mockReset();
|
||||
this.instantiatePlugin.mockClear();
|
||||
this.initializeProperties();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user