Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
Warnings (#62)
Browse files Browse the repository at this point in the history
* warnings api for reporter

* tests

* clean code

* clean code

* clean code

* fix unit tests warnings

* renaming

* lint fixed

* api changed

* lint

* new report warnings event

* tests

* clean code

* lint

* add import

* fix aduit

* upd testcafe

* upd lockfile

* update testcafe

* using tc 1.17.0

* update testcafe version

* renaming

* text changed
  • Loading branch information
AlexanderMoiseev committed Nov 15, 2021
1 parent 97f1a6a commit d8a9e9f
Show file tree
Hide file tree
Showing 22 changed files with 345 additions and 94 deletions.
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -52,7 +52,7 @@
"normalize-newline": "^1.0.2",
"publish-please": "^5.5.2",
"read-file-relative": "^1.2.0",
"testcafe": "^1.15.0",
"testcafe": "^1.17.0",
"ts-node": "^8.7.0",
"typescript": "^3.8.3"
},
Expand All @@ -72,7 +72,7 @@
"lodash": "4.17.21",
"glob-parent": "5.1.2",
"yargs-parser": "13.1.2",
"set-value": "4.0.1",
"ansi-regex": "5.0.1"
"ansi-regex": "5.0.1",
"set-value": "4.0.1"
}
}
10 changes: 5 additions & 5 deletions src/blank-reporter.ts
Expand Up @@ -3,11 +3,11 @@ import { ReporterPluginObject } from './types/internal';
const noop = () => Promise.resolve();

const BLANK_REPORTER: ReporterPluginObject = {
reportTaskStart: noop,
reportFixtureStart: noop,
reportTestDone: noop,
reportTaskDone: noop,

reportTaskStart: noop,
reportFixtureStart: noop,
reportTestDone: noop,
reportTaskDone: noop,
reportWarnings: noop,
createErrorDecorator: () => ({})
};

Expand Down
5 changes: 4 additions & 1 deletion src/report-commands-factory.ts
@@ -1,5 +1,5 @@
import { AggregateCommandType, AggregateNames } from './types/internal/';
import { TaskStartArgs, TestStartArgs, TestDoneArgs, TaskDoneArgs } from './types/';
import { TaskStartArgs, TestStartArgs, TaskDoneArgs, TestDoneArgs, ReportWarningArgs } from './types/';
import Transport from './transport';

export default function reportCommandsFactory (reportId: string, transport: Transport) {
Expand Down Expand Up @@ -27,6 +27,9 @@ export default function reportCommandsFactory (reportId: string, transport: Tran
},
sendTaskDoneCommand (payload: TaskDoneArgs): Promise<void> {
return sendReportCommand(AggregateCommandType.reportTaskDone, payload);
},
sendReportWarningsCommand (payload: ReportWarningArgs): Promise<void> {
return sendReportCommand(AggregateCommandType.reportWarnings, payload);
}
};
};
56 changes: 53 additions & 3 deletions src/reporter-object-factory.ts
Expand Up @@ -18,7 +18,9 @@ import {
ReportedTestStructureItem,
ShortId,
TestDoneArgs,
TestError
TestError,
Warning,
WarningsInfo
} from './types';
import { Uploader } from './upload';
import { errorDecorator, curly } from './error-decorator';
Expand Down Expand Up @@ -68,11 +70,31 @@ export default function reporterObjectFactory (
const uploader = new Uploader(readFile, transport, logger);
const reportCommands = reportCommandsFactory(id, transport);

const testRunToWarningsMap: Record<string, Warning[]> = {};
const runWarnings: Warning[] = [];
const testRunToActionsMap: Record<string, ActionInfo[]> = {};
const browserToRunsMap: Record<string, Record<string, any[]>> = {};
const testRunIdToTestIdMap: Record<string, string> = {};

const reporterPluginObject: ReporterPluginObject = { ...BLANK_REPORTER, createErrorDecorator: errorDecorator };

async function uploadWarnings (): Promise<string | undefined> {
const warningsRunIds = Object.keys(testRunToWarningsMap);

if (!warningsRunIds.length && !runWarnings.length)
return void 0;

const warningsInfo: WarningsInfo[] = [];

for (const testRunId of warningsRunIds)
warningsInfo.push({ testRunId, warnings: testRunToWarningsMap[testRunId] });

if (runWarnings.length)
warningsInfo.push({ warnings: runWarnings });

return await uploader.uploadRunWarning(id, warningsInfo);
}

assignReporterMethods(reporterPluginObject, {
async reportTaskStart (startTime, userAgents, testCount, taskStructure: ReportedTestStructureItem[]): Promise<void> {
logger.log(createReportUrlMessage(buildId || id, authenticationToken, dashboardUrl));
Expand All @@ -86,9 +108,32 @@ export default function reporterObjectFactory (
return void 0;
},

async reportWarnings (warning: Warning): Promise<void> {
if (warning.testRunId) {
if (!testRunToWarningsMap[warning.testRunId])
testRunToWarningsMap[warning.testRunId] = [];

testRunToWarningsMap[warning.testRunId].push(warning);

const testId = testRunIdToTestIdMap[warning.testRunId];

if (testId) {
await reportCommands.sendReportWarningsCommand({
testId: testId as ShortId,
});
}
}
else
runWarnings.push(warning);

},

async reportTestStart (name, meta, testStartInfo): Promise<void> {
const testId = testStartInfo.testId as ShortId;

for (const testRunId of testStartInfo.testRunIds)
testRunIdToTestIdMap[testRunId] = testId;

browserToRunsMap[testId] = {};

await reportCommands.sendTestStartCommand({ testId });
Expand Down Expand Up @@ -189,10 +234,12 @@ export default function reporterObjectFactory (
videoUploadIds,
actions: testRunToActionsMap[attemptRunId],
thirdPartyError: testRunToErrorsMap[attemptRunId],
quarantineAttempt: attempt
quarantineAttempt: attempt,
warnings: testRunToWarningsMap[attemptRunId],
};

delete testRunToActionsMap[attemptRunId];
delete testRunToWarningsMap[attemptRunId];

return result;
};
Expand Down Expand Up @@ -233,9 +280,12 @@ export default function reporterObjectFactory (
},

async reportTaskDone (endTime, passed, warnings, result): Promise<void> {
const warningsUploadId = await uploadWarnings();

await uploader.waitUploads();

await reportCommands.sendTaskDoneCommand({
endTime, passed, warnings, result, buildId: buildId as BuildId
endTime, passed, warningsUploadId, warnings, result, buildId: buildId as BuildId
});
}
}, isLogEnabled);
Expand Down
3 changes: 3 additions & 0 deletions src/texts.ts
Expand Up @@ -18,6 +18,9 @@ export const createFileUploadError = (uploadId: string, filePath: string): strin
export const createTestUploadError = (uploadId: string, testName: string): string =>
`Failed to upload a test log. Upload ID: ${uploadId}, test name: ${testName}.`;

export const createWarningUploadError = (uploadId: string, uploadEntityId: string): string =>
`Failed to upload warning data. Upload ID: ${uploadId}, upload entity id: ${uploadEntityId}.`;

export const createGetUploadInfoError = (uploadEntityId: string, response: string): string =>
`Cannot get an upload URL. Upload entity ID: ${uploadEntityId}. Response: ${response}`;

Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Expand Up @@ -2,5 +2,6 @@ export * from './task-start-args';
export * from './test-done-args';
export * from './test-start-args';
export * from './task-done-args';
export * from './report-warning-args';
export * from './common';
export * from './testcafe';
4 changes: 2 additions & 2 deletions src/types/internal/dashboard.ts
Expand Up @@ -13,8 +13,8 @@ export enum AggregateCommandType {
reportTestStart = 'reportTestStart',
reportTestDone = 'reportTestDone',
reportTaskDone = 'reportTaskDone',

createUpload = 'createUpload'
createUpload = 'createUpload',
reportWarnings = 'reportWarnings',
};

export enum AggregateNames {
Expand Down
5 changes: 4 additions & 1 deletion src/types/internal/testcafe.ts
@@ -1,8 +1,9 @@
import { BrowserInfo, Meta, ReportedTestStructureItem, TestRunInfo, Error, TestPhase, CommandType, TaskResult } from '../';
import { BrowserInfo, Meta, ReportedTestStructureItem, TestRunInfo, Error, TestPhase, CommandType, TaskResult, Warning } from '../';

export type TestStartInfo = {
testId: string;
testRunId: string[];
testRunIds: string[];
}

export type TestCafeActionInfo = {
Expand Down Expand Up @@ -39,6 +40,8 @@ export type ReporterMethods = {
reportTestActionDone?: (apiActionName: string, actionInfo: TestCafeActionInfo) => Promise<void>;
reportTestDone: (name: string, testRunInfo: TestRunInfo, meta?: Meta) => Promise<void>;
reportTaskDone: (endTime: Date, passed: number, warnings: string[], result: TaskResult) => Promise<void>;

reportWarnings: (warnings: Warning) => Promise<void>;
};

export type ReporterPluginObject = ReporterMethods & {
Expand Down
13 changes: 13 additions & 0 deletions src/types/report-warning-args.ts
@@ -0,0 +1,13 @@

import * as t from 'io-ts';
import { ShortIdSchema } from './common';

export const ReportWarningsSchema = t.readonly(
t.exact(
t.type({
testId: ShortIdSchema,
})
)
);

export type ReportWarningArgs = t.TypeOf<typeof ReportWarningsSchema>;
15 changes: 7 additions & 8 deletions src/types/task-done-args.ts
@@ -1,10 +1,8 @@
import { DateFromISOString } from 'io-ts-types';


import * as t from 'io-ts';
import { BuildIdSchema } from './common';


export const TaskResultSchema = t.readonly(
t.exact(
t.type({
Expand All @@ -20,14 +18,15 @@ export type TaskResult = t.TypeOf<typeof TaskResultSchema>;
export const TaskDoneArgsSchema = t.readonly(
t.exact(
t.type({
endTime: DateFromISOString,
passed: t.number,
warnings: t.array(t.string),
result: TaskResultSchema,
buildId: BuildIdSchema
endTime: DateFromISOString,
passed: t.number,
warnings: t.array(t.string),
warningsUploadId: t.union([t.string, t.undefined]),

result: TaskResultSchema,
buildId: BuildIdSchema
})
)
);


export type TaskDoneArgs = t.TypeOf<typeof TaskDoneArgsSchema>;
11 changes: 11 additions & 0 deletions src/types/testcafe.ts
Expand Up @@ -88,6 +88,7 @@ export type BrowserRunInfo = {
actions?: ActionInfo[];
thirdPartyError?: TestError;
quarantineAttempt?: number;
warnings?: Warning[];
}

export type ActionInfo = {
Expand All @@ -98,6 +99,16 @@ export type ActionInfo = {
error?: TestError;
}

export type Warning = {
message: string;
testRunId?: string;
}

export type WarningsInfo = {
testRunId?: string;
warnings: Warning[];
}

export enum TestPhase {
initial = 'initial',
inFixtureBeforeHook = 'inFixtureBeforeHook',
Expand Down
24 changes: 17 additions & 7 deletions src/upload.ts
@@ -1,8 +1,8 @@
import { AggregateCommandType, AggregateNames, Logger, ReadFileMethod, UploadStatus } from './types/internal';
import { UploadInfo } from './types/internal/resolve';
import { createGetUploadInfoError, createFileUploadError, createTestUploadError } from './texts';
import { createGetUploadInfoError, createFileUploadError, createTestUploadError, createWarningUploadError } from './texts';
import Transport from './transport';
import { DashboardTestRunInfo } from './types/';
import { WarningsInfo } from './types/';

export class Uploader {
private _transport: Transport;
Expand Down Expand Up @@ -67,15 +67,25 @@ export class Uploader {
return uploadInfo.uploadId;
}

async uploadTest (testName: string, testRunInfo: DashboardTestRunInfo): Promise<string | undefined> {
const uploadInfo = await this._getUploadInfo(testName);
requestUploadEntity ( uploadInfo: UploadInfo, uploadObject: object, error: string): void {
const buffer = Buffer.from(JSON.stringify(uploadObject, (key, value) => value instanceof RegExp ? value.toString() : value));

if (!uploadInfo) return void 0;
this._uploads.push(this._upload(uploadInfo, buffer, error));
}

const buffer = Buffer.from(JSON.stringify(testRunInfo, (key, value) => value instanceof RegExp ? value.toString() : value));
async uploadTest (uploadEntityId: string, testRunInfo: object): Promise<string | undefined> {
const uploadInfo = await this._getUploadInfo(uploadEntityId);

this._uploads.push(this._upload(uploadInfo, buffer, createTestUploadError(uploadInfo.uploadId, testName)));
if (!uploadInfo) return void 0;
this.requestUploadEntity(uploadInfo, testRunInfo, createTestUploadError(uploadInfo.uploadId, uploadEntityId));
return uploadInfo.uploadId;
}

async uploadRunWarning (uploadEntityId: string, warningInfo: WarningsInfo[]): Promise<string | undefined> {
const uploadInfo = await this._getUploadInfo(uploadEntityId);

if (!uploadInfo) return void 0;
this.requestUploadEntity(uploadInfo, warningInfo, createWarningUploadError(uploadInfo.uploadId, uploadEntityId));
return uploadInfo.uploadId;
}

Expand Down
3 changes: 2 additions & 1 deletion test/data/test-quarantine-mode-info.ts
Expand Up @@ -94,5 +94,6 @@ export const quarantineTestDoneInfo: TestRunInfo = {

export const quarantiteTestStartInfo: TestStartInfo = {
testId,
testRunId: [testRunId1]
testRunId: [testRunId1],
testRunIds: []
};
26 changes: 26 additions & 0 deletions test/data/test-warnings-info.ts
@@ -0,0 +1,26 @@
import { TestRunInfo } from '../../src/types/testcafe';
import { CHROME, CHROME_HEADLESS, FIREFOX } from './test-browser-info';

export const WARNINGS_TEST_RUN_ID_1 = 'Xsa6hZIR5';
export const WARNINGS_TEST_RUN_ID_2 = 'Xsa6hZIR6';
export const WARNINGS_TEST_RUN_ID_3 = 'Xsa6hZIR67';

const testId = 'testId';

export const testWarningsInfo: TestRunInfo = {
browsers: [ { ...FIREFOX, testRunId: WARNINGS_TEST_RUN_ID_1 }, { ...CHROME, testRunId: WARNINGS_TEST_RUN_ID_2 }, { ...CHROME_HEADLESS, testRunId: WARNINGS_TEST_RUN_ID_3 } ],
durationMs: 1,

errs: [

],

quarantine: null,
screenshotPath: null,
screenshots: [],
skipped: false,
testId,
unstable: false,
videos: [],
warnings: []
};
2 changes: 1 addition & 1 deletion test/data/two-errors-test-action-done.ts
@@ -1,4 +1,4 @@
export const testId = 'test_1';
export const testId = 'Test_1';

export const twoErrorsTestActionDone = [
{ 'err': { 'code': 'E24', 'isTestCafeError': true, 'callsite': { 'filename': 'c:\\Projects\\testcafe-reporter-dashboard\\sandbox\\test.ts', 'lineNum': 7, 'callsiteFrameIdx': 6, 'stackFrames': [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], 'isV8Frames': true }, 'apiFnChain': ["Selector('#developer-name1')"], 'apiFnIndex': 0 }, 'testRunId': 'firefox_1', 'test': { 'id': testId, 'name': 'Test 1', 'phase': 'inTest' }, 'fixture': { 'name': 'Fixture 1', 'id': 'zLv6jKS' }, 'command': { 'type': 'click', 'selector': { 'expression': "Selector('#developer-name1')" }, 'options': { 'speed': 0.5, 'offsetX': null, 'offsetY': null, 'modifiers': { 'ctrl': true, 'alt': false, 'shift': false, 'meta': false }, 'caretPos': null } }, 'browser': { 'name': 'Firefox', 'version': '73.0', 'platform': 'desktop', 'os': { 'name': 'Windows', 'version': '10' }, 'engine': { 'name': 'Gecko', 'version': '20100101' }, 'prettyUserAgent': 'Firefox 73.0 / Windows 10', 'userAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0', 'alias': 'firefox', 'headless': false } },
Expand Down
17 changes: 16 additions & 1 deletion test/mocks.ts
@@ -1,8 +1,23 @@
import { ReadFileMethod } from '../src/types/internal/dashboard';
import { DashboardSettings, ReadFileMethod } from '../src/types/internal/dashboard';
import { CI_DETECTION_VARIABLES, CI_INFO_VARIABLES } from './data/ci-variables';

const originalVariables = {};

export const TESTCAFE_DASHBOARD_URL = 'http://localhost';

export const UPLOAD_URL_PREFIX = 'http://upload_url/';

export const SETTINGS: DashboardSettings = {
authenticationToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9qZWN0SWQiOiI4MmUwMTNhNy01YzFlLTRkMzQtODdmZC0xYWRmNzg0ZGM2MDciLCJpYXQiOjE2Mjg4NTQxODF9.j-CKkD-T3IIVw9CMx5-cFu6516v0FXbMJYDT4lbH9rs',
buildId: void 0,
dashboardUrl: TESTCAFE_DASHBOARD_URL,
isLogEnabled: false,
noScreenshotUpload: false,
noVideoUpload: false,
responseTimeout: 1000,
requestRetryCount: 10
};

export const mockReadFile = (() => void 0) as unknown as ReadFileMethod;

export const clearCIDetectionVariables = () => {
Expand Down

0 comments on commit d8a9e9f

Please sign in to comment.