ZDDC — Zero Day Document Control. A file-naming convention plus five single-file HTML tools (archive, transmittal, classifier, mdedit, landing) and an optional Go HTTP server (zddc-server) with ACL and a virtual archive index. Self-contained, offline-capable, dependency-free. See README.md for an overview, AGENTS.md and ARCHITECTURE.md for the build/release/architecture detail, bootstrap/README.md for the two-level deployment install pattern, and zddc/README.md for the HTTP server.
113 lines
5.5 KiB
JavaScript
113 lines
5.5 KiB
JavaScript
import { test, expect } from '@playwright/test';
|
|
import { MOCK_FS_INIT_SCRIPT } from './fixtures/mock-fs-api.js';
|
|
import * as path from 'path';
|
|
|
|
const HTML_PATH = path.resolve('archive/dist/archive.html');
|
|
|
|
test.describe('Archive Browser', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.addInitScript(MOCK_FS_INIT_SCRIPT);
|
|
});
|
|
|
|
test('loads without errors', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#appContainer', { timeout: 15000 });
|
|
|
|
// Page title contains "Archive"
|
|
await expect(page).toHaveTitle(/Archive/i);
|
|
|
|
// No-directory message is shown before any directory is opened
|
|
await expect(page.locator('#noDirectoryMessage')).toBeVisible();
|
|
|
|
// The open-directory button is present
|
|
await expect(page.locator('#addDirectoryBtn')).toBeVisible();
|
|
});
|
|
|
|
test('scans a mock directory tree and displays files', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
// Log to see if the scan is working
|
|
page.on('console', msg => {
|
|
console.log('Browser console:', msg.text());
|
|
});
|
|
page.on('pageerror', err => {
|
|
console.log('Page error:', err.message);
|
|
});
|
|
|
|
// The archive expects a two-level structure: root → transmittal-folder → files.
|
|
// Flat files at the root are not counted — they must be inside subdirectories.
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('test-project', {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First Transmittal': {
|
|
'123456-EL-SPC-2623_A (IFC) - Specification.pdf': '%PDF',
|
|
'123456-EL-DRW-0001_B (IFR) - Drawing.dwg': 'DWG',
|
|
},
|
|
'2025-02-10_123456-EM-TRN-0002 (IFC) - Second Transmittal': {
|
|
'789012-ME-CAL-0001_A (IFA) - Calculation.pdf': '%PDF',
|
|
},
|
|
});
|
|
console.log('Mock directory set up');
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
|
|
// Wait for scanning to complete
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Log state for debugging
|
|
await page.evaluate(() => {
|
|
console.log('After scanning:');
|
|
console.log(' window.app exists:', typeof window.app !== 'undefined');
|
|
if (typeof window.app !== 'undefined') {
|
|
console.log(' window.app type:', typeof window.app);
|
|
console.log(' window.app constructor:', window.app.constructor.name);
|
|
console.log(' window.app.directories:', Array.isArray(window.app.directories) ? window.app.directories.length : window.app.directories);
|
|
console.log(' window.app.files:', Array.isArray(window.app.files) ? window.app.files.length : window.app.files);
|
|
console.log(' window.app.filteredFiles:', Array.isArray(window.app.filteredFiles) ? window.app.filteredFiles.length : window.app.filteredFiles);
|
|
console.log(' window.app modules:', Object.keys(window.app || {}).filter(k => k.startsWith('modules')));
|
|
} else {
|
|
console.log(' window.app is undefined!');
|
|
}
|
|
});
|
|
|
|
// Select all grouping folders so files are included in the file list
|
|
await page.evaluate(() => {
|
|
const cb = document.getElementById('selectAllGroupingCheckbox');
|
|
if (cb && !cb.checked) cb.click();
|
|
});
|
|
await page.waitForTimeout(500);
|
|
|
|
// The files table should have at least one data row
|
|
const rowCount = await page.locator('#filesTableBody tr').count();
|
|
expect(rowCount).toBeGreaterThanOrEqual(1);
|
|
|
|
// Status bar should show files were found (any non-empty text is fine)
|
|
const fileCountText = await page.locator('#fileCount').textContent();
|
|
expect(fileCountText).toBeTruthy();
|
|
});
|
|
|
|
test('parser module uses shared zddc helpers (not its own wrappers)', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#appContainer', { timeout: 15000 });
|
|
|
|
const probe = await page.evaluate(() => ({
|
|
// archive's parser module should NOT re-export wrappers we removed
|
|
hasParseFileNameWrapper: typeof window.app.modules.parser?.parseFileName === 'function',
|
|
hasParseRevisionWrapper: typeof window.app.modules.parser?.parseRevision === 'function',
|
|
// but should still expose archive-specific helpers
|
|
hasIsTransmittalFolder: typeof window.app.modules.parser?.isTransmittalFolder === 'function',
|
|
hasGroupFiles: typeof window.app.modules.parser?.groupFilesByTrackingNumber === 'function',
|
|
// and isTransmittalFolder should agree with shared zddc.parseFolder
|
|
validFolder: window.app.modules.parser.isTransmittalFolder('2025-10-31_123456-EM-SUB-0001 (IFR) - General Arrangement'),
|
|
invalidFolder: window.app.modules.parser.isTransmittalFolder('not-a-zddc-folder'),
|
|
}));
|
|
|
|
expect(probe.hasParseFileNameWrapper).toBe(false);
|
|
expect(probe.hasParseRevisionWrapper).toBe(false);
|
|
expect(probe.hasIsTransmittalFolder).toBe(true);
|
|
expect(probe.hasGroupFiles).toBe(true);
|
|
expect(probe.validFolder).toBe(true);
|
|
expect(probe.invalidFolder).toBe(false);
|
|
});
|
|
});
|