File size: 2,121 Bytes
33e51e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { describe, expect, it } from 'vitest';
import {
  inferArtifactMime,
  normalizeArtifactFiles,
  normalizeArtifactPath,
} from './artifact-workspace';

describe('artifact workspace paths', () => {
  it('normalizes relative paths and infers browser MIME types', () => {
    expect(normalizeArtifactPath('./src/components/chart.js')).toBe('src/components/chart.js');
    expect(inferArtifactMime('styles/app.css')).toBe('text/css; charset=utf-8');
    expect(inferArtifactMime('assets/logo.svg')).toBe('image/svg+xml; charset=utf-8');
  });

  it.each([
    '/index.html',
    '../index.html',
    'src/../../index.html',
    'src\\main.js',
    'src//main.js',
    '.bonsai-workspace.json',
  ])('rejects paths that escape or collide with the workspace: %s', (path) => {
    expect(() => normalizeArtifactPath(path)).toThrow();
  });
});

describe('artifact workspace files', () => {
  it('builds one bounded manifest with a real HTML entry file', () => {
    const deployment = normalizeArtifactFiles([
      { path: 'index.html', content: '<link rel="stylesheet" href="./styles/app.css">' },
      { path: 'styles/app.css', content: 'body { color: green; }' },
      { path: 'src/main.js', content: 'console.log("ready")' },
    ]);
    expect(deployment.entryPath).toBe('index.html');
    expect(deployment.files.map((file) => file.path)).toEqual([
      'index.html',
      'styles/app.css',
      'src/main.js',
    ]);
    expect(deployment.totalBytes).toBeGreaterThan(0);
  });

  it('rejects duplicate, missing-entry, oversized, and non-HTML-entry deployments', () => {
    expect(() => normalizeArtifactFiles([
      { path: 'index.html', content: 'a' },
      { path: './index.html', content: 'b' },
    ])).toThrow('duplicated');
    expect(() => normalizeArtifactFiles([{ path: 'main.js', content: 'x' }])).toThrow('entry file is missing');
    expect(() => normalizeArtifactFiles([
      { path: 'index.html', content: 'x'.repeat(512 * 1024 + 1) },
    ])).toThrow('512 KiB');
    expect(() => normalizeArtifactFiles([{ path: 'main.js', content: 'x' }], 'main.js')).toThrow('must be HTML');
  });
});