刘光辉
12 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// @vitest-environment node
 
import type { ConfigEnv, UserConfig, UserConfigFn } from 'vite';
 
import { spawnSync } from 'node:child_process';
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import process from 'node:process';
 
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
 
import config from '../vite.config';
 
const developmentEnvironmentNames = [
  'ONLYOFFICE_DOCS_URL',
  'ONLYOFFICE_PLUGIN_DEV_HOST',
  'ONLYOFFICE_PLUGIN_DEV_PORT',
  'ONLYOFFICE_PLUGIN_HMR_CLIENT_PORT',
  'ONLYOFFICE_PLUGIN_HMR_HOST',
  'ONLYOFFICE_PLUGIN_HMR_PROTOCOL',
  'ONLYOFFICE_PLUGIN_PUBLIC_HOST',
] as const;
const originalEnvironment = Object.fromEntries(developmentEnvironmentNames.map((name) => [name, process.env[name]]));
const pluginRoot = process.cwd();
const repositoryRoot = resolve(pluginRoot, '../../..');
const testEnvironmentPath = resolve(pluginRoot, '.env.task4-test.local');
 
function resolveConfig(command: ConfigEnv['command'], mode = command === 'serve' ? 'development' : 'production'): UserConfig {
  expect(config).toBeTypeOf('function');
  const resolved = (config as UserConfigFn)({
    command,
    isPreview: false,
    isSsrBuild: false,
    mode,
  });
  if (resolved instanceof Promise) throw new Error('测试要求 Vite 配置同步解析');
  return resolved;
}
 
describe('vite config', () => {
  beforeEach(() => {
    for (const name of developmentEnvironmentNames) delete process.env[name];
  });
 
  afterEach(() => {
    try {
      unlinkSync(testEnvironmentPath);
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
    }
    for (const name of developmentEnvironmentNames) {
      const value = originalEnvironment[name];
      if (value === undefined) delete process.env[name];
      else process.env[name] = value;
    }
  });
 
  it('从 mode local env 加载 ONLYOFFICE 配置且 shell 环境优先', () => {
    writeFileSync(
      testEnvironmentPath,
      [
        'ONLYOFFICE_PLUGIN_DEV_HOST=127.0.0.1',
        'ONLYOFFICE_PLUGIN_DEV_PORT=4311',
        'ONLYOFFICE_PLUGIN_PUBLIC_HOST=env-file.example.com',
        'ONLYOFFICE_PLUGIN_HMR_HOST=hmr.env-file.example.com',
        'UNRELATED_BROWSER_SECRET=must-not-be-injected',
      ].join('\n'),
    );
    process.env.ONLYOFFICE_PLUGIN_DEV_PORT = '4312';
 
    const serveConfig = resolveConfig('serve', 'task4-test');
 
    expect(serveConfig.server).toMatchObject({
      hmr: { clientPort: 4312, host: 'hmr.env-file.example.com' },
      host: '127.0.0.1',
      port: 4312,
    });
    expect(serveConfig.define).toBeUndefined();
  });
 
  it('serve 使用固定开发 release、端口和浏览器可访问的 HMR 配置', () => {
    const serveConfig = resolveConfig('serve');
 
    expect(serveConfig.base).toBe('/onlyoffice-plugins/0.1.0-dev/eln-template-filler/');
    expect(serveConfig.server).toMatchObject({
      hmr: { clientPort: 4173, host: 'localhost', protocol: 'ws' },
      host: '0.0.0.0',
      port: 4173,
      strictPort: true,
    });
    expect(serveConfig.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'onlyoffice-development' })]));
  });
 
  it('build 保持正式相对资源路径、生产资产和入口语义', () => {
    const buildConfig = resolveConfig('build');
 
    expect(buildConfig.base).toBe('./');
    expect(buildConfig.server).toBeUndefined();
    expect(buildConfig.build?.sourcemap).toBe(false);
    expect(buildConfig.build?.rollupOptions?.input).toBe(resolve(process.cwd(), 'index.html'));
    expect(buildConfig.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'eln-production-assets' })]));
  });
 
  it('包级 dev 脚本由根 turbo-run 选择器发现', () => {
    const packageJson = JSON.parse(readFileSync(resolve(process.cwd(), 'package.json'), 'utf8')) as {
      scripts: Record<string, string>;
      version: string;
    };
    const turboJson = JSON.parse(readFileSync(resolve(process.cwd(), '../../../turbo.json'), 'utf8')) as {
      tasks: Record<string, Record<string, unknown>>;
    };
 
    expect(packageJson.version).toBe('0.1.0');
    expect(packageJson.scripts.dev).toBe('vite');
    expect(turboJson.tasks.dev).toMatchObject({ cache: false, persistent: true });
 
    const discovery = spawnSync(
      'pnpm',
      [
        'exec',
        'node',
        '--input-type=module',
        '-e',
        "import { getPackages } from '@vben/node-utils'; const { packages } = await getPackages(); console.log(packages.filter((pkg) => pkg.packageJson.scripts?.dev).map((pkg) => pkg.packageJson.name).includes('onlyoffice-eln-template-filler'));",
      ],
      { cwd: resolve(repositoryRoot, 'scripts/turbo-run'), encoding: 'utf8' },
    );
    expect(discovery.status, discovery.stderr).toBe(0);
    expect(discovery.stdout.trim()).toBe('true');
  });
});