diff --git a/VideoDownloader.App/AppPaths.cs b/VideoDownloader.App/AppPaths.cs new file mode 100644 index 0000000..aaf14f1 --- /dev/null +++ b/VideoDownloader.App/AppPaths.cs @@ -0,0 +1,14 @@ +namespace VideoDownloader.App; + +/// +/// 앱 데이터 디렉터리 결정. 기본 %AppData%/VideoDownloader. +/// 환경변수 VD_DATA_DIR 로 오버라이드 — E2E 테스트가 실사용자 프로필/설정/세션과 +/// 격리된 임시 디렉터리에서 실행되도록 한다(결정적 테스트를 위한 공식 후크). +/// +public static class AppPaths +{ + public static string DataDir => + Environment.GetEnvironmentVariable("VD_DATA_DIR") is { Length: > 0 } env + ? env + : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); +} diff --git a/VideoDownloader.App/Browser/BrowserStore.cs b/VideoDownloader.App/Browser/BrowserStore.cs index 37bc140..159dfd2 100644 --- a/VideoDownloader.App/Browser/BrowserStore.cs +++ b/VideoDownloader.App/Browser/BrowserStore.cs @@ -7,8 +7,7 @@ namespace VideoDownloader.App.Browser; /// 손상 파일은 백업 후 빈 목록을 반환(다음 저장이 원본을 덮어쓰는 데이터 손실 방지). public static class BrowserStore { - private static string Dir => Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); + private static string Dir => AppPaths.DataDir; private static string BookmarksPath => Path.Combine(Dir, "bookmarks.json"); private static string HistoryPath => Path.Combine(Dir, "history.json"); private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true }; diff --git a/VideoDownloader.App/Core/ConfigStore.cs b/VideoDownloader.App/Core/ConfigStore.cs index f5f0ec3..d9ad23b 100644 --- a/VideoDownloader.App/Core/ConfigStore.cs +++ b/VideoDownloader.App/Core/ConfigStore.cs @@ -6,8 +6,7 @@ namespace VideoDownloader.App.Core; /// %AppData%/VideoDownloader/config.json 으로 설정 영속화 public static class ConfigStore { - private static string Dir => Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); + private static string Dir => AppPaths.DataDir; private static string FilePath => Path.Combine(Dir, "config.json"); private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true }; diff --git a/VideoDownloader.App/MainWindow.xaml.cs b/VideoDownloader.App/MainWindow.xaml.cs index 2c0c9bf..1f302d0 100644 --- a/VideoDownloader.App/MainWindow.xaml.cs +++ b/VideoDownloader.App/MainWindow.xaml.cs @@ -145,9 +145,8 @@ public partial class MainWindow : Window [DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attribute, ref int pvAttribute, int cbAttribute); - /// WebView2 영속 프로필 경로. 쿠키·세션·localStorage·캐시가 여기 보존되어 앱/빌드 재시작에도 유지. - internal static string AppDataDir => Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "VideoDownloader"); + /// 앱 데이터 디렉터리(AppPaths.DataDir — VD_DATA_DIR 오버라이드 지원). + internal static string AppDataDir => AppPaths.DataDir; internal static string ProfileFolder => Path.Combine(AppDataDir, "webview"); diff --git a/VideoDownloader.Tests/E2E/MainWindowSmokeE2ETests.cs b/VideoDownloader.Tests/E2E/MainWindowSmokeE2ETests.cs index 324ab17..1a31466 100644 --- a/VideoDownloader.Tests/E2E/MainWindowSmokeE2ETests.cs +++ b/VideoDownloader.Tests/E2E/MainWindowSmokeE2ETests.cs @@ -14,6 +14,11 @@ public class MainWindowSmokeE2ETests [Fact] public async Task MainWindow_기동_탐색_탭전환_닫기_복원_검색바_전체화면_E2E() { + // VD_DATA_DIR 격리: 실사용자 설정/세션/프로필과 분리된 임시 데이터 디렉터리 (결정적 테스트) + var dataDir = Path.Combine(Path.GetTempPath(), $"vd_e2e_data_{Guid.NewGuid():N}"); + Environment.SetEnvironmentVariable("VD_DATA_DIR", dataDir); + try + { using var sta = StaDispatcher.Start(); WpfTestApp.Ensure(sta.Dispatcher); var ok = await sta.InvokeAsync(async () => @@ -77,6 +82,12 @@ public class MainWindowSmokeE2ETests Assert.True(ok.findCollapsed, "검색 바 미닫힘"); Assert.True(ok.toolbarHidden, "전체화면에서 크롬 미숨김"); Assert.True(ok.toolbarBack, "전체화면 복원 실패"); + } + finally + { + Environment.SetEnvironmentVariable("VD_DATA_DIR", null); + try { Directory.Delete(dataDir, true); } catch { } + } } private static Task WaitUntilNavCompleted(Microsoft.Web.WebView2.Core.CoreWebView2 cv)