From ac4272fd56289cadf973c2e9dd78abf52f6ee15a Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:00:43 -0700 Subject: [PATCH 1/5] check if `getCitations()` exists in build --- packages/jspsych/tests/citations/citations.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/jspsych/tests/citations/citations.test.ts b/packages/jspsych/tests/citations/citations.test.ts index a03e26c63d..93431bd92d 100644 --- a/packages/jspsych/tests/citations/citations.test.ts +++ b/packages/jspsych/tests/citations/citations.test.ts @@ -16,12 +16,16 @@ let JsPsych; * This is because the citation functionality is only available in the built version * due to code injections that run during the build. */ - try { // Try to import built version JsPsych = require("../../dist/index").JsPsych; let jspsych: typeof JsPsych; + // Check if getCitations exists in current built version + if (!jspsych.hasOwnProperty("getCitations")) { + throw new Error("getCitations not found"); + } + beforeEach(() => { jspsych = new JsPsych(); }); @@ -35,7 +39,7 @@ try { }); test("citing without input and with invalid format", () => { expect(() => jspsych.getCitations(null, "apa")).toThrow( - "Expected array of plugins/extensions" + "Expected array of plugins/extensionss" ); }); }); From 7e66039ab8d5f0e352da4265eacc19e832219433 Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:03:34 -0700 Subject: [PATCH 2/5] cleanup `console.log` in tests --- packages/jspsych/tests/core/simulation-mode.test.ts | 2 -- packages/plugin-instructions/src/index.spec.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/jspsych/tests/core/simulation-mode.test.ts b/packages/jspsych/tests/core/simulation-mode.test.ts index 94e9e8fcfb..095cc3315c 100644 --- a/packages/jspsych/tests/core/simulation-mode.test.ts +++ b/packages/jspsych/tests/core/simulation-mode.test.ts @@ -542,8 +542,6 @@ describe("data simulation mode", () => { const data = getData().values()[1]; - console.log(data); - expect(data.rt).toBeGreaterThan(0); expect(data.response).toBeDefined(); }); diff --git a/packages/plugin-instructions/src/index.spec.ts b/packages/plugin-instructions/src/index.spec.ts index 6ed199784b..72245f17f7 100644 --- a/packages/plugin-instructions/src/index.spec.ts +++ b/packages/plugin-instructions/src/index.spec.ts @@ -155,8 +155,6 @@ describe("instructions plugin simulation", () => { const data = getData().values()[0]; - console.log(data.view_history); - expect(data.rt).toBe(4000); let sum_view_history_rt = 0; From 89b489e6f40e2ed062beb5e152558a13b6c50954 Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:47:50 -0700 Subject: [PATCH 3/5] fix typo --- packages/jspsych/tests/citations/citations.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jspsych/tests/citations/citations.test.ts b/packages/jspsych/tests/citations/citations.test.ts index 93431bd92d..65ceee478c 100644 --- a/packages/jspsych/tests/citations/citations.test.ts +++ b/packages/jspsych/tests/citations/citations.test.ts @@ -39,7 +39,7 @@ try { }); test("citing without input and with invalid format", () => { expect(() => jspsych.getCitations(null, "apa")).toThrow( - "Expected array of plugins/extensionss" + "Expected array of plugins/extensions" ); }); }); From b12ce3051ddd11831613532e3f1bb352a736756e Mon Sep 17 00:00:00 2001 From: Josh de Leeuw Date: Mon, 27 Jan 2025 15:37:37 -0500 Subject: [PATCH 4/5] rework citation testing --- package-lock.json | 27 ++-- packages/config/generateCitations.js | 10 +- packages/config/jest.config.cjs | 1 + packages/config/package.json | 8 +- .../config/tests/generateCitations.test.js | 94 ++++++++++++ packages/jspsych/src/JsPsych.ts | 7 +- .../jspsych/tests/citations/citations.test.ts | 142 ++++++++---------- 7 files changed, 182 insertions(+), 107 deletions(-) create mode 100644 packages/config/jest.config.cjs create mode 100644 packages/config/tests/generateCitations.test.js diff --git a/package-lock.json b/package-lock.json index 5da89c7606..0ac2f4c7a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16074,6 +16074,7 @@ "@sucrase/jest-plugin": "3.0.0", "@types/gulp": "4.0.17", "@types/jest": "29.5.8", + "@types/node": "^22.10.10", "alias-hq": "6.2.4", "app-root-path": "^3.1.0", "canvas": "^2.11.2", @@ -16095,13 +16096,20 @@ "rollup-plugin-node-externals": "7.1.3", "sucrase": "3.34.0", "tslib": "2.6.2", - "typescript": "^5.2.2", - "yaml": "^2.5.1" + "typescript": "^5.2.2" }, "engines": { "node": ">=18.0.0" } }, + "packages/config/node_modules/@types/node": { + "version": "22.10.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", + "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", + "dependencies": { + "undici-types": "~6.20.0" + } + }, "packages/config/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -16142,17 +16150,10 @@ "node": "*" } }, - "packages/config/node_modules/yaml": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", - "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } + "packages/config/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, "packages/extension-mouse-tracking": { "name": "@jspsych/extension-mouse-tracking", diff --git a/packages/config/generateCitations.js b/packages/config/generateCitations.js index 9b4dbdadfb..bebc6a9ca3 100644 --- a/packages/config/generateCitations.js +++ b/packages/config/generateCitations.js @@ -7,7 +7,6 @@ import path from "node:path"; import { Cite } from "@citation-js/core"; import appRootPath from "app-root-path"; -import yaml from "yaml"; /** * Generate citation data from CITATION.cff file @@ -23,11 +22,8 @@ export default function generateCitations() { let rawCff; const getCff = (path) => { rawCff = fs.readFileSync(path, "utf-8").toString(); - const cffData = yaml.parse(rawCff); - if (cffData["preferred-citation"]) { - preferredCitation = true; - } - return yaml.stringify(rawCff); + preferredCitation = rawCff.includes("preferred-citation:"); + return rawCff; }; try { @@ -80,7 +76,7 @@ export default function generateCitations() { return citationBibtex; } catch (error) { console.log(`Error converting CITATION.cff to BibTeX string: ${error.message}`); - return null; + return ""; } })(); diff --git a/packages/config/jest.config.cjs b/packages/config/jest.config.cjs new file mode 100644 index 0000000000..abd3e30837 --- /dev/null +++ b/packages/config/jest.config.cjs @@ -0,0 +1 @@ +module.exports = require("./jest.cjs").makePackageConfig(__dirname); diff --git a/packages/config/package.json b/packages/config/package.json index c36154b4d5..1e89db6cc7 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -3,6 +3,10 @@ "version": "3.2.1", "description": "Shared (build) configuration for jsPsych packages", "type": "module", + "scripts": { + "test": "jest", + "test:watch": "npm test -- --watch" + }, "exports": { "./gulp": { "import": "./gulp.js", @@ -45,6 +49,7 @@ "@sucrase/jest-plugin": "3.0.0", "@types/gulp": "4.0.17", "@types/jest": "29.5.8", + "@types/node": "^22.10.10", "alias-hq": "6.2.4", "app-root-path": "^3.1.0", "canvas": "^2.11.2", @@ -66,7 +71,6 @@ "rollup-plugin-node-externals": "7.1.3", "sucrase": "3.34.0", "tslib": "2.6.2", - "typescript": "^5.2.2", - "yaml": "^2.5.1" + "typescript": "^5.2.2" } } diff --git a/packages/config/tests/generateCitations.test.js b/packages/config/tests/generateCitations.test.js new file mode 100644 index 0000000000..6198c2acab --- /dev/null +++ b/packages/config/tests/generateCitations.test.js @@ -0,0 +1,94 @@ +import fs from "node:fs"; + +import generateCitations from "../generateCitations"; + +// Mock filesystem +jest.mock("node:fs"); +jest.mock("app-root-path", () => ({ + path: "/mock/root/path", +})); + +describe("generateCitations", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const validCitationCff = ` +cff-version: 1.2.0 +message: Please cite this software using these metadata +title: Test Software +authors: + - family-names: Doe + given-names: John +version: 1.0.0 +date-released: 2023-01-01 + `; + + const citationCffWithPreferred = ` +cff-version: 1.2.0 +message: Please cite this software using these metadata +title: Test Software +authors: + - family-names: Doe + given-names: John +preferred-citation: + title: Preferred Citation + authors: + - family-names: Smith + given-names: Jane + `; + + test("should generate citations when CITATION.cff exists in current directory", () => { + fs.readFileSync.mockReturnValue(validCitationCff); + + const result = generateCitations(); + + expect(result).toHaveProperty("apa"); + expect(result).toHaveProperty("bibtex"); + expect(result.apa).not.toBe(""); + expect(result.bibtex).not.toBe(""); + }); + + test("should handle preferred-citation when present", () => { + fs.readFileSync.mockReturnValue(citationCffWithPreferred); + + const result = generateCitations(); + + expect(result).toHaveProperty("apa"); + expect(result).toHaveProperty("bibtex"); + expect(result.apa.includes("Smith")).toBeTruthy(); + }); + + test("should return empty strings when CITATION.cff is not found", () => { + fs.readFileSync.mockImplementation(() => { + throw new Error("File not found"); + }); + + const result = generateCitations(); + + expect(result).toEqual({ + apa: "", + bibtex: "", + }); + }); + + test("should handle malformed CITATION.cff", () => { + fs.readFileSync.mockReturnValue("invalid: yaml: content:"); + + const result = generateCitations(); + + expect(result).toEqual({ + apa: "", + bibtex: "", + }); + }); + + test("should remove newlines from citations", () => { + fs.readFileSync.mockReturnValue(validCitationCff); + + const result = generateCitations(); + + expect(result.apa).not.toMatch(/\n/); + expect(result.bibtex).not.toMatch(/\n/); + }); +}); diff --git a/packages/jspsych/src/JsPsych.ts b/packages/jspsych/src/JsPsych.ts index eeff974de2..1a7d519174 100644 --- a/packages/jspsych/src/JsPsych.ts +++ b/packages/jspsych/src/JsPsych.ts @@ -36,6 +36,9 @@ export class JsPsych { return version; } + // prettier-ignore + private citation: any = '__CITATIONS__'; + /** Options */ private options: any = {}; @@ -274,8 +277,6 @@ export class JsPsych { format: "apa" | "bibtex" = "apa" ) { const formatOptions = ["apa", "bibtex"]; - // prettier-ignore - const jsPsychCitations: any = '__CITATIONS__'; format = format.toLowerCase() as "apa" | "bibtex"; // Check if plugins is an array if (!Array.isArray(plugins)) { @@ -287,7 +288,7 @@ export class JsPsych { } // Print citations else { - const jsPsychCitation = jsPsychCitations[format]; + const jsPsychCitation = this.citation[format]; const citationSet = new Set([jsPsychCitation]); for (const plugin of plugins) { diff --git a/packages/jspsych/tests/citations/citations.test.ts b/packages/jspsych/tests/citations/citations.test.ts index 65ceee478c..bb8ad6ee95 100644 --- a/packages/jspsych/tests/citations/citations.test.ts +++ b/packages/jspsych/tests/citations/citations.test.ts @@ -1,98 +1,76 @@ +import { initJsPsych } from "../../src"; import { TestExtension } from "../extensions/TestExtension"; import TestPlugin from "../TestPlugin"; -const jsPsychApaCitation = - "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 "; -const jsPsychBibtexCitation = - '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '; +const jsPsychApaCitation = "Test base APA citation"; +const jsPsychBibtexCitation = "Test base BibTeX citation"; const testPluginApaCitation = "Test plugin APA citation"; const testPluginBibtexCitation = "Test plugin BibTeX citation"; const testExtensionApaCitation = "Test extension APA citation"; -let JsPsych; +let jspsych; -/** - * These tests are skipped if the built version of JsPsych is not found. - * This is because the citation functionality is only available in the built version - * due to code injections that run during the build. - */ -try { - // Try to import built version - JsPsych = require("../../dist/index").JsPsych; - let jspsych: typeof JsPsych; +beforeEach(() => { + jspsych = initJsPsych(); + (jspsych as any).citation = { + apa: "Test base APA citation", + bibtex: "Test base BibTeX citation", + }; +}); - // Check if getCitations exists in current built version - if (!jspsych.hasOwnProperty("getCitations")) { - throw new Error("getCitations not found"); - } - - beforeEach(() => { - jspsych = new JsPsych(); +describe("citing not using an array", () => { + test("citing without input", () => { + expect(jspsych.getCitations()).toBe(jsPsychApaCitation); }); - - describe("citing not using an array", () => { - test("citing without input", () => { - expect(jspsych.getCitations()).toBe(jsPsychApaCitation); - }); - test("citing null", () => { - expect(() => jspsych.getCitations(null)).toThrow("Expected array of plugins/extensions"); - }); - test("citing without input and with invalid format", () => { - expect(() => jspsych.getCitations(null, "apa")).toThrow( - "Expected array of plugins/extensions" - ); - }); + test("citing null", () => { + expect(() => jspsych.getCitations(null)).toThrow("Expected array of plugins/extensions"); + }); + test("citing without input and with invalid format", () => { + expect(() => jspsych.getCitations(null, "apa")).toThrow("Expected array of plugins/extensions"); }); +}); - describe("citing using an array in different formats", () => { - test("citing empty array with APA format", () => { - expect(jspsych.getCitations([], "apa")).toBe(jsPsychApaCitation); - }); - test("citing empty array with BibTeX format", () => { - expect(jspsych.getCitations([], "bibtex")).toBe(jsPsychBibtexCitation); - }); - test("citing empty array without format", () => { - expect(jspsych.getCitations([])).toBe(jsPsychApaCitation); - }); - test("citing one plugin with valid format in all caps", () => { - expect(jspsych.getCitations([TestPlugin], "APA")).toBe( - jsPsychApaCitation + "\n" + testPluginApaCitation - ); - }); - test("citing with unsupported format", () => { - expect(() => jspsych.getCitations([TestPlugin], "DummyTex")).toThrow( - "Unsupported citation format" - ); - }); +describe("citing using an array in different formats", () => { + test("citing empty array with APA format", () => { + expect(jspsych.getCitations([], "apa")).toBe(jsPsychApaCitation); + }); + test("citing empty array with BibTeX format", () => { + expect(jspsych.getCitations([], "bibtex")).toBe(jsPsychBibtexCitation); + }); + test("citing empty array without format", () => { + expect(jspsych.getCitations([])).toBe(jsPsychApaCitation); }); + test("citing one plugin with valid format in all caps", () => { + expect(jspsych.getCitations([TestPlugin], "APA")).toBe( + jsPsychApaCitation + "\n" + testPluginApaCitation + ); + }); + test("citing with unsupported format", () => { + expect(() => jspsych.getCitations([TestPlugin], "DummyTex")).toThrow( + "Unsupported citation format" + ); + }); +}); - describe("citing mix of valid plugins/extensions", () => { - test("citing a plugin", () => { - expect(jspsych.getCitations([TestPlugin])).toBe( - jsPsychApaCitation + "\n" + testPluginApaCitation - ); - }); - test("citing a plugin in BibTeX", () => { - expect(jspsych.getCitations([TestPlugin], "bibtex")).toBe( - jsPsychBibtexCitation + "\n" + testPluginBibtexCitation - ); - }); - test("citing multiple plugins", () => { - expect(jspsych.getCitations([TestPlugin, TestPlugin])).toBe( - jsPsychApaCitation + "\n" + testPluginApaCitation - ); - }); - test("citing mix of plugins and extensions", () => { - expect(jspsych.getCitations([TestPlugin, TestExtension])).toBe( - jsPsychApaCitation + "\n" + testPluginApaCitation + "\n" + testExtensionApaCitation - ); - }); +describe("citing mix of valid plugins/extensions", () => { + test("citing a plugin", () => { + expect(jspsych.getCitations([TestPlugin])).toBe( + jsPsychApaCitation + "\n" + testPluginApaCitation + ); + }); + test("citing a plugin in BibTeX", () => { + expect(jspsych.getCitations([TestPlugin], "bibtex")).toBe( + jsPsychBibtexCitation + "\n" + testPluginBibtexCitation + ); + }); + test("citing multiple plugins", () => { + expect(jspsych.getCitations([TestPlugin, TestPlugin])).toBe( + jsPsychApaCitation + "\n" + testPluginApaCitation + ); }); -} catch (e) { - // Fall back to development version if built version not found - describe("skipping citation tests because of missing built version", () => { - test.skip("skip", () => { - expect(true).toBe(true); - }); + test("citing mix of plugins and extensions", () => { + expect(jspsych.getCitations([TestPlugin, TestExtension])).toBe( + jsPsychApaCitation + "\n" + testPluginApaCitation + "\n" + testExtensionApaCitation + ); }); -} +}); From e710cb01e8ab2f992d0be902016e3e6540197f67 Mon Sep 17 00:00:00 2001 From: Josh de Leeuw Date: Mon, 27 Jan 2025 19:13:47 -0500 Subject: [PATCH 5/5] add a changeset --- .changeset/rich-fans-jump.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/rich-fans-jump.md diff --git a/.changeset/rich-fans-jump.md b/.changeset/rich-fans-jump.md new file mode 100644 index 0000000000..f46f33c672 --- /dev/null +++ b/.changeset/rich-fans-jump.md @@ -0,0 +1,6 @@ +--- +"jspsych": patch +"@jspsych/config": patch +--- + +Patches some edge cases for `getCitations` and the build process that reads CITATION.CFF files to include citation info