ipc-integration.test.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /**
  2. * @fileoverview IPC Integration Tests
  3. * @author GrabZilla Development Team
  4. * @version 2.1.0
  5. * @since 2024-01-01
  6. */
  7. import { describe, it, expect, beforeEach, vi } from 'vitest';
  8. describe('IPC Integration', () => {
  9. let mockElectronAPI;
  10. beforeEach(() => {
  11. // Create fresh mock for each test
  12. mockElectronAPI = {
  13. selectSaveDirectory: vi.fn(),
  14. selectCookieFile: vi.fn(),
  15. checkBinaryVersions: vi.fn(),
  16. getVideoMetadata: vi.fn(),
  17. downloadVideo: vi.fn(),
  18. onDownloadProgress: vi.fn(),
  19. removeDownloadProgressListener: vi.fn(),
  20. getAppVersion: vi.fn(() => '2.1.0'),
  21. getPlatform: vi.fn(() => 'darwin')
  22. };
  23. // Set up window.electronAPI for each test
  24. global.window = global.window || {};
  25. global.window.electronAPI = mockElectronAPI;
  26. });
  27. describe('File System Operations', () => {
  28. it('should handle save directory selection', async () => {
  29. const testPath = '/Users/test/Downloads';
  30. mockElectronAPI.selectSaveDirectory.mockResolvedValue(testPath);
  31. const result = await window.electronAPI.selectSaveDirectory();
  32. expect(mockElectronAPI.selectSaveDirectory).toHaveBeenCalled();
  33. expect(result).toBe(testPath);
  34. });
  35. it('should handle cookie file selection', async () => {
  36. const testPath = '/Users/test/cookies.txt';
  37. mockElectronAPI.selectCookieFile.mockResolvedValue(testPath);
  38. const result = await window.electronAPI.selectCookieFile();
  39. expect(mockElectronAPI.selectCookieFile).toHaveBeenCalled();
  40. expect(result).toBe(testPath);
  41. });
  42. it('should handle cancelled file selection', async () => {
  43. mockElectronAPI.selectSaveDirectory.mockResolvedValue(null);
  44. const result = await window.electronAPI.selectSaveDirectory();
  45. expect(result).toBeNull();
  46. });
  47. });
  48. describe('Binary Management', () => {
  49. it('should check binary versions', async () => {
  50. const mockVersions = {
  51. ytDlp: { available: true, version: '2023.12.30' },
  52. ffmpeg: { available: true, version: '6.0' }
  53. };
  54. mockElectronAPI.checkBinaryVersions.mockResolvedValue(mockVersions);
  55. const result = await window.electronAPI.checkBinaryVersions();
  56. expect(mockElectronAPI.checkBinaryVersions).toHaveBeenCalled();
  57. expect(result).toEqual(mockVersions);
  58. });
  59. it('should handle missing binaries', async () => {
  60. const mockVersions = {
  61. ytDlp: { available: false },
  62. ffmpeg: { available: false }
  63. };
  64. mockElectronAPI.checkBinaryVersions.mockResolvedValue(mockVersions);
  65. const result = await window.electronAPI.checkBinaryVersions();
  66. expect(result.ytDlp.available).toBe(false);
  67. expect(result.ffmpeg.available).toBe(false);
  68. });
  69. });
  70. describe('Video Operations', () => {
  71. it('should fetch video metadata', async () => {
  72. const mockMetadata = {
  73. title: 'Test Video',
  74. duration: '5:30',
  75. thumbnail: 'https://example.com/thumb.jpg',
  76. uploader: 'Test Channel'
  77. };
  78. mockElectronAPI.getVideoMetadata.mockResolvedValue(mockMetadata);
  79. const result = await window.electronAPI.getVideoMetadata('https://youtube.com/watch?v=test');
  80. expect(mockElectronAPI.getVideoMetadata).toHaveBeenCalledWith('https://youtube.com/watch?v=test');
  81. expect(result).toEqual(mockMetadata);
  82. });
  83. it('should handle video download', async () => {
  84. const downloadOptions = {
  85. url: 'https://youtube.com/watch?v=test',
  86. quality: '720p',
  87. format: 'mp4',
  88. savePath: '/Users/test/Downloads',
  89. cookieFile: null
  90. };
  91. const mockResult = { success: true, filename: 'test-video.mp4' };
  92. mockElectronAPI.downloadVideo.mockResolvedValue(mockResult);
  93. const result = await window.electronAPI.downloadVideo(downloadOptions);
  94. expect(mockElectronAPI.downloadVideo).toHaveBeenCalledWith(downloadOptions);
  95. expect(result).toEqual(mockResult);
  96. });
  97. it('should handle download progress events', () => {
  98. const mockCallback = vi.fn();
  99. window.electronAPI.onDownloadProgress(mockCallback);
  100. expect(mockElectronAPI.onDownloadProgress).toHaveBeenCalledWith(mockCallback);
  101. });
  102. });
  103. describe('App Information', () => {
  104. it('should get app version', () => {
  105. const version = window.electronAPI.getAppVersion();
  106. expect(mockElectronAPI.getAppVersion).toHaveBeenCalled();
  107. expect(version).toBe('2.1.0');
  108. });
  109. it('should get platform information', () => {
  110. const platform = window.electronAPI.getPlatform();
  111. expect(mockElectronAPI.getPlatform).toHaveBeenCalled();
  112. expect(platform).toBe('darwin');
  113. });
  114. });
  115. describe('Error Handling', () => {
  116. it('should handle IPC errors gracefully', async () => {
  117. const error = new Error('IPC communication failed');
  118. mockElectronAPI.selectSaveDirectory.mockRejectedValue(error);
  119. await expect(window.electronAPI.selectSaveDirectory()).rejects.toThrow('IPC communication failed');
  120. });
  121. it('should handle binary check errors', async () => {
  122. const error = new Error('Binary check failed');
  123. mockElectronAPI.checkBinaryVersions.mockRejectedValue(error);
  124. await expect(window.electronAPI.checkBinaryVersions()).rejects.toThrow('Binary check failed');
  125. });
  126. it('should handle metadata fetch errors', async () => {
  127. const error = new Error('Failed to fetch metadata');
  128. mockElectronAPI.getVideoMetadata.mockRejectedValue(error);
  129. await expect(window.electronAPI.getVideoMetadata('invalid-url')).rejects.toThrow('Failed to fetch metadata');
  130. });
  131. });
  132. });
  133. describe('IPC Security', () => {
  134. it('should not expose dangerous Node.js APIs', () => {
  135. // Ensure that dangerous APIs are not exposed through the context bridge
  136. expect(window.require).toBeUndefined();
  137. // Note: process is available in test environment but should not be in real Electron renderer
  138. expect(window.__dirname).toBeUndefined();
  139. expect(window.__filename).toBeUndefined();
  140. });
  141. it('should only expose safe, specific methods', () => {
  142. const expectedMethods = [
  143. 'selectSaveDirectory',
  144. 'selectCookieFile',
  145. 'checkBinaryVersions',
  146. 'getVideoMetadata',
  147. 'downloadVideo',
  148. 'onDownloadProgress',
  149. 'removeDownloadProgressListener',
  150. 'getAppVersion',
  151. 'getPlatform'
  152. ];
  153. expectedMethods.forEach(method => {
  154. expect(typeof window.electronAPI[method]).toBe('function');
  155. });
  156. });
  157. it('should validate input parameters', async () => {
  158. // Test that the IPC layer validates inputs
  159. const invalidOptions = {
  160. url: '', // Invalid empty URL
  161. quality: 'invalid',
  162. format: 'unknown',
  163. savePath: null
  164. };
  165. // The main process should validate these and reject
  166. global.window.electronAPI.downloadVideo.mockRejectedValue(new Error('Invalid parameters'));
  167. await expect(window.electronAPI.downloadVideo(invalidOptions)).rejects.toThrow('Invalid parameters');
  168. });
  169. });