diff --git a/jest.config.cjs b/jest.config.cjs index b68d17a4..4028b4c9 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -11,5 +11,6 @@ module.exports = { testMatch: [ "/tests/**/*.[jt]s?(x)", "/tests/**/?(*.)+(spec|test).[jt]s?(x)", + "/server/__tests__/**/*.test.cjs", ], }; diff --git a/server/__tests__/prepare-glossary.test.cjs b/server/__tests__/prepare-glossary.test.cjs new file mode 100644 index 00000000..78865d1e --- /dev/null +++ b/server/__tests__/prepare-glossary.test.cjs @@ -0,0 +1,44 @@ +"use strict"; + +const fs = require("fs"); +const os = require("os"); +const path = require("path"); + +let writeGlossaryFiles; +beforeAll(() => { + ({ writeGlossaryFiles } = require("../prepare-glossary.cjs")); +}); + +describe("writeGlossaryFiles", () => { + let tmpDir; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "glossary-test-")); + fs.mkdirSync(path.join(tmpDir, "parameters")); + }); + + afterEach(() => { + fs.rmSync(tmpDir, { recursive: true }); + }); + + test("glossary.ts exists on disk when the promise resolves", async () => { + await writeGlossaryFiles(tmpDir, {}, [], []); + expect(fs.existsSync(path.join(tmpDir, "parameters", "glossary.ts"))).toBe(true); + }); + + test("glossary-full.ts exists on disk when the promise resolves", async () => { + await writeGlossaryFiles(tmpDir, {}, [], []); + expect(fs.existsSync(path.join(tmpDir, "parameters", "glossary-full.ts"))).toBe(true); + }); + + test("resolves (does not reject) when a write fails, and logs the error", async () => { + const badDir = path.join(tmpDir, "nonexistent"); + const consoleSpy = jest.spyOn(console, "log").mockImplementation(() => {}); + await expect(writeGlossaryFiles(badDir, {}, [], [])).resolves.toBeUndefined(); + expect(consoleSpy).toHaveBeenCalledWith( + "Error! Couldn't write to the file.", + expect.objectContaining({ code: "ENOENT" }) + ); + consoleSpy.mockRestore(); + }); +}); diff --git a/server/prepare-glossary.cjs b/server/prepare-glossary.cjs index c83f3071..4b838deb 100644 --- a/server/prepare-glossary.cjs +++ b/server/prepare-glossary.cjs @@ -31,7 +31,7 @@ async function processLanguageSheet() { XLSX.utils.aoa_to_sheet(rows.data.values), { defval: "", - } + }, ); /* -------------------------------------------------------------------------- */ @@ -51,7 +51,7 @@ async function processLanguageSheet() { parameterInfo.type === "multicategorical" ) parameterInfo.categories = getCategoriesFromString( - parameter["CATEGORIES"] + parameter["CATEGORIES"], ); // Exclude rows that Denis used for other notes // if (parameterInfo.name && parameterInfo.type) @@ -80,9 +80,13 @@ async function processLanguageSheet() { /* -------------------------------------------------------------------------- */ const superMatchingParams = Object.keys(data).filter((key) => - key.includes("@") + key.includes("@"), ); + await writeGlossaryFiles(process.cwd(), data, dataFull, superMatchingParams); +} + +async function writeGlossaryFiles(cwd, data, dataFull, superMatchingParams) { const exportWarning = `/* Do not modify this file! Run npm \`npm run glossary\` at ROOT of this project to fetch from the Google Sheets. https://docs.google.com/spreadsheets/d/1x65NjykMm-XUOz98Eu_oo6ON2xspm_h0Q0M2u6UGtug/edit#gid=1287694458 @@ -90,45 +94,41 @@ async function processLanguageSheet() { const exportHandle = `interface Glossary {[parameter: string]: { [field: string]: string | string[] };}\n\nexport const GLOSSARY: Glossary =`; const exportSuperMatchingParamArray = `\n\nexport const SUPER_MATCHING_PARAMS: string[] = ${JSON.stringify( - superMatchingParams + superMatchingParams, )};\n`; - fs.writeFile( - `${process.cwd()}/parameters/glossary.ts`, - exportWarning + - exportHandle + - JSON.stringify(data) + - exportSuperMatchingParamArray, - (error) => { - if (error) { - console.log("Error! Couldn't write to the file.", error); - } else { - console.log( - "EasyEyes glossary of inputs fetched and written into files successfully." - ); - } - } - ); + try { + await fs.promises.writeFile( + `${cwd}/parameters/glossary.ts`, + exportWarning + + exportHandle + + JSON.stringify(data) + + exportSuperMatchingParamArray, + ); + console.log( + "EasyEyes glossary of inputs fetched and written into files successfully.", + ); + } catch (error) { + console.log("Error! Couldn't write to the file.", error); + } const exportHandleFull1 = `interface GlossaryFullItem { [field: string]: string | string[] };\n\n`; const exportHandleFull2 = `export const GLOSSARY: GlossaryFullItem[] =`; - fs.writeFile( - `${process.cwd()}/parameters/glossary-full.ts`, - exportWarning + - exportHandleFull1 + - exportHandleFull2 + - JSON.stringify(dataFull) + - exportSuperMatchingParamArray, - (error) => { - if (error) { - console.log("Error! Couldn't write to the file.", error); - } else { - console.log( - "EasyEyes glossary (FULL VERSION) of inputs fetched and written into files successfully." - ); - } - } - ); + try { + await fs.promises.writeFile( + `${cwd}/parameters/glossary-full.ts`, + exportWarning + + exportHandleFull1 + + exportHandleFull2 + + JSON.stringify(dataFull) + + exportSuperMatchingParamArray, + ); + console.log( + "EasyEyes glossary (FULL VERSION) of inputs fetched and written into files successfully.", + ); + } catch (error) { + console.log("Error! Couldn't write to the file.", error); + } } require("dns").resolve("www.google.com", function (err) { @@ -138,7 +138,7 @@ require("dns").resolve("www.google.com", function (err) { try { if (fs.existsSync(credentialPath)) { console.log("Fetching up-to-date glossary..."); - processLanguageSheet(); + processLanguageSheet().catch(console.error); } else { console.log(":( Failed to fetch GLOSSARY. No credentials.json found."); }