@jspsych/test-utils 1.2.0 → 1.3.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/dist/index.cjs CHANGED
@@ -10,16 +10,20 @@ function dispatchEvent(event, target = document.body) {
10
10
  target.dispatchEvent(event);
11
11
  return flushPromises();
12
12
  }
13
- async function keyDown(key) {
14
- await dispatchEvent(new KeyboardEvent("keydown", { key }));
13
+ async function keyDown(key, code) {
14
+ await dispatchEvent(new KeyboardEvent("keydown", { key, code }));
15
15
  }
16
- async function keyUp(key) {
17
- await dispatchEvent(new KeyboardEvent("keyup", { key }));
16
+ async function keyUp(key, code) {
17
+ await dispatchEvent(new KeyboardEvent("keyup", { key, code }));
18
18
  }
19
19
  async function pressKey(key) {
20
20
  await keyDown(key);
21
21
  await keyUp(key);
22
22
  }
23
+ async function windowBlur() {
24
+ window.dispatchEvent(new Event("blur"));
25
+ await flushPromises();
26
+ }
23
27
  async function mouseDownMouseUpTarget(target) {
24
28
  await dispatchEvent(new MouseEvent("mousedown", { bubbles: true }), target);
25
29
  await dispatchEvent(new MouseEvent("mouseup", { bubbles: true }), target);
@@ -64,7 +68,9 @@ async function startTimeline(timeline, jsPsych = {}) {
64
68
  return {
65
69
  jsPsych: jsPsychInstance,
66
70
  displayElement,
71
+ /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */
67
72
  getHTML: () => displayElement.innerHTML,
73
+ /** Shorthand for `jsPsych.data.get()` */
68
74
  getData: () => jsPsychInstance.data.get(),
69
75
  expectFinished: async () => {
70
76
  await flushPromises();
@@ -74,6 +80,7 @@ async function startTimeline(timeline, jsPsych = {}) {
74
80
  await flushPromises();
75
81
  expect(hasFinished).toBe(false);
76
82
  },
83
+ /** A promise that is resolved when `jsPsych.run()` is done. */
77
84
  finished
78
85
  };
79
86
  }
@@ -88,7 +95,9 @@ async function simulateTimeline(timeline, simulation_mode, simulation_options =
88
95
  return {
89
96
  jsPsych: jsPsychInstance,
90
97
  displayElement,
98
+ /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */
91
99
  getHTML: () => displayElement.innerHTML,
100
+ /** Shorthand for `jsPsych.data.get()` */
92
101
  getData: () => jsPsychInstance.data.get(),
93
102
  expectFinished: async () => {
94
103
  await flushPromises();
@@ -98,6 +107,7 @@ async function simulateTimeline(timeline, simulation_mode, simulation_options =
98
107
  await flushPromises();
99
108
  expect(hasFinished).toBe(false);
100
109
  },
110
+ /** A promise that is resolved when `jsPsych.simulate()` is done. */
101
111
  finished
102
112
  };
103
113
  }
@@ -114,4 +124,5 @@ exports.mouseUp = mouseUp;
114
124
  exports.pressKey = pressKey;
115
125
  exports.simulateTimeline = simulateTimeline;
116
126
  exports.startTimeline = startTimeline;
127
+ exports.windowBlur = windowBlur;
117
128
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { setImmediate as flushMicroTasks } from \"timers\";\n\nimport { JsPsych } from \"jspsych\";\n\n/**\n * https://github.com/facebook/jest/issues/2157#issuecomment-279171856\n */\nexport function flushPromises() {\n return new Promise((resolve) => flushMicroTasks(resolve));\n}\n\nexport function dispatchEvent(event: Event, target: Element = document.body) {\n target.dispatchEvent(event);\n return flushPromises();\n}\n\nexport async function keyDown(key: string) {\n await dispatchEvent(new KeyboardEvent(\"keydown\", { key }));\n}\n\nexport async function keyUp(key: string) {\n await dispatchEvent(new KeyboardEvent(\"keyup\", { key }));\n}\n\nexport async function pressKey(key: string) {\n await keyDown(key);\n await keyUp(key);\n}\n\nexport async function mouseDownMouseUpTarget(target: Element) {\n await dispatchEvent(new MouseEvent(\"mousedown\", { bubbles: true }), target);\n await dispatchEvent(new MouseEvent(\"mouseup\", { bubbles: true }), target);\n}\n\nexport async function clickTarget(target: Element) {\n // Check if the target is a form element and if it's disabled\n if (target instanceof HTMLButtonElement || target instanceof HTMLInputElement) {\n if (target.disabled) {\n console.log(\"Target is disabled, not dispatching click event.\");\n return; // Exit the function if the target is disabled\n }\n }\n await dispatchEvent(new MouseEvent(\"click\", { bubbles: true }), target);\n}\n\n/**\n * Dispatch a `MouseEvent` of type `eventType`, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nasync function dispatchMouseEvent(eventType: string, x: number, y: number, container: Element) {\n const containerRect = container.getBoundingClientRect();\n await dispatchEvent(\n new MouseEvent(eventType, {\n clientX: containerRect.x + x,\n clientY: containerRect.y + y,\n bubbles: true,\n }),\n container\n );\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseMove(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousemove\", x, y, container);\n}\n\n/**\n * Dispatch a `mouseup` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseUp(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mouseup\", x, y, container);\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseDown(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousedown\", x, y, container);\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.run()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function startTimeline(timeline: any[], jsPsych: JsPsych | any = {}) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance.run(timeline).then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.run()` is done. */\n finished,\n };\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.simulate()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param simulation_mode Either 'data-only' mode or 'visual' mode.\n * @param simulation_options Options to pass to `jsPsych.simulate()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function simulateTimeline(\n timeline: any[],\n simulation_mode?: \"data-only\" | \"visual\",\n simulation_options: any = {},\n jsPsych: JsPsych | any = {}\n) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance\n .simulate(timeline, simulation_mode, simulation_options)\n .then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.simulate()` is done. */\n finished,\n };\n}\n"],"names":["flushMicroTasks","JsPsych"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { setImmediate as flushMicroTasks } from \"timers\";\n\nimport { JsPsych } from \"jspsych\";\n\n/**\n * https://github.com/facebook/jest/issues/2157#issuecomment-279171856\n */\nexport function flushPromises() {\n return new Promise((resolve) => flushMicroTasks(resolve));\n}\n\nexport function dispatchEvent(event: Event, target: Element = document.body) {\n target.dispatchEvent(event);\n return flushPromises();\n}\n\nexport async function keyDown(key: string, code?: string) {\n await dispatchEvent(new KeyboardEvent(\"keydown\", { key, code }));\n}\n\nexport async function keyUp(key: string, code?: string) {\n await dispatchEvent(new KeyboardEvent(\"keyup\", { key, code }));\n}\n\nexport async function pressKey(key: string) {\n await keyDown(key);\n await keyUp(key);\n}\n\nexport async function windowBlur() {\n window.dispatchEvent(new Event(\"blur\"));\n await flushPromises();\n}\n\nexport async function mouseDownMouseUpTarget(target: Element) {\n await dispatchEvent(new MouseEvent(\"mousedown\", { bubbles: true }), target);\n await dispatchEvent(new MouseEvent(\"mouseup\", { bubbles: true }), target);\n}\n\nexport async function clickTarget(target: Element) {\n // Check if the target is a form element and if it's disabled\n if (target instanceof HTMLButtonElement || target instanceof HTMLInputElement) {\n if (target.disabled) {\n console.log(\"Target is disabled, not dispatching click event.\");\n return; // Exit the function if the target is disabled\n }\n }\n await dispatchEvent(new MouseEvent(\"click\", { bubbles: true }), target);\n}\n\n/**\n * Dispatch a `MouseEvent` of type `eventType`, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nasync function dispatchMouseEvent(eventType: string, x: number, y: number, container: Element) {\n const containerRect = container.getBoundingClientRect();\n await dispatchEvent(\n new MouseEvent(eventType, {\n clientX: containerRect.x + x,\n clientY: containerRect.y + y,\n bubbles: true,\n }),\n container\n );\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseMove(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousemove\", x, y, container);\n}\n\n/**\n * Dispatch a `mouseup` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseUp(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mouseup\", x, y, container);\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseDown(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousedown\", x, y, container);\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.run()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function startTimeline(timeline: any[], jsPsych: JsPsych | any = {}) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance.run(timeline).then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.run()` is done. */\n finished,\n };\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.simulate()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param simulation_mode Either 'data-only' mode or 'visual' mode.\n * @param simulation_options Options to pass to `jsPsych.simulate()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function simulateTimeline(\n timeline: any[],\n simulation_mode?: \"data-only\" | \"visual\",\n simulation_options: any = {},\n jsPsych: JsPsych | any = {}\n) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance\n .simulate(timeline, simulation_mode, simulation_options)\n .then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.simulate()` is done. */\n finished,\n };\n}\n"],"names":["flushMicroTasks","JsPsych"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,9 +6,10 @@ import { JsPsych } from 'jspsych';
6
6
  */
7
7
  declare function flushPromises(): Promise<unknown>;
8
8
  declare function dispatchEvent(event: Event, target?: Element): Promise<unknown>;
9
- declare function keyDown(key: string): Promise<void>;
10
- declare function keyUp(key: string): Promise<void>;
9
+ declare function keyDown(key: string, code?: string): Promise<void>;
10
+ declare function keyUp(key: string, code?: string): Promise<void>;
11
11
  declare function pressKey(key: string): Promise<void>;
12
+ declare function windowBlur(): Promise<void>;
12
13
  declare function mouseDownMouseUpTarget(target: Element): Promise<void>;
13
14
  declare function clickTarget(target: Element): Promise<void>;
14
15
  /**
@@ -79,4 +80,4 @@ declare function simulateTimeline(timeline: any[], simulation_mode?: "data-only"
79
80
  finished: Promise<void>;
80
81
  }>;
81
82
 
82
- export { clickTarget, dispatchEvent, flushPromises, keyDown, keyUp, mouseDown, mouseDownMouseUpTarget, mouseMove, mouseUp, pressKey, simulateTimeline, startTimeline };
83
+ export { clickTarget, dispatchEvent, flushPromises, keyDown, keyUp, mouseDown, mouseDownMouseUpTarget, mouseMove, mouseUp, pressKey, simulateTimeline, startTimeline, windowBlur };
package/dist/index.js CHANGED
@@ -8,16 +8,20 @@ function dispatchEvent(event, target = document.body) {
8
8
  target.dispatchEvent(event);
9
9
  return flushPromises();
10
10
  }
11
- async function keyDown(key) {
12
- await dispatchEvent(new KeyboardEvent("keydown", { key }));
11
+ async function keyDown(key, code) {
12
+ await dispatchEvent(new KeyboardEvent("keydown", { key, code }));
13
13
  }
14
- async function keyUp(key) {
15
- await dispatchEvent(new KeyboardEvent("keyup", { key }));
14
+ async function keyUp(key, code) {
15
+ await dispatchEvent(new KeyboardEvent("keyup", { key, code }));
16
16
  }
17
17
  async function pressKey(key) {
18
18
  await keyDown(key);
19
19
  await keyUp(key);
20
20
  }
21
+ async function windowBlur() {
22
+ window.dispatchEvent(new Event("blur"));
23
+ await flushPromises();
24
+ }
21
25
  async function mouseDownMouseUpTarget(target) {
22
26
  await dispatchEvent(new MouseEvent("mousedown", { bubbles: true }), target);
23
27
  await dispatchEvent(new MouseEvent("mouseup", { bubbles: true }), target);
@@ -62,7 +66,9 @@ async function startTimeline(timeline, jsPsych = {}) {
62
66
  return {
63
67
  jsPsych: jsPsychInstance,
64
68
  displayElement,
69
+ /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */
65
70
  getHTML: () => displayElement.innerHTML,
71
+ /** Shorthand for `jsPsych.data.get()` */
66
72
  getData: () => jsPsychInstance.data.get(),
67
73
  expectFinished: async () => {
68
74
  await flushPromises();
@@ -72,6 +78,7 @@ async function startTimeline(timeline, jsPsych = {}) {
72
78
  await flushPromises();
73
79
  expect(hasFinished).toBe(false);
74
80
  },
81
+ /** A promise that is resolved when `jsPsych.run()` is done. */
75
82
  finished
76
83
  };
77
84
  }
@@ -86,7 +93,9 @@ async function simulateTimeline(timeline, simulation_mode, simulation_options =
86
93
  return {
87
94
  jsPsych: jsPsychInstance,
88
95
  displayElement,
96
+ /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */
89
97
  getHTML: () => displayElement.innerHTML,
98
+ /** Shorthand for `jsPsych.data.get()` */
90
99
  getData: () => jsPsychInstance.data.get(),
91
100
  expectFinished: async () => {
92
101
  await flushPromises();
@@ -96,9 +105,10 @@ async function simulateTimeline(timeline, simulation_mode, simulation_options =
96
105
  await flushPromises();
97
106
  expect(hasFinished).toBe(false);
98
107
  },
108
+ /** A promise that is resolved when `jsPsych.simulate()` is done. */
99
109
  finished
100
110
  };
101
111
  }
102
112
 
103
- export { clickTarget, dispatchEvent, flushPromises, keyDown, keyUp, mouseDown, mouseDownMouseUpTarget, mouseMove, mouseUp, pressKey, simulateTimeline, startTimeline };
113
+ export { clickTarget, dispatchEvent, flushPromises, keyDown, keyUp, mouseDown, mouseDownMouseUpTarget, mouseMove, mouseUp, pressKey, simulateTimeline, startTimeline, windowBlur };
104
114
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { setImmediate as flushMicroTasks } from \"timers\";\n\nimport { JsPsych } from \"jspsych\";\n\n/**\n * https://github.com/facebook/jest/issues/2157#issuecomment-279171856\n */\nexport function flushPromises() {\n return new Promise((resolve) => flushMicroTasks(resolve));\n}\n\nexport function dispatchEvent(event: Event, target: Element = document.body) {\n target.dispatchEvent(event);\n return flushPromises();\n}\n\nexport async function keyDown(key: string) {\n await dispatchEvent(new KeyboardEvent(\"keydown\", { key }));\n}\n\nexport async function keyUp(key: string) {\n await dispatchEvent(new KeyboardEvent(\"keyup\", { key }));\n}\n\nexport async function pressKey(key: string) {\n await keyDown(key);\n await keyUp(key);\n}\n\nexport async function mouseDownMouseUpTarget(target: Element) {\n await dispatchEvent(new MouseEvent(\"mousedown\", { bubbles: true }), target);\n await dispatchEvent(new MouseEvent(\"mouseup\", { bubbles: true }), target);\n}\n\nexport async function clickTarget(target: Element) {\n // Check if the target is a form element and if it's disabled\n if (target instanceof HTMLButtonElement || target instanceof HTMLInputElement) {\n if (target.disabled) {\n console.log(\"Target is disabled, not dispatching click event.\");\n return; // Exit the function if the target is disabled\n }\n }\n await dispatchEvent(new MouseEvent(\"click\", { bubbles: true }), target);\n}\n\n/**\n * Dispatch a `MouseEvent` of type `eventType`, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nasync function dispatchMouseEvent(eventType: string, x: number, y: number, container: Element) {\n const containerRect = container.getBoundingClientRect();\n await dispatchEvent(\n new MouseEvent(eventType, {\n clientX: containerRect.x + x,\n clientY: containerRect.y + y,\n bubbles: true,\n }),\n container\n );\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseMove(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousemove\", x, y, container);\n}\n\n/**\n * Dispatch a `mouseup` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseUp(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mouseup\", x, y, container);\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseDown(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousedown\", x, y, container);\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.run()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function startTimeline(timeline: any[], jsPsych: JsPsych | any = {}) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance.run(timeline).then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.run()` is done. */\n finished,\n };\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.simulate()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param simulation_mode Either 'data-only' mode or 'visual' mode.\n * @param simulation_options Options to pass to `jsPsych.simulate()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function simulateTimeline(\n timeline: any[],\n simulation_mode?: \"data-only\" | \"visual\",\n simulation_options: any = {},\n jsPsych: JsPsych | any = {}\n) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance\n .simulate(timeline, simulation_mode, simulation_options)\n .then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.simulate()` is done. */\n finished,\n };\n}\n"],"names":["flushMicroTasks"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { setImmediate as flushMicroTasks } from \"timers\";\n\nimport { JsPsych } from \"jspsych\";\n\n/**\n * https://github.com/facebook/jest/issues/2157#issuecomment-279171856\n */\nexport function flushPromises() {\n return new Promise((resolve) => flushMicroTasks(resolve));\n}\n\nexport function dispatchEvent(event: Event, target: Element = document.body) {\n target.dispatchEvent(event);\n return flushPromises();\n}\n\nexport async function keyDown(key: string, code?: string) {\n await dispatchEvent(new KeyboardEvent(\"keydown\", { key, code }));\n}\n\nexport async function keyUp(key: string, code?: string) {\n await dispatchEvent(new KeyboardEvent(\"keyup\", { key, code }));\n}\n\nexport async function pressKey(key: string) {\n await keyDown(key);\n await keyUp(key);\n}\n\nexport async function windowBlur() {\n window.dispatchEvent(new Event(\"blur\"));\n await flushPromises();\n}\n\nexport async function mouseDownMouseUpTarget(target: Element) {\n await dispatchEvent(new MouseEvent(\"mousedown\", { bubbles: true }), target);\n await dispatchEvent(new MouseEvent(\"mouseup\", { bubbles: true }), target);\n}\n\nexport async function clickTarget(target: Element) {\n // Check if the target is a form element and if it's disabled\n if (target instanceof HTMLButtonElement || target instanceof HTMLInputElement) {\n if (target.disabled) {\n console.log(\"Target is disabled, not dispatching click event.\");\n return; // Exit the function if the target is disabled\n }\n }\n await dispatchEvent(new MouseEvent(\"click\", { bubbles: true }), target);\n}\n\n/**\n * Dispatch a `MouseEvent` of type `eventType`, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nasync function dispatchMouseEvent(eventType: string, x: number, y: number, container: Element) {\n const containerRect = container.getBoundingClientRect();\n await dispatchEvent(\n new MouseEvent(eventType, {\n clientX: containerRect.x + x,\n clientY: containerRect.y + y,\n bubbles: true,\n }),\n container\n );\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseMove(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousemove\", x, y, container);\n}\n\n/**\n * Dispatch a `mouseup` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseUp(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mouseup\", x, y, container);\n}\n\n/**\n * Dispatch a `mousemove` event, with x and y defined relative to the container element.\n * @param x The x location of the event, relative to the x location of `container`.\n * @param y The y location of the event, relative to the y location of `container`.\n * @param container The DOM element for relative location of the event.\n */\nexport async function mouseDown(x: number, y: number, container: Element) {\n await dispatchMouseEvent(\"mousedown\", x, y, container);\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.run()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function startTimeline(timeline: any[], jsPsych: JsPsych | any = {}) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance.run(timeline).then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.run()` is done. */\n finished,\n };\n}\n\n/**\n * Runs the given timeline by calling `jsPsych.simulate()` on the provided JsPsych object.\n *\n * @param timeline The timeline that is passed to `jsPsych.run()`\n * @param simulation_mode Either 'data-only' mode or 'visual' mode.\n * @param simulation_options Options to pass to `jsPsych.simulate()`\n * @param jsPsych The jsPsych instance to be used. If left empty, a new instance will be created. If\n * a settings object is passed instead, the settings will be used to create the jsPsych instance.\n *\n * @returns An object containing test helper functions, the jsPsych instance, and the jsPsych\n * display element\n */\nexport async function simulateTimeline(\n timeline: any[],\n simulation_mode?: \"data-only\" | \"visual\",\n simulation_options: any = {},\n jsPsych: JsPsych | any = {}\n) {\n const jsPsychInstance = jsPsych instanceof JsPsych ? jsPsych : new JsPsych(jsPsych);\n\n let hasFinished = false;\n const finished = jsPsychInstance\n .simulate(timeline, simulation_mode, simulation_options)\n .then(() => {\n hasFinished = true;\n });\n await flushPromises();\n\n const displayElement = jsPsychInstance.getDisplayElement();\n\n return {\n jsPsych: jsPsychInstance,\n displayElement,\n /** Shorthand for `jsPsych.getDisplayElement().innerHTML` */\n getHTML: () => displayElement.innerHTML,\n /** Shorthand for `jsPsych.data.get()` */\n getData: () => jsPsychInstance.data.get(),\n expectFinished: async () => {\n await flushPromises();\n expect(hasFinished).toBe(true);\n },\n expectRunning: async () => {\n await flushPromises();\n expect(hasFinished).toBe(false);\n },\n /** A promise that is resolved when `jsPsych.simulate()` is done. */\n finished,\n };\n}\n"],"names":["flushMicroTasks"],"mappings":";;;AAOO,SAAS,aAAA,GAAgB;AAC9B,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAYA,YAAA,CAAgB,OAAO,CAAC,CAAA;AAC1D;AAEO,SAAS,aAAA,CAAc,KAAA,EAAc,MAAA,GAAkB,QAAA,CAAS,IAAA,EAAM;AAC3E,EAAA,MAAA,CAAO,cAAc,KAAK,CAAA;AAC1B,EAAA,OAAO,aAAA,EAAc;AACvB;AAEA,eAAsB,OAAA,CAAQ,KAAa,IAAA,EAAe;AACxD,EAAA,MAAM,aAAA,CAAc,IAAI,aAAA,CAAc,SAAA,EAAW,EAAE,GAAA,EAAK,IAAA,EAAM,CAAC,CAAA;AACjE;AAEA,eAAsB,KAAA,CAAM,KAAa,IAAA,EAAe;AACtD,EAAA,MAAM,aAAA,CAAc,IAAI,aAAA,CAAc,OAAA,EAAS,EAAE,GAAA,EAAK,IAAA,EAAM,CAAC,CAAA;AAC/D;AAEA,eAAsB,SAAS,GAAA,EAAa;AAC1C,EAAA,MAAM,QAAQ,GAAG,CAAA;AACjB,EAAA,MAAM,MAAM,GAAG,CAAA;AACjB;AAEA,eAAsB,UAAA,GAAa;AACjC,EAAA,MAAA,CAAO,aAAA,CAAc,IAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AACtC,EAAA,MAAM,aAAA,EAAc;AACtB;AAEA,eAAsB,uBAAuB,MAAA,EAAiB;AAC5D,EAAA,MAAM,aAAA,CAAc,IAAI,UAAA,CAAW,WAAA,EAAa,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,EAAG,MAAM,CAAA;AAC1E,EAAA,MAAM,aAAA,CAAc,IAAI,UAAA,CAAW,SAAA,EAAW,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,EAAG,MAAM,CAAA;AAC1E;AAEA,eAAsB,YAAY,MAAA,EAAiB;AAEjD,EAAA,IAAI,MAAA,YAAkB,iBAAA,IAAqB,MAAA,YAAkB,gBAAA,EAAkB;AAC7E,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,OAAA,CAAQ,IAAI,kDAAkD,CAAA;AAC9D,MAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,MAAM,aAAA,CAAc,IAAI,UAAA,CAAW,OAAA,EAAS,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,EAAG,MAAM,CAAA;AACxE;AAQA,eAAe,kBAAA,CAAmB,SAAA,EAAmB,CAAA,EAAW,CAAA,EAAW,SAAA,EAAoB;AAC7F,EAAA,MAAM,aAAA,GAAgB,UAAU,qBAAA,EAAsB;AACtD,EAAA,MAAM,aAAA;AAAA,IACJ,IAAI,WAAW,SAAA,EAAW;AAAA,MACxB,OAAA,EAAS,cAAc,CAAA,GAAI,CAAA;AAAA,MAC3B,OAAA,EAAS,cAAc,CAAA,GAAI,CAAA;AAAA,MAC3B,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,IACD;AAAA,GACF;AACF;AAQA,eAAsB,SAAA,CAAU,CAAA,EAAW,CAAA,EAAW,SAAA,EAAoB;AACxE,EAAA,MAAM,kBAAA,CAAmB,WAAA,EAAa,CAAA,EAAG,CAAA,EAAG,SAAS,CAAA;AACvD;AAQA,eAAsB,OAAA,CAAQ,CAAA,EAAW,CAAA,EAAW,SAAA,EAAoB;AACtE,EAAA,MAAM,kBAAA,CAAmB,SAAA,EAAW,CAAA,EAAG,CAAA,EAAG,SAAS,CAAA;AACrD;AAQA,eAAsB,SAAA,CAAU,CAAA,EAAW,CAAA,EAAW,SAAA,EAAoB;AACxE,EAAA,MAAM,kBAAA,CAAmB,WAAA,EAAa,CAAA,EAAG,CAAA,EAAG,SAAS,CAAA;AACvD;AAYA,eAAsB,aAAA,CAAc,QAAA,EAAiB,OAAA,GAAyB,EAAC,EAAG;AAChF,EAAA,MAAM,kBAAkB,OAAA,YAAmB,OAAA,GAAU,OAAA,GAAU,IAAI,QAAQ,OAAO,CAAA;AAElF,EAAA,IAAI,WAAA,GAAc,KAAA;AAClB,EAAA,MAAM,WAAW,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA,CAAE,KAAK,MAAM;AACxD,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB,CAAC,CAAA;AACD,EAAA,MAAM,aAAA,EAAc;AAEpB,EAAA,MAAM,cAAA,GAAiB,gBAAgB,iBAAA,EAAkB;AAEzD,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,eAAA;AAAA,IACT,cAAA;AAAA;AAAA,IAEA,OAAA,EAAS,MAAM,cAAA,CAAe,SAAA;AAAA;AAAA,IAE9B,OAAA,EAAS,MAAM,eAAA,CAAgB,IAAA,CAAK,GAAA,EAAI;AAAA,IACxC,gBAAgB,YAAY;AAC1B,MAAA,MAAM,aAAA,EAAc;AACpB,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,eAAe,YAAY;AACzB,MAAA,MAAM,aAAA,EAAc;AACpB,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AACF;AAcA,eAAsB,gBAAA,CACpB,UACA,eAAA,EACA,kBAAA,GAA0B,EAAC,EAC3B,OAAA,GAAyB,EAAC,EAC1B;AACA,EAAA,MAAM,kBAAkB,OAAA,YAAmB,OAAA,GAAU,OAAA,GAAU,IAAI,QAAQ,OAAO,CAAA;AAElF,EAAA,IAAI,WAAA,GAAc,KAAA;AAClB,EAAA,MAAM,QAAA,GAAW,gBACd,QAAA,CAAS,QAAA,EAAU,iBAAiB,kBAAkB,CAAA,CACtD,KAAK,MAAM;AACV,IAAA,WAAA,GAAc,IAAA;AAAA,EAChB,CAAC,CAAA;AACH,EAAA,MAAM,aAAA,EAAc;AAEpB,EAAA,MAAM,cAAA,GAAiB,gBAAgB,iBAAA,EAAkB;AAEzD,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,eAAA;AAAA,IACT,cAAA;AAAA;AAAA,IAEA,OAAA,EAAS,MAAM,cAAA,CAAe,SAAA;AAAA;AAAA,IAE9B,OAAA,EAAS,MAAM,eAAA,CAAgB,IAAA,CAAK,GAAA,EAAI;AAAA,IACxC,gBAAgB,YAAY;AAC1B,MAAA,MAAM,aAAA,EAAc;AACpB,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,eAAe,YAAY;AACzB,MAAA,MAAM,aAAA,EAAc;AACpB,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jspsych/test-utils",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Test utility functions for jsPsych-related test cases",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -34,7 +34,7 @@
34
34
  "@types/jest": "*"
35
35
  },
36
36
  "devDependencies": {
37
- "@jspsych/config": "^3.0.0",
38
- "jspsych": "^8.0.0"
37
+ "@jspsych/config": "^3.3.4",
38
+ "jspsych": "^8.3.0"
39
39
  }
40
40
  }
package/src/index.ts CHANGED
@@ -14,12 +14,12 @@ export function dispatchEvent(event: Event, target: Element = document.body) {
14
14
  return flushPromises();
15
15
  }
16
16
 
17
- export async function keyDown(key: string) {
18
- await dispatchEvent(new KeyboardEvent("keydown", { key }));
17
+ export async function keyDown(key: string, code?: string) {
18
+ await dispatchEvent(new KeyboardEvent("keydown", { key, code }));
19
19
  }
20
20
 
21
- export async function keyUp(key: string) {
22
- await dispatchEvent(new KeyboardEvent("keyup", { key }));
21
+ export async function keyUp(key: string, code?: string) {
22
+ await dispatchEvent(new KeyboardEvent("keyup", { key, code }));
23
23
  }
24
24
 
25
25
  export async function pressKey(key: string) {
@@ -27,6 +27,11 @@ export async function pressKey(key: string) {
27
27
  await keyUp(key);
28
28
  }
29
29
 
30
+ export async function windowBlur() {
31
+ window.dispatchEvent(new Event("blur"));
32
+ await flushPromises();
33
+ }
34
+
30
35
  export async function mouseDownMouseUpTarget(target: Element) {
31
36
  await dispatchEvent(new MouseEvent("mousedown", { bubbles: true }), target);
32
37
  await dispatchEvent(new MouseEvent("mouseup", { bubbles: true }), target);