Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/smart-planes-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'arui-scripts': minor
---

добавлена возможность запускать тесты c помощью vitest
34 changes: 34 additions & 0 deletions packages/arui-scripts/docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,40 @@ _package.json_
arui-scripts test
```

### test:vitest
Команда `arui-scripts test:vitest` запускает unit тесты через [Vitest](https://vitest.dev/).

Если в корне проекта есть `vitest.config.ts` (или `.js`, `.mjs`, `.cjs`), то используется он.
Иначе применяется конфигурация arui-scripts.

**Рекомендуемый способ настройки** - создать `vitest.config.js` с `mergeConfig`:

```javascript
import { defineConfig, mergeConfig } from 'vitest/config';
import aruiConfig from 'arui-scripts/vitest';

export default mergeConfig(aruiConfig, defineConfig({
test: {
setupFiles: ['./__tests__/setup.js'],
// другие настройки Vitest
},
}));
```

Базовый конфиг arui-scripts включает:
- API Vitest - используйте явные импорты: `import { describe, it, expect } from 'vitest'` (без глобальных переменных)
- Замену импортов `.css` на пустые модули, ассетов (svg, png, шрифты и др.) - на строку с именем файла
- Маппинг путей из `tsconfig.json` (paths) через [vite-tsconfig-paths](https://www.npmjs.com/package/vite-tsconfig-paths)
- Маски для тестов: `src/**/__tests__/**/*`, `src/**/__test__/**/*`, `src/**/*.{test,spec,tests}.*`

**Обратная совместимость**: при отсутствии `vitest.config.*` по-прежнему читается `jest.setupFiles` из `package.json`.

**Как запустить?**

```bash
arui-scripts test:vitest
```

### docker-build
Собирает клиентский и серверный код в production-режиме, создает docker-образ и пушит его в docker-репозиторий.

Expand Down
7 changes: 7 additions & 0 deletions packages/arui-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"version": "21.0.4",
"main": "./build/index.js",
"typings": "./build/index.d.ts",
"exports": {
".": "./build/index.js",
"./vitest": "./build/configs/vitest/config.js"
},
"license": "MPL-2.0",
"repository": {
"type": "git",
Expand Down Expand Up @@ -114,6 +118,8 @@
"ts-jest": "29.1.0",
"ts-loader": "9.4.4",
"ts-node": "10.9.2",
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.1.5",
"webpack-bundle-analyzer": "4.10.2",
"webpack-deduplication-plugin": "^0.0.8",
"webpack-manifest-plugin": "3.2.0",
Expand Down Expand Up @@ -147,6 +153,7 @@
"scripts": {
"build": "sh bin/build.sh",
"test": "jest",
"test:vitest": "vitest",
"lint:scripts": "arui-presets-lint scripts",
"format": "arui-presets-lint format",
"format:check": "arui-presets-lint format:check",
Expand Down
1 change: 1 addition & 0 deletions packages/arui-scripts/src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const commands: Record<string, () => void> = {
'docker-build': () => require('../commands/docker-build'),
'docker-build:compiled': () => require('../commands/docker-build-compiled'),
test: () => require('../commands/test'),
'test:vitest': () => require('../commands/test-vitest'),
'ensure-yarn': () => require('../commands/ensure-yarn'),
'archive-build': () => require('../commands/archive-build'),
'bundle-analyze': () => require('../commands/bundle-analyze'),
Expand Down
2 changes: 1 addition & 1 deletion packages/arui-scripts/src/commands/bundle-analyze/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
import { type WebpackPluginInstance, rspack } from '@rspack/core';
import { rspack, type WebpackPluginInstance } from '@rspack/core';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';

import { configs } from '../../configs/app-configs';
Expand Down
16 changes: 16 additions & 0 deletions packages/arui-scripts/src/commands/test-vitest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { runVitest } from '../util/run-vitest';

process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';

const args = process.argv.slice(3);

runVitest({ args })
.then((code) => {
process.exit(code);
})
.catch((error) => {
console.error('Error running Vitest:', error);
process.exit(1);
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { types } from 'util';
import getPort from 'get-port';

import { type Configuration, rspack, type Stats } from '@rspack/core';
import { RspackDevServer } from '@rspack/dev-server';
import getPort from 'get-port';

import { devServerConfig } from '../../configs/dev-server';
import { printCompilerOutput } from '../start/print-compiler-output';
Expand Down
46 changes: 46 additions & 0 deletions packages/arui-scripts/src/commands/util/run-vitest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';

const VITEST_CONFIG_FILES = [
'vitest.config.js',
'vitest.config.mjs',
'vitest.config.ts',
'vitest.config.cjs',
'vitest.config.mts',
'vitest.config.cts',
];

export function hasProjectVitestConfig(cwd: string): boolean {
return VITEST_CONFIG_FILES.some((file) => fs.existsSync(path.join(cwd, file)));
}

type RunVitestParams = {
args: string[];
cwd?: string;
};

export function runVitest({ args, cwd = process.cwd() }: RunVitestParams): Promise<number> {
const aruiVitestConfigPath = path.resolve(__dirname, '../../configs/vitest/config.js');
const vitestArgs = hasProjectVitestConfig(cwd)
? ['run', ...args]
: ['run', '--config', aruiVitestConfigPath, ...args];

const vitestDir = path.dirname(require.resolve('vitest/package.json'));
const vitestBin = path.join(vitestDir, 'vitest.mjs');

return new Promise((resolve, reject) => {
const vitestProcess = spawn(process.execPath, [vitestBin, ...vitestArgs], {
stdio: 'inherit',
shell: false,
});

vitestProcess.on('close', (code) => {
resolve(code ?? 0);
});

vitestProcess.on('error', (error) => {
reject(error);
});
});
}
5 changes: 5 additions & 0 deletions packages/arui-scripts/src/configs/vitest/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from 'vitest/config';

import { getVitestConfig } from './settings';

export default defineConfig(getVitestConfig());
86 changes: 86 additions & 0 deletions packages/arui-scripts/src/configs/vitest/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import fs from 'fs';
import path from 'path';

import tsconfigPaths from 'vite-tsconfig-paths';

function getSetupFiles(cwd: string): string[] {
const packagePath = path.join(cwd, 'package.json');

let setupFiles: string[] = [];

if (fs.existsSync(packagePath)) {
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')) as {
jest?: { setupFiles?: string[] };
};

setupFiles = pkg.jest?.setupFiles ?? [];
}

return setupFiles.map((file: string) => path.resolve(cwd, file.replace('<rootDir>', '.')));
}

const ASSET_EXTENSIONS = [
'.svg',
'.png',
'.jpg',
'.jpeg',
'.gif',
'.webp',
'.ico',
'.bmp',
'.woff',
'.woff2',
'.ttf',
'.eot',
];

function isAsset(id: string): boolean {
return ASSET_EXTENSIONS.some((extension) => id.endsWith(extension));
}

const staticFilesMockPlugin = {
name: 'arui-scripts-static-files-mock',
enforce: 'pre' as const,
load(id: string) {
if (id.endsWith('.css')) {
return 'export default {}';
}

if (isAsset(id)) {
const filename = path.basename(id);

return `export default ${JSON.stringify(filename)}`;
}

return undefined;
},
};

export function getVitestConfig() {
const cwd = process.cwd();
const setupFiles = getSetupFiles(cwd);

return {
plugins: [tsconfigPaths({ root: cwd }), staticFilesMockPlugin],
test: {
environment: 'jsdom' as const,
setupFiles,
include: [
'src/**/__tests__/**/*.{ts,tsx,js,jsx}',
'src/**/__test__/**/*.{ts,tsx,js,jsx}',
'src/**/*.{test,spec,tests}.{ts,tsx,js,jsx}',
],
exclude: ['**/node_modules/**', '**/build/**', '**/.build/**'],
coverage: {
provider: 'v8' as const,
include: ['src/**/*.{js,jsx,ts,tsx}'],
exclude: ['**/*.d.ts', '**/__tests__/**'],
},
environmentOptions: {
jsdom: {
url: 'http://localhost',
},
},
},
};
}
2 changes: 1 addition & 1 deletion packages/arui-scripts/src/configs/webpack.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin';
import nodeExternals from 'webpack-node-externals';

import { getLocalIdent } from '../commands/util/get-local-ident';
import { ReloadServerPlugin } from '../plugins/reload-server-plugin';
import { WatchMissingNodeModulesPlugin } from '../plugins/watch-missing-node-modules-plugin';

Expand All @@ -23,7 +24,6 @@
import { postcssConfig as postcssConf } from './postcss';
import { serverExternalsExemptions } from './server-externals-exemptions';
import { swcServerConfig } from './swc';
import { getLocalIdent } from '../commands/util/get-local-ident';

const assetsIgnoreBanner = fs.readFileSync(require.resolve('./util/node-assets-ignore'), 'utf8');
const sourceMapSupportBanner = fs.readFileSync(
Expand Down Expand Up @@ -298,7 +298,7 @@
}

function getExternalCodeLoader(mode: 'dev' | 'prod'): RuleSetRule {
const baseLoaderConfig = {

Check warning on line 301 in packages/arui-scripts/src/configs/webpack.server.ts

View workflow job for this annotation

GitHub Actions / lint

File has too many lines (328). Maximum allowed is 300
test: /\.(js|mjs|cjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
resolve: {
Expand Down
1 change: 1 addition & 0 deletions packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"bundle-analyze": "arui-scripts bundle-analyze",
"start": "NODE_ENV=localhost arui-scripts start",
"test": "arui-scripts test",
"test:vitest": "arui-scripts test:vitest",
"lint:styles": "arui-presets-lint styles",
"lint:scripts": "arui-presets-lint scripts",
"format": "arui-presets-lint format",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`app > should be match to snapshot 1`] = `ShallowWrapper {}`;

exports[`app should be match to snapshot 1`] = `ShallowWrapper {}`;
3 changes: 2 additions & 1 deletion packages/example/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import express from 'express';

import { readAssetsManifest } from '@alfalab/scripts-server';

import icon from './server.png';
import svgIcon from '../clock.svg';

import icon from './server.png';

const app = express();

app.use('/assets', express.static(path.join(process.cwd(), '.build', 'assets')));
Expand Down
Loading
Loading