mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
478 lines
11 KiB
TypeScript
478 lines
11 KiB
TypeScript
import callFunction from "@jspsych/plugin-call-function";
|
|
import htmlButtonResponse from "@jspsych/plugin-html-button-response";
|
|
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
|
|
import { pressKey, startTimeline } from "@jspsych/test-utils";
|
|
|
|
import { initJsPsych } from "../../src";
|
|
|
|
describe("randomize order", () => {});
|
|
|
|
describe("repetitons", () => {});
|
|
|
|
describe("sampling", () => {
|
|
test("alternate-groups method produces alternating groups", async () => {
|
|
const jsPsych = initJsPsych();
|
|
|
|
const { getHTML } = await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: jsPsych.timelineVariable("stimulus"),
|
|
},
|
|
],
|
|
timeline_variables: ["a", "a", "b", "b", "c", "c"].map((stimulus) => ({ stimulus })),
|
|
sample: {
|
|
type: "alternate-groups",
|
|
groups: [
|
|
[0, 0, 0, 0, 1, 1, 1, 1],
|
|
[2, 2, 2, 2, 3, 3, 3, 3],
|
|
[4, 4, 4, 4, 5, 5, 5, 5],
|
|
],
|
|
randomize_group_order: true,
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
let last = getHTML();
|
|
for (let i = 0; i < 23; i++) {
|
|
await pressKey("a");
|
|
let curr = getHTML();
|
|
expect(last).not.toMatch(curr);
|
|
last = curr;
|
|
}
|
|
await pressKey("a");
|
|
});
|
|
|
|
test("sampling functions run when timeline loops", async () => {
|
|
let count = 0;
|
|
const reps = 100;
|
|
|
|
const jsPsych = initJsPsych();
|
|
|
|
const { getHTML } = await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: jsPsych.timelineVariable("stimulus"),
|
|
},
|
|
],
|
|
timeline_variables: ["1", "2", "3"].map((stimulus) => ({ stimulus })),
|
|
sample: {
|
|
type: "without-replacement",
|
|
size: 1,
|
|
},
|
|
loop_function: () => {
|
|
count++;
|
|
return count < reps;
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
const result1 = [];
|
|
const result2 = [];
|
|
for (let i = 0; i < reps / 2; i++) {
|
|
result1.push(getHTML());
|
|
await pressKey("a");
|
|
result2.push(getHTML());
|
|
await pressKey("a");
|
|
}
|
|
|
|
expect(result1).not.toEqual(result2);
|
|
});
|
|
});
|
|
|
|
describe("timeline variables are correctly evaluated", () => {
|
|
// Something's wrong with the parameters of `htmlButtonResponse`
|
|
test.skip("when used as trial type parameter", async () => {
|
|
const jsPsych = initJsPsych();
|
|
|
|
const { getHTML } = await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: jsPsych.timelineVariable("type"),
|
|
stimulus: "hello",
|
|
choices: ["a", "b"],
|
|
},
|
|
],
|
|
timeline_variables: [{ type: htmlKeyboardResponse }, { type: htmlButtonResponse }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
expect(getHTML()).not.toMatch("button");
|
|
await pressKey("a");
|
|
expect(getHTML()).toMatch("button");
|
|
});
|
|
|
|
test("when used with a plugin that has a FUNCTION parameter type", async () => {
|
|
const jsPsych = initJsPsych();
|
|
|
|
const mockFn = jest.fn();
|
|
|
|
const { finished } = await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: callFunction,
|
|
func: jsPsych.timelineVariable("fn"),
|
|
},
|
|
],
|
|
timeline_variables: [{ fn: mockFn }, { fn: mockFn }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await finished;
|
|
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
test("custom sampling returns correct trials", async () => {
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "foo",
|
|
data: {
|
|
id: jsPsych.timelineVariable("id"),
|
|
},
|
|
},
|
|
],
|
|
timeline_variables: [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }],
|
|
sample: {
|
|
type: "custom",
|
|
fn: () => [2, 0],
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
await pressKey("a");
|
|
expect(jsPsych.data.get().select("id").values).toEqual([2, 0]);
|
|
});
|
|
|
|
test("custom sampling works with a loop", async () => {
|
|
let reps = 0;
|
|
let sample = 3;
|
|
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "foo",
|
|
data: {
|
|
id: jsPsych.timelineVariable("id"),
|
|
},
|
|
},
|
|
],
|
|
timeline_variables: [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }],
|
|
sample: {
|
|
type: "custom",
|
|
fn: () => [sample],
|
|
},
|
|
loop_function: () => {
|
|
reps++;
|
|
if (reps < 4) {
|
|
sample = 3 - reps;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
await pressKey("a");
|
|
await pressKey("a");
|
|
await pressKey("a");
|
|
expect(jsPsych.data.get().select("id").values).toEqual([3, 2, 1, 0]);
|
|
});
|
|
|
|
test("when used inside a function", async () => {
|
|
const jsPsych = initJsPsych();
|
|
const { getHTML } = await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: () => jsPsych.timelineVariable("x"),
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }, { x: "bar" }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
expect(getHTML()).toMatch("foo");
|
|
await pressKey("a");
|
|
expect(getHTML()).toMatch("bar");
|
|
});
|
|
|
|
test("when used in a conditional_function", async () => {
|
|
let x: string;
|
|
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "hello world",
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }],
|
|
conditional_function: () => {
|
|
x = jsPsych.evaluateTimelineVariable("x");
|
|
return true;
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
expect(x).toBe("foo");
|
|
});
|
|
|
|
test("when used in a loop_function", async () => {
|
|
let x: string;
|
|
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "hello world",
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }],
|
|
loop_function: () => {
|
|
x = jsPsych.evaluateTimelineVariable("x");
|
|
return false;
|
|
},
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
expect(x).toBe("foo");
|
|
});
|
|
|
|
test("when used in on_finish", async () => {
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "hello world",
|
|
on_finish: (data) => {
|
|
data.x = jsPsych.evaluateTimelineVariable("x");
|
|
},
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
expect(jsPsych.data.get().values()[0].x).toBe("foo");
|
|
});
|
|
|
|
test("when used in on_start", async () => {
|
|
let x: string;
|
|
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "hello world",
|
|
on_start: () => {
|
|
x = jsPsych.evaluateTimelineVariable("x");
|
|
},
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
expect(x).toBe("foo");
|
|
});
|
|
|
|
test("when used in on_load", async () => {
|
|
let x: string;
|
|
|
|
const jsPsych = initJsPsych();
|
|
await startTimeline(
|
|
[
|
|
{
|
|
timeline: [
|
|
{
|
|
type: htmlKeyboardResponse,
|
|
stimulus: "hello world",
|
|
on_load: () => {
|
|
x = jsPsych.evaluateTimelineVariable("x");
|
|
},
|
|
},
|
|
],
|
|
timeline_variables: [{ x: "foo" }],
|
|
},
|
|
],
|
|
jsPsych
|
|
);
|
|
|
|
await pressKey("a");
|
|
expect(x).toBe("foo");
|
|
});
|
|
});
|
|
|
|
// TODO keep this function?
|
|
// describe("jsPsych.getAllTimelineVariables()", () => {
|
|
// test("gets all timeline variables for a simple timeline", async () => {
|
|
// const jsPsych = initJsPsych();
|
|
// await startTimeline(
|
|
// [
|
|
// {
|
|
// timeline: [
|
|
// {
|
|
// type: htmlKeyboardResponse,
|
|
// stimulus: "foo",
|
|
// on_finish: (data) => {
|
|
// var all_tvs = jsPsych.getAllTimelineVariables();
|
|
// Object.assign(data, all_tvs);
|
|
// },
|
|
// },
|
|
// ],
|
|
// timeline_variables: [
|
|
// { a: 1, b: 2 },
|
|
// { a: 2, b: 3 },
|
|
// ],
|
|
// },
|
|
// ],
|
|
// jsPsych
|
|
// );
|
|
|
|
// pressKey("a");
|
|
// pressKey("a");
|
|
|
|
// expect(jsPsych.data.get().values()).toEqual([
|
|
// expect.objectContaining({ a: 1, b: 2 }),
|
|
// expect.objectContaining({ a: 2, b: 3 }),
|
|
// ]);
|
|
// });
|
|
|
|
// test("gets all timeline variables for a nested timeline", async () => {
|
|
// const jsPsych = initJsPsych();
|
|
// await startTimeline(
|
|
// [
|
|
// {
|
|
// timeline: [
|
|
// {
|
|
// timeline: [
|
|
// {
|
|
// type: htmlKeyboardResponse,
|
|
// stimulus: "foo",
|
|
// on_finish: (data) => {
|
|
// var all_tvs = jsPsych.getAllTimelineVariables();
|
|
// Object.assign(data, all_tvs);
|
|
// },
|
|
// },
|
|
// ],
|
|
// timeline_variables: [
|
|
// { a: 1, b: 2 },
|
|
// { a: 2, b: 3 },
|
|
// ],
|
|
// },
|
|
// ],
|
|
// timeline_variables: [{ c: 1 }, { c: 2 }],
|
|
// },
|
|
// ],
|
|
// jsPsych
|
|
// );
|
|
|
|
// for (let i = 0; i < 4; i++) {
|
|
// pressKey("a");
|
|
// }
|
|
|
|
// expect(jsPsych.data.get().values()).toEqual([
|
|
// expect.objectContaining({ a: 1, b: 2, c: 1 }),
|
|
// expect.objectContaining({ a: 2, b: 3, c: 1 }),
|
|
// expect.objectContaining({ a: 1, b: 2, c: 2 }),
|
|
// expect.objectContaining({ a: 2, b: 3, c: 2 }),
|
|
// ]);
|
|
// });
|
|
|
|
// test("gets the right values in a conditional_function", async () => {
|
|
// let a: number, b: number;
|
|
|
|
// const jsPsych = initJsPsych();
|
|
// await startTimeline(
|
|
// [
|
|
// {
|
|
// timeline: [
|
|
// {
|
|
// type: htmlKeyboardResponse,
|
|
// stimulus: "foo",
|
|
// },
|
|
// ],
|
|
// timeline_variables: [
|
|
// { a: 1, b: 2 },
|
|
// { a: 2, b: 3 },
|
|
// ],
|
|
// conditional_function: () => {
|
|
// var all_tvs = jsPsych.getAllTimelineVariables();
|
|
// a = all_tvs.a;
|
|
// b = all_tvs.b;
|
|
// return true;
|
|
// },
|
|
// },
|
|
// ],
|
|
// jsPsych
|
|
// );
|
|
|
|
// pressKey("a");
|
|
// pressKey("a");
|
|
|
|
// expect(a).toBe(1);
|
|
// expect(b).toBe(2);
|
|
// });
|
|
// });
|