// @vitest-environment node
|
|
import type { Server as HttpServer } from 'node:http';
|
|
import { unlinkSync, writeFileSync } from 'node:fs';
|
import { createServer as createHttpServer } from 'node:http';
|
import { resolve } from 'node:path';
|
import process from 'node:process';
|
import { fileURLToPath } from 'node:url';
|
|
import { createServer, loadConfigFromFile } from 'vite';
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
const pluginRoot = fileURLToPath(new URL('../..', import.meta.url));
|
const repositoryRoot = resolve(pluginRoot, '../../..');
|
const configFile = resolve(pluginRoot, 'vite.config.ts');
|
const environmentNames = [
|
'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(environmentNames.map((name) => [name, process.env[name]]));
|
const testEnvironmentPath = resolve(pluginRoot, '.env.task4-integration.local');
|
|
async function reservePort(): Promise<number> {
|
const server = createHttpServer();
|
await new Promise<void>((resolveListen, reject) => {
|
server.once('error', reject);
|
server.listen(0, '127.0.0.1', () => resolveListen());
|
});
|
const address = server.address();
|
if (!address || typeof address === 'string') throw new Error('未获得测试端口');
|
const port = address.port;
|
await close(server);
|
return port;
|
}
|
|
async function close(server: HttpServer): Promise<void> {
|
await new Promise<void>((resolveClose, reject) => server.close((error) => (error ? reject(error) : resolveClose())));
|
}
|
|
describe('真实 Vite config 集成', () => {
|
afterEach(() => {
|
process.chdir(pluginRoot);
|
try {
|
unlinkSync(testEnvironmentPath);
|
} catch (error) {
|
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
}
|
for (const name of environmentNames) {
|
const value = originalEnvironment[name];
|
if (value === undefined) delete process.env[name];
|
else process.env[name] = value;
|
}
|
});
|
|
it('从仓库根解析 build config 时仍使用插件根和正式构建语义', async () => {
|
process.chdir(repositoryRoot);
|
|
const loaded = await loadConfigFromFile(
|
{ command: 'build', isPreview: false, isSsrBuild: false, mode: 'production' },
|
configFile,
|
repositoryRoot,
|
'silent',
|
);
|
|
expect(loaded?.config?.base).toBe('./');
|
expect(resolve(loaded?.config?.root ?? '')).toBe(resolve(pluginRoot));
|
expect(loaded?.config.build?.rollupOptions?.input).toBe(resolve(pluginRoot, 'index.html'));
|
expect(loaded?.config.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'eln-production-assets' })]));
|
});
|
|
it('从仓库根用真实 config 启动 serve 并应用 env、base、server 与开发插件', async () => {
|
const port = await reservePort();
|
writeFileSync(
|
testEnvironmentPath,
|
[
|
'ONLYOFFICE_PLUGIN_DEV_HOST=127.0.0.1',
|
`ONLYOFFICE_PLUGIN_DEV_PORT=${port}`,
|
'ONLYOFFICE_PLUGIN_PUBLIC_HOST=localhost',
|
'ONLYOFFICE_PLUGIN_HMR_HOST=localhost',
|
`ONLYOFFICE_PLUGIN_HMR_CLIENT_PORT=${port}`,
|
].join('\n'),
|
);
|
for (const name of environmentNames) delete process.env[name];
|
process.chdir(repositoryRoot);
|
const server = await createServer({ configFile, logLevel: 'silent', mode: 'task4-integration' });
|
|
try {
|
expect(resolve(server.config.root)).toBe(resolve(pluginRoot));
|
expect(server.config.base).toBe('/onlyoffice-plugins/0.1.0-dev/eln-template-filler/');
|
expect(server.config.server).toMatchObject({
|
hmr: { clientPort: port, host: 'localhost', protocol: 'ws' },
|
host: '127.0.0.1',
|
port,
|
strictPort: true,
|
});
|
expect(server.config.plugins).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'onlyoffice-development' })]));
|
|
await server.listen();
|
const response = await fetch(`http://127.0.0.1:${port}${server.config.base}config.json`);
|
expect(response.status).toBe(200);
|
await expect(response.json()).resolves.toMatchObject({ version: '0.1.0' });
|
|
const indexResponse = await fetch(`http://127.0.0.1:${port}${server.config.base}index.html?v=integration`);
|
expect(indexResponse.status).toBe(200);
|
const indexHtml = await indexResponse.text();
|
expect(indexHtml).toContain('src="/onlyoffice-sdk/v1/plugins.js"');
|
expect(indexHtml).toContain('href="/onlyoffice-sdk/v1/plugins.css"');
|
|
for (const resource of ['@vite/client', 'resources/icon.png', 'src/main.ts']) {
|
const resourceResponse = await fetch(`http://127.0.0.1:${port}${server.config.base}${resource}`);
|
expect(resourceResponse.status).toBe(200);
|
await resourceResponse.arrayBuffer();
|
}
|
await server.waitForRequestsIdle();
|
} finally {
|
await server.close();
|
}
|
});
|
});
|