566 lines
26 KiB
JavaScript
566 lines
26 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('a .zip transmittal folder is scanned like an uncompressed one', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
// One plain transmittal folder + one delivered as a single .zip
|
|
// whose name parses as a transmittal-folder name. The zip's
|
|
// members should land in the file list exactly like the plain
|
|
// folder's files. (JSZip is bundled into archive.html.)
|
|
await page.evaluate(async () => {
|
|
const zip = new window.JSZip();
|
|
zip.file('789012-ME-CAL-0001_A (IFA) - Calculation.pdf', '%PDF calc');
|
|
zip.file('sub/789012-ME-DRW-0001_A (IFA) - Detail.dwg', 'DWG detail');
|
|
const buf = await zip.generateAsync({ type: 'uint8array' });
|
|
window.__setMockDirectoryTree('test-project', {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First Transmittal': {
|
|
'123456-EL-SPC-2623_A (IFC) - Specification.pdf': '%PDF',
|
|
},
|
|
'2025-02-10_123456-EM-TRN-0002 (IFC) - Second Transmittal.zip': buf,
|
|
});
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForFunction(() => window.app && Array.isArray(window.app.files) && window.app.files.length >= 3, { timeout: 10000 });
|
|
|
|
// 1 file from the plain folder + 2 from inside the zip.
|
|
const fileCount = await page.evaluate(() => window.app.files.length);
|
|
expect(fileCount).toBeGreaterThanOrEqual(3);
|
|
|
|
// The zip is surfaced as a transmittal folder, named without ".zip".
|
|
const zipFolder = await page.evaluate(() =>
|
|
window.app.transmittalFolders.find(f => /Second Transmittal$/.test(f.name)) || null);
|
|
expect(zipFolder).toBeTruthy();
|
|
expect(zipFolder.name).not.toMatch(/\.zip$/i);
|
|
|
|
// The zip's members are parsed like normal archive files (tracking
|
|
// numbers extracted) and tied to the zip transmittal's folder.
|
|
const memberTracking = await page.evaluate(() =>
|
|
window.app.files.filter(f => f.folderPath && /\.zip$/i.test(f.folderPath)).map(f => f.trackingNumber).sort());
|
|
expect(memberTracking).toEqual(['789012-ME-CAL-0001', '789012-ME-DRW-0001']);
|
|
|
|
// Select all grouping folders + render the table; zip members show.
|
|
await page.evaluate(() => {
|
|
const cb = document.getElementById('selectAllGroupingCheckbox');
|
|
if (cb && !cb.checked) cb.click();
|
|
});
|
|
await page.waitForTimeout(300);
|
|
const rowCount = await page.locator('#filesTableBody tr').count();
|
|
expect(rowCount).toBeGreaterThanOrEqual(3);
|
|
});
|
|
|
|
test('Mode 1: ?projects=A,B enters each project\'s Archive subfolder', async ({ page }) => {
|
|
// Multi-project layout: server root holds project folders, each containing an
|
|
// Archive/ subfolder with third-party folders. ?projects=A,B (set as
|
|
// window.app.projectFilter; url-state.restore() handles parsing in real flow)
|
|
// selects the projects to scan. Each is descended into <project>/Archive/.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('combined-root', {
|
|
'Project-A': {
|
|
'Archive': {
|
|
'ACME': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecA.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'Project-B': {
|
|
'Archive': {
|
|
'Beta': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - Second': {
|
|
'789012-EL-SPC-0002_A (IFC) - SpecB.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'Project-C': {
|
|
'Archive': {
|
|
'Gamma': {
|
|
'2025-03-01_345678-EM-TRN-0001 (IFC) - Third': {
|
|
'345678-EL-SPC-0003_A (IFC) - SpecC.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
window.app.projectFilter = new Set(['Project-A', 'Project-B']);
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Third-party (grouping) folders should be ACME and Beta — never project IDs or "Archive"
|
|
const groupingFolders = await page.evaluate(() =>
|
|
window.app.groupingFolders.map(f => f.name)
|
|
);
|
|
expect(groupingFolders).toContain('ACME');
|
|
expect(groupingFolders).toContain('Beta');
|
|
expect(groupingFolders).not.toContain('Project-A');
|
|
expect(groupingFolders).not.toContain('Project-B');
|
|
expect(groupingFolders).not.toContain('Archive');
|
|
expect(groupingFolders).not.toContain('Gamma');
|
|
|
|
await page.evaluate(() => {
|
|
const cb = document.getElementById('selectAllGroupingCheckbox');
|
|
if (cb && !cb.checked) cb.click();
|
|
});
|
|
await page.waitForTimeout(500);
|
|
|
|
const tableText = await page.locator('#filesTableBody').textContent();
|
|
expect(tableText).toContain('SpecA');
|
|
expect(tableText).toContain('SpecB');
|
|
expect(tableText).not.toContain('SpecC');
|
|
});
|
|
|
|
test('same-name third-parties across projects merge into one party row', async ({ page }) => {
|
|
// Both projects have a "BM" third-party folder. The parties pane must
|
|
// show "BM" once, and selecting it must surface files from both projects.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('combined-root', {
|
|
'176109': {
|
|
'Archive': {
|
|
'BM': {
|
|
'Issued': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecFromA.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'197072': {
|
|
'Archive': {
|
|
'BM': {
|
|
'Issued': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - Second': {
|
|
'789012-EL-SPC-0002_A (IFC) - SpecFromB.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
window.app.projectFilter = new Set(['176109', '197072']);
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// The DOM should render exactly one BM row, not two.
|
|
const renderedNames = await page.locator('#groupingFoldersList .folder-item-name').allTextContents();
|
|
const bmRows = renderedNames.filter(n => n.trim() === 'BM');
|
|
expect(bmRows.length).toBe(1);
|
|
|
|
// Both projects' files should be visible under the single BM party.
|
|
const tableText = await page.locator('#filesTableBody').textContent();
|
|
expect(tableText).toContain('SpecFromA');
|
|
expect(tableText).toContain('SpecFromB');
|
|
});
|
|
|
|
test('toggling visibleProjects hides files without re-scanning', async ({ page }) => {
|
|
// Two projects scanned. Toggling 197072 out of visibleProjects should
|
|
// hide its files; window.app.files (the in-memory scan result) must NOT
|
|
// shrink — only the visible/filtered set changes.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('combined-root', {
|
|
'176109': {
|
|
'Archive': {
|
|
'BM': {
|
|
'Issued': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecFromA.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'197072': {
|
|
'Archive': {
|
|
'BM': {
|
|
'Issued': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - Second': {
|
|
'789012-EL-SPC-0002_A (IFC) - SpecFromB.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
window.app.projectFilter = new Set(['176109', '197072']);
|
|
window.app.visibleProjects = new Set(['176109', '197072']);
|
|
window.app.isMultiProject = true;
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
const beforeFileCount = await page.evaluate(() => window.app.files.length);
|
|
expect(beforeFileCount).toBeGreaterThanOrEqual(2);
|
|
|
|
// Toggle 197072 out of the visible set — must NOT shrink window.app.files.
|
|
await page.evaluate(() => {
|
|
window.app.visibleProjects = new Set(['176109']);
|
|
window.app.modules.app.updateUI();
|
|
window.app.modules.filtering.applyFilters();
|
|
});
|
|
|
|
const afterFileCount = await page.evaluate(() => window.app.files.length);
|
|
expect(afterFileCount).toBe(beforeFileCount);
|
|
|
|
const tableText = await page.locator('#filesTableBody').textContent();
|
|
expect(tableText).toContain('SpecFromA');
|
|
expect(tableText).not.toContain('SpecFromB');
|
|
|
|
// Toggle 197072 back — file reappears immediately, no rescan needed.
|
|
await page.evaluate(() => {
|
|
window.app.visibleProjects = new Set(['176109', '197072']);
|
|
window.app.modules.app.updateUI();
|
|
window.app.modules.filtering.applyFilters();
|
|
});
|
|
const tableTextAfter = await page.locator('#filesTableBody').textContent();
|
|
expect(tableTextAfter).toContain('SpecFromA');
|
|
expect(tableTextAfter).toContain('SpecFromB');
|
|
});
|
|
|
|
test('?show= URL param round-trips: serialize emits it, restore reads it', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
// Serialize: visibleProjects ⊊ projectFilter → ?show= present
|
|
const qsWithSubset = await page.evaluate(() => {
|
|
window.app.projectFilter = new Set(['A', 'B', 'C']);
|
|
window.app.visibleProjects = new Set(['A']);
|
|
return window.app.modules.urlState.serialize();
|
|
});
|
|
expect(qsWithSubset).toContain('projects=A%2CB%2CC');
|
|
expect(qsWithSubset).toContain('show=A');
|
|
|
|
// Serialize: visibleProjects equals projectFilter → ?show= omitted
|
|
const qsAllVisible = await page.evaluate(() => {
|
|
window.app.projectFilter = new Set(['A', 'B']);
|
|
window.app.visibleProjects = new Set(['A', 'B']);
|
|
return window.app.modules.urlState.serialize();
|
|
});
|
|
expect(qsAllVisible).not.toContain('show=');
|
|
|
|
// Restore: ?show= populates visibleProjects from URL.
|
|
await page.goto(`file://${HTML_PATH}?projects=A,B,C&show=A,B`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
const restored = await page.evaluate(() => {
|
|
// Re-run restore in case the early init() raced with DOM availability —
|
|
// matches how the existing projectFilter test bypasses this path too.
|
|
window.app.modules.urlState.restore();
|
|
return {
|
|
search: location.search,
|
|
projectFilter: Array.from(window.app.projectFilter).sort(),
|
|
visibleProjects: Array.from(window.app.visibleProjects).sort(),
|
|
};
|
|
});
|
|
expect(restored.search).toBe('?projects=A,B,C&show=A,B');
|
|
expect(restored.projectFilter).toEqual(['A', 'B', 'C']);
|
|
expect(restored.visibleProjects).toEqual(['A', 'B']);
|
|
});
|
|
|
|
test('Mode 2: project-root with Archive child auto-descends into Archive only', async ({ page }) => {
|
|
// Picked directory is a project root containing Archive/ plus Reviewing/.
|
|
// The app should enter Archive/ automatically and ignore Reviewing/.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('project-176109', {
|
|
'Archive': {
|
|
'ACME': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - InArchive.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
'Reviewing': {
|
|
'ShouldNotShow': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - HiddenStage': {
|
|
'789012-EL-SPC-0002_A (IFC) - InReviewing.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
const groupingFolders = await page.evaluate(() =>
|
|
window.app.groupingFolders.map(f => f.name)
|
|
);
|
|
expect(groupingFolders).toContain('ACME');
|
|
expect(groupingFolders).not.toContain('Archive');
|
|
expect(groupingFolders).not.toContain('Reviewing');
|
|
expect(groupingFolders).not.toContain('ShouldNotShow');
|
|
|
|
const fileNames = await page.evaluate(() => window.app.files.map(f => f.name));
|
|
expect(fileNames.some(n => n.includes('InArchive'))).toBe(true);
|
|
expect(fileNames.some(n => n.includes('InReviewing'))).toBe(false);
|
|
});
|
|
|
|
test('Mode 3: in-archive layout (no projects=, no Archive child) uses today\'s scan', async ({ page }) => {
|
|
// Picked directory IS the Archive folder — children are third-parties directly.
|
|
// Behavior must match pre-change baseline.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('Archive', {
|
|
'ACME': {
|
|
'Issued': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecA.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
'Beta': {
|
|
'Received': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - Second': {
|
|
'789012-EL-SPC-0002_A (IFC) - SpecB.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
const groupingFolders = await page.evaluate(() =>
|
|
window.app.groupingFolders.map(f => f.name)
|
|
);
|
|
expect(groupingFolders).toContain('ACME');
|
|
expect(groupingFolders).toContain('Beta');
|
|
|
|
await page.evaluate(() => {
|
|
const cb = document.getElementById('selectAllGroupingCheckbox');
|
|
if (cb && !cb.checked) cb.click();
|
|
});
|
|
await page.waitForTimeout(500);
|
|
|
|
const tableText = await page.locator('#filesTableBody').textContent();
|
|
expect(tableText).toContain('SpecA');
|
|
expect(tableText).toContain('SpecB');
|
|
});
|
|
|
|
test('disabled folder types are skipped at scan time (not just hidden in UI)', async ({ page }) => {
|
|
// Default enabledFolderTypes is {issued, received}. The Incoming folder should
|
|
// never be listed — its files must not appear in window.app.files at all.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('Archive', {
|
|
'ACME': {
|
|
'Issued': {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - First': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecIssued.pdf': '%PDF',
|
|
},
|
|
},
|
|
'Incoming': {
|
|
'2025-02-10_789012-EM-TRN-0001 (IFC) - Second': {
|
|
'789012-EL-SPC-0002_A (IFC) - SpecIncoming.pdf': '%PDF',
|
|
},
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
const fileNames = await page.evaluate(() => window.app.files.map(f => f.name));
|
|
expect(fileNames.some(n => n.includes('SpecIssued'))).toBe(true);
|
|
// Incoming is in FOLDER_TYPE_NAMES but not in default enabledFolderTypes — must be skipped
|
|
expect(fileNames.some(n => n.includes('SpecIncoming'))).toBe(false);
|
|
});
|
|
|
|
test('Preview toggle is checked by default', async ({ page }) => {
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
// The checkbox lives inside the (hidden) preview-controls area
|
|
// before any directory is loaded — waitForSelector defaults to
|
|
// 'visible' which would time out. Wait for it to be ATTACHED
|
|
// and verify the underlying state instead.
|
|
await page.waitForSelector('#filePreviewToggle', { state: 'attached', timeout: 15000 });
|
|
await expect(page.locator('#filePreviewToggle')).toBeChecked();
|
|
});
|
|
|
|
test('default modifier filter selects only base and +C revisions', async ({ page }) => {
|
|
// Files with mixed revision modifiers — by default only base + +C should
|
|
// surface in the visible file table; +B (and any other non-+C modifier)
|
|
// should be hidden until the user explicitly opts in.
|
|
await page.goto(`file://${HTML_PATH}`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForSelector('#addDirectoryBtn', { timeout: 15000 });
|
|
|
|
await page.evaluate(() => {
|
|
window.__setMockDirectoryTree('test-project', {
|
|
'2025-01-15_123456-EM-TRN-0001 (IFC) - Mixed Mods': {
|
|
'123456-EL-SPC-0001_A (IFC) - SpecBase.pdf': '%PDF',
|
|
'123456-EL-SPC-0001_A+C1 (IFC) - SpecComment.pdf': '%PDF',
|
|
'123456-EL-SPC-0001_A+B1 (IFC) - SpecScratch.pdf': '%PDF',
|
|
'123456-EL-SPC-0001_A+D1 (IFC) - SpecDraft.pdf': '%PDF',
|
|
},
|
|
});
|
|
});
|
|
|
|
await page.locator('#addDirectoryBtn').click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
await page.evaluate(() => {
|
|
const cb = document.getElementById('selectAllGroupingCheckbox');
|
|
if (cb && !cb.checked) cb.click();
|
|
});
|
|
await page.waitForTimeout(300);
|
|
|
|
const state = await page.evaluate(() => ({
|
|
available: Array.from(window.app.availableModifiers).sort(),
|
|
selected: Array.from(window.app.selectedModifiers).sort(),
|
|
visibleNames: window.app.filteredFiles.map(f => f.name),
|
|
}));
|
|
|
|
// The dropdown still LISTS all modifiers found in the data…
|
|
expect(state.available).toEqual(['+B', '+C', '+D', 'base']);
|
|
// …but only base + +C are pre-selected by default.
|
|
expect(state.selected).toEqual(['+C', 'base']);
|
|
// Files with hidden modifier types must be absent from the table.
|
|
expect(state.visibleNames.some(n => n.includes('SpecBase'))).toBe(true);
|
|
expect(state.visibleNames.some(n => n.includes('SpecComment'))).toBe(true);
|
|
expect(state.visibleNames.some(n => n.includes('SpecScratch'))).toBe(false);
|
|
expect(state.visibleNames.some(n => n.includes('SpecDraft'))).toBe(false);
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|