Skip to content

Commit

Permalink
Merge pull request #3484 from jspsych/fix-build-citations-test
Browse files Browse the repository at this point in the history
handle citation test edge case
  • Loading branch information
jodeleeuw authored Jan 28, 2025
2 parents ec7e611 + e710cb0 commit 6e74767
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 107 deletions.
6 changes: 6 additions & 0 deletions .changeset/rich-fans-jump.md
Original file line number Diff line number Diff line change
@@ -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
27 changes: 14 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 3 additions & 7 deletions packages/config/generateCitations.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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 "";
}
})();

Expand Down
1 change: 1 addition & 0 deletions packages/config/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("./jest.cjs").makePackageConfig(__dirname);
8 changes: 6 additions & 2 deletions packages/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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"
}
}
94 changes: 94 additions & 0 deletions packages/config/tests/generateCitations.test.js
Original file line number Diff line number Diff line change
@@ -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/);
});
});
7 changes: 4 additions & 3 deletions packages/jspsych/src/JsPsych.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export class JsPsych {
return version;
}

// prettier-ignore
private citation: any = '__CITATIONS__';

/** Options */
private options: any = {};

Expand Down Expand Up @@ -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)) {
Expand All @@ -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) {
Expand Down
138 changes: 60 additions & 78 deletions packages/jspsych/tests/citations/citations.test.ts
Original file line number Diff line number Diff line change
@@ -1,94 +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.
*/
beforeEach(() => {
jspsych = initJsPsych();
(jspsych as any).citation = {
apa: "Test base APA citation",
bibtex: "Test base BibTeX citation",
};
});

try {
// Try to import built version
JsPsych = require("../../dist/index").JsPsych;
let jspsych: typeof JsPsych;

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
);
});
}
});
Loading

0 comments on commit 6e74767

Please sign in to comment.