Files
networkSetup/src/apps/desktop/tests/start-screen.test.mjs
T
jychoi4 388e1e3327 feat: implement Installer Studio MSIX authoring workflow
Add the shared Rust engine, Tauri UI and CLI, registry authoring, developer signing, branded start screen and .isproj persistence. Remove the unused project ID.

Validation: frontend build and tests, Rust workspace tests, native build and real Windows SDK package generation passed.

Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
2026-11-02 15:12:00 +09:00

50 lines
3.0 KiB
JavaScript

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, '<img src=x onerror=alert(1)>'), available: false };
const html = renderStartScreen({ ...base, projects: [unsafe] });
assert.match(html, /&lt;img/);
assert.doesNotMatch(html, /<img src=x/);
assert.match(html, /파일을 찾을 수 없습니다/);
});
test('cancel keeps edits, discard does not save, and a save failure prevents closing', async () => {
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);
});