Merge pull request #977 from pano9000/test_vitest

test: add vitest as test framework and port current tests
This commit is contained in:
Elian Doran 2025-01-17 22:22:00 +02:00 committed by GitHub
commit 7fc5f9ab83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 1614 additions and 135 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
node_modules/ node_modules/
dist/ dist/
build/ build/
coverage/
src/public/app-dist/ src/public/app-dist/
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log

1531
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -37,9 +37,8 @@
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs", "build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
"webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts", "webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
"test-playwright": "playwright test", "test-playwright": "playwright test",
"test-jasmine": "cross-env TRILIUM_DATA_DIR=./data-test tsx ./node_modules/jasmine/bin/jasmine.js", "test": "cross-env TRILIUM_DATA_DIR=./data-test vitest",
"test-es6": "tsx -r esm spec-es6/attribute_parser.spec.ts", "test-coverage": "cross-env TRILIUM_DATA_DIR=./data-test vitest --coverage",
"test": "npm run test-jasmine && npm run test-es6",
"start-electron-forge": "npm run prepare-dist && electron-forge start", "start-electron-forge": "npm run prepare-dist && electron-forge start",
"make-electron": "npm run webpack && npm run prepare-dist && electron-forge make", "make-electron": "npm run webpack && npm run prepare-dist && electron-forge make",
"package-electron": "electron-forge package", "package-electron": "electron-forge package",
@ -189,6 +188,7 @@
"@types/ws": "8.5.13", "@types/ws": "8.5.13",
"@types/xml2js": "0.4.14", "@types/xml2js": "0.4.14",
"@types/yargs": "17.0.33", "@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.0.2",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"electron": "34.0.0", "electron": "34.0.0",
"esm": "3.2.25", "esm": "3.2.25",
@ -203,6 +203,7 @@
"tsx": "4.19.2", "tsx": "4.19.2",
"typedoc": "0.27.6", "typedoc": "0.27.6",
"typescript": "5.7.3", "typescript": "5.7.3",
"vitest": "3.0.2",
"webpack": "5.97.1", "webpack": "5.97.1",
"webpack-cli": "6.0.1", "webpack-cli": "6.0.1",
"webpack-dev-middleware": "7.4.2" "webpack-dev-middleware": "7.4.2"

View File

@ -1,6 +1,6 @@
import * as attributeParser from "../src/public/app/services/attribute_parser.js"; import { describe, it, expect } from "vitest";
import attributeParser from "../src/public/app/services/attribute_parser.ts";
import { describe, it, expect, execute } from "./mini_test.js";
describe("Lexing", () => { describe("Lexing", () => {
it("simple label", () => { it("simple label", () => {
@ -40,7 +40,7 @@ describe("Lexing", () => {
}); });
}); });
describe("Parser", () => { describe.todo("Parser", () => {
it("simple label", () => { it("simple label", () => {
const attrs = attributeParser.parse(["#token"].map((t: any) => ({ text: t }))); const attrs = attributeParser.parse(["#token"].map((t: any) => ({ text: t })));
@ -96,5 +96,3 @@ describe("error cases", () => {
expect(() => attributeParser.lexAndParse("#")).toThrow(`Attribute name is empty, please fill the name.`); expect(() => attributeParser.lexAndParse("#")).toThrow(`Attribute name is empty, please fill the name.`);
}); });
}); });
execute();

View File

@ -1,9 +1,8 @@
import { describe, it, execute, expect } from "./mini_test.ts"; import { describe, it, expect } from "vitest";
import { getPlatformAppDataDir, getDataDirs} from "../src/services/data_dir.ts" import { getPlatformAppDataDir, getDataDirs} from "../src/services/data_dir.ts"
describe("data_dir.ts unit tests", () => { describe("data_dir.ts unit tests", () => {
describe("#getPlatformAppDataDir()", () => { describe("#getPlatformAppDataDir()", () => {
@ -65,7 +64,7 @@ describe("data_dir.ts unit tests", () => {
}) })
describe("#getTriliumDataDir", () => { describe.todo("#getTriliumDataDir", () => {
// TODO // TODO
}) })
@ -121,18 +120,37 @@ describe("data_dir.ts unit tests", () => {
// make sure values are undefined // make sure values are undefined
setMockedEnv(null); setMockedEnv(null);
const mockDataDir = "/home/test/MOCK_TRILIUM_DATA_DIR" const mockDataDirBase = "/home/test/MOCK_TRILIUM_DATA_DIR"
const result = getDataDirs(mockDataDir); const result = getDataDirs(mockDataDirBase);
//@ts-expect-error - attempt to change value of readonly property // as per MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#description
result.BACKUP_DIR = "attempt to change"; // Any attempt to change a frozen object will, either silently be ignored or
// throw a TypeError exception (most commonly, but not exclusively, when in strict mode).
// so be safe and check for both, even though it looks weird
for (const key in result) { const getChangeAttemptResult = () => {
expect(result[key].startsWith(mockDataDir)).toBeTruthy() try {
//@ts-expect-error - attempt to change value of readonly property
result.BACKUP_DIR = "attempt to change";
return result.BACKUP_DIR;
}
catch(error) {
return error
}
} }
const changeAttemptResult = getChangeAttemptResult();
if (typeof changeAttemptResult === "string") {
// if it didn't throw above: assert that it did not change the value of it or any other keys of the object
for (const key in result) {
expect(result[key].startsWith(mockDataDirBase)).toBeTruthy()
}
} else {
expect(changeAttemptResult).toBeInstanceOf(TypeError)
}
}) })
}) })
}); });
execute()

View File

@ -1,79 +0,0 @@
export function describe(name: string, cb: () => any) {
console.log(`Running ${name}`);
cb();
}
export async function it(name: string, cb: () => any) {
console.log(` Running ${name}`);
cb();
}
let errorCount = 0;
export function expect(val: any) {
return {
toEqual: (comparedVal: any) => {
const jsonVal = JSON.stringify(val);
const comparedJsonVal = JSON.stringify(comparedVal);
if (jsonVal !== comparedJsonVal) {
console.trace("toEqual check failed.");
console.error(`expected: ${comparedJsonVal}`);
console.error(`got: ${jsonVal}`);
errorCount++;
}
},
toBeTruthy: () => {
if (!val) {
console.trace("toBeTruthy failed.");
console.error(`expected: truthy value`);
console.error(`got: ${val}`);
errorCount++;
}
},
toBeFalsy: () => {
if (!!val) {
console.trace("toBeFalsy failed.");
console.error(`expected: null, false, undefined, 0 or empty string`);
console.error(`got: ${val}`);
errorCount++;
}
},
toThrow: (errorMessage: any) => {
try {
val();
} catch (e: any) {
if (e.message !== errorMessage) {
console.trace("toThrow caught exception, but messages differ");
console.error(`expected: ${errorMessage}`);
console.error(`got: ${e.message}`);
console.error(`${e.stack}`);
errorCount++;
}
return;
}
console.trace("toThrow did not catch any exception.");
console.error(`expected: ${errorMessage}`);
console.error(`got: [none]`);
errorCount++;
}
};
}
export function execute() {
console.log("");
if (errorCount) {
console.log(`!!!${errorCount} tests failed!!!`);
} else {
console.log("All tests passed!");
}
}

View File

@ -1,5 +1,5 @@
import { expect, describe, it } from "vitest";
import sanitizeAttributeName from "../src/services/sanitize_attribute_name"; import sanitizeAttributeName from "../src/services/sanitize_attribute_name";
import { describe, it, execute, expect } from "./mini_test";
// fn value, expected value // fn value, expected value
const testCases: [fnValue: string, expectedValue: string][] = [ const testCases: [fnValue: string, expectedValue: string][] = [
@ -31,9 +31,7 @@ describe("sanitizeAttributeName unit tests", () => {
return it(`'${testCase[0]}' should return '${testCase[1]}'`, () => { return it(`'${testCase[0]}' should return '${testCase[1]}'`, () => {
const [value, expected] = testCase; const [value, expected] = testCase;
const actual = sanitizeAttributeName(value); const actual = sanitizeAttributeName(value);
expect(actual).toEqual(expected); expect(actual).toStrictEqual(expected);
}); });
}); });
}); });
execute();

View File

@ -1,5 +1,5 @@
import { expect, describe, it } from "vitest";
import { formatDownloadTitle } from "../../src/services/utils.ts"; import { formatDownloadTitle } from "../../src/services/utils.ts";
import { describe, it, execute, expect } from "../mini_test.ts";
const testCases: [fnValue: Parameters<typeof formatDownloadTitle>, expectedValue: ReturnType<typeof formatDownloadTitle>][] = [ const testCases: [fnValue: Parameters<typeof formatDownloadTitle>, expectedValue: ReturnType<typeof formatDownloadTitle>][] = [
// empty fileName tests // empty fileName tests
@ -55,9 +55,7 @@ describe("utils/formatDownloadTitle unit tests", () => {
return it(`With args '${JSON.stringify(testCase[0])}' it should return '${testCase[1]}'`, () => { return it(`With args '${JSON.stringify(testCase[0])}' it should return '${testCase[1]}'`, () => {
const [value, expected] = testCase; const [value, expected] = testCase;
const actual = formatDownloadTitle(...value); const actual = formatDownloadTitle(...value);
expect(actual).toEqual(expected); expect(actual).toStrictEqual(expected);
}); });
}); });
}); });
execute();

View File

@ -1,3 +1,5 @@
describe("Notes", () => { import { describe, it } from "vitest";
describe.todo("Notes", () => {
it("zzz", () => {}); it("zzz", () => {});
}); });

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import lex from "../../src/services/search/services/lex.js"; import lex from "../../src/services/search/services/lex.js";
describe("Lexer fulltext", () => { describe("Lexer fulltext", () => {

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import handleParens from "../../src/services/search/services/handle_parens.js"; import handleParens from "../../src/services/search/services/handle_parens.js";
import type { TokenStructure } from "../../src/services/search/services/types.js"; import type { TokenStructure } from "../../src/services/search/services/types.js";

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import AndExp from "../../src/services/search/expressions/and.js"; import AndExp from "../../src/services/search/expressions/and.js";
import AttributeExistsExp from "../../src/services/search/expressions/attribute_exists.js"; import AttributeExistsExp from "../../src/services/search/expressions/attribute_exists.js";
import type Expression from "../../src/services/search/expressions/expression.js"; import type Expression from "../../src/services/search/expressions/expression.js";

View File

@ -1,3 +1,4 @@
import { describe, it, expect, beforeEach, } from "vitest";
import searchService from "../../src/services/search/services/search.js"; import searchService from "../../src/services/search/services/search.js";
import BNote from "../../src/becca/entities/bnote.js"; import BNote from "../../src/becca/entities/bnote.js";
import BBranch from "../../src/becca/entities/bbranch.js"; import BBranch from "../../src/becca/entities/bbranch.js";
@ -21,7 +22,7 @@ describe("Search", () => {
}); });
}); });
xit("simple path match", () => { it.skip("simple path match", () => {
rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria"))); rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria")));
const searchContext = new SearchContext(); const searchContext = new SearchContext();
@ -31,7 +32,7 @@ describe("Search", () => {
expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy(); expect(becca_mocking.findNoteByTitle(searchResults, "Austria")).toBeTruthy();
}); });
xit("normal search looks also at attributes", () => { it.skip("normal search looks also at attributes", () => {
const austria = becca_mocking.note("Austria"); const austria = becca_mocking.note("Austria");
const vienna = becca_mocking.note("Vienna"); const vienna = becca_mocking.note("Vienna");
@ -49,7 +50,7 @@ describe("Search", () => {
expect(becca_mocking.findNoteByTitle(searchResults, "Vienna")).toBeTruthy(); expect(becca_mocking.findNoteByTitle(searchResults, "Vienna")).toBeTruthy();
}); });
xit("normal search looks also at type and mime", () => { it.skip("normal search looks also at type and mime", () => {
rootNote.child(becca_mocking.note("Effective Java", { type: "book", mime: "" })).child(becca_mocking.note("Hello World.java", { type: "code", mime: "text/x-java" })); rootNote.child(becca_mocking.note("Effective Java", { type: "book", mime: "" })).child(becca_mocking.note("Hello World.java", { type: "code", mime: "text/x-java" }));
const searchContext = new SearchContext(); const searchContext = new SearchContext();
@ -68,7 +69,7 @@ describe("Search", () => {
expect(searchResults.length).toEqual(2); expect(searchResults.length).toEqual(2);
}); });
xit("only end leafs are results", () => { it.skip("only end leafs are results", () => {
rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria"))); rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria")));
const searchContext = new SearchContext(); const searchContext = new SearchContext();
@ -78,7 +79,7 @@ describe("Search", () => {
expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy(); expect(becca_mocking.findNoteByTitle(searchResults, "Europe")).toBeTruthy();
}); });
xit("only end leafs are results", () => { it.skip("only end leafs are results", () => {
rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria").label("capital", "Vienna"))); rootNote.child(becca_mocking.note("Europe").child(becca_mocking.note("Austria").label("capital", "Vienna")));
const searchContext = new SearchContext(); const searchContext = new SearchContext();
@ -133,7 +134,7 @@ describe("Search", () => {
expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy(); expect(becca_mocking.findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
}); });
xit("inherited label comparison", () => { it.skip("inherited label comparison", () => {
rootNote.child(becca_mocking.note("Europe").label("country", "", true).child(becca_mocking.note("Austria")).child(becca_mocking.note("Czech Republic"))); rootNote.child(becca_mocking.note("Europe").label("country", "", true).child(becca_mocking.note("Austria")).child(becca_mocking.note("Czech Republic")));
const searchContext = new SearchContext(); const searchContext = new SearchContext();
@ -549,7 +550,7 @@ describe("Search", () => {
expect(becca.notes[searchResults[0].noteId].title).toEqual("Europe"); expect(becca.notes[searchResults[0].noteId].title).toEqual("Europe");
}); });
xit("test note.text *=* something", () => { it.skip("test note.text *=* something", () => {
const italy = becca_mocking.note("Italy").label("capital", "Rome"); const italy = becca_mocking.note("Italy").label("capital", "Rome");
const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava");
@ -562,7 +563,7 @@ describe("Search", () => {
expect(becca.notes[searchResults[0].noteId].title).toEqual("Slovakia"); expect(becca.notes[searchResults[0].noteId].title).toEqual("Slovakia");
}); });
xit("test that fulltext does not match archived notes", () => { it.skip("test that fulltext does not match archived notes", () => {
const italy = becca_mocking.note("Italy").label("capital", "Rome"); const italy = becca_mocking.note("Italy").label("capital", "Rome");
const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava"); const slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava");

View File

@ -1,3 +1,4 @@
import { describe, it, expect, beforeEach } from "vitest";
import becca_mocking from "./becca_mocking.js"; import becca_mocking from "./becca_mocking.js";
import ValueExtractor from "../../src/services/search/value_extractor.js"; import ValueExtractor from "../../src/services/search/value_extractor.js";
import becca from "../../src/becca/becca.js"; import becca from "../../src/becca/becca.js";

View File

@ -1,10 +0,0 @@
{
"spec_dir": "",
"spec_files": [
"spec/**/*.spec.ts",
"src/**/*.spec.ts"
],
"helpers": ["helpers/**/*.js"],
"stopSpecOnExpectationFailure": false,
"random": true
}

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import { trimIndentation } from "./utils.js"; import { trimIndentation } from "./utils.js";
describe("Utils", () => { describe("Utils", () => {

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import markdownExportService from "./md.js"; import markdownExportService from "./md.js";
import { trimIndentation } from "../../../spec/support/utils.js"; import { trimIndentation } from "../../../spec/support/utils.js";

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import { trimIndentation } from "../../../spec/support/utils.js"; import { trimIndentation } from "../../../spec/support/utils.js";
import markdownService from "./markdown.js"; import markdownService from "./markdown.js";

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import { renderCode, type Result } from "./content_renderer.js"; import { renderCode, type Result } from "./content_renderer.js";
describe("content_renderer", () => { describe("content_renderer", () => {
@ -8,7 +9,7 @@ describe("content_renderer", () => {
content: " " content: " "
}; };
renderCode(emptyResult); renderCode(emptyResult);
expect(emptyResult.isEmpty).toBeTrue(); expect(emptyResult.isEmpty).toBeTruthy();
}); });
it("identifies unsupported content type", () => { it("identifies unsupported content type", () => {
@ -17,7 +18,7 @@ describe("content_renderer", () => {
content: Buffer.from("Hello world") content: Buffer.from("Hello world")
}; };
renderCode(emptyResult); renderCode(emptyResult);
expect(emptyResult.isEmpty).toBeTrue(); expect(emptyResult.isEmpty).toBeTruthy();
}); });
it("wraps code in <pre>", () => { it("wraps code in <pre>", () => {

24
vitest.config.ts Normal file
View File

@ -0,0 +1,24 @@
import { defineConfig } from "vitest/config";
import { configDefaults, coverageConfigDefaults } from "vitest/config";
const customExcludes = [
"build/**",
"e2e/**",
"integration-tests/**",
"tests-examples/**",
"node_modules/**",
"src/public/app-dist/**",
"libraries/**",
"docs/**",
"out/**",
"*.config.[jt]s" // playwright.config.ts and similar
];
export default defineConfig({
test: {
exclude: [...configDefaults.exclude, ...customExcludes],
coverage: {
exclude: [...coverageConfigDefaults.exclude, ...customExcludes]
}
}
});