fix(ui): resolve JS try-block syntax error and add SSR script syntax test suite
This commit is contained in:
parent
22bcd889c3
commit
8d4069709d
@ -1007,7 +1007,7 @@ export const SessionsPage = ({
|
|||||||
const eventId = e.currentTarget.getAttribute('data-event-id');
|
const eventId = e.currentTarget.getAttribute('data-event-id');
|
||||||
e.currentTarget.disabled = true;
|
e.currentTarget.disabled = true;
|
||||||
try {
|
try {
|
||||||
const res = await fetch(\`/api/events/\${eventId}/extend\`, {
|
const res = await fetch('/api/events/' + eventId + '/extend', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ extendHours: 1 })
|
body: JSON.stringify({ extendHours: 1 })
|
||||||
@ -1036,7 +1036,7 @@ export const SessionsPage = ({
|
|||||||
e.currentTarget.textContent = 'Revoking...';
|
e.currentTarget.textContent = 'Revoking...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(\`/api/events/\${eventId}/end\`, {
|
const res = await fetch('/api/events/' + eventId + '/end', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
@ -1047,6 +1047,7 @@ export const SessionsPage = ({
|
|||||||
showNotice(data.error || 'Failed to end event', true);
|
showNotice(data.error || 'Failed to end event', true);
|
||||||
e.currentTarget.disabled = false;
|
e.currentTarget.disabled = false;
|
||||||
e.currentTarget.textContent = '🔴 End & Revoke All';
|
e.currentTarget.textContent = '🔴 End & Revoke All';
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showNotice('Network error ending event', true);
|
showNotice('Network error ending event', true);
|
||||||
e.currentTarget.disabled = false;
|
e.currentTarget.disabled = false;
|
||||||
@ -1066,7 +1067,7 @@ export const SessionsPage = ({
|
|||||||
e.currentTarget.disabled = true;
|
e.currentTarget.disabled = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(\`/api/sessions/\${sessionId}\`, {
|
const res = await fetch('/api/sessions/' + sessionId, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
135
ui/ui_scripts.test.ts
Normal file
135
ui/ui_scripts.test.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import { assertEquals } from "jsr:@std/assert@1";
|
||||||
|
import { SessionsPage } from "./components/SessionsPage.tsx";
|
||||||
|
import { LoginPage } from "./components/LoginPage.tsx";
|
||||||
|
import { RegisterPage } from "./components/RegisterPage.tsx";
|
||||||
|
import { EventJoinPage } from "./components/EventJoinPage.tsx";
|
||||||
|
import { EventSplashPage } from "./components/EventSplashPage.tsx";
|
||||||
|
import { PasskeysPage } from "./components/PasskeysPage.tsx";
|
||||||
|
import { AdminAppsPage } from "./components/AdminAppsPage.tsx";
|
||||||
|
import { AdminInvitesPage } from "./components/AdminInvitesPage.tsx";
|
||||||
|
import { AdminRolesPage } from "./components/AdminRolesPage.tsx";
|
||||||
|
import { AdminUsersPage } from "./components/AdminUsersPage.tsx";
|
||||||
|
import { AdminUserDetailsPage } from "./components/AdminUserDetailsPage.tsx";
|
||||||
|
import { AuditLogPage } from "./components/AuditLogPage.tsx";
|
||||||
|
import { AAGUIDPage } from "./components/AAGUIDPage.tsx";
|
||||||
|
|
||||||
|
function validateJsSyntax(componentName: string, jsxResult: any) {
|
||||||
|
const html = String(jsxResult);
|
||||||
|
const scriptRegex = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
|
||||||
|
let match;
|
||||||
|
let scriptCount = 0;
|
||||||
|
while ((match = scriptRegex.exec(html)) !== null) {
|
||||||
|
const isModule = match[1].includes('type="module"') ||
|
||||||
|
match[1].includes("type='module'");
|
||||||
|
const scriptContent = match[2].trim();
|
||||||
|
if (!scriptContent) continue;
|
||||||
|
scriptCount++;
|
||||||
|
try {
|
||||||
|
if (isModule) {
|
||||||
|
// Strip import statements for syntax compilation check in new Function
|
||||||
|
const cleanContent = scriptContent.replace(
|
||||||
|
/import\s+[\s\S]*?from\s+['"][^'"]+['"];?/g,
|
||||||
|
"// import stripped",
|
||||||
|
);
|
||||||
|
new Function(cleanContent);
|
||||||
|
} else {
|
||||||
|
new Function(scriptContent);
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
throw new Error(
|
||||||
|
`Syntax error in <script> inside ${componentName}: ${err.message}\n---\n${scriptContent}\n---`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scriptCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Deno.test("UI Script Validation - SessionsPage", () => {
|
||||||
|
const result = SessionsPage({
|
||||||
|
sessions: [
|
||||||
|
{
|
||||||
|
id: "ay_sess_1",
|
||||||
|
label: "Test Session",
|
||||||
|
is_agent: true,
|
||||||
|
custom_scopes: ["read:audit"],
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
expires_at: new Date(Date.now() + 3600000).toISOString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
currentSessionId: "ay_sess_1",
|
||||||
|
apps: [],
|
||||||
|
isAdmin: true,
|
||||||
|
eventPasses: [
|
||||||
|
{
|
||||||
|
id: "evt-1",
|
||||||
|
name: "Workshop 101",
|
||||||
|
slug: "workshop-101",
|
||||||
|
pin_code: "123-456",
|
||||||
|
max_seats: 50,
|
||||||
|
seats_claimed: 10,
|
||||||
|
is_active: true,
|
||||||
|
expires_at: new Date(Date.now() + 3600000).toISOString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const count = validateJsSyntax("SessionsPage", result);
|
||||||
|
assertEquals(count > 0, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("UI Script Validation - LoginPage & RegisterPage", () => {
|
||||||
|
validateJsSyntax("LoginPage", LoginPage());
|
||||||
|
validateJsSyntax("RegisterPage", RegisterPage({ initialCode: "" }));
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("UI Script Validation - Event Pages", () => {
|
||||||
|
validateJsSyntax("EventJoinPage", EventJoinPage());
|
||||||
|
validateJsSyntax(
|
||||||
|
"EventSplashPage",
|
||||||
|
EventSplashPage({
|
||||||
|
event: {
|
||||||
|
id: "evt-1",
|
||||||
|
name: "Workshop",
|
||||||
|
slug: "workshop",
|
||||||
|
pin_code: "123-456",
|
||||||
|
max_seats: 50,
|
||||||
|
seats_claimed: 5,
|
||||||
|
lifespan_hours: 2,
|
||||||
|
role: "viewer",
|
||||||
|
expires_at: new Date(Date.now() + 3600000).toISOString(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("UI Script Validation - Admin Pages", () => {
|
||||||
|
validateJsSyntax(
|
||||||
|
"PasskeysPage",
|
||||||
|
PasskeysPage({ passkeys: [], isAdmin: true }),
|
||||||
|
);
|
||||||
|
validateJsSyntax("AdminAppsPage", AdminAppsPage({ apps: [] }));
|
||||||
|
validateJsSyntax(
|
||||||
|
"AdminInvitesPage",
|
||||||
|
AdminInvitesPage({ invites: [], apps: [], allRoles: [] }),
|
||||||
|
);
|
||||||
|
validateJsSyntax(
|
||||||
|
"AdminRolesPage",
|
||||||
|
AdminRolesPage({ roles: [], apps: [] }),
|
||||||
|
);
|
||||||
|
validateJsSyntax(
|
||||||
|
"AdminUsersPage",
|
||||||
|
AdminUsersPage({ users: [] }),
|
||||||
|
);
|
||||||
|
validateJsSyntax(
|
||||||
|
"AdminUserDetailsPage",
|
||||||
|
AdminUserDetailsPage({
|
||||||
|
user: { id: "u-1", username: "test", account_status: "active" },
|
||||||
|
sessions: [],
|
||||||
|
passkeys: [],
|
||||||
|
grants: [],
|
||||||
|
allApps: [],
|
||||||
|
allRoles: [],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
validateJsSyntax("AuditLogPage", AuditLogPage({ logs: [] }));
|
||||||
|
validateJsSyntax("AAGUIDPage", AAGUIDPage({ allowlist: [] }));
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user