mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
Merge main into massive-terminal-upgrade
Resolves merge conflicts: - apps/server/src/routes/terminal/common.ts: Keep randomBytes import, use @automaker/utils for createLogger - apps/ui/eslint.config.mjs: Use main's explicit globals list with XMLHttpRequest and MediaQueryListEvent additions - apps/ui/src/components/views/terminal-view.tsx: Keep our terminal improvements (killAllSessions, beforeunload, better error handling) - apps/ui/src/config/terminal-themes.ts: Keep our search highlight colors for all themes - apps/ui/src/store/app-store.ts: Keep our terminal settings persistence improvements (merge function) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { mkdirSafe, existsSafe } from "@/lib/fs-utils.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { mkdirSafe, existsSafe } from '@automaker/utils';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
describe("fs-utils.ts", () => {
|
||||
describe('fs-utils.ts', () => {
|
||||
let testDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -22,43 +22,41 @@ describe("fs-utils.ts", () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe("mkdirSafe", () => {
|
||||
it("should create a new directory", async () => {
|
||||
const newDir = path.join(testDir, "new-directory");
|
||||
describe('mkdirSafe', () => {
|
||||
it('should create a new directory', async () => {
|
||||
const newDir = path.join(testDir, 'new-directory');
|
||||
await mkdirSafe(newDir);
|
||||
|
||||
const stats = await fs.stat(newDir);
|
||||
expect(stats.isDirectory()).toBe(true);
|
||||
});
|
||||
|
||||
it("should succeed if directory already exists", async () => {
|
||||
const existingDir = path.join(testDir, "existing");
|
||||
it('should succeed if directory already exists', async () => {
|
||||
const existingDir = path.join(testDir, 'existing');
|
||||
await fs.mkdir(existingDir);
|
||||
|
||||
// Should not throw
|
||||
await expect(mkdirSafe(existingDir)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should create nested directories", async () => {
|
||||
const nestedDir = path.join(testDir, "a", "b", "c");
|
||||
it('should create nested directories', async () => {
|
||||
const nestedDir = path.join(testDir, 'a', 'b', 'c');
|
||||
await mkdirSafe(nestedDir);
|
||||
|
||||
const stats = await fs.stat(nestedDir);
|
||||
expect(stats.isDirectory()).toBe(true);
|
||||
});
|
||||
|
||||
it("should throw if path exists as a file", async () => {
|
||||
const filePath = path.join(testDir, "file.txt");
|
||||
await fs.writeFile(filePath, "content");
|
||||
it('should throw if path exists as a file', async () => {
|
||||
const filePath = path.join(testDir, 'file.txt');
|
||||
await fs.writeFile(filePath, 'content');
|
||||
|
||||
await expect(mkdirSafe(filePath)).rejects.toThrow(
|
||||
"Path exists and is not a directory"
|
||||
);
|
||||
await expect(mkdirSafe(filePath)).rejects.toThrow('Path exists and is not a directory');
|
||||
});
|
||||
|
||||
it("should succeed if path is a symlink to a directory", async () => {
|
||||
const realDir = path.join(testDir, "real-dir");
|
||||
const symlinkPath = path.join(testDir, "link-to-dir");
|
||||
it('should succeed if path is a symlink to a directory', async () => {
|
||||
const realDir = path.join(testDir, 'real-dir');
|
||||
const symlinkPath = path.join(testDir, 'link-to-dir');
|
||||
await fs.mkdir(realDir);
|
||||
await fs.symlink(realDir, symlinkPath);
|
||||
|
||||
@@ -66,12 +64,12 @@ describe("fs-utils.ts", () => {
|
||||
await expect(mkdirSafe(symlinkPath)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should handle ELOOP error gracefully when checking path", async () => {
|
||||
it('should handle ELOOP error gracefully when checking path', async () => {
|
||||
// Mock lstat to throw ELOOP error
|
||||
const originalLstat = fs.lstat;
|
||||
const mkdirSafePath = path.join(testDir, "eloop-path");
|
||||
|
||||
vi.spyOn(fs, "lstat").mockRejectedValueOnce({ code: "ELOOP" });
|
||||
const mkdirSafePath = path.join(testDir, 'eloop-path');
|
||||
|
||||
vi.spyOn(fs, 'lstat').mockRejectedValueOnce({ code: 'ELOOP' });
|
||||
|
||||
// Should not throw, should return gracefully
|
||||
await expect(mkdirSafe(mkdirSafePath)).resolves.toBeUndefined();
|
||||
@@ -79,13 +77,13 @@ describe("fs-utils.ts", () => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should handle EEXIST error gracefully when creating directory", async () => {
|
||||
const newDir = path.join(testDir, "race-condition-dir");
|
||||
|
||||
it('should handle EEXIST error gracefully when creating directory', async () => {
|
||||
const newDir = path.join(testDir, 'race-condition-dir');
|
||||
|
||||
// Mock lstat to return ENOENT (path doesn't exist)
|
||||
// Then mock mkdir to throw EEXIST (race condition)
|
||||
vi.spyOn(fs, "lstat").mockRejectedValueOnce({ code: "ENOENT" });
|
||||
vi.spyOn(fs, "mkdir").mockRejectedValueOnce({ code: "EEXIST" });
|
||||
vi.spyOn(fs, 'lstat').mockRejectedValueOnce({ code: 'ENOENT' });
|
||||
vi.spyOn(fs, 'mkdir').mockRejectedValueOnce({ code: 'EEXIST' });
|
||||
|
||||
// Should not throw, should return gracefully
|
||||
await expect(mkdirSafe(newDir)).resolves.toBeUndefined();
|
||||
@@ -93,13 +91,13 @@ describe("fs-utils.ts", () => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should handle ELOOP error gracefully when creating directory", async () => {
|
||||
const newDir = path.join(testDir, "eloop-create-dir");
|
||||
|
||||
it('should handle ELOOP error gracefully when creating directory', async () => {
|
||||
const newDir = path.join(testDir, 'eloop-create-dir');
|
||||
|
||||
// Mock lstat to return ENOENT (path doesn't exist)
|
||||
// Then mock mkdir to throw ELOOP
|
||||
vi.spyOn(fs, "lstat").mockRejectedValueOnce({ code: "ENOENT" });
|
||||
vi.spyOn(fs, "mkdir").mockRejectedValueOnce({ code: "ELOOP" });
|
||||
vi.spyOn(fs, 'lstat').mockRejectedValueOnce({ code: 'ENOENT' });
|
||||
vi.spyOn(fs, 'mkdir').mockRejectedValueOnce({ code: 'ELOOP' });
|
||||
|
||||
// Should not throw, should return gracefully
|
||||
await expect(mkdirSafe(newDir)).resolves.toBeUndefined();
|
||||
@@ -108,34 +106,34 @@ describe("fs-utils.ts", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("existsSafe", () => {
|
||||
it("should return true for existing file", async () => {
|
||||
const filePath = path.join(testDir, "test-file.txt");
|
||||
await fs.writeFile(filePath, "content");
|
||||
describe('existsSafe', () => {
|
||||
it('should return true for existing file', async () => {
|
||||
const filePath = path.join(testDir, 'test-file.txt');
|
||||
await fs.writeFile(filePath, 'content');
|
||||
|
||||
const exists = await existsSafe(filePath);
|
||||
expect(exists).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for existing directory", async () => {
|
||||
const dirPath = path.join(testDir, "test-dir");
|
||||
it('should return true for existing directory', async () => {
|
||||
const dirPath = path.join(testDir, 'test-dir');
|
||||
await fs.mkdir(dirPath);
|
||||
|
||||
const exists = await existsSafe(dirPath);
|
||||
expect(exists).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for non-existent path", async () => {
|
||||
const nonExistent = path.join(testDir, "does-not-exist");
|
||||
it('should return false for non-existent path', async () => {
|
||||
const nonExistent = path.join(testDir, 'does-not-exist');
|
||||
|
||||
const exists = await existsSafe(nonExistent);
|
||||
expect(exists).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for symlink", async () => {
|
||||
const realFile = path.join(testDir, "real-file.txt");
|
||||
const symlinkPath = path.join(testDir, "link-to-file");
|
||||
await fs.writeFile(realFile, "content");
|
||||
it('should return true for symlink', async () => {
|
||||
const realFile = path.join(testDir, 'real-file.txt');
|
||||
const symlinkPath = path.join(testDir, 'link-to-file');
|
||||
await fs.writeFile(realFile, 'content');
|
||||
await fs.symlink(realFile, symlinkPath);
|
||||
|
||||
const exists = await existsSafe(symlinkPath);
|
||||
@@ -143,29 +141,29 @@ describe("fs-utils.ts", () => {
|
||||
});
|
||||
|
||||
it("should return true for broken symlink (symlink exists even if target doesn't)", async () => {
|
||||
const symlinkPath = path.join(testDir, "broken-link");
|
||||
const nonExistent = path.join(testDir, "non-existent-target");
|
||||
const symlinkPath = path.join(testDir, 'broken-link');
|
||||
const nonExistent = path.join(testDir, 'non-existent-target');
|
||||
await fs.symlink(nonExistent, symlinkPath);
|
||||
|
||||
const exists = await existsSafe(symlinkPath);
|
||||
expect(exists).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for ELOOP error (symlink loop)", async () => {
|
||||
it('should return true for ELOOP error (symlink loop)', async () => {
|
||||
// Mock lstat to throw ELOOP error
|
||||
vi.spyOn(fs, "lstat").mockRejectedValueOnce({ code: "ELOOP" });
|
||||
vi.spyOn(fs, 'lstat').mockRejectedValueOnce({ code: 'ELOOP' });
|
||||
|
||||
const exists = await existsSafe("/some/path/with/loop");
|
||||
const exists = await existsSafe('/some/path/with/loop');
|
||||
expect(exists).toBe(true);
|
||||
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should throw for other errors", async () => {
|
||||
it('should throw for other errors', async () => {
|
||||
// Mock lstat to throw a non-ENOENT, non-ELOOP error
|
||||
vi.spyOn(fs, "lstat").mockRejectedValueOnce({ code: "EACCES" });
|
||||
vi.spyOn(fs, 'lstat').mockRejectedValueOnce({ code: 'EACCES' });
|
||||
|
||||
await expect(existsSafe("/some/path")).rejects.toMatchObject({ code: "EACCES" });
|
||||
await expect(existsSafe('/some/path')).rejects.toMatchObject({ code: 'EACCES' });
|
||||
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user