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/
dist/
build/
coverage/
src/public/app-dist/
npm-debug.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",
"webpack": "tsx node_modules/webpack/bin/webpack.js -c webpack.config.ts",
"test-playwright": "playwright test",
"test-jasmine": "cross-env TRILIUM_DATA_DIR=./data-test tsx ./node_modules/jasmine/bin/jasmine.js",
"test-es6": "tsx -r esm spec-es6/attribute_parser.spec.ts",
"test": "npm run test-jasmine && npm run test-es6",
"test": "cross-env TRILIUM_DATA_DIR=./data-test vitest",
"test-coverage": "cross-env TRILIUM_DATA_DIR=./data-test vitest --coverage",
"start-electron-forge": "npm run prepare-dist && electron-forge start",
"make-electron": "npm run webpack && npm run prepare-dist && electron-forge make",
"package-electron": "electron-forge package",
@ -189,6 +188,7 @@
"@types/ws": "8.5.13",
"@types/xml2js": "0.4.14",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.0.2",
"cross-env": "7.0.3",
"electron": "34.0.0",
"esm": "3.2.25",
@ -203,6 +203,7 @@
"tsx": "4.19.2",
"typedoc": "0.27.6",
"typescript": "5.7.3",
"vitest": "3.0.2",
"webpack": "5.97.1",
"webpack-cli": "6.0.1",
"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", () => {
it("simple label", () => {
@ -40,7 +40,7 @@ describe("Lexing", () => {
});
});
describe("Parser", () => {
describe.todo("Parser", () => {
it("simple label", () => {
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.`);
});
});
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"
describe("data_dir.ts unit tests", () => {
describe("#getPlatformAppDataDir()", () => {
@ -65,7 +64,7 @@ describe("data_dir.ts unit tests", () => {
})
describe("#getTriliumDataDir", () => {
describe.todo("#getTriliumDataDir", () => {
// TODO
})
@ -121,18 +120,37 @@ describe("data_dir.ts unit tests", () => {
// make sure values are undefined
setMockedEnv(null);
const mockDataDir = "/home/test/MOCK_TRILIUM_DATA_DIR"
const result = getDataDirs(mockDataDir);
const mockDataDirBase = "/home/test/MOCK_TRILIUM_DATA_DIR"
const result = getDataDirs(mockDataDirBase);
//@ts-expect-error - attempt to change value of readonly property
result.BACKUP_DIR = "attempt to change";
// as per MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#description
// 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) {
expect(result[key].startsWith(mockDataDir)).toBeTruthy()
const getChangeAttemptResult = () => {
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 { describe, it, execute, expect } from "./mini_test";
// fn value, expected value
const testCases: [fnValue: string, expectedValue: string][] = [
@ -31,9 +31,7 @@ describe("sanitizeAttributeName unit tests", () => {
return it(`'${testCase[0]}' should return '${testCase[1]}'`, () => {
const [value, expected] = testCase;
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 { describe, it, execute, expect } from "../mini_test.ts";
const testCases: [fnValue: Parameters<typeof formatDownloadTitle>, expectedValue: ReturnType<typeof formatDownloadTitle>][] = [
// 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]}'`, () => {
const [value, expected] = testCase;
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", () => {});
});

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import lex from "../../src/services/search/services/lex.js";
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 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 AttributeExistsExp from "../../src/services/search/expressions/attribute_exists.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 BNote from "../../src/becca/entities/bnote.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")));
const searchContext = new SearchContext();
@ -31,7 +32,7 @@ describe("Search", () => {
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 vienna = becca_mocking.note("Vienna");
@ -49,7 +50,7 @@ describe("Search", () => {
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" }));
const searchContext = new SearchContext();
@ -68,7 +69,7 @@ describe("Search", () => {
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")));
const searchContext = new SearchContext();
@ -78,7 +79,7 @@ describe("Search", () => {
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")));
const searchContext = new SearchContext();
@ -133,7 +134,7 @@ describe("Search", () => {
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")));
const searchContext = new SearchContext();
@ -549,7 +550,7 @@ describe("Search", () => {
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 slovakia = becca_mocking.note("Slovakia").label("capital", "Bratislava");
@ -562,7 +563,7 @@ describe("Search", () => {
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 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 ValueExtractor from "../../src/services/search/value_extractor.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";
describe("Utils", () => {

View File

@ -1,3 +1,4 @@
import { describe, it, expect } from "vitest";
import markdownExportService from "./md.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 markdownService from "./markdown.js";

View File

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