Skip to content

Commit 9b3e78e

Browse files
authored
feat(reporters): jest html reporter (#633)
* feat(jest-html-reporter): add dependencies * feat(jest-html-reporter): update tsconfig * feat(jest-html-reporter): draft reporter implementation * feat(jest-html-report): history tree * feat(jest-html-report): create adapter for each assertion result * fix(jest-html-report): fix navigation and naming * feat(jest-html-report): update meta fields * feat(jest-html-report): do not show steps section when empty * style(jest-html-reporter): replace any with unknown * feat(html-reporter): CR changes * docs(html-reporter): add installation docs * feat(html-reporter): delete file performance information from meta * fix(jest-html-reporter): remove unused lodash import * test(jest-html-reporter): unit test for JestTestResultAdapter --------- Co-authored-by: = <=>
1 parent f92dee5 commit 9b3e78e

File tree

12 files changed

+36125
-27916
lines changed

12 files changed

+36125
-27916
lines changed

docs/en/html-reporter-jest.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Connecting a reporter to Jest
2+
3+
## Before connecting
4+
We recommend that you read the [Jest documentation on connecting reporters](https://jestjs.io/docs/configuration#reporters-arraymodulename--modulename-options) beforehand.
5+
6+
In our case, there are no special differences, but for convenience, all the necessary information is provided below.
7+
8+
## Minimal configuration
9+
To connect the reporter, just go to jest.config.specify in the js file:
10+
```
11+
const config = {
12+
reporters: [
13+
'html-reporter/build/jest.js ' // Connecting our reporter
14+
'default' // Built-in Jest reporter, can be removed
15+
// You can also connect other reporters
16+
],
17+
};
18+
```
19+
20+
After such a setup, in order to receive the report, it is enough to simply run the tests.
21+
The command to run the tests in your project is stored in the package.json, most often it is:
22+
23+
```
24+
npm run build
25+
```
26+
27+
After the report is generated, it must be distributed from the local server.
28+
29+
This requires the serve library, a package for quick and easy maintenance of static files. It allows you to turn the current working directory into a virtual server where you can open HTML, CSS, JavaScript files and other static assets in the browser.
30+
31+
To install serve globally, run the following command:
32+
33+
```
34+
npm i -g serve
35+
```
36+
37+
After installing serve, you can start the local server using the command:
38+
39+
```
40+
serve html-report
41+
```
42+
43+
> The default folder with the report is called `html-report'. If you want to change the folder name, you can specify it in the reporter configuration. See below how to do this.
44+
45+
The finished report can be viewed at `http://localhost:3000` in the browser.
46+
47+
## Maximum configuration
48+
49+
You can configure the html reporter in the same way as it is specified in the [configuration guide](./html-reporter-setup.md ). All available settings are listed in the section "Description of configuration parameters".
50+
51+
To transfer the settings to the reporter, you will need to slightly change content of jest.config.js.
52+
53+
```
54+
const config = {
55+
reporters: [
56+
['html-reporter/build/jest.js', {
57+
path: 'reports/html-report', // Changing the path to the report folder
58+
}]
59+
],
60+
};
61+
```
62+
63+
In this example, the path to the report folder is changed to `reports/html-report`.

docs/ru/html-reporter-jest.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Подключение репортера к Jest
2+
3+
## Перед подключением
4+
5+
Рекомендуем предварительно прочитать [документацию Jest по подключению репортеров](https://jestjs.io/docs/configuration#reporters-arraymodulename--modulename-options).
6+
7+
В нашем случае никаких особых отличий нет, но для удобства вся необходимая информация предоставлена ниже.
8+
9+
## Минимальная конфигурация
10+
11+
Для того, чтобы подключить репортер, достаточно в jest.config.js файле указать:
12+
13+
```
14+
const config = {
15+
reporters: [
16+
'html-reporter/build/jest.js' // Подключаем наш репортер
17+
'default' // Встроенный репортер Jest, можно убрать
18+
// Можно также подключать и другие репортеры
19+
],
20+
};
21+
```
22+
23+
После такой настройки, для того чтобы получить отчет достаточно просто выполнить тесты. Команда для выполнения тестов в вашем проекте хранится в package.json, чаще всего это:
24+
25+
```
26+
npm run build
27+
```
28+
29+
После того, как отчет будет сгенерирован, его нужно раздать с локального сервера.
30+
31+
Для этого потребуется библиотека serve - пакет для быстрого и лёгкого обслуживания статических файлов. Он позволяет превратить текущий рабочий каталог в виртуальный сервер, где можно открывать HTML, CSS, JavaScript файлы и другие статические активы в браузере.
32+
33+
Для установки serve глобально выполните следующую команду:
34+
```
35+
npm i -g serve
36+
```
37+
38+
После установки serve вы можете запустить локальный сервер с помощью команды:
39+
```
40+
serve html-report
41+
```
42+
43+
> Папка с отчетом по умолчанию называется `html-report`. Если вы хотите изменить имя папки, то можно указать его в конфигурации репортера. Как это сделать смотрите ниже
44+
45+
Готовый отчет можно увидеть по адресу `http://localhost:3000` в браузере.
46+
47+
## Максимальная конфигурация
48+
49+
Вы можете настраивать html-reporter так же, как это указано в [гайде по настройке](./html-reporter-setup.md). Все доступные настройки перечислены в разделе "Расшифровка параметров конфигурации".
50+
51+
Чтобы передать настройки репортеру, потребуется слегка изменить конфигурацию jest.config.js.
52+
53+
```
54+
const config = {
55+
reporters: [
56+
['html-reporter/build/jest.js', {
57+
// Настройки репортера
58+
path: 'reports/html-report', // Изменим путь к папке с отчетом
59+
}]
60+
],
61+
};
62+
```
63+
64+
В примере выше, мы изменили путь к папке с отчетом на `reports/html-report`.

jest.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import PQueue from 'p-queue';
2+
3+
import type {Config as JestConfig} from 'jest';
4+
import type {AggregatedResult, Reporter as JestReporter, Test, TestContext, TestResult} from '@jest/reporters';
5+
6+
import {StaticReportBuilder} from './lib/report-builder/static';
7+
import {HtmlReporter} from './lib/plugin-api';
8+
import {ReporterConfig, TestSpecByPath} from './lib/types';
9+
import {parseConfig} from './lib/config';
10+
import {PluginEvents, ToolName} from './lib/constants';
11+
import {SqliteClient} from './lib/sqlite-client';
12+
import {SqliteImageStore} from './lib/image-store';
13+
import {ImagesInfoSaver} from './lib/images-info-saver';
14+
import {Cache} from './lib/cache';
15+
import {getExpectedCacheKey} from './lib/server-utils';
16+
import {JestTestResultAdapter} from './lib/adapters/test-result/jest';
17+
18+
export {ReporterConfig} from './lib/types';
19+
20+
class JestHtmlReporter implements JestReporter {
21+
protected _promiseQueue: PQueue = new PQueue();
22+
protected _staticReportBuilder: StaticReportBuilder | null;
23+
protected _htmlReporter: HtmlReporter;
24+
protected _initPromise: Promise<void>;
25+
26+
protected _globalConfig: JestConfig;
27+
protected _config: ReporterConfig;
28+
protected _context: unknown; // Reporter context passed from test scheduler
29+
30+
constructor(globalConfig: JestConfig, opts: Partial<ReporterConfig>, reporterContext: unknown) {
31+
this._config = parseConfig(opts);
32+
33+
this._globalConfig = globalConfig;
34+
this._context = reporterContext;
35+
36+
this._htmlReporter = HtmlReporter.create(this._config, {toolName: ToolName.Jest});
37+
this._staticReportBuilder = null;
38+
39+
this._initPromise = (async (htmlReporter: HtmlReporter, config: ReporterConfig): Promise<void> => {
40+
const dbClient = await SqliteClient.create({htmlReporter, reportPath: config.path});
41+
const imageStore = new SqliteImageStore(dbClient);
42+
const expectedPathsCache = new Cache<[TestSpecByPath, string | undefined], string>(getExpectedCacheKey);
43+
44+
const imagesInfoSaver = new ImagesInfoSaver({
45+
imageFileSaver: htmlReporter.imagesSaver,
46+
expectedPathsCache,
47+
imageStore,
48+
reportPath: htmlReporter.config.path
49+
});
50+
51+
this._staticReportBuilder = StaticReportBuilder.create({htmlReporter, reporterConfig: config, dbClient, imagesInfoSaver});
52+
53+
await this._staticReportBuilder.saveStaticFiles();
54+
})(this._htmlReporter, this._config);
55+
56+
this._promiseQueue.add(async () => this._initPromise);
57+
}
58+
59+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
60+
onTestResult(test: Test, testResult: TestResult, _aggregatedResult: AggregatedResult): void {
61+
this._promiseQueue.add(async () => {
62+
await this._initPromise;
63+
64+
const staticReportBuilder = this._staticReportBuilder as StaticReportBuilder;
65+
66+
await Promise.all(
67+
testResult.testResults.map(
68+
assertion => staticReportBuilder.addTestResult(
69+
new JestTestResultAdapter(test, testResult, assertion)
70+
)
71+
)
72+
);
73+
});
74+
}
75+
76+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
77+
async onRunComplete(_testContexts: Set<TestContext>, _results: AggregatedResult) : Promise<void> {
78+
await this._promiseQueue.onIdle();
79+
80+
await this._staticReportBuilder?.finalize();
81+
82+
await this._htmlReporter.emitAsync(PluginEvents.REPORT_SAVED);
83+
}
84+
}
85+
86+
module.exports = JestHtmlReporter;

0 commit comments

Comments
 (0)