Skip to content

Commit

Permalink
feat(reporters): jest html reporter (#633)
Browse files Browse the repository at this point in the history
* 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: = <=>
  • Loading branch information
mordvinx authored Jan 31, 2025
1 parent f92dee5 commit 9b3e78e
Show file tree
Hide file tree
Showing 12 changed files with 36,125 additions and 27,916 deletions.
63 changes: 63 additions & 0 deletions docs/en/html-reporter-jest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Connecting a reporter to Jest

## Before connecting
We recommend that you read the [Jest documentation on connecting reporters](https://jestjs.io/docs/configuration#reporters-arraymodulename--modulename-options) beforehand.

In our case, there are no special differences, but for convenience, all the necessary information is provided below.

## Minimal configuration
To connect the reporter, just go to jest.config.specify in the js file:
```
const config = {
reporters: [
'html-reporter/build/jest.js ' // Connecting our reporter
'default' // Built-in Jest reporter, can be removed
// You can also connect other reporters
],
};
```

After such a setup, in order to receive the report, it is enough to simply run the tests.
The command to run the tests in your project is stored in the package.json, most often it is:

```
npm run build
```

After the report is generated, it must be distributed from the local server.

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.

To install serve globally, run the following command:

```
npm i -g serve
```

After installing serve, you can start the local server using the command:

```
serve html-report
```

> 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.
The finished report can be viewed at `http://localhost:3000` in the browser.

## Maximum configuration

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".

To transfer the settings to the reporter, you will need to slightly change content of jest.config.js.

```
const config = {
reporters: [
['html-reporter/build/jest.js', {
path: 'reports/html-report', // Changing the path to the report folder
}]
],
};
```

In this example, the path to the report folder is changed to `reports/html-report`.
64 changes: 64 additions & 0 deletions docs/ru/html-reporter-jest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Подключение репортера к Jest

## Перед подключением

Рекомендуем предварительно прочитать [документацию Jest по подключению репортеров](https://jestjs.io/docs/configuration#reporters-arraymodulename--modulename-options).

В нашем случае никаких особых отличий нет, но для удобства вся необходимая информация предоставлена ниже.

## Минимальная конфигурация

Для того, чтобы подключить репортер, достаточно в jest.config.js файле указать:

```
const config = {
reporters: [
'html-reporter/build/jest.js' // Подключаем наш репортер
'default' // Встроенный репортер Jest, можно убрать
// Можно также подключать и другие репортеры
],
};
```

После такой настройки, для того чтобы получить отчет достаточно просто выполнить тесты. Команда для выполнения тестов в вашем проекте хранится в package.json, чаще всего это:

```
npm run build
```

После того, как отчет будет сгенерирован, его нужно раздать с локального сервера.

Для этого потребуется библиотека serve - пакет для быстрого и лёгкого обслуживания статических файлов. Он позволяет превратить текущий рабочий каталог в виртуальный сервер, где можно открывать HTML, CSS, JavaScript файлы и другие статические активы в браузере.

Для установки serve глобально выполните следующую команду:
```
npm i -g serve
```

После установки serve вы можете запустить локальный сервер с помощью команды:
```
serve html-report
```

> Папка с отчетом по умолчанию называется `html-report`. Если вы хотите изменить имя папки, то можно указать его в конфигурации репортера. Как это сделать смотрите ниже
Готовый отчет можно увидеть по адресу `http://localhost:3000` в браузере.

## Максимальная конфигурация

Вы можете настраивать html-reporter так же, как это указано в [гайде по настройке](./html-reporter-setup.md). Все доступные настройки перечислены в разделе "Расшифровка параметров конфигурации".

Чтобы передать настройки репортеру, потребуется слегка изменить конфигурацию jest.config.js.

```
const config = {
reporters: [
['html-reporter/build/jest.js', {
// Настройки репортера
path: 'reports/html-report', // Изменим путь к папке с отчетом
}]
],
};
```

В примере выше, мы изменили путь к папке с отчетом на `reports/html-report`.
86 changes: 86 additions & 0 deletions jest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import PQueue from 'p-queue';

import type {Config as JestConfig} from 'jest';
import type {AggregatedResult, Reporter as JestReporter, Test, TestContext, TestResult} from '@jest/reporters';

import {StaticReportBuilder} from './lib/report-builder/static';
import {HtmlReporter} from './lib/plugin-api';
import {ReporterConfig, TestSpecByPath} from './lib/types';
import {parseConfig} from './lib/config';
import {PluginEvents, ToolName} from './lib/constants';
import {SqliteClient} from './lib/sqlite-client';
import {SqliteImageStore} from './lib/image-store';
import {ImagesInfoSaver} from './lib/images-info-saver';
import {Cache} from './lib/cache';
import {getExpectedCacheKey} from './lib/server-utils';
import {JestTestResultAdapter} from './lib/adapters/test-result/jest';

export {ReporterConfig} from './lib/types';

class JestHtmlReporter implements JestReporter {
protected _promiseQueue: PQueue = new PQueue();
protected _staticReportBuilder: StaticReportBuilder | null;
protected _htmlReporter: HtmlReporter;
protected _initPromise: Promise<void>;

protected _globalConfig: JestConfig;
protected _config: ReporterConfig;
protected _context: unknown; // Reporter context passed from test scheduler

constructor(globalConfig: JestConfig, opts: Partial<ReporterConfig>, reporterContext: unknown) {
this._config = parseConfig(opts);

this._globalConfig = globalConfig;
this._context = reporterContext;

this._htmlReporter = HtmlReporter.create(this._config, {toolName: ToolName.Jest});
this._staticReportBuilder = null;

this._initPromise = (async (htmlReporter: HtmlReporter, config: ReporterConfig): Promise<void> => {
const dbClient = await SqliteClient.create({htmlReporter, reportPath: config.path});
const imageStore = new SqliteImageStore(dbClient);
const expectedPathsCache = new Cache<[TestSpecByPath, string | undefined], string>(getExpectedCacheKey);

const imagesInfoSaver = new ImagesInfoSaver({
imageFileSaver: htmlReporter.imagesSaver,
expectedPathsCache,
imageStore,
reportPath: htmlReporter.config.path
});

this._staticReportBuilder = StaticReportBuilder.create({htmlReporter, reporterConfig: config, dbClient, imagesInfoSaver});

await this._staticReportBuilder.saveStaticFiles();
})(this._htmlReporter, this._config);

this._promiseQueue.add(async () => this._initPromise);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
onTestResult(test: Test, testResult: TestResult, _aggregatedResult: AggregatedResult): void {
this._promiseQueue.add(async () => {
await this._initPromise;

const staticReportBuilder = this._staticReportBuilder as StaticReportBuilder;

await Promise.all(
testResult.testResults.map(
assertion => staticReportBuilder.addTestResult(
new JestTestResultAdapter(test, testResult, assertion)
)
)
);
});
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async onRunComplete(_testContexts: Set<TestContext>, _results: AggregatedResult) : Promise<void> {
await this._promiseQueue.onIdle();

await this._staticReportBuilder?.finalize();

await this._htmlReporter.emitAsync(PluginEvents.REPORT_SAVED);
}
}

module.exports = JestHtmlReporter;
Loading

0 comments on commit 9b3e78e

Please sign in to comment.