Skip to content

Commit

Permalink
[scout] unique runId for reporting, disabled failed test reporter loc…
Browse files Browse the repository at this point in the history
…ally (elastic#209507)

## Summary

This PR makes few changes to scout reporter:

Recently I found out that Playwright load configuration file _multiple
times_:
- first time after you run `npx playwright test -c ...`
- on every worker start

log before:

```
[main][~/github/kibana]$ npx playwright test --config x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts
[createPlaywrightConfig] called with runId: 18f35f735a10155c

Running 1 test using 1 worker

[createPlaywrightConfig] called with runId: 2633b4e4c20afa15
[chromium] › full_screen_mode.spec.ts:28:9 › Maps › Full screen mode @svlSecurity @svlOblt @svlSearch @ess
```

With our current logic unique `runId` will be generated on each
configuration load, meaning for parallel run we will report failures in
different directories instead of the same one.

Playwright doesn't expose any unique identifier for the run, so we have
do something similar described in

microsoft/playwright#28941 (comment)

log after fix:

```
[main][~/github/kibana]$ npx playwright test --config x-pack/platform/plugins/shared/maps/ui_tests/playwright.config.ts
[createPlaywrightConfig] called with runId: 310a576f32d3b8a5

Running 1 test using 1 worker

[createPlaywrightConfig] called with runId: 310a576f32d3b8a5
[chromium] › full_screen_mode.spec.ts:28:9 › Maps › Full screen mode @svlSecurity @svlOblt @svlSearch @ess
```

We also had a chat with @dolaru and agreed that Scout reporters to be
disabled for local test run. Few reasons:
- Scout custom reporting targets CI execution: events-based reporter was
already disabled
- Failed test reporter purpose is to provide html boilerplate to be
annotated in pipeline build
- When you run tests with IDE playwright plugin it provides its own
reporter / history, should be enough.
  • Loading branch information
dmlemeshko authored Feb 5, 2025
1 parent 5af4d37 commit 6635fe5
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 15 deletions.
4 changes: 3 additions & 1 deletion packages/kbn-scout-reporting/src/reporting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ export const scoutPlaywrightReporter = (
export const scoutFailedTestsReporter = (
options?: ScoutPlaywrightReporterOptions
): ReporterDescription => {
return ['@kbn/scout-reporting/src/reporting/playwright/failed_test', options];
return SCOUT_REPORTER_ENABLED
? ['@kbn/scout-reporting/src/reporting/playwright/failed_test', options]
: ['null'];
};
70 changes: 57 additions & 13 deletions packages/kbn-scout/src/playwright/config/create_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,35 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { SCOUT_REPORTER_ENABLED, SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { scoutPlaywrightReporter, scoutFailedTestsReporter } from '@kbn/scout-reporting';
import { createPlaywrightConfig } from './create_config';
import { VALID_CONFIG_MARKER } from '../types';
import { generateTestRunId } from '@kbn/scout-reporting';

jest.mock('@kbn/scout-reporting', () => ({
...jest.requireActual('@kbn/scout-reporting'),
generateTestRunId: jest.fn(),
scoutPlaywrightReporter: jest.fn(),
scoutFailedTestsReporter: jest.fn(),
}));

describe('createPlaywrightConfig', () => {
const mockedRunId = 'mocked-run-id';
const mockGenerateTestRunId = generateTestRunId as jest.Mock;
const mockedScoutPlaywrightReporter = scoutPlaywrightReporter as jest.Mock;
const mockedScoutFailedTestsReporter = scoutFailedTestsReporter as jest.Mock;

beforeEach(() => {
jest.clearAllMocks();
delete process.env.TEST_RUN_ID;
});

it('should return a valid default Playwright configuration', () => {
const testRunId = 'test-run-id';
mockGenerateTestRunId.mockImplementationOnce(() => testRunId);
mockGenerateTestRunId.mockImplementationOnce(() => mockedRunId);
// Scout reporters are disabled by default
mockedScoutPlaywrightReporter.mockReturnValueOnce(['null']);
mockedScoutFailedTestsReporter.mockReturnValueOnce(['null']);

const testDir = './my_tests';
const config = createPlaywrightConfig({ testDir });
Expand All @@ -49,28 +58,63 @@ describe('createPlaywrightConfig', () => {
expect(config.reporter).toEqual([
['html', { open: 'never', outputFolder: './output/reports' }],
['json', { outputFile: './output/reports/test-results.json' }],
SCOUT_REPORTER_ENABLED
? [
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: testRunId },
]
: ['null'],
[
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: testRunId },
],
['null'],
['null'],
]);
expect(config.timeout).toBe(60000);
expect(config.expect?.timeout).toBe(10000);
expect(config.outputDir).toBe('./output/test-artifacts');
expect(config.projects![0].name).toEqual('chromium');
});

it('should return a Playwright configuration with Scout reporters', () => {
mockGenerateTestRunId.mockImplementationOnce(() => mockedRunId);
mockedScoutPlaywrightReporter.mockReturnValueOnce([
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: mockedRunId },
]);
mockedScoutFailedTestsReporter.mockReturnValueOnce([
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: mockedRunId },
]);

const testDir = './my_tests';
const config = createPlaywrightConfig({ testDir });

expect(mockGenerateTestRunId).toHaveBeenCalledTimes(1);
expect(config.reporter).toEqual([
['html', { open: 'never', outputFolder: './output/reports' }],
['json', { outputFile: './output/reports/test-results.json' }],
[
'@kbn/scout-reporting/src/reporting/playwright/events',
{ name: 'scout-playwright', runId: mockedRunId },
],
[
'@kbn/scout-reporting/src/reporting/playwright/failed_test',
{ name: 'scout-playwright-failed-tests', runId: mockedRunId },
],
]);
});

it(`should override 'workers' count in Playwright configuration`, () => {
const testDir = './my_tests';
const workers = 2;

const config = createPlaywrightConfig({ testDir, workers });
expect(config.workers).toBe(workers);
});

it('should generate and cache runId in process.env.TEST_RUN_ID', () => {
mockGenerateTestRunId.mockReturnValue(mockedRunId);

// First call to create config
createPlaywrightConfig({ testDir: 'tests' });
expect(process.env.TEST_RUN_ID).toBe(mockedRunId);

// Second call (should use the cached value)
createPlaywrightConfig({ testDir: 'tests' });

expect(generateTestRunId).toHaveBeenCalledTimes(1);
expect(process.env.TEST_RUN_ID).toBe(mockedRunId);
});
});
10 changes: 9 additions & 1 deletion packages/kbn-scout/src/playwright/config/create_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ import { SCOUT_SERVERS_ROOT } from '@kbn/scout-info';
import { ScoutPlaywrightOptions, ScoutTestOptions, VALID_CONFIG_MARKER } from '../types';

export function createPlaywrightConfig(options: ScoutPlaywrightOptions): PlaywrightTestConfig {
const runId = generateTestRunId();
/**
* Playwright loads the config file multiple times, so we need to generate a unique run id
* and store it in the environment to be used across all config function calls.
*/
let runId = process.env.TEST_RUN_ID;
if (!runId) {
runId = generateTestRunId();
process.env.TEST_RUN_ID = runId;
}

return defineConfig<ScoutTestOptions>({
testDir: options.testDir,
Expand Down

0 comments on commit 6635fe5

Please sign in to comment.