|
1 |
| -import {bundleExtension, bundleThemeExtension} from './bundle.js' |
| 1 | +import {bundleExtension, bundleThemeExtension, copyFilesForExtension} from './bundle.js' |
2 | 2 | import {testApp, testUIExtension} from '../../models/app/app.test-data.js'
|
3 | 3 | import {loadLocalExtensionsSpecifications} from '../../models/extensions/load-specifications.js'
|
4 | 4 | import {ExtensionInstance} from '../../models/extensions/extension-instance.js'
|
@@ -277,3 +277,118 @@ describe('bundleExtension()', () => {
|
277 | 277 | })
|
278 | 278 | })
|
279 | 279 | })
|
| 280 | + |
| 281 | +describe('copyFilesForExtension()', () => { |
| 282 | + test('copies files matching include patterns to output directory', async () => { |
| 283 | + await inTemporaryDirectory(async (tmpDir) => { |
| 284 | + // Given |
| 285 | + const extensionDir = joinPath(tmpDir, 'extension') |
| 286 | + const outputDir = joinPath(tmpDir, 'output') |
| 287 | + |
| 288 | + // Create extension directory structure |
| 289 | + await mkdir(joinPath(extensionDir, 'src')) |
| 290 | + await mkdir(joinPath(extensionDir, 'assets')) |
| 291 | + await mkdir(joinPath(extensionDir, 'assets', 'images')) |
| 292 | + |
| 293 | + // Create test files |
| 294 | + touchFileSync(joinPath(extensionDir, 'config.json')) |
| 295 | + touchFileSync(joinPath(extensionDir, 'src', 'index.js')) |
| 296 | + touchFileSync(joinPath(extensionDir, 'src', 'styles.css')) |
| 297 | + touchFileSync(joinPath(extensionDir, 'assets', 'logo.png')) |
| 298 | + touchFileSync(joinPath(extensionDir, 'assets', 'images', 'banner.jpg')) |
| 299 | + |
| 300 | + const extension = { |
| 301 | + directory: extensionDir, |
| 302 | + outputPath: outputDir, |
| 303 | + localIdentifier: 'test-extension', |
| 304 | + } as ExtensionInstance |
| 305 | + |
| 306 | + const stdout = {write: vi.fn()} |
| 307 | + const stderr = {write: vi.fn()} |
| 308 | + const options = {stdout, stderr} as any |
| 309 | + |
| 310 | + // When - copy all .json and .png files |
| 311 | + await copyFilesForExtension(extension, options, ['*.json', '*.png'], []) |
| 312 | + |
| 313 | + // Then |
| 314 | + const copiedFiles = await glob(joinPath(outputDir, '**/*')) |
| 315 | + const relativeFiles = copiedFiles.map((file) => file.replace(`${outputDir}/`, '')) |
| 316 | + |
| 317 | + expect(relativeFiles.sort()).toEqual(['assets/logo.png', 'config.json']) |
| 318 | + expect(stdout.write).toHaveBeenCalledWith('Copying files for extension test-extension...') |
| 319 | + expect(stdout.write).toHaveBeenCalledWith('test-extension successfully built') |
| 320 | + }) |
| 321 | + }) |
| 322 | + |
| 323 | + test('respects ignore patterns when copying files', async () => { |
| 324 | + await inTemporaryDirectory(async (tmpDir) => { |
| 325 | + // Given |
| 326 | + const extensionDir = joinPath(tmpDir, 'extension') |
| 327 | + const outputDir = joinPath(tmpDir, 'output') |
| 328 | + |
| 329 | + // Create extension directory structure |
| 330 | + await mkdir(joinPath(extensionDir, 'dist')) |
| 331 | + await mkdir(joinPath(extensionDir, 'src')) |
| 332 | + await mkdir(joinPath(extensionDir, 'test')) |
| 333 | + |
| 334 | + // Create test files |
| 335 | + touchFileSync(joinPath(extensionDir, 'README.md')) |
| 336 | + touchFileSync(joinPath(extensionDir, 'package.json')) |
| 337 | + touchFileSync(joinPath(extensionDir, 'dist', 'bundle.js')) |
| 338 | + touchFileSync(joinPath(extensionDir, 'src', 'index.js')) |
| 339 | + touchFileSync(joinPath(extensionDir, 'test', 'test.js')) |
| 340 | + touchFileSync(joinPath(extensionDir, 'test', 'README.md')) |
| 341 | + |
| 342 | + const extension = { |
| 343 | + directory: extensionDir, |
| 344 | + outputPath: outputDir, |
| 345 | + localIdentifier: 'test-extension', |
| 346 | + } as ExtensionInstance |
| 347 | + |
| 348 | + const stdout = {write: vi.fn()} |
| 349 | + const stderr = {write: vi.fn()} |
| 350 | + const options = {stdout, stderr} as any |
| 351 | + |
| 352 | + // When - copy all files but ignore test directory and dist files |
| 353 | + await copyFilesForExtension(extension, options, ['*'], ['test/**', 'dist/**']) |
| 354 | + |
| 355 | + // Then |
| 356 | + const copiedFiles = await glob(joinPath(outputDir, '**/*')) |
| 357 | + const relativeFiles = copiedFiles.map((file) => file.replace(`${outputDir}/`, '')) |
| 358 | + |
| 359 | + expect(relativeFiles.sort()).toEqual(['README.md', 'package.json', 'src/index.js']) |
| 360 | + // Verify ignored files were not copied |
| 361 | + expect(relativeFiles).not.toContain('test/test.js') |
| 362 | + expect(relativeFiles).not.toContain('test/README.md') |
| 363 | + expect(relativeFiles).not.toContain('dist/bundle.js') |
| 364 | + }) |
| 365 | + }) |
| 366 | + |
| 367 | + test('handles empty include patterns gracefully', async () => { |
| 368 | + await inTemporaryDirectory(async (tmpDir) => { |
| 369 | + // Given |
| 370 | + const extensionDir = joinPath(tmpDir, 'extension') |
| 371 | + const outputDir = joinPath(tmpDir, 'output') |
| 372 | + |
| 373 | + await mkdir(extensionDir) |
| 374 | + touchFileSync(joinPath(extensionDir, 'file.txt')) |
| 375 | + |
| 376 | + const extension = { |
| 377 | + directory: extensionDir, |
| 378 | + outputPath: outputDir, |
| 379 | + localIdentifier: 'test-extension', |
| 380 | + } as ExtensionInstance |
| 381 | + |
| 382 | + const stdout = {write: vi.fn()} |
| 383 | + const stderr = {write: vi.fn()} |
| 384 | + const options = {stdout, stderr} as any |
| 385 | + |
| 386 | + // When - no include patterns provided |
| 387 | + await copyFilesForExtension(extension, options, [], []) |
| 388 | + |
| 389 | + // Then - no files should be copied |
| 390 | + const copiedFiles = await glob(joinPath(outputDir, '**/*')) |
| 391 | + expect(copiedFiles).toEqual([]) |
| 392 | + }) |
| 393 | + }) |
| 394 | +}) |
0 commit comments