Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/apps
diff options
context:
space:
mode:
authorLeitwolf112026-09-26 16:57:36 +0300
committerLeitwolf112026-09-26 16:57:36 +0300
commit07b91c2966ffe5daa9501f41436b3a45b3a2d774 (patch)
tree4a8771a38cbd7bc61735c3ae59b8b440f03d0d42 /apps
parent1855533fa44547e568471303530c67e5d2fa69c5 (diff)
downloadprogmaweb-07b91c2966ffe5daa9501f41436b3a45b3a2d774.tar.gz
Add Progmaweb frontend tests and full-stack security and coverage workflows
Diffstat (limited to 'apps')
-rw-r--r--apps/api-tests/Progmaweb.Api.Tests.csproj1
-rw-r--r--apps/api-tests/packages.lock.json11
-rw-r--r--apps/api/packages.lock.json2
-rw-r--r--apps/web/package.json3
-rw-r--r--apps/web/tests/localization.test.mjs62
5 files changed, 78 insertions, 1 deletions
diff --git a/apps/api-tests/Progmaweb.Api.Tests.csproj b/apps/api-tests/Progmaweb.Api.Tests.csproj
index 63b5f6c..efb6a2f 100644
--- a/apps/api-tests/Progmaweb.Api.Tests.csproj
+++ b/apps/api-tests/Progmaweb.Api.Tests.csproj
@@ -11,6 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.11" />
+ <PackageReference Include="coverlet.MTP" Version="8.0.0" />
<!-- xUnit's MTP-v2 package is the native .NET 10 test host. Keeping the
VSTest adapter here would make the solution mix incompatible runners. -->
<PackageReference Include="xunit.v3.mtp-v2" Version="4.0.0" />
diff --git a/apps/api-tests/packages.lock.json b/apps/api-tests/packages.lock.json
index 38c06e7..ca4dbb9 100644
--- a/apps/api-tests/packages.lock.json
+++ b/apps/api-tests/packages.lock.json
@@ -2,6 +2,17 @@
"version": 1,
"dependencies": {
"net10.0": {
+ "coverlet.MTP": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "r3+GPhzJd8G/qlw8UFOYGECZSFvpg0j+yRTGbSr8ikk1ed4Hui+Y56ghPcBT43S3DWYKEzZLGmZ/KFS28k1zHg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.1",
+ "Microsoft.Extensions.DependencyInjection": "8.0.1",
+ "Microsoft.Testing.Platform": "2.0.2"
+ }
+ },
"Microsoft.AspNetCore.Mvc.Testing": {
"type": "Direct",
"requested": "[10.0.11, )",
diff --git a/apps/api/packages.lock.json b/apps/api/packages.lock.json
index d134eda..b7d7ff4 100644
--- a/apps/api/packages.lock.json
+++ b/apps/api/packages.lock.json
@@ -10,4 +10,4 @@
}
}
}
-}
+} \ No newline at end of file
diff --git a/apps/web/package.json b/apps/web/package.json
index ba3bcf5..fef38d7 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -12,6 +12,8 @@
"build": "next build",
"start": "next start",
"check": "next typegen && tsc --noEmit",
+ "test": "node --experimental-strip-types --test tests/*.test.mjs",
+ "test:coverage": "c8 --reporter=lcov --reporter=text npm test",
"lint": "eslint . --max-warnings=0",
"format": "prettier --write ."
},
@@ -21,6 +23,7 @@
"react-dom": "19.2.8"
},
"devDependencies": {
+ "c8": "12.0.0",
"@types/node": "24.10.1",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
diff --git a/apps/web/tests/localization.test.mjs b/apps/web/tests/localization.test.mjs
new file mode 100644
index 0000000..3d499ed
--- /dev/null
+++ b/apps/web/tests/localization.test.mjs
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
+// SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1
+
+import assert from "node:assert/strict";
+import { test } from "node:test";
+import {
+ getMessages,
+ isLocale,
+ messages,
+ supportedLocales,
+} from "../lib/localization.ts";
+
+test("only the two published locales are accepted", () => {
+ assert.deepEqual(supportedLocales, ["en-US", "de-DE"]);
+ assert.equal(isLocale("en-US"), true);
+ assert.equal(isLocale("de-DE"), true);
+ for (const value of ["en", "de", "en-us", "tr-TR", "", undefined]) {
+ assert.equal(isLocale(value), false, `unexpected locale: ${value}`);
+ }
+});
+
+test("both locales give the account and ViGet routes distinct page metadata", () => {
+ const english = messages["en-US"].metadata;
+ const german = messages["de-DE"].metadata;
+ for (const key of [
+ "homeTitle",
+ "accountTitle",
+ "loginTitle",
+ "registerTitle",
+ "vigetTitle",
+ "dslPluginsTitle",
+ ]) {
+ assert.equal(typeof english[key], "string");
+ assert.equal(typeof german[key], "string");
+ assert.notEqual(english[key].trim(), "");
+ assert.notEqual(german[key].trim(), "");
+ }
+ assert.notEqual(english.loginTitle, german.loginTitle);
+ assert.notEqual(english.registerTitle, german.registerTitle);
+ assert.match(english.vigetTitle, /ViGet/);
+ assert.match(german.vigetTitle, /ViGet/);
+});
+
+test("each supported locale resolves to its own complete message tree", () => {
+ for (const locale of supportedLocales) {
+ assert.strictEqual(getMessages(locale), messages[locale]);
+ }
+
+ function shape(value) {
+ if (Array.isArray(value)) return value.map(shape);
+ if (value !== null && typeof value === "object") {
+ return Object.fromEntries(
+ Object.entries(value).map(([key, child]) => [key, shape(child)]),
+ );
+ }
+ assert.equal(typeof value, "string");
+ assert.notEqual(value.trim(), "");
+ return "text";
+ }
+
+ assert.deepEqual(shape(messages["de-DE"]), shape(messages["en-US"]));
+});