import test from 'node:test';
import assert from 'node:assert/strict';
import { displayPath, groupRecentProjects, renderStartScreen } from '../src/start-screen.ts';
import { allowProjectTransition } from '../src/project-transition.ts';
const recent = (id, year, month, day, name = id) => ({
id, path: `C:\\projects\\${id}\\InstallerProject.isproj`, displayName: name,
lastOpenedAt: new Date(year, month - 1, day, 10).getTime() / 1000, available: true,
});
test('recent projects are grouped in local calendar order and searchable by name or path', () => {
const projects = [recent('older', 2026, 9, 30), recent('today', 2026, 10, 21), recent('month', 2026, 10, 4), recent('week', 2026, 10, 20, '패키지 도구')];
const now = new Date(2026, 9, 21, 18);
assert.deepEqual([...groupRecentProjects(projects, '', now).keys()], ['오늘', '이번 주', '이번 달', '이전']);
assert.equal([...groupRecentProjects(projects, '패키지', now).values()][0][0].id, 'week');
assert.equal([...groupRecentProjects(projects, 'PROJECTS\\month', now).values()][0][0].id, 'month');
assert.equal(groupRecentProjects(projects, 'not found', now).size, 0);
});
test('extended Windows paths are displayed without changing their UNC semantics', () => {
assert.equal(displayPath('\\\\?\\C:\\apps\\project.isproj'), 'C:\\apps\\project.isproj');
assert.equal(displayPath('\\\\?\\UNC\\server\\share\\project.isproj'), '\\\\server\\share\\project.isproj');
});
test('start screen has left recent projects and right actions without fabricated entries', () => {
const base = { projects: [], query: '', busy: false, loading: false, error: '', notice: '', recentError: '', native: true };
const empty = renderStartScreen(base);
assert.match(empty, /최근 프로젝트가 없습니다/);
assert.ok(empty.indexOf('recent-panel') < empty.indexOf('class="start-actions"'));
assert.match(empty, /data-action="open"/);
assert.match(empty, /data-action="new"/);
assert.doesNotMatch(empty, /class="sidebar"/);
const unsafe = { ...recent('a', 2026, 10, 21, '
'), available: false };
const html = renderStartScreen({ ...base, projects: [unsafe] });
assert.match(html, /<img/);
assert.doesNotMatch(html, /
{
let saves = 0;
assert.equal(await allowProjectTransition(true, async () => 'cancel', async () => { saves++; }), false);
assert.equal(await allowProjectTransition(true, async () => 'discard', async () => { saves++; }), true);
assert.equal(saves, 0);
await assert.rejects(allowProjectTransition(true, async () => 'save', async () => { throw new Error('RevisionConflict'); }), /RevisionConflict/);
assert.equal(await allowProjectTransition(true, async () => 'save', async () => { saves++; }), true);
assert.equal(saves, 1);
assert.equal(await allowProjectTransition(false, async () => { throw new Error('should not ask'); }, async () => {}), true);
});