fix: address Windows smoke review findings (#122)
Co-authored-by: iliya <iliyazelenkog@gmail.com>
This commit is contained in:
parent
9c438e7c84
commit
f08e228a7d
5 changed files with 103 additions and 4 deletions
|
|
@ -173,4 +173,13 @@ async function main() {
|
|||
fail(`Timed out after ${STARTUP_TIMEOUT_MS}ms waiting for packaged startup`, log);
|
||||
}
|
||||
|
||||
main().catch((error) => fail(error?.stack || String(error)));
|
||||
if (require.main === module) {
|
||||
main().catch((error) => fail(error?.stack || String(error)));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
_internal: {
|
||||
terminateChild,
|
||||
waitForProcessClose,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ import type { ClaudeMdContextInjection } from '@renderer/types/contextInjection'
|
|||
*/
|
||||
export function buildDirectoryTree(
|
||||
injections: ClaudeMdContextInjection[],
|
||||
projectRoot: string
|
||||
projectRoot?: string
|
||||
): TreeNode {
|
||||
const root: TreeNode = { name: '', path: '', isFile: false, children: new Map() };
|
||||
|
||||
for (const injection of injections) {
|
||||
const relativePath = projectRoot
|
||||
? getRelativePathWithinPrefix(projectRoot, injection.path) ?? injection.path
|
||||
? (getRelativePathWithinPrefix(projectRoot, injection.path) ?? injection.path)
|
||||
: injection.path;
|
||||
|
||||
const parts = relativePath.split(/[\\/]/);
|
||||
|
|
|
|||
|
|
@ -169,6 +169,21 @@ describe('recentProjectOpenHistory', () => {
|
|||
|
||||
it('ignores blank project paths without throwing', () => {
|
||||
expect(() => recordRecentProjectOpenPaths([' '], 10_000)).not.toThrow();
|
||||
expect(getRecentProjectLastOpenedAt(makeProject({ primaryPath: ' ', associatedPaths: [' '] }))).toBe(0);
|
||||
expect(
|
||||
getRecentProjectLastOpenedAt(makeProject({ primaryPath: ' ', associatedPaths: [' '] }))
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it('ignores paths that normalize to an empty history key', () => {
|
||||
recordRecentProjectOpenPaths(['///'], 10_000);
|
||||
|
||||
expect(
|
||||
getRecentProjectLastOpenedAt(
|
||||
makeProject({
|
||||
primaryPath: '/',
|
||||
associatedPaths: ['/'],
|
||||
})
|
||||
)
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
69
test/main/build/smokePackagedApp.test.ts
Normal file
69
test/main/build/smokePackagedApp.test.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// @vitest-environment node
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
interface SmokePackagedAppInternals {
|
||||
terminateChild(
|
||||
child: { exitCode: number | null; signalCode: string | null; kill: () => void },
|
||||
exitPromise: Promise<unknown>,
|
||||
platform: string
|
||||
): Promise<void>;
|
||||
waitForProcessClose(
|
||||
child: { exitCode: number | null; signalCode: string | null },
|
||||
exitPromise: Promise<unknown>,
|
||||
timeoutMs: number
|
||||
): Promise<boolean>;
|
||||
}
|
||||
|
||||
interface SmokePackagedAppModule {
|
||||
default?: { _internal?: SmokePackagedAppInternals };
|
||||
_internal?: SmokePackagedAppInternals;
|
||||
}
|
||||
|
||||
const requireFromTest: (id: string) => unknown = createRequire(import.meta.url);
|
||||
const smokePackagedApp = requireFromTest(
|
||||
'../../../scripts/electron-builder/smokePackagedApp.cjs'
|
||||
) as SmokePackagedAppModule;
|
||||
const smokePackagedAppInternals =
|
||||
smokePackagedApp._internal ?? smokePackagedApp.default?._internal;
|
||||
if (!smokePackagedAppInternals) {
|
||||
throw new Error('smokePackagedApp internals were not exported');
|
||||
}
|
||||
const { terminateChild, waitForProcessClose } = smokePackagedAppInternals;
|
||||
|
||||
describe('smokePackagedApp shutdown handling', () => {
|
||||
it('reports successful process closure before the timeout', async () => {
|
||||
let resolveExit!: (value: unknown) => void;
|
||||
const exitPromise = new Promise((resolve) => {
|
||||
resolveExit = resolve;
|
||||
});
|
||||
const child = { exitCode: null, signalCode: null };
|
||||
|
||||
const closed = waitForProcessClose(child, exitPromise, 1_000);
|
||||
resolveExit({ code: 0, signal: null });
|
||||
|
||||
await expect(closed).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('reports shutdown timeout instead of treating it as success', async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const exitPromise = new Promise(() => undefined);
|
||||
const child = {
|
||||
exitCode: null,
|
||||
signalCode: null,
|
||||
kill: vi.fn(),
|
||||
};
|
||||
|
||||
const termination = terminateChild(child, exitPromise, 'linux');
|
||||
const rejection = expect(termination).rejects.toThrow('Timed out after 5000ms');
|
||||
await vi.advanceTimersByTimeAsync(5_000);
|
||||
|
||||
await rejection;
|
||||
expect(child.kill).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -44,4 +44,10 @@ describe('buildDirectoryTree Windows paths', () => {
|
|||
|
||||
expect(root.children.get('C:')?.children.get('Users')).toBeDefined();
|
||||
});
|
||||
|
||||
it('falls back to absolute injection paths when project root is unavailable', () => {
|
||||
const root = buildDirectoryTree([injection('C:\\Users\\Alice\\Repo\\CLAUDE.md')]);
|
||||
|
||||
expect(root.children.get('C:')?.children.get('Users')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue