mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-11 16:24:11 +01:00
Frontend: Integrate Vitest test framework #4990
- Includes fixtures and mocks system for API and models as well as npm scripts for running tests, watch mode, coverage and UI - Adds test setup with JSDOM environment and utility function tests - Converts marker model tests from Mocha/Chai to Vitest
This commit is contained in:
2698
frontend/package-lock.json
generated
2698
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,10 @@
|
||||
"gettext-extract": "gettext-extract --output src/locales/translations.pot $(find ${SRC:-src} -type f \\( -iname \\*.vue -o -iname \\*.js \\) -not -path src/common/gettext.js)",
|
||||
"lint": "eslint --cache src/ *.js",
|
||||
"test": "karma start",
|
||||
"test:vitest": "vitest run",
|
||||
"test:vitest:watch": "vitest",
|
||||
"test:vitest:coverage": "vitest run --coverage",
|
||||
"test:vitest:ui": "vitest --ui",
|
||||
"testcafe": "testcafe",
|
||||
"trace": "webpack --stats-children",
|
||||
"upgrade": "npm update && npm audit fix",
|
||||
@@ -37,6 +41,11 @@
|
||||
"@eslint/js": "^9.26.0",
|
||||
"@lcdp/offline-plugin": "^5.1.1",
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@vitejs/plugin-react": "^4.4.1",
|
||||
"@vitest/coverage-v8": "^3.1.3",
|
||||
"@vitest/ui": "^3.1.3",
|
||||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"@vue/language-server": "^2.2.10",
|
||||
"@vvo/tzdb": "^6.161.0",
|
||||
@@ -52,7 +61,7 @@
|
||||
"core-js": "^3.42.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"cssnano": "^7.0.6",
|
||||
"cssnano": "^7.0.7",
|
||||
"easygettext": "^2.17.0",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
@@ -60,7 +69,7 @@
|
||||
"eslint-plugin-html": "^8.1.2",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^5.3.1",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"eslint-plugin-promise": "^7.2.1",
|
||||
"eslint-plugin-vue": "^10.1.0",
|
||||
"eslint-plugin-vuetify": "^2.5.2",
|
||||
@@ -72,6 +81,7 @@
|
||||
"globals": "^16.0.0",
|
||||
"hls.js": "^1.6.2",
|
||||
"i": "^0.3.7",
|
||||
"jsdom": "^26.1.0",
|
||||
"karma": "^6.4.4",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage-istanbul-reporter": "^3.0.3",
|
||||
@@ -80,7 +90,7 @@
|
||||
"karma-verbose-reporter": "^0.0.8",
|
||||
"karma-webpack": "^5.0.1",
|
||||
"luxon": "^3.6.1",
|
||||
"maplibre-gl": "^5.4.0",
|
||||
"maplibre-gl": "^5.5.0",
|
||||
"memoize-one": "^6.0.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"minimist": ">=1.2.8",
|
||||
@@ -108,6 +118,8 @@
|
||||
"tar": "^7.4.3",
|
||||
"url-loader": "^4.1.1",
|
||||
"util": "^0.12.5",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.1.3",
|
||||
"vue": "^3.5.13",
|
||||
"vue-3-sanitize": "^0.1.4",
|
||||
"vue-loader": "^17.4.2",
|
||||
@@ -118,7 +130,7 @@
|
||||
"vue-style-loader": "^4.1.3",
|
||||
"vue3-gettext": "^2.4.0",
|
||||
"vuetify": "^3.8.3",
|
||||
"webpack": "^5.99.7",
|
||||
"webpack": "^5.99.8",
|
||||
"webpack-bundle-analyzer": "^4.10.2",
|
||||
"webpack-cli": "^6.0.1",
|
||||
"webpack-hot-middleware": "^2.26.1",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
plugins: ["postcss-import", "postcss-preset-env", "cssnano"],
|
||||
plugins: [require("postcss-import"), require("postcss-preset-env"), require("cssnano")],
|
||||
};
|
||||
|
||||
108
frontend/tests/vitest/common/util.test.js
Normal file
108
frontend/tests/vitest/common/util.test.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import $util from "common/util";
|
||||
|
||||
describe("$util", () => {
|
||||
describe("formatBytes", () => {
|
||||
it("should format bytes as KB", () => {
|
||||
expect($util.formatBytes(1000)).toBe("1 KB");
|
||||
expect($util.formatBytes(2000)).toBe("2 KB");
|
||||
expect($util.formatBytes("3000")).toBe("3 KB");
|
||||
});
|
||||
|
||||
it("should format bytes as MB", () => {
|
||||
expect($util.formatBytes(1048576)).toBe("1.0 MB");
|
||||
expect($util.formatBytes(2097152)).toBe("2.0 MB");
|
||||
expect($util.formatBytes(3145728)).toBe("3.0 MB");
|
||||
});
|
||||
|
||||
it("should format bytes as GB", () => {
|
||||
expect($util.formatBytes(1073741824)).toBe("1.0 GB");
|
||||
expect($util.formatBytes(2147483648)).toBe("2.0 GB");
|
||||
expect($util.formatBytes(3221225472)).toBe("3.0 GB");
|
||||
});
|
||||
|
||||
it("should handle zero and falsy values", () => {
|
||||
expect($util.formatBytes(0)).toBe("0 KB");
|
||||
expect($util.formatBytes(null)).toBe("0 KB");
|
||||
expect($util.formatBytes(undefined)).toBe("0 KB");
|
||||
expect($util.formatBytes("")).toBe("0 KB");
|
||||
});
|
||||
});
|
||||
|
||||
describe("truncate", () => {
|
||||
it("should truncate text longer than specified length", () => {
|
||||
expect($util.truncate("This is a test", 7)).toBe("This i…");
|
||||
expect($util.truncate("Hello world!", 5)).toBe("Hell…");
|
||||
});
|
||||
|
||||
it("should not truncate text shorter than specified length", () => {
|
||||
expect($util.truncate("Test", 10)).toBe("Test");
|
||||
expect($util.truncate("Short", 10)).toBe("Short");
|
||||
});
|
||||
|
||||
it("should use custom ending if specified", () => {
|
||||
expect($util.truncate("This is a test", 7, "...")).toBe("This...");
|
||||
expect($util.truncate("Hello world!", 5, " [more]")).toBe(" [more]");
|
||||
});
|
||||
|
||||
it("should use default values if not specified", () => {
|
||||
expect($util.truncate("This is a very long text that should be truncated")).toBe(
|
||||
"This is a very long text that should be truncated"
|
||||
);
|
||||
// Default length is 100 characters
|
||||
});
|
||||
});
|
||||
|
||||
describe("capitalize", () => {
|
||||
it("should capitalize first letter of each word", () => {
|
||||
expect($util.capitalize("hello world")).toBe("Hello World");
|
||||
expect($util.capitalize("test string")).toBe("Test String");
|
||||
});
|
||||
|
||||
it("should handle empty strings", () => {
|
||||
expect($util.capitalize("")).toBe("");
|
||||
expect($util.capitalize(null)).toBe("");
|
||||
expect($util.capitalize(undefined)).toBe("");
|
||||
});
|
||||
|
||||
it("should handle already capitalized text", () => {
|
||||
expect($util.capitalize("Hello World")).toBe("Hello World");
|
||||
expect($util.capitalize("HELLO WORLD")).toBe("HELLO WORLD");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ucFirst", () => {
|
||||
it("should capitalize only first letter of string", () => {
|
||||
expect($util.ucFirst("hello world")).toBe("Hello world");
|
||||
expect($util.ucFirst("test string")).toBe("Test string");
|
||||
});
|
||||
|
||||
it("should handle empty strings", () => {
|
||||
expect($util.ucFirst("")).toBe("");
|
||||
expect($util.ucFirst(null)).toBe("");
|
||||
expect($util.ucFirst(undefined)).toBe("");
|
||||
});
|
||||
|
||||
it("should handle already capitalized text", () => {
|
||||
expect($util.ucFirst("Hello world")).toBe("Hello world");
|
||||
expect($util.ucFirst("HELLO world")).toBe("HELLO world");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatSeconds", () => {
|
||||
it("should format seconds as mm:ss", () => {
|
||||
expect($util.formatSeconds(0)).toBe("0:00");
|
||||
expect($util.formatSeconds(1)).toBe("0:01");
|
||||
expect($util.formatSeconds(10)).toBe("0:10");
|
||||
expect($util.formatSeconds(60)).toBe("1:00");
|
||||
expect($util.formatSeconds(65)).toBe("1:05");
|
||||
expect($util.formatSeconds(125)).toBe("2:05");
|
||||
});
|
||||
|
||||
it("should handle negative or falsy values", () => {
|
||||
expect($util.formatSeconds(-1)).toBe("0:00");
|
||||
expect($util.formatSeconds(null)).toBe("0:00");
|
||||
expect($util.formatSeconds(undefined)).toBe("0:00");
|
||||
});
|
||||
});
|
||||
});
|
||||
100
frontend/tests/vitest/config.js
Normal file
100
frontend/tests/vitest/config.js
Normal file
@@ -0,0 +1,100 @@
|
||||
export default {
|
||||
mode: "user",
|
||||
name: "PhotoPrism",
|
||||
about: "PhotoPrism® CE",
|
||||
edition: "ce",
|
||||
version: "210710-bae1f2d7-Linux-x86_64-DEBUG",
|
||||
copyright: "(c) 2018-2025 PhotoPrism UG. All rights reserved.",
|
||||
flags: "public debug develop experimental settings",
|
||||
baseUri: "",
|
||||
staticUri: "/static",
|
||||
apiUri: "/api/v1",
|
||||
contentUri: "/api/v1",
|
||||
siteUrl: "http://localhost:2342/",
|
||||
sitePreview: "http://localhost:2342/static/img/preview.jpg",
|
||||
siteTitle: "PhotoPrism",
|
||||
siteCaption: "AI-Powered Photos App",
|
||||
siteDescription: "Open-Source Photo Management",
|
||||
siteAuthor: "@photoprism_app",
|
||||
debug: false,
|
||||
readonly: false,
|
||||
uploadNSFW: false,
|
||||
public: false,
|
||||
develop: true,
|
||||
experimental: true,
|
||||
disableSettings: false,
|
||||
test: true,
|
||||
demo: false,
|
||||
sponsor: true,
|
||||
albumCategories: ["Animal", "Holiday"],
|
||||
albums: [
|
||||
{
|
||||
ID: 69,
|
||||
UID: "aqw0vmr32zb4560f",
|
||||
Slug: "test-album-1",
|
||||
Type: "album",
|
||||
Title: "Test Album 1",
|
||||
Favorite: true,
|
||||
Private: false,
|
||||
},
|
||||
{
|
||||
ID: 70,
|
||||
UID: "aqw0vmzrkc202vty",
|
||||
Slug: "test-album-2",
|
||||
Type: "album",
|
||||
Title: "Test Album 2",
|
||||
Favorite: true,
|
||||
Private: false,
|
||||
},
|
||||
],
|
||||
cameras: [
|
||||
{
|
||||
ID: 7,
|
||||
Slug: "apple-iphone-se",
|
||||
Name: "Apple iPhone SE",
|
||||
Make: "Apple",
|
||||
Model: "iPhone SE",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Slug: "canon-eos-6d",
|
||||
Name: "Canon EOS 6D",
|
||||
Make: "Canon",
|
||||
Model: "EOS 6D",
|
||||
},
|
||||
],
|
||||
mapKey: "D9ve6edlcVR2mEsNvCXa",
|
||||
downloadToken: "2lbh9x09",
|
||||
previewToken: "public",
|
||||
settings: {
|
||||
ui: {
|
||||
scrollbar: true,
|
||||
zoom: false,
|
||||
theme: "default",
|
||||
language: "en",
|
||||
},
|
||||
search: {
|
||||
batchSize: 90,
|
||||
},
|
||||
maps: {
|
||||
animate: 0,
|
||||
style: "streets",
|
||||
},
|
||||
features: {
|
||||
upload: true,
|
||||
download: true,
|
||||
private: true,
|
||||
review: false,
|
||||
files: true,
|
||||
videos: true,
|
||||
folders: true,
|
||||
albums: true,
|
||||
moments: true,
|
||||
places: true,
|
||||
edit: true,
|
||||
share: true,
|
||||
library: true,
|
||||
import: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
138
frontend/tests/vitest/fixtures.js
Normal file
138
frontend/tests/vitest/fixtures.js
Normal file
@@ -0,0 +1,138 @@
|
||||
import { vi } from "vitest";
|
||||
import { Settings } from "luxon";
|
||||
|
||||
Settings.defaultLocale = "en";
|
||||
Settings.defaultZoneName = "UTC";
|
||||
|
||||
// Mock Config
|
||||
export const mockConfig = {
|
||||
contentUri: "/api/v1",
|
||||
previewToken: "public",
|
||||
apiUri: "/api/v1",
|
||||
baseUri: "",
|
||||
staticUri: "/static",
|
||||
downloadToken: "2lbh9x09",
|
||||
mode: "user",
|
||||
debug: false,
|
||||
};
|
||||
|
||||
// Mock RestModel
|
||||
export class MockRestModel {
|
||||
constructor(values) {
|
||||
this.__originalValues = {};
|
||||
this.setValues(values || {});
|
||||
}
|
||||
|
||||
setValues(values) {
|
||||
if (!values) return this;
|
||||
|
||||
for (let key in values) {
|
||||
if (values.hasOwnProperty(key)) {
|
||||
this[key] = values[key];
|
||||
this.__originalValues[key] = values[key];
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.UID || this.ID;
|
||||
}
|
||||
|
||||
getValues() {
|
||||
return { ...this.__originalValues };
|
||||
}
|
||||
|
||||
getEntityResource() {
|
||||
return `${this.constructor.getCollectionResource()}/${this.getId()}`;
|
||||
}
|
||||
|
||||
update() {
|
||||
return Promise.resolve({ success: "ok" });
|
||||
}
|
||||
|
||||
static getCollectionResource() {
|
||||
return "items";
|
||||
}
|
||||
}
|
||||
|
||||
// API Response Helpers
|
||||
export const mockApiResponse = (data) => {
|
||||
return { data };
|
||||
};
|
||||
|
||||
export const mockPutResponse = (data = { success: "ok" }) => {
|
||||
return vi.fn().mockResolvedValue(mockApiResponse(data));
|
||||
};
|
||||
|
||||
export const mockDeleteResponse = (data = { success: "ok" }) => {
|
||||
return vi.fn().mockResolvedValue(mockApiResponse(data));
|
||||
};
|
||||
|
||||
export const mockGetResponse = (data) => {
|
||||
return vi.fn().mockResolvedValue(mockApiResponse(data));
|
||||
};
|
||||
|
||||
export const mockPostResponse = (data = { success: "ok" }) => {
|
||||
return vi.fn().mockResolvedValue(mockApiResponse(data));
|
||||
};
|
||||
|
||||
// Global mock variables
|
||||
export const apiMock = {
|
||||
put: mockPutResponse(),
|
||||
delete: mockDeleteResponse(),
|
||||
get: mockGetResponse(),
|
||||
post: mockPostResponse(),
|
||||
};
|
||||
|
||||
// Setup common mocks
|
||||
export const setupCommonMocks = () => {
|
||||
// Mock Model
|
||||
vi.mock("model/rest", () => ({
|
||||
default: MockRestModel,
|
||||
}));
|
||||
|
||||
// Mock API
|
||||
vi.mock("common/api", () => ({
|
||||
default: apiMock,
|
||||
}));
|
||||
|
||||
// Mock session
|
||||
vi.mock("app/session", () => ({
|
||||
$config: mockConfig,
|
||||
}));
|
||||
|
||||
// Mock gettext
|
||||
vi.mock("common/gettext", () => ({
|
||||
$gettext: vi.fn((text) => text),
|
||||
}));
|
||||
};
|
||||
|
||||
// Setup common headers
|
||||
export const mockHeaders = {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
};
|
||||
|
||||
export const setupMarkerMocks = () => {
|
||||
apiMock.put.mockImplementation((url, data) => {
|
||||
if (url.includes("markers/mBC123ghytr")) {
|
||||
return Promise.resolve({ data: { success: "ok" } });
|
||||
} else if (url.includes("markers/mCC123ghytr")) {
|
||||
return Promise.resolve({ data: { success: "ok" } });
|
||||
} else if (url.includes("markers/mDC123ghytr")) {
|
||||
return Promise.resolve({ data: { success: "ok", Name: "testname" } });
|
||||
}
|
||||
|
||||
return Promise.resolve({ data: { success: "ok" } });
|
||||
});
|
||||
|
||||
apiMock.delete.mockImplementation((url) => {
|
||||
if (url.includes("markers/mEC123ghytr/subject")) {
|
||||
return Promise.resolve({ data: { success: "ok" } });
|
||||
}
|
||||
return Promise.resolve({ data: { success: "ok" } });
|
||||
});
|
||||
};
|
||||
|
||||
export default { setupCommonMocks, setupMarkerMocks };
|
||||
213
frontend/tests/vitest/model/marker.test.js
Normal file
213
frontend/tests/vitest/model/marker.test.js
Normal file
@@ -0,0 +1,213 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { Marker, BatchSize } from "model/marker";
|
||||
import { setupMarkerMocks } from "../fixtures";
|
||||
|
||||
beforeEach(() => {
|
||||
setupMarkerMocks();
|
||||
});
|
||||
|
||||
describe("model/marker", () => {
|
||||
it("should get marker defaults", () => {
|
||||
const values = { FileUID: "fghjojp" };
|
||||
const marker = new Marker(values);
|
||||
const result = marker.getDefaults();
|
||||
expect(result.UID).toBe("");
|
||||
expect(result.FileUID).toBe("");
|
||||
});
|
||||
|
||||
it("should get route view", () => {
|
||||
const values = { UID: "ABC123ghytr", FileUID: "fhjouohnnmnd", Type: "face", Src: "image" };
|
||||
const marker = new Marker(values);
|
||||
const result = marker.route("test");
|
||||
expect(result.name).toBe("test");
|
||||
expect(result.query.q).toBe("marker:ABC123ghytr");
|
||||
});
|
||||
|
||||
it("should return classes", () => {
|
||||
const values = { UID: "ABC123ghytr", FileUID: "fhjouohnnmnd", Type: "face", Src: "image" };
|
||||
const marker = new Marker(values);
|
||||
const result = marker.classes(true);
|
||||
expect(result).toContain("is-marker");
|
||||
expect(result).toContain("uid-ABC123ghytr");
|
||||
expect(result).toContain("is-selected");
|
||||
expect(result).not.toContain("is-review");
|
||||
expect(result).not.toContain("is-invalid");
|
||||
|
||||
const result2 = marker.classes(false);
|
||||
expect(result2).toContain("is-marker");
|
||||
expect(result2).toContain("uid-ABC123ghytr");
|
||||
expect(result2).not.toContain("is-selected");
|
||||
expect(result2).not.toContain("is-review");
|
||||
expect(result2).not.toContain("is-invalid");
|
||||
|
||||
const values2 = {
|
||||
UID: "mBC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Invalid: true,
|
||||
Review: true,
|
||||
};
|
||||
const marker2 = new Marker(values2);
|
||||
const result3 = marker2.classes(true);
|
||||
expect(result3).toContain("is-marker");
|
||||
expect(result3).toContain("uid-mBC123ghytr");
|
||||
expect(result3).toContain("is-selected");
|
||||
expect(result3).toContain("is-review");
|
||||
expect(result3).toContain("is-invalid");
|
||||
});
|
||||
|
||||
it("should get marker entity name", () => {
|
||||
const values = {
|
||||
UID: "ABC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Name: "test",
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
const result = marker.getEntityName();
|
||||
expect(result).toBe("test");
|
||||
});
|
||||
|
||||
it("should get marker title", () => {
|
||||
const values = {
|
||||
UID: "ABC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Name: "test",
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
const result = marker.getTitle();
|
||||
expect(result).toBe("test");
|
||||
});
|
||||
|
||||
it("should get thumbnail url", () => {
|
||||
const values = { UID: "ABC123ghytr", FileUID: "fhjouohnnmnd", Type: "face", Src: "image" };
|
||||
const marker = new Marker(values);
|
||||
const result = marker.thumbnailUrl("xyz");
|
||||
expect(result).toBe("/api/v1/svg/portrait");
|
||||
|
||||
const values2 = {
|
||||
UID: "ABC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Thumb: "nicethumbuid",
|
||||
};
|
||||
const marker2 = new Marker(values2);
|
||||
const result2 = marker2.thumbnailUrl();
|
||||
expect(result2).toBe("/api/v1/t/nicethumbuid/public/tile_160");
|
||||
});
|
||||
|
||||
it("should get date string", () => {
|
||||
const values = {
|
||||
UID: "ABC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
CreatedAt: "2012-07-08T14:45:39Z",
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
const result = marker.getDateString();
|
||||
expect(result).toBe("2023-10-01 10:00:00");
|
||||
});
|
||||
|
||||
it("should approve marker", () => {
|
||||
const values = {
|
||||
UID: "mBC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Invalid: true,
|
||||
Review: true,
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
expect(marker.Review).toBe(true);
|
||||
expect(marker.Invalid).toBe(true);
|
||||
marker.approve();
|
||||
expect(marker.Review).toBe(false);
|
||||
expect(marker.Invalid).toBe(false);
|
||||
});
|
||||
|
||||
it("should reject marker", () => {
|
||||
const values = {
|
||||
UID: "mCC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Invalid: false,
|
||||
Review: true,
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
expect(marker.Review).toBe(true);
|
||||
expect(marker.Invalid).toBe(false);
|
||||
marker.reject();
|
||||
expect(marker.Review).toBe(false);
|
||||
expect(marker.Invalid).toBe(true);
|
||||
});
|
||||
|
||||
it("should rename marker", async () => {
|
||||
const values = {
|
||||
UID: "mDC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Subject: "skhljkpigh",
|
||||
Name: "",
|
||||
SubjSrc: "manual",
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
expect(marker.Name).toBe("");
|
||||
marker.setName();
|
||||
expect(marker.Name).toBe("");
|
||||
|
||||
const values2 = {
|
||||
UID: "mDC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Subject: "skhljkpigh",
|
||||
Name: "testname",
|
||||
SubjSrc: "manual",
|
||||
};
|
||||
const marker2 = new Marker(values2);
|
||||
expect(marker2.Name).toBe("testname");
|
||||
|
||||
const response = await marker2.setName();
|
||||
expect(response.success).toBe("ok");
|
||||
});
|
||||
|
||||
it("should clear subject", async () => {
|
||||
const values = {
|
||||
UID: "mEC123ghytr",
|
||||
FileUID: "fhjouohnnmnd",
|
||||
Type: "face",
|
||||
Src: "image",
|
||||
Subject: "skhljkpigh",
|
||||
Name: "testname",
|
||||
SubjSrc: "manual",
|
||||
};
|
||||
const marker = new Marker(values);
|
||||
const response = await marker.clearSubject();
|
||||
expect(response.success).toBe("ok");
|
||||
});
|
||||
|
||||
it("should return batch size", () => {
|
||||
expect(Marker.batchSize()).toBe(BatchSize);
|
||||
Marker.setBatchSize(30);
|
||||
expect(Marker.batchSize()).toBe(30);
|
||||
Marker.setBatchSize(BatchSize);
|
||||
});
|
||||
|
||||
it("should get collection resource", () => {
|
||||
const result = Marker.getCollectionResource();
|
||||
expect(result).toBe("markers");
|
||||
});
|
||||
|
||||
it("should get model name", () => {
|
||||
const result = Marker.getModelName();
|
||||
expect(result).toBe("Marker");
|
||||
});
|
||||
});
|
||||
59
frontend/tests/vitest/setup.js
Normal file
59
frontend/tests/vitest/setup.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import "@testing-library/jest-dom";
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import { afterEach, vi, beforeAll } from "vitest";
|
||||
import { setupCommonMocks } from "./fixtures";
|
||||
|
||||
global.window = global.window || {};
|
||||
global.window.__CONFIG__ = {
|
||||
debug: false,
|
||||
trace: false,
|
||||
};
|
||||
|
||||
global.window.location = {
|
||||
protocol: "https:",
|
||||
};
|
||||
|
||||
global.navigator = {
|
||||
userAgent: "node.js",
|
||||
maxTouchPoints: 0,
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
setupCommonMocks();
|
||||
});
|
||||
|
||||
vi.mock("luxon", () => ({
|
||||
DateTime: {
|
||||
fromISO: vi.fn().mockReturnValue({
|
||||
toLocaleString: vi.fn().mockReturnValue("2023-10-01 10:00:00"),
|
||||
}),
|
||||
DATETIME_MED: {},
|
||||
DATETIME_MED_WITH_WEEKDAY: {},
|
||||
DATE_MED: {},
|
||||
TIME_24_SIMPLE: {},
|
||||
},
|
||||
Settings: {
|
||||
defaultLocale: "en",
|
||||
defaultZoneName: "UTC",
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("common/gettext", () => ({
|
||||
$gettext: vi.fn((text) => text),
|
||||
}));
|
||||
|
||||
vi.mock("app/session", () => ({
|
||||
$config: {},
|
||||
}));
|
||||
|
||||
vi.mock("common/notify", () => ({
|
||||
default: {
|
||||
success: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
27
frontend/vitest.config.js
Normal file
27
frontend/vitest.config.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tsconfigPaths()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
setupFiles: "./tests/vitest/setup.js",
|
||||
include: ["tests/vitest/**/*.{test,spec}.{js,jsx}"],
|
||||
coverage: {
|
||||
reporter: ["text", "html"],
|
||||
include: ["src/**/*.{js,jsx}"],
|
||||
exclude: ["src/locales/**"],
|
||||
},
|
||||
alias: {
|
||||
app: path.resolve(__dirname, "./src/app"),
|
||||
common: path.resolve(__dirname, "./src/common"),
|
||||
component: path.resolve(__dirname, "./src/component"),
|
||||
model: path.resolve(__dirname, "./src/model"),
|
||||
options: path.resolve(__dirname, "./src/options"),
|
||||
page: path.resolve(__dirname, "./src/page"),
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user