| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- import fs from 'fs';
- import path from 'path';
- const html = fs.readFileSync(path.join(process.cwd(), 'public/metadata-viewer.html'), 'utf8');
- const scriptMatch = html.match(/<script>([\s\S]*)<\/script>/);
- if (!scriptMatch) {
- console.error('Cannot extract <script> from public/metadata-viewer.html');
- process.exit(1);
- }
- const jsCode = scriptMatch[1];
- function createNode(id) {
- return {
- id,
- dataset: {},
- style: { display: '', minWidth: '', minHeight: '' },
- innerHTML: '',
- textContent: '',
- children: [],
- className: '',
- onclick: null,
- onmouseenter: null,
- onmouseleave: null,
- appendChild(child) { this.children.push(child); return child; },
- setAttribute() {},
- getAttribute() { return null; },
- querySelectorAll() { return []; },
- };
- }
- const elements = {};
- function $(id) {
- if (!elements[id]) elements[id] = createNode(id);
- return elements[id];
- }
- global.document = {
- getElementById: (id) => $(id),
- createElement: (tag) => createNode(`${tag}-${Math.random()}`),
- createElementNS: (ns, tag) => createNode(`${tag}-${Math.random()}`),
- };
- global.window = {
- parent: { postMessage() {} },
- addEventListener() {},
- removeEventListener() {},
- };
- global.addEventListener = () => {};
- eval(`(function(){
- ${jsCode}
- global._metadataViewer = {
- parseMeta,
- getState: () => ({ nodes, connections }),
- };
- })()`);
- let passed = 0;
- let failed = 0;
- function test(name, fn) {
- try {
- fn();
- console.log(` ✓ ${name}`);
- passed++;
- } catch (e) {
- console.log(` ✗ ${name}: ${e.message}`);
- failed++;
- }
- }
- function assert(cond, msg) {
- if (!cond) throw new Error(msg || 'Assertion failed');
- }
- function getCounts() {
- const { nodes, connections } = global._metadataViewer.getState();
- const counts = nodes.reduce((acc, node) => {
- acc[node.type] = (acc[node.type] || 0) + 1;
- return acc;
- }, {});
- return { nodes, connections, counts };
- }
- console.log('\n── Metadata Viewer Regression ──');
- test('renders legacy database.tables even before apps/services exist', () => {
- global._metadataViewer.parseMeta({
- project: { name: 'PartialLegacy' },
- database: {
- name: 'PartialLegacy',
- tables: [
- { name: 'Courses', fields: [{ name: 'title', type: 'STRING' }] },
- { name: 'PrepNotes', fields: [{ name: 'courseId', type: 'INT' }] },
- ],
- },
- serviceDomains: [],
- components: [],
- sections: [],
- apps: [],
- });
- const { counts } = getCounts();
- assert(counts.table === 2, `Expected 2 table nodes, got ${counts.table || 0}`);
- });
- test('uses legacy sourceTable for VT labels and table connections', () => {
- global._metadataViewer.parseMeta({
- project: { name: 'LegacySourceTable' },
- database: {
- name: 'LegacySourceTable',
- tables: [
- { name: 'Courses', fields: [{ name: 'title', type: 'STRING' }] },
- ],
- },
- serviceDomains: [
- {
- domainId: 'Course',
- virtualTables: [
- {
- name: 'CourseList',
- sourceTable: 'Courses',
- fields: [{ name: 'title', type: 'STRING' }],
- },
- ],
- services: [
- { serviceId: 'Course.GetCourseList', name: 'GetCourseList' },
- ],
- },
- ],
- components: [],
- sections: [],
- apps: [],
- });
- const { nodes, connections, counts } = getCounts();
- const vtNode = nodes.find((node) => node.id === 'Course.CourseList');
- assert(vtNode, 'Expected Course.CourseList VT node');
- assert(vtNode.sub === 'source: Courses', `Expected VT source label, got ${vtNode.sub}`);
- assert(counts.table === 1, `Expected 1 table node, got ${counts.table || 0}`);
- assert(connections.some((conn) => conn.from === 'Course.CourseList' && conn.to === 'Courses' && conn.type === 'data'),
- 'Expected VT → table data connection');
- });
- test('connects app page sectionRefs and section servicesUsed from extracted metadata', () => {
- global._metadataViewer.parseMeta({
- project: { name: 'TeacherPrep' },
- apps: [
- {
- appId: 'TeacherPrepApp',
- pages: [
- {
- pageId: 'Main',
- sectionRefs: [
- { sectionId: 'NavSidebar', instanceId: 'navSidebar' },
- { sectionId: 'DashboardMain', instanceId: 'dashboardMain' },
- ],
- componentRefs: [
- { componentId: 'ConfirmDialog', instanceId: 'confirmDialog' },
- ],
- routeMap: {
- dashboard: 'DashboardMain',
- },
- },
- ],
- },
- ],
- sections: [
- {
- sectionId: 'DashboardMain',
- servicesUsed: [
- {
- domainId: 'Dashboard',
- services: [
- { serviceId: 'Dashboard.GetStats', serviceName: 'GetStats' },
- ],
- },
- ],
- },
- { sectionId: 'NavSidebar' },
- ],
- components: [
- { componentId: 'ConfirmDialog' },
- ],
- services: [
- {
- domainId: 'Dashboard',
- methods: [
- { name: 'GetStats' },
- ],
- },
- ],
- dataSchema: { tables: [] },
- });
- const { connections } = getCounts();
- assert(connections.some((conn) => conn.from === 'Main' && conn.to === 'DashboardMain' && conn.type === 'ui'),
- 'Expected page → section connection from sectionRefs/routeMap');
- assert(connections.some((conn) => conn.from === 'Main' && conn.to === 'ConfirmDialog' && conn.type === 'comp'),
- 'Expected page → component connection from componentRefs');
- assert(connections.some((conn) => conn.from === 'DashboardMain' && conn.to === 'Dashboard.GetStats' && conn.type === 'service'),
- 'Expected section → service connection from servicesUsed');
- });
- console.log(`\n── Results ──\n\n ${passed} passed, ${failed} failed\n`);
- process.exit(failed > 0 ? 1 : 0);
|