From ce509b618b45fb9af2013651d7adc4d054caea47 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Wed, 27 Sep 2023 14:42:35 +0300 Subject: [PATCH] fix: review issues fixes, use pwt delimiter instead of space --- lib/constants/index.ts | 3 + lib/constants/tests.ts | 1 + lib/constants/tool-names.ts | 4 + lib/db-utils/server.ts | 6 +- lib/plugin-adapter.ts | 3 +- lib/plugin-api.ts | 24 +- lib/report-builder/static.ts | 3 +- lib/static/modules/actions.js | 3 +- lib/static/modules/utils.js | 218 ------------------ lib/static/modules/utils/index.js | 16 +- lib/test-adapter/cache/playwright.ts | 1 - lib/test-adapter/playwright.ts | 49 ++-- lib/tests-tree-builder/base.ts | 25 +- lib/tests-tree-builder/static.ts | 9 +- package.json | 1 + playwright.ts | 25 +- .../fixtures/playwright/playwright.config.ts | 4 +- 17 files changed, 106 insertions(+), 289 deletions(-) create mode 100644 lib/constants/tests.ts create mode 100644 lib/constants/tool-names.ts delete mode 100644 lib/static/modules/utils.js delete mode 100644 lib/test-adapter/cache/playwright.ts diff --git a/lib/constants/index.ts b/lib/constants/index.ts index be8296aa2..ea288b471 100644 --- a/lib/constants/index.ts +++ b/lib/constants/index.ts @@ -2,8 +2,11 @@ export * from './browser'; export * from './database'; export * from './defaults'; export * from './diff-modes'; +export * from './group-tests'; export * from './paths'; +export * from './tests'; export * from './plugin-events'; export * from './save-formats'; export * from './test-statuses'; +export * from './tool-names'; export * from './view-modes'; diff --git a/lib/constants/tests.ts b/lib/constants/tests.ts new file mode 100644 index 000000000..072614418 --- /dev/null +++ b/lib/constants/tests.ts @@ -0,0 +1 @@ +export const PWT_TITLE_DELIMITER = ' › '; diff --git a/lib/constants/tool-names.ts b/lib/constants/tool-names.ts new file mode 100644 index 000000000..9fddacf89 --- /dev/null +++ b/lib/constants/tool-names.ts @@ -0,0 +1,4 @@ +export enum ToolName { + Hermione = 'hermione', + Playwright = 'playwright' +} diff --git a/lib/db-utils/server.ts b/lib/db-utils/server.ts index a814d4845..fbdb54560 100644 --- a/lib/db-utils/server.ts +++ b/lib/db-utils/server.ts @@ -9,7 +9,7 @@ import NestedError from 'nested-error-stacks'; import {StaticTestsTreeBuilder} from '../tests-tree-builder/static'; import * as commonSqliteUtils from './common'; import {isUrl, fetchFile, normalizeUrls, logger} from '../common-utils'; -import {DATABASE_URLS_JSON_NAME, DB_COLUMNS, LOCAL_DATABASE_NAME, TestStatus} from '../constants'; +import {DATABASE_URLS_JSON_NAME, DB_COLUMNS, LOCAL_DATABASE_NAME, TestStatus, ToolName} from '../constants'; import {DbLoadResult, HandleDatabasesOptions} from './common'; import {DbUrlsJsonData, RawSuitesRow, ReporterConfig} from '../types'; import {Tree} from '../tests-tree-builder/base'; @@ -57,10 +57,10 @@ export async function mergeDatabases(srcDbPaths: string[], reportPath: string): } } -export function getTestsTreeFromDatabase(dbPath: string): Tree { +export function getTestsTreeFromDatabase(toolName: ToolName, dbPath: string): Tree { try { const db = new Database(dbPath, {readonly: true, fileMustExist: true}); - const testsTreeBuilder = StaticTestsTreeBuilder.create(); + const testsTreeBuilder = StaticTestsTreeBuilder.create({toolName}); const suitesRows = (db.prepare(commonSqliteUtils.selectAllSuitesQuery()) .raw() diff --git a/lib/plugin-adapter.ts b/lib/plugin-adapter.ts index 401979a62..4c08c3e08 100644 --- a/lib/plugin-adapter.ts +++ b/lib/plugin-adapter.ts @@ -8,6 +8,7 @@ import * as utils from './server-utils'; import {cliCommands} from './cli-commands'; import {HtmlReporter} from './plugin-api'; import {HtmlReporterApi, ReporterConfig, ReporterOptions} from './types'; +import {ToolName} from './constants'; type PrepareFn = (hermione: Hermione & HtmlReporterApi, reportBuilder: StaticReportBuilder, config: ReporterConfig) => Promise; @@ -33,7 +34,7 @@ export class PluginAdapter { } addApi(): this { - this._hermione.htmlReporter = HtmlReporter.create(this._config); + this._hermione.htmlReporter = HtmlReporter.create(this._config, {toolName: ToolName.Hermione}); return this; } diff --git a/lib/plugin-api.ts b/lib/plugin-api.ts index e99fc3faf..0c8b8e7ea 100644 --- a/lib/plugin-api.ts +++ b/lib/plugin-api.ts @@ -1,31 +1,43 @@ import EventsEmitter2 from 'eventemitter2'; -import {PluginEvents} from './constants'; +import {PluginEvents, ToolName} from './constants'; import {downloadDatabases, mergeDatabases, getTestsTreeFromDatabase} from './db-utils/server'; import {LocalImagesSaver} from './local-images-saver'; import {version} from '../package.json'; import {ImagesSaver, ReporterConfig, ReportsSaver} from './types'; interface HtmlReporterValues { + toolName: ToolName; extraItems: Record; metaInfoExtenders: Record; imagesSaver: ImagesSaver; reportsSaver: ReportsSaver | null; } +interface ReporterOptions { + toolName: ToolName; +} + +type ParametersExceptFirst = F extends (arg0: any, ...rest: infer R) => any ? R : never; + export class HtmlReporter extends EventsEmitter2 { protected _config: ReporterConfig; protected _values: HtmlReporterValues; protected _version: string; - static create(this: new (config: ReporterConfig) => T, config: ReporterConfig): T { - return new this(config); + static create( + this: new (config: ReporterConfig, options: ReporterOptions) => T, + config: ReporterConfig, + options: ReporterOptions + ): T { + return new this(config, options); } - constructor(config: ReporterConfig) { + constructor(config: ReporterConfig, {toolName}: ReporterOptions) { super(); this._config = config; this._values = { + toolName, extraItems: {}, metaInfoExtenders: {}, imagesSaver: LocalImagesSaver, @@ -91,7 +103,7 @@ export class HtmlReporter extends EventsEmitter2 { return mergeDatabases(...args); } - getTestsTreeFromDatabase(...args: Parameters): ReturnType { - return getTestsTreeFromDatabase(...args); + getTestsTreeFromDatabase(...args: ParametersExceptFirst): ReturnType { + return getTestsTreeFromDatabase(this.values.toolName, ...args); } } diff --git a/lib/report-builder/static.ts b/lib/report-builder/static.ts index e779494e1..dbb43d809 100644 --- a/lib/report-builder/static.ts +++ b/lib/report-builder/static.ts @@ -16,13 +16,12 @@ import { } from '../constants'; import {PreparedTestResult, SqliteAdapter} from '../sqlite-adapter'; import {ReporterTestResult} from '../test-adapter'; -import {hasNoRefImageErrors} from '../static/modules/utils'; import {hasImage, saveStaticFilesToReportDir, writeDatabaseUrlsFile} from '../server-utils'; import {ReporterConfig} from '../types'; import {HtmlReporter} from '../plugin-api'; import {ImageHandler} from '../image-handler'; import {SqliteImageStore} from '../image-store'; -import {getUrlWithBase, getError, getRelativeUrl, hasDiff} from '../common-utils'; +import {getUrlWithBase, getError, getRelativeUrl, hasDiff, hasNoRefImageErrors} from '../common-utils'; import {getTestFromDb} from '../db-utils/server'; const ignoredStatuses = [RUNNING, IDLE]; diff --git a/lib/static/modules/actions.js b/lib/static/modules/actions.js index 5fce0d369..b3e13232f 100644 --- a/lib/static/modules/actions.js +++ b/lib/static/modules/actions.js @@ -91,7 +91,8 @@ export const initStaticReport = () => { await plugins.loadAll(dataFromStaticFile.config); performance?.mark?.(performanceMarks.PLUGINS_LOADED); - const testsTreeBuilder = StaticTestsTreeBuilder.create(); + const {toolName} = dataFromStaticFile.apiValues; + const testsTreeBuilder = StaticTestsTreeBuilder.create({toolName}); if (!db || isEmpty(fetchDbDetails)) { return dispatch({ diff --git a/lib/static/modules/utils.js b/lib/static/modules/utils.js deleted file mode 100644 index df0b1a7cb..000000000 --- a/lib/static/modules/utils.js +++ /dev/null @@ -1,218 +0,0 @@ -'use strict'; - -const {get, isEmpty, find, isFunction, flatMap, isPlainObject, isUndefined} = require('lodash'); -const {isIdleStatus, isSuccessStatus, isUpdatedStatus, isFailStatus, isErrorStatus, isSkippedStatus} = require('../../common-utils'); -const {getCommonErrors} = require('../../constants/errors'); -const {ViewMode} = require('../../constants/view-modes'); -const {SECTIONS, RESULT_KEYS, KEY_DELIMITER} = require('../../constants/group-tests'); - -const AVAILABLE_GROUP_SECTIONS = Object.values(SECTIONS); -const {NO_REF_IMAGE_ERROR, ASSERT_VIEW_ERROR} = getCommonErrors(); - -function hasFailedImages(result) { - const {imagesInfo = []} = result; - - return imagesInfo.some(({error, status}) => !isAssertViewError(error) && (isErrorStatus(status) || isFailStatus(status))); -} - -function isNoRefImageError(error) { - const stack = get(error, 'stack', ''); - return stack.startsWith(NO_REF_IMAGE_ERROR); -} - -function isAssertViewError(error) { - const stack = get(error, 'stack', ''); - return stack.startsWith(ASSERT_VIEW_ERROR); -} - -function hasNoRefImageErrors({imagesInfo = []}) { - return Boolean(imagesInfo.filter(({error}) => isNoRefImageError(error)).length); -} - -function hasResultFails(testResult) { - return hasFailedImages(testResult) || isErrorStatus(testResult.status) || isFailStatus(testResult.status); -} - -function isSuiteIdle(suite) { - return isIdleStatus(suite.status); -} - -function isSuiteSuccessful(suite) { - return isSuccessStatus(suite.status); -} - -function isNodeFailed(node) { - return isFailStatus(node.status) || isErrorStatus(node.status); -} - -function isNodeSuccessful(node) { - return isSuccessStatus(node.status) || isUpdatedStatus(node.status); -} - -function isAcceptable({status, error}) { - return isErrorStatus(status) && isNoRefImageError(error) || isFailStatus(status) || isSkippedStatus(status); -} - -function isScreenRevertable({gui, image, isLastResult}) { - return gui && image.stateName && isLastResult && isUpdatedStatus(image.status); -} - -function dateToLocaleString(date) { - if (!date) { - return ''; - } - const lang = isEmpty(navigator.languages) ? navigator.language : navigator.languages[0]; - return new Date(date).toLocaleString(lang); -} - -function getHttpErrorMessage(error) { - const {message, response} = error; - - return response ? `(${response.status}) ${response.data}` : message; -} - -function isTestNameMatchFilters(testName, testNameFilter, strictMatchFilter) { - if (!testNameFilter) { - return true; - } - - return strictMatchFilter - ? testName === testNameFilter - : testName.includes(testNameFilter); -} - -function isBrowserMatchViewMode(browser, lastResult, viewMode, diff = browser) { - const {status} = lastResult; - - if (viewMode === ViewMode.ALL) { - return true; - } - - if (viewMode === ViewMode.PASSED && isSuccessStatus(status)) { - return true; - } - - if (viewMode === ViewMode.FAILED && (isFailStatus(status) || isErrorStatus(status))) { - return true; - } - - if (viewMode === ViewMode.RETRIED) { - return getUpdatedProperty(browser, diff, 'resultIds.length') > 1; - } - - return status === viewMode; -} - -function shouldShowBrowser(browser, filteredBrowsers, diff = browser) { - if (isEmpty(filteredBrowsers)) { - return true; - } - - const browserToFilterBy = find(filteredBrowsers, {id: getUpdatedProperty(browser, diff, 'name')}); - - if (!browserToFilterBy) { - return false; - } - - const browserVersionsToFilterBy = [].concat(browserToFilterBy.versions).filter(Boolean); - - if (isEmpty(browserVersionsToFilterBy)) { - return true; - } - - return browserVersionsToFilterBy.includes(getUpdatedProperty(browser, diff, 'version')); -} - -function iterateSuites(node, {suiteCb, browserCb, browserIdsCb}) { - let resultFromBrowsers = []; - let resultFromSuites = []; - - if (node.browserIds && [browserCb, browserIdsCb].some(isFunction)) { - resultFromBrowsers = browserIdsCb - ? browserIdsCb(node.browserIds, node) - : flatMap(node.browserIds, (browserId) => browserCb(browserId, node)); - } - - if (node.suiteIds && isFunction(suiteCb)) { - resultFromSuites = flatMap(node.suiteIds, (suiteId) => suiteCb(suiteId, node)); - } - - return [...resultFromBrowsers, ...resultFromSuites]; -} - -function parseKeyToGroupTestsBy(key) { - let [groupSection, ...groupKey] = key.split(KEY_DELIMITER); - groupKey = groupKey.join(KEY_DELIMITER); - - if (!AVAILABLE_GROUP_SECTIONS.includes(groupSection)) { - throw new Error(`Group section must be one of ${AVAILABLE_GROUP_SECTIONS.join(', ')}, but got ${groupSection}`); - } - - if (groupSection === SECTIONS.RESULT && !RESULT_KEYS.includes(groupKey)) { - throw new Error(`Group key must be one of ${RESULT_KEYS.join(', ')}, but got ${groupKey}`); - } - - return [groupSection, groupKey]; -} - -function preloadImage(url) { - new Image().src = url; -} - -function applyStateUpdate(state, diff) { - const result = {...state}; - - for (const key in diff) { - if (isPlainObject(diff[key]) && isPlainObject(state[key])) { - result[key] = applyStateUpdate(state[key], diff[key]); - } else if (diff[key] !== undefined) { - result[key] = diff[key]; - } else { - delete result[key]; - } - } - - return result; -} - -function ensureDiffProperty(diff, path) { - let state = diff; - - for (let i = 0; i < path.length; i++) { - const property = path[i]; - - state[property] = state[property] || {}; - - state = state[property]; - } -} - -function getUpdatedProperty(state, diff, path) { - const diffValue = get(diff, path); - - return isUndefined(diffValue) ? get(state, path) : diffValue; -} - -module.exports = { - isNoRefImageError, - isAssertViewError, - hasNoRefImageErrors, - hasResultFails, - isSuiteIdle, - isSuiteSuccessful, - isNodeFailed, - isNodeSuccessful, - isAcceptable, - isScreenRevertable, - dateToLocaleString, - getHttpErrorMessage, - isTestNameMatchFilters, - isBrowserMatchViewMode, - shouldShowBrowser, - iterateSuites, - parseKeyToGroupTestsBy, - preloadImage, - applyStateUpdate, - ensureDiffProperty, - getUpdatedProperty -}; diff --git a/lib/static/modules/utils/index.js b/lib/static/modules/utils/index.js index d9e45c44d..91698141f 100644 --- a/lib/static/modules/utils/index.js +++ b/lib/static/modules/utils/index.js @@ -2,9 +2,9 @@ const {isEmpty, find, isFunction, flatMap} = require('lodash'); const {isIdleStatus, isSuccessStatus, isUpdatedStatus, isFailStatus, isErrorStatus, isSkippedStatus, isNoRefImageError} = require('../../../common-utils'); -const {ViewMode} = require('../../constants/view-modes'); -const {SECTIONS, RESULT_KEYS, KEY_DELIMITER} = require('../../constants/group-tests'); -const {getUpdatedProperty} = require('./state'); +const {ViewMode, SECTIONS, RESULT_KEYS, KEY_DELIMITER} = require('../../../constants'); +const {applyStateUpdate, ensureDiffProperty, getUpdatedProperty} = require('./state'); +const {PWT_TITLE_DELIMITER} = require('../../../constants'); const AVAILABLE_GROUP_SECTIONS = Object.values(SECTIONS); @@ -51,9 +51,12 @@ function isTestNameMatchFilters(testName, testNameFilter, strictMatchFilter) { return true; } + const testNamePlain = testName.replaceAll(PWT_TITLE_DELIMITER, ' '); + const testNameFilterPlain = testNameFilter.replaceAll(PWT_TITLE_DELIMITER, ' '); + return strictMatchFilter - ? testName === testNameFilter - : testName.includes(testNameFilter); + ? testNamePlain === testNameFilterPlain + : testNamePlain.includes(testNameFilterPlain); } function isBrowserMatchViewMode(browser, lastResult, viewMode, diff = browser) { @@ -135,6 +138,9 @@ function preloadImage(url) { } module.exports = { + applyStateUpdate, + ensureDiffProperty, + getUpdatedProperty, isSuiteIdle, isSuiteSuccessful, isNodeFailed, diff --git a/lib/test-adapter/cache/playwright.ts b/lib/test-adapter/cache/playwright.ts deleted file mode 100644 index d040676b2..000000000 --- a/lib/test-adapter/cache/playwright.ts +++ /dev/null @@ -1 +0,0 @@ -export const testsAttempts: Map = new Map(); diff --git a/lib/test-adapter/playwright.ts b/lib/test-adapter/playwright.ts index 3c2f797e1..574bdfdbe 100644 --- a/lib/test-adapter/playwright.ts +++ b/lib/test-adapter/playwright.ts @@ -1,7 +1,11 @@ +import path from 'path'; import {TestCase as PlaywrightTestCase, TestResult as PlaywrightTestResult} from '@playwright/test/reporter'; import sizeOf from 'image-size'; +import _ from 'lodash'; +import stripAnsi from 'strip-ansi'; + import {ReporterTestResult} from './index'; -import {FAIL, TestStatus} from '../constants'; +import {FAIL, TestStatus, PWT_TITLE_DELIMITER} from '../constants'; import { AssertViewResult, ErrorDetails, @@ -11,13 +15,8 @@ import { ImageSize, TestError } from '../types'; -import path from 'path'; -import * as utils from '../server-utils'; -import {testsAttempts} from './cache/playwright'; -import _ from 'lodash'; -import {getShortMD5, isAssertViewError, isImageDiffError, isNoRefImageError, mkTestId} from '../common-utils'; +import {getShortMD5, isImageDiffError, isNoRefImageError} from '../common-utils'; import {ImagesInfoFormatter} from '../image-handler'; -import stripAnsi from 'strip-ansi'; import {ErrorName} from '../errors'; export type PlaywrightAttachment = PlaywrightTestResult['attachments'][number]; @@ -97,20 +96,12 @@ export interface PlaywrightTestAdapterOptions { export class PlaywrightTestAdapter implements ReporterTestResult { private readonly _testCase: PlaywrightTestCase; private readonly _testResult: PlaywrightTestResult; - private _attempt: number; private _imagesInfoFormatter: ImagesInfoFormatter; constructor(testCase: PlaywrightTestCase, testResult: PlaywrightTestResult, {imagesInfoFormatter}: PlaywrightTestAdapterOptions) { this._testCase = testCase; this._testResult = testResult; this._imagesInfoFormatter = imagesInfoFormatter; - - const testId = mkTestId(this.fullName, this.browserId); - if (utils.shouldUpdateAttempt(this.status)) { - testsAttempts.set(testId, _.isUndefined(testsAttempts.get(testId)) ? 0 : testsAttempts.get(testId) as number + 1); - } - - this._attempt = testsAttempts.get(testId) || 0; } get assertViewResults(): AssertViewResult[] { @@ -142,14 +133,17 @@ export class PlaywrightTestAdapter implements ReporterTestResult { } get attempt(): number { - return this._attempt; + return this._testResult.retry; } + get browserId(): string { return this._testCase.parent.project()?.name as string; } + get description(): string | undefined { return undefined; } + get error(): TestError | undefined { const message = extractErrorMessage(this._testResult); if (message) { @@ -170,30 +164,39 @@ export class PlaywrightTestAdapter implements ReporterTestResult { } return undefined; } + get errorDetails(): ErrorDetails | null { return null; } + get file(): string { return path.relative(process.cwd(), this._testCase.location.file); } + get fullName(): string { - return this.testPath.join(' '); + return this.testPath.join(PWT_TITLE_DELIMITER); } + get history(): string[] { return this._testResult.steps.map(step => `${step.title} <- ${step.duration}ms\n`); } + get id(): string { return this.testPath.concat(this.browserId, this.attempt.toString()).join(' '); } + get imageDir(): string { return getShortMD5(this.fullName); } + get imagesInfo(): ImageInfoFull[] | undefined { return this._imagesInfoFormatter.getImagesInfo(this); } + get isUpdated(): boolean { return false; } + get meta(): Record { return Object.fromEntries(this._testCase.annotations.map(a => [a.type, a.description ?? ''])); } @@ -205,8 +208,10 @@ export class PlaywrightTestAdapter implements ReporterTestResult { get screenshot(): ImageBase64 | undefined { return undefined; } + get sessionId(): string { - return this._testCase.annotations.find(a => a.type === 'surfwax.sessionId')?.description || ''; + // TODO: implement getting sessionId + return ''; } get skipReason(): string { @@ -218,7 +223,7 @@ export class PlaywrightTestAdapter implements ReporterTestResult { } get status(): TestStatus { - if (isNoRefImageError(this.error) || isImageDiffError(this.error) || isAssertViewError(this.error)) { + if (isNoRefImageError(this.error) || isImageDiffError(this.error)) { return FAIL; } return getStatus(this._testResult); @@ -228,11 +233,15 @@ export class PlaywrightTestAdapter implements ReporterTestResult { // slicing because first entries are not actually test-name, but a file, etc. return this._testCase.titlePath().slice(3); } + get timestamp(): number | undefined { return this._testResult.startTime.getTime(); } + get url(): string { - return this._testCase.annotations.find(a => a.type === 'annotations.lastOpenedUrl')?.description || ''; + // TODO: implement this getter. One of the possible solutions would be to provide a fixture similar to + // page.goto(), which would write last visited URL to test annotations + return ''; } private get _attachmentsByState(): Record { diff --git a/lib/tests-tree-builder/base.ts b/lib/tests-tree-builder/base.ts index e89b784d8..f2a650260 100644 --- a/lib/tests-tree-builder/base.ts +++ b/lib/tests-tree-builder/base.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import {determineStatus} from '../common-utils'; -import {TestStatus, BrowserVersions} from '../constants'; +import {BrowserVersions, PWT_TITLE_DELIMITER, TestStatus, ToolName} from '../constants'; import {ReporterTestResult} from '../test-adapter'; import {ImageInfoFull, ParsedSuitesRow} from '../types'; @@ -73,14 +73,24 @@ interface ImagesPayload { parentId: string; } +export interface BaseTestsTreeBuilderOptions { + toolName: ToolName; +} + export class BaseTestsTreeBuilder { protected _tree: Tree; + protected _toolName: ToolName; - static create(this: new () => T): T { - return new this(); + static create( + this: new (options: BaseTestsTreeBuilderOptions) => T, + options: BaseTestsTreeBuilderOptions + ): T { + return new this(options); } - constructor() { + constructor({toolName}: BaseTestsTreeBuilderOptions) { + this._toolName = toolName; + this._tree = { suites: {byId: {}, allIds: [], allRootIds: []}, browsers: {byId: {}, allIds: []}, @@ -129,7 +139,12 @@ export class BaseTestsTreeBuilder { } protected _buildId(parentId: string | string[] = [], name: string | string[] = []): string { - return ([] as string[]).concat(parentId, name).join(' '); + let delimiter = ' '; + if (this._toolName === ToolName.Playwright) { + delimiter = PWT_TITLE_DELIMITER; + } + + return ([] as string[]).concat(parentId, name).join(delimiter); } protected _addSuites(testPath: string[], browserId: string): void { diff --git a/lib/tests-tree-builder/static.ts b/lib/tests-tree-builder/static.ts index 24bb64e94..f8ccbf816 100644 --- a/lib/tests-tree-builder/static.ts +++ b/lib/tests-tree-builder/static.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import {BaseTestsTreeBuilder, Tree} from './base'; +import {BaseTestsTreeBuilder, BaseTestsTreeBuilderOptions, Tree} from './base'; import {BrowserVersions, DB_COLUMN_INDEXES, TestStatus} from '../constants'; import {Attempt, ParsedSuitesRow, RawSuitesRow} from '../types'; @@ -30,14 +30,17 @@ interface BrowserItem { versions: string[]; } +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StaticTestsTreeBuilderOptions extends BaseTestsTreeBuilderOptions {} + export class StaticTestsTreeBuilder extends BaseTestsTreeBuilder { protected _stats: FinalStats; protected _skips: SkipItem[]; protected _failedBrowserIds: { [key: string]: boolean }; protected _passedBrowserIds: { [key: string]: boolean }; - constructor() { - super(); + constructor(options: StaticTestsTreeBuilderOptions) { + super(options); this._stats = { ...initStats(), diff --git a/package.json b/package.json index 70f6661dd..65e4cf17f 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "fs-extra": "^7.0.1", "gemini-configparser": "^1.0.0", "http-codes": "1.0.0", + "image-size": "^1.0.2", "inquirer": "^8.2.0", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.4", diff --git a/playwright.ts b/playwright.ts index 5173c8c3c..7357da111 100644 --- a/playwright.ts +++ b/playwright.ts @@ -1,20 +1,13 @@ import {promisify} from 'util'; import _ from 'lodash'; -import type { - FullConfig, - FullResult, - Reporter, - Suite, - TestCase, - TestResult as PwtTestResult -} from '@playwright/test/reporter'; +import type {Reporter, TestCase, TestResult as PwtTestResult} from '@playwright/test/reporter'; import workerFarm, {Workers} from 'worker-farm'; import {StaticReportBuilder} from './lib/report-builder/static'; import {HtmlReporter} from './lib/plugin-api'; import {ReporterConfig} from './lib/types'; import {parseConfig} from './lib/config'; -import {TestStatus} from './lib/constants'; +import {TestStatus, ToolName} from './lib/constants'; import {RegisterWorkers} from './lib/workers/create-workers'; import {EventEmitter} from 'events'; import {PlaywrightTestAdapter} from './lib/test-adapter/playwright'; @@ -53,7 +46,7 @@ class MyReporter implements Reporter { constructor(opts: Partial) { this._config = parseConfig(_.omit(opts, ['configDir'])); - this._htmlReporter = HtmlReporter.create(this._config); + this._htmlReporter = HtmlReporter.create(this._config, {toolName: ToolName.Playwright}); this._staticReportBuilder = StaticReportBuilder.create(this._htmlReporter, this._config); this._workerFarm = workerFarm(require.resolve('./lib/workers/worker'), ['saveDiffTo']); @@ -69,14 +62,6 @@ class MyReporter implements Reporter { this._resultPromise = this._resultPromise.then(() => promise); } - onBegin(config: FullConfig, suite: Suite): void { - console.log(`Starting the run with ${suite.allTests().length} tests, config: ${config}`); - } - - onTestBegin(test: TestCase, result: PwtTestResult): void { - console.log(`Starting test ${test.title}, result: ${result}`); - } - onTestEnd(test: TestCase, result: PwtTestResult): void { const status = getStatus(result); const formattedResult = new PlaywrightTestAdapter(test, result, {imagesInfoFormatter: this._staticReportBuilder.imageHandler}); @@ -95,9 +80,7 @@ class MyReporter implements Reporter { } } - async onEnd(result: FullResult): Promise { - console.log(`Finished the run: ${result.status}`); - + async onEnd(): Promise { this._addTask(this._staticReportBuilder.finalize()); // TODO: emit report saved event or not? diff --git a/test/func/fixtures/playwright/playwright.config.ts b/test/func/fixtures/playwright/playwright.config.ts index 9f1a735d8..62e49d8d8 100644 --- a/test/func/fixtures/playwright/playwright.config.ts +++ b/test/func/fixtures/playwright/playwright.config.ts @@ -13,10 +13,9 @@ export default defineConfig({ fullyParallel: true, forbidOnly: !!process.env.CI, retries: 2, - workers: process.env.CI ? 1 : undefined, + workers: 1, reporter: [ ['html-reporter-tester/playwright', { - enabled: true, path: path.resolve(__dirname, 'report'), saveFormat: 'sqlite', defaultView: 'failed', @@ -26,7 +25,6 @@ export default defineConfig({ use: { actionTimeout: 0, baseURL: `http://${serverHost}:${serverPort}/fixtures/hermione/index.html`, - trace: 'off' }, projects: [