testit-adapter-jest 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/debug.d.ts +2 -0
- package/dist/debug.js +8 -0
- package/dist/globalSetup.d.ts +3 -0
- package/dist/globalSetup.js +35 -0
- package/dist/globalTeardown.d.ts +3 -0
- package/dist/globalTeardown.js +16 -0
- package/dist/mappers.d.ts +7 -0
- package/dist/mappers.js +46 -0
- package/dist/testClient.d.ts +18 -0
- package/dist/testClient.js +128 -0
- package/dist/testitEnvironment.d.ts +56 -0
- package/dist/testitEnvironment.js +358 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +85 -0
- package/package.json +2 -2
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type AdapterMode = 0 | 1 | 2;
|
package/dist/config.js
ADDED
package/dist/debug.d.ts
ADDED
package/dist/debug.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.debug = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
exports.debug = (0, debug_1.default)('testit');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const testClient_1 = require("./testClient");
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
exports.default = async (globalConfig, projectConfig) => {
|
|
6
|
+
const adapterMode = projectConfig.testEnvironmentOptions?.adapterMode ?? 0;
|
|
7
|
+
const automaticCreationTestCases = projectConfig.testEnvironmentOptions?.automaticCreationTestCases ?? false;
|
|
8
|
+
let testRunId;
|
|
9
|
+
try {
|
|
10
|
+
switch (adapterMode) {
|
|
11
|
+
case 0:
|
|
12
|
+
case 1: {
|
|
13
|
+
testRunId = projectConfig.testEnvironmentOptions?.testRunId;
|
|
14
|
+
if (!testRunId) {
|
|
15
|
+
throw new Error('testRunId is required when mode is 1');
|
|
16
|
+
}
|
|
17
|
+
globalThis.testClient = new testClient_1.TestClient(projectConfig.testEnvironmentOptions);
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
case 2: {
|
|
21
|
+
globalThis.testClient = new testClient_1.TestClient(projectConfig.testEnvironmentOptions);
|
|
22
|
+
testRunId = await globalThis.testClient.createTestRun();
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
default:
|
|
26
|
+
throw new Error(`Unknown adapter mode ${adapterMode}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.error('Failed to setup', (0, utils_1.formatError)(err));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
projectConfig.globals['testRunId'] = testRunId;
|
|
34
|
+
projectConfig.globals['automaticCreationTestCases'] = automaticCreationTestCases;
|
|
35
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("./utils");
|
|
4
|
+
exports.default = async (globalConfig, projectConfig) => {
|
|
5
|
+
const testRunId = projectConfig.globals['testRunId'];
|
|
6
|
+
if (!testRunId) {
|
|
7
|
+
console.error('Looks like globalSetup was not called');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
await globalThis.testClient.completeTestRun();
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
console.error('Failed to complete test run', (0, utils_1.formatError)(err));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AttachmentPut, AttachmentPutModelAutotestStepResults, AutotestStep, Parameters } from 'testit-api-client';
|
|
2
|
+
import { StepData } from './types';
|
|
3
|
+
export declare function mapDate(date: number): string;
|
|
4
|
+
export declare function mapStep(step: StepData): AutotestStep;
|
|
5
|
+
export declare function mapParams(params: any): Parameters;
|
|
6
|
+
export declare function mapStepResult(step: StepData): AttachmentPutModelAutotestStepResults;
|
|
7
|
+
export declare function mapAttachments(attachments: string[]): AttachmentPut[];
|
package/dist/mappers.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapAttachments = exports.mapStepResult = exports.mapParams = exports.mapStep = exports.mapDate = void 0;
|
|
4
|
+
function mapDate(date) {
|
|
5
|
+
return new Date(date).toISOString();
|
|
6
|
+
}
|
|
7
|
+
exports.mapDate = mapDate;
|
|
8
|
+
function mapStep(step) {
|
|
9
|
+
return {
|
|
10
|
+
title: step.title,
|
|
11
|
+
description: step.description,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
exports.mapStep = mapStep;
|
|
15
|
+
function mapParams(params) {
|
|
16
|
+
switch (typeof params) {
|
|
17
|
+
case 'string':
|
|
18
|
+
case 'bigint':
|
|
19
|
+
case 'number':
|
|
20
|
+
case 'boolean':
|
|
21
|
+
return { value: params.toString() };
|
|
22
|
+
case 'object':
|
|
23
|
+
if (params === null) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
return Object.keys(params).reduce((acc, key) => {
|
|
27
|
+
acc[key] = params[key].toString();
|
|
28
|
+
return acc;
|
|
29
|
+
}, {});
|
|
30
|
+
default:
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.mapParams = mapParams;
|
|
35
|
+
function mapStepResult(step) {
|
|
36
|
+
return {
|
|
37
|
+
title: step.title,
|
|
38
|
+
description: step.description,
|
|
39
|
+
attachments: mapAttachments(step.attachments),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
exports.mapStepResult = mapStepResult;
|
|
43
|
+
function mapAttachments(attachments) {
|
|
44
|
+
return attachments.map((id) => ({ id }));
|
|
45
|
+
}
|
|
46
|
+
exports.mapAttachments = mapAttachments;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AutotestPost, AutotestResultsForTestRun, ClientConfig } from 'testit-api-client';
|
|
2
|
+
export declare class TestClient {
|
|
3
|
+
constructor(clientConfig?: Partial<ClientConfig>);
|
|
4
|
+
private client;
|
|
5
|
+
private _testRunId;
|
|
6
|
+
get testRunId(): string;
|
|
7
|
+
get projectId(): string;
|
|
8
|
+
get configurationId(): string;
|
|
9
|
+
createTestRun(): Promise<string>;
|
|
10
|
+
startTestRun(): Promise<void>;
|
|
11
|
+
completeTestRun(): Promise<void>;
|
|
12
|
+
loadAutotest(autotestPost: AutotestPost): Promise<string>;
|
|
13
|
+
loadPassedAutotest(autotest: AutotestPost): Promise<void>;
|
|
14
|
+
getAutotestId(externalId: string): Promise<string>;
|
|
15
|
+
linkWorkItem(externalId: string, workItemId: string): Promise<void>;
|
|
16
|
+
loadAutotestResults(results: AutotestResultsForTestRun[]): Promise<void>;
|
|
17
|
+
uploadAttachments(attachments: string[]): Promise<string[]>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TestClient = void 0;
|
|
4
|
+
const testit_api_client_1 = require("testit-api-client");
|
|
5
|
+
const debug_1 = require("./debug");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const log = debug_1.debug.extend('client');
|
|
8
|
+
class TestClient {
|
|
9
|
+
constructor(clientConfig = {}) {
|
|
10
|
+
this.client = new testit_api_client_1.Client(clientConfig);
|
|
11
|
+
this._testRunId = clientConfig.testRunId;
|
|
12
|
+
}
|
|
13
|
+
get testRunId() {
|
|
14
|
+
if (this._testRunId === undefined) {
|
|
15
|
+
throw new Error('Test run id is not set');
|
|
16
|
+
}
|
|
17
|
+
return this._testRunId;
|
|
18
|
+
}
|
|
19
|
+
get projectId() {
|
|
20
|
+
return this.client.getConfig().projectId;
|
|
21
|
+
}
|
|
22
|
+
get configurationId() {
|
|
23
|
+
return this.client.getConfig().configurationId;
|
|
24
|
+
}
|
|
25
|
+
async createTestRun() {
|
|
26
|
+
const { projectId, testRunId } = this.client.getConfig();
|
|
27
|
+
if (testRunId === undefined) {
|
|
28
|
+
log('Test run id is not provided, creating test run for project %s', projectId);
|
|
29
|
+
this._testRunId = await this.client
|
|
30
|
+
.createTestRun({ projectId })
|
|
31
|
+
.then((testRun) => testRun.id);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
log('Using provided test run id %s', testRunId);
|
|
35
|
+
this._testRunId = testRunId;
|
|
36
|
+
}
|
|
37
|
+
log('Starting test run %s', this.testRunId);
|
|
38
|
+
return this.testRunId;
|
|
39
|
+
}
|
|
40
|
+
async startTestRun() {
|
|
41
|
+
log('Starting test run %s', this.testRunId);
|
|
42
|
+
await this.client.startTestRun(this.testRunId);
|
|
43
|
+
}
|
|
44
|
+
async completeTestRun() {
|
|
45
|
+
log('Completing test run %s', this.testRunId);
|
|
46
|
+
const testRun = await this.client.getTestRun(this.testRunId);
|
|
47
|
+
if (testRun.stateName === 'InProgress') {
|
|
48
|
+
await this.client.completeTestRun(this.testRunId);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async loadAutotest(autotestPost) {
|
|
52
|
+
try {
|
|
53
|
+
log('Creating autotest %o', autotestPost);
|
|
54
|
+
const { id } = await this.client.createAutotest(autotestPost);
|
|
55
|
+
return id;
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const axiosError = err;
|
|
59
|
+
if (axiosError.response?.status === 409) {
|
|
60
|
+
log('Autotest %s already exists, updating with %o', autotestPost.externalId, autotestPost);
|
|
61
|
+
const [autotest] = await this.client.getAutotest({
|
|
62
|
+
projectId: this.client.getConfig().projectId,
|
|
63
|
+
externalId: autotestPost.externalId,
|
|
64
|
+
});
|
|
65
|
+
await this.client.updateAutotest({
|
|
66
|
+
...autotest,
|
|
67
|
+
links: autotest.links,
|
|
68
|
+
});
|
|
69
|
+
return autotest.id;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.error((0, utils_1.formatError)(err));
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async loadPassedAutotest(autotest) {
|
|
78
|
+
try {
|
|
79
|
+
log('Creating autotest %o', autotest);
|
|
80
|
+
await this.client.createAutotest(autotest);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const axiosError = err;
|
|
84
|
+
if (axiosError.response?.status === 409) {
|
|
85
|
+
log('Autotest %s already exists, updating with %o', autotest.externalId, autotest);
|
|
86
|
+
await this.client.updateAutotest(autotest);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.error((0, utils_1.formatError)(err));
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async getAutotestId(externalId) {
|
|
95
|
+
const [autotest] = await this.client.getAutotest({
|
|
96
|
+
projectId: this.client.getConfig().projectId,
|
|
97
|
+
externalId,
|
|
98
|
+
});
|
|
99
|
+
return autotest.id;
|
|
100
|
+
}
|
|
101
|
+
async linkWorkItem(externalId, workItemId) {
|
|
102
|
+
log('Linking work item %s to autotest %s', workItemId, externalId);
|
|
103
|
+
return this.client.linkToWorkItem(externalId, { id: workItemId });
|
|
104
|
+
}
|
|
105
|
+
async loadAutotestResults(results) {
|
|
106
|
+
log('Loading autotest results %o', results);
|
|
107
|
+
await this.client.loadTestRunResults(this.testRunId, results);
|
|
108
|
+
}
|
|
109
|
+
async uploadAttachments(attachments) {
|
|
110
|
+
const attachmentIds = [];
|
|
111
|
+
for (const attachment of attachments) {
|
|
112
|
+
try {
|
|
113
|
+
log('Uploading attachment %s', attachment);
|
|
114
|
+
const { id } = await this.client.loadAttachment(attachment);
|
|
115
|
+
if (!id) {
|
|
116
|
+
log('Attachment id is not returned');
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
attachmentIds.push(id);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error(`Failed to load attachment`, (0, utils_1.formatError)(err));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return attachmentIds;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.TestClient = TestClient;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { EnvironmentContext, JestEnvironmentConfig } from '@jest/environment';
|
|
3
|
+
import { Event, State } from 'jest-circus';
|
|
4
|
+
import NodeEnvironment from 'jest-environment-node';
|
|
5
|
+
import { LinkPost } from 'testit-api-client';
|
|
6
|
+
export default class TestItEnvironment extends NodeEnvironment {
|
|
7
|
+
private autotestData;
|
|
8
|
+
private currentStepData;
|
|
9
|
+
private testClient;
|
|
10
|
+
private beforeAllSteps;
|
|
11
|
+
private afterAllSteps;
|
|
12
|
+
private currentType;
|
|
13
|
+
private autotestResults;
|
|
14
|
+
private autotests;
|
|
15
|
+
private testPath;
|
|
16
|
+
private attachmentsQueue;
|
|
17
|
+
private automaticCreationTestCases;
|
|
18
|
+
constructor(config: JestEnvironmentConfig, context: EnvironmentContext);
|
|
19
|
+
setup(): Promise<void>;
|
|
20
|
+
teardown(): Promise<void>;
|
|
21
|
+
getVmContext(): import("vm").Context | null;
|
|
22
|
+
exportConditions(): string[];
|
|
23
|
+
handleTestEvent(event: Event, state: State): Promise<void>;
|
|
24
|
+
startHookCapture(hook: Extract<Event, {
|
|
25
|
+
name: 'hook_start';
|
|
26
|
+
}>['hook']): void;
|
|
27
|
+
finishHookCapture(hook: Extract<Event, {
|
|
28
|
+
name: 'hook_start';
|
|
29
|
+
}>['hook']): void;
|
|
30
|
+
startTestCapture(test: Extract<Event, {
|
|
31
|
+
name: 'test_fn_start';
|
|
32
|
+
}>['test']): void;
|
|
33
|
+
finishTestCapture(test: Extract<Event, {
|
|
34
|
+
name: 'test_fn_success';
|
|
35
|
+
}>['test']): void;
|
|
36
|
+
saveResult(test: Extract<Event, {
|
|
37
|
+
name: 'test_done';
|
|
38
|
+
}>['test']): void;
|
|
39
|
+
loadResults(): Promise<void>;
|
|
40
|
+
resetTest(): void;
|
|
41
|
+
resetStep(): void;
|
|
42
|
+
setExternalId(id: string): void;
|
|
43
|
+
setDisplayName(name: string): void;
|
|
44
|
+
setTitle(title: string): void;
|
|
45
|
+
setDescription(description: string): void;
|
|
46
|
+
addAttachments(attachment: string, name?: string): void;
|
|
47
|
+
addAttachments(attachments: string[]): void;
|
|
48
|
+
addLinks(links: LinkPost[]): void;
|
|
49
|
+
addMessage(message: string): void;
|
|
50
|
+
setAutotestLinks(links: LinkPost[]): void;
|
|
51
|
+
setLabels(labels: string[]): void;
|
|
52
|
+
setWorkItems(workItems: string[]): void;
|
|
53
|
+
setParams(params: any): void;
|
|
54
|
+
startStep(name: string, description?: string): void;
|
|
55
|
+
generateExternalId(testName: string): string;
|
|
56
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const jest_environment_node_1 = __importDefault(require("jest-environment-node"));
|
|
7
|
+
const debug_1 = require("./debug");
|
|
8
|
+
const mappers_1 = require("./mappers");
|
|
9
|
+
const testClient_1 = require("./testClient");
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
|
+
const log = debug_1.debug.extend('environment');
|
|
12
|
+
const emptyTitle = '__EMPTY__';
|
|
13
|
+
const emptyAutotestData = () => ({
|
|
14
|
+
name: emptyTitle,
|
|
15
|
+
steps: [],
|
|
16
|
+
afterEach: [],
|
|
17
|
+
beforeEach: [],
|
|
18
|
+
attachments: [],
|
|
19
|
+
links: [],
|
|
20
|
+
runtimeLinks: [],
|
|
21
|
+
labels: [],
|
|
22
|
+
workItems: [],
|
|
23
|
+
});
|
|
24
|
+
const emptyStepData = () => ({
|
|
25
|
+
title: emptyTitle,
|
|
26
|
+
attachments: [],
|
|
27
|
+
});
|
|
28
|
+
class TestItEnvironment extends jest_environment_node_1.default {
|
|
29
|
+
constructor(config, context) {
|
|
30
|
+
super(config, context);
|
|
31
|
+
this.autotestData = emptyAutotestData();
|
|
32
|
+
this.currentStepData = emptyStepData();
|
|
33
|
+
this.beforeAllSteps = [];
|
|
34
|
+
this.afterAllSteps = [];
|
|
35
|
+
this.autotestResults = [];
|
|
36
|
+
this.autotests = [];
|
|
37
|
+
this.attachmentsQueue = [];
|
|
38
|
+
const testRunId = config.projectConfig.globals['testRunId'];
|
|
39
|
+
const automaticCreationTestCases = config.projectConfig.globals['automaticCreationTestCases'];
|
|
40
|
+
if (!testRunId || typeof testRunId !== 'string') {
|
|
41
|
+
throw new Error('Looks like globalSetup was not called');
|
|
42
|
+
}
|
|
43
|
+
if (!automaticCreationTestCases || typeof automaticCreationTestCases !== 'boolean') {
|
|
44
|
+
throw new Error('Looks like globalSetup was not called');
|
|
45
|
+
}
|
|
46
|
+
this.automaticCreationTestCases = automaticCreationTestCases;
|
|
47
|
+
this.testClient = new testClient_1.TestClient({
|
|
48
|
+
...config.projectConfig.testEnvironmentOptions,
|
|
49
|
+
testRunId,
|
|
50
|
+
});
|
|
51
|
+
this.testPath = (0, utils_1.excludePath)(context.testPath, config.globalConfig.rootDir);
|
|
52
|
+
}
|
|
53
|
+
async setup() {
|
|
54
|
+
await super.setup();
|
|
55
|
+
(0, utils_1.createTempDir)();
|
|
56
|
+
this.global.testit = {
|
|
57
|
+
externalId: this.setExternalId.bind(this),
|
|
58
|
+
displayName: this.setDisplayName.bind(this),
|
|
59
|
+
links: this.setAutotestLinks.bind(this),
|
|
60
|
+
labels: this.setLabels.bind(this),
|
|
61
|
+
workItemIds: this.setWorkItems.bind(this),
|
|
62
|
+
params: this.setParams.bind(this),
|
|
63
|
+
step: this.startStep.bind(this),
|
|
64
|
+
title: this.setTitle.bind(this),
|
|
65
|
+
description: this.setDescription.bind(this),
|
|
66
|
+
addAttachments: this.addAttachments.bind(this),
|
|
67
|
+
addLinks: this.addLinks.bind(this),
|
|
68
|
+
addMessage: this.addMessage.bind(this),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async teardown() {
|
|
72
|
+
await super.teardown();
|
|
73
|
+
(0, utils_1.removeTempDir)();
|
|
74
|
+
}
|
|
75
|
+
getVmContext() {
|
|
76
|
+
return super.getVmContext();
|
|
77
|
+
}
|
|
78
|
+
exportConditions() {
|
|
79
|
+
return super.exportConditions();
|
|
80
|
+
}
|
|
81
|
+
async handleTestEvent(event, state) {
|
|
82
|
+
switch (event.name) {
|
|
83
|
+
case 'hook_start': {
|
|
84
|
+
this.startHookCapture(event.hook);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'hook_success':
|
|
88
|
+
case 'hook_failure': {
|
|
89
|
+
this.finishHookCapture(event.hook);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'test_fn_start': {
|
|
93
|
+
this.startTestCapture(event.test);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case 'test_fn_success':
|
|
97
|
+
case 'test_fn_failure': {
|
|
98
|
+
this.finishTestCapture(event.test);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case 'test_done': {
|
|
102
|
+
this.saveResult(event.test);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case 'test_skip': {
|
|
106
|
+
this.resetTest();
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'run_finish': {
|
|
110
|
+
await this.loadResults();
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
startHookCapture(hook) {
|
|
116
|
+
log('Starting hook capture %s', hook.type);
|
|
117
|
+
this.currentType = hook.type;
|
|
118
|
+
// Use the hook type as the step name
|
|
119
|
+
this.currentStepData.title = hook.type;
|
|
120
|
+
}
|
|
121
|
+
finishHookCapture(hook) {
|
|
122
|
+
log('Finishing hook capture %s', hook.type);
|
|
123
|
+
switch (hook.type) {
|
|
124
|
+
case 'beforeAll': {
|
|
125
|
+
this.beforeAllSteps.push(this.currentStepData);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'afterAll': {
|
|
129
|
+
this.afterAllSteps.push(this.currentStepData);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case 'beforeEach': {
|
|
133
|
+
this.autotestData.beforeEach.push(this.currentStepData);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'afterEach': {
|
|
137
|
+
this.autotestData.afterEach.push(this.currentStepData);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
this.resetStep();
|
|
142
|
+
}
|
|
143
|
+
startTestCapture(test) {
|
|
144
|
+
log('Starting test capture %s', test.name);
|
|
145
|
+
this.currentType = 'test';
|
|
146
|
+
this.setDisplayName(test.name);
|
|
147
|
+
}
|
|
148
|
+
finishTestCapture(test) {
|
|
149
|
+
log('Finishing test capture %s', test.name);
|
|
150
|
+
if (this.currentStepData.title !== emptyTitle) {
|
|
151
|
+
this.autotestData.steps.push(this.currentStepData);
|
|
152
|
+
this.resetStep();
|
|
153
|
+
}
|
|
154
|
+
this.currentType = undefined;
|
|
155
|
+
}
|
|
156
|
+
saveResult(test) {
|
|
157
|
+
log('Saving result for %s', test.name);
|
|
158
|
+
const errorMessage = test.errors.length > 0
|
|
159
|
+
? test.errors.map((err) => err[0]?.message).join('\n')
|
|
160
|
+
: undefined;
|
|
161
|
+
const errorTraces = test.errors.length > 0
|
|
162
|
+
? test.errors.map((err) => err[0]?.stack).join('\n')
|
|
163
|
+
: undefined;
|
|
164
|
+
const result = {
|
|
165
|
+
isFailed: test.errors.length > 0,
|
|
166
|
+
startedAt: test.startedAt ?? undefined,
|
|
167
|
+
duration: test.duration ?? undefined,
|
|
168
|
+
finishedAt: test.startedAt && (0, utils_1.isDefined)(test.duration)
|
|
169
|
+
? test.startedAt + test.duration
|
|
170
|
+
: undefined,
|
|
171
|
+
message: errorMessage,
|
|
172
|
+
trace: errorTraces,
|
|
173
|
+
};
|
|
174
|
+
this.autotests.push(this.autotestData);
|
|
175
|
+
this.autotestResults.push(result);
|
|
176
|
+
this.resetTest();
|
|
177
|
+
}
|
|
178
|
+
async loadResults() {
|
|
179
|
+
log('Waiting for attachments to be uploaded');
|
|
180
|
+
await Promise.all(this.attachmentsQueue);
|
|
181
|
+
const results = [];
|
|
182
|
+
for (let i = 0; i < this.autotests.length; i++) {
|
|
183
|
+
const autotest = this.autotests[i];
|
|
184
|
+
const result = this.autotestResults[i];
|
|
185
|
+
log('Mapping autotest %s', autotest.name);
|
|
186
|
+
const setupSteps = this.beforeAllSteps.concat(autotest.beforeEach);
|
|
187
|
+
const teardownSteps = autotest.afterEach.concat(this.afterAllSteps);
|
|
188
|
+
const autotestPost = {
|
|
189
|
+
projectId: this.testClient.projectId,
|
|
190
|
+
externalId: autotest.externalId ?? this.generateExternalId(autotest.name),
|
|
191
|
+
title: autotest.title,
|
|
192
|
+
name: autotest.name,
|
|
193
|
+
description: autotest.description,
|
|
194
|
+
namespace: (0, utils_1.getDir)(this.testPath),
|
|
195
|
+
classname: (0, utils_1.getFileName)(this.testPath),
|
|
196
|
+
setup: setupSteps.map(mappers_1.mapStep),
|
|
197
|
+
steps: autotest.steps.map(mappers_1.mapStep),
|
|
198
|
+
teardown: teardownSteps.map(mappers_1.mapStep),
|
|
199
|
+
links: autotest.links,
|
|
200
|
+
labels: autotest.labels.map((label) => ({ name: label })),
|
|
201
|
+
shouldCreateWorkItem: this.automaticCreationTestCases,
|
|
202
|
+
};
|
|
203
|
+
if (!result.isFailed) {
|
|
204
|
+
await this.testClient.loadPassedAutotest(autotestPost);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
await this.testClient.loadAutotest(autotestPost);
|
|
208
|
+
}
|
|
209
|
+
if (autotest.workItems.length > 0) {
|
|
210
|
+
const id = await this.testClient.getAutotestId(autotestPost.externalId);
|
|
211
|
+
try {
|
|
212
|
+
await Promise.all(autotest.workItems.map((workItem) => {
|
|
213
|
+
return this.testClient.linkWorkItem(id, workItem);
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.error('Failed to link work items', (0, utils_1.formatError)(err));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const messages = [];
|
|
221
|
+
if (autotest.message) {
|
|
222
|
+
messages.push(autotest.message);
|
|
223
|
+
}
|
|
224
|
+
if (result.message) {
|
|
225
|
+
messages.push(result.message);
|
|
226
|
+
}
|
|
227
|
+
results.push({
|
|
228
|
+
autotestExternalId: autotestPost.externalId,
|
|
229
|
+
configurationId: this.testClient.configurationId,
|
|
230
|
+
outcome: result.isFailed ? 'Failed' : 'Passed',
|
|
231
|
+
startedOn: result.startedAt ? (0, mappers_1.mapDate)(result.startedAt) : undefined,
|
|
232
|
+
duration: result.duration ? result.duration : undefined,
|
|
233
|
+
completedOn: result.finishedAt ? (0, mappers_1.mapDate)(result.finishedAt) : undefined,
|
|
234
|
+
attachments: (0, mappers_1.mapAttachments)(autotest.attachments),
|
|
235
|
+
message: messages.length > 0 ? messages.join('\n') : undefined,
|
|
236
|
+
traces: result.trace,
|
|
237
|
+
stepResults: autotest.steps.map(mappers_1.mapStepResult),
|
|
238
|
+
setupResults: setupSteps.map(mappers_1.mapStepResult),
|
|
239
|
+
teardownResults: teardownSteps.map(mappers_1.mapStepResult),
|
|
240
|
+
links: autotest.runtimeLinks,
|
|
241
|
+
parameters: autotest.params !== undefined
|
|
242
|
+
? (0, mappers_1.mapParams)(autotest.params)
|
|
243
|
+
: undefined,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
log('Loading results');
|
|
247
|
+
await this.testClient.loadAutotestResults(results);
|
|
248
|
+
}
|
|
249
|
+
resetTest() {
|
|
250
|
+
this.autotestData = emptyAutotestData();
|
|
251
|
+
this.currentType = undefined;
|
|
252
|
+
}
|
|
253
|
+
resetStep() {
|
|
254
|
+
this.currentStepData = emptyStepData();
|
|
255
|
+
}
|
|
256
|
+
setExternalId(id) {
|
|
257
|
+
log('Setting external id to %s', id);
|
|
258
|
+
this.autotestData.externalId = id;
|
|
259
|
+
}
|
|
260
|
+
setDisplayName(name) {
|
|
261
|
+
log('Setting display name to %s', name);
|
|
262
|
+
this.autotestData.name = name;
|
|
263
|
+
}
|
|
264
|
+
setTitle(title) {
|
|
265
|
+
if (this.currentType === 'test') {
|
|
266
|
+
log('Setting autotest title to %s', title);
|
|
267
|
+
this.autotestData.title = title;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
log('Setting step title to %s', title);
|
|
271
|
+
this.currentStepData.title = title;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
setDescription(description) {
|
|
275
|
+
if (this.currentType === 'test') {
|
|
276
|
+
log('Setting autotest description to %s', description);
|
|
277
|
+
this.autotestData.description = description;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
log('Setting step description to %s', description);
|
|
281
|
+
this.currentStepData.description = description;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
addAttachments(attachments, name) {
|
|
285
|
+
const autotest = this.autotestData;
|
|
286
|
+
const step = this.currentStepData;
|
|
287
|
+
let target;
|
|
288
|
+
if (this.currentType === 'test') {
|
|
289
|
+
log('Adding attachments to %s', autotest.name);
|
|
290
|
+
target = autotest.attachments;
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
log('Adding attachments to %s', step.title);
|
|
294
|
+
target = step.attachments;
|
|
295
|
+
}
|
|
296
|
+
let files;
|
|
297
|
+
if (Array.isArray(attachments)) {
|
|
298
|
+
files = attachments;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
if (!name) {
|
|
302
|
+
name = (0, utils_1.generateFileName)();
|
|
303
|
+
}
|
|
304
|
+
const path = (0, utils_1.createTempFile)(name, attachments);
|
|
305
|
+
files = [path];
|
|
306
|
+
}
|
|
307
|
+
const promise = this.testClient.uploadAttachments(files).then((ids) => {
|
|
308
|
+
target.push(...ids);
|
|
309
|
+
});
|
|
310
|
+
this.attachmentsQueue.push(promise);
|
|
311
|
+
return promise;
|
|
312
|
+
}
|
|
313
|
+
addLinks(links) {
|
|
314
|
+
log('Adding links to %s', this.autotestData.name);
|
|
315
|
+
this.autotestData.runtimeLinks.push(...links);
|
|
316
|
+
}
|
|
317
|
+
addMessage(message) {
|
|
318
|
+
log('Adding message to %s', this.autotestData.name);
|
|
319
|
+
this.autotestData.message = message;
|
|
320
|
+
}
|
|
321
|
+
setAutotestLinks(links) {
|
|
322
|
+
log('Setting autotest links to %s', this.autotestData.name);
|
|
323
|
+
this.autotestData.links = links;
|
|
324
|
+
}
|
|
325
|
+
setLabels(labels) {
|
|
326
|
+
log('Setting labels to %s', this.autotestData.name);
|
|
327
|
+
this.autotestData.labels = labels;
|
|
328
|
+
}
|
|
329
|
+
setWorkItems(workItems) {
|
|
330
|
+
log('Setting work items to %s', this.autotestData.name);
|
|
331
|
+
this.autotestData.workItems = workItems;
|
|
332
|
+
}
|
|
333
|
+
setParams(params) {
|
|
334
|
+
log('Setting params to %s', this.autotestData.name);
|
|
335
|
+
this.autotestData.params = params;
|
|
336
|
+
}
|
|
337
|
+
startStep(name, description) {
|
|
338
|
+
log('Starting step %s', name);
|
|
339
|
+
if (this.currentType !== 'test' && this.currentType !== 'step') {
|
|
340
|
+
log('Step can only be started in test');
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (this.currentType === 'step') {
|
|
344
|
+
this.autotestData.steps.push(this.currentStepData);
|
|
345
|
+
this.resetStep();
|
|
346
|
+
}
|
|
347
|
+
this.currentType = 'step';
|
|
348
|
+
this.currentStepData.title = name;
|
|
349
|
+
this.currentStepData.description = description;
|
|
350
|
+
}
|
|
351
|
+
generateExternalId(testName) {
|
|
352
|
+
return (0, utils_1.getHash)(JSON.stringify({
|
|
353
|
+
path: this.testPath,
|
|
354
|
+
name: testName,
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
exports.default = TestItEnvironment;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LinkPost } from 'testit-api-client';
|
|
2
|
+
export type StepData = {
|
|
3
|
+
title: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
attachments: string[];
|
|
6
|
+
};
|
|
7
|
+
export type AutotestData = {
|
|
8
|
+
name: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
externalId?: string;
|
|
12
|
+
namespace?: string;
|
|
13
|
+
classname?: string;
|
|
14
|
+
attachments: string[];
|
|
15
|
+
beforeEach: StepData[];
|
|
16
|
+
steps: StepData[];
|
|
17
|
+
afterEach: StepData[];
|
|
18
|
+
links: LinkPost[];
|
|
19
|
+
runtimeLinks: LinkPost[];
|
|
20
|
+
message?: string;
|
|
21
|
+
labels: string[];
|
|
22
|
+
workItems: string[];
|
|
23
|
+
params?: any;
|
|
24
|
+
};
|
|
25
|
+
export type AutotestResult = {
|
|
26
|
+
startedAt?: number;
|
|
27
|
+
duration?: number;
|
|
28
|
+
finishedAt?: number;
|
|
29
|
+
isFailed: boolean;
|
|
30
|
+
message?: string;
|
|
31
|
+
trace?: string;
|
|
32
|
+
};
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function isDefined<T>(value: T | undefined | null): value is T;
|
|
2
|
+
export declare function nullToUndefined<T>(value: T | undefined | null): T | undefined;
|
|
3
|
+
export declare function excludePath(source: string, toRemove: string): string;
|
|
4
|
+
export declare function normalizePath(path: string): string;
|
|
5
|
+
export declare function getHash(input: string): string;
|
|
6
|
+
export declare function getDir(file: string): string;
|
|
7
|
+
export declare function getFileName(file: string): string;
|
|
8
|
+
export declare function createTempDir(): void;
|
|
9
|
+
export declare function createTempFile(name: string, content: string): string;
|
|
10
|
+
export declare function removeTempDir(): void;
|
|
11
|
+
export declare function generateExternalId(path: string, testName: string): string;
|
|
12
|
+
export declare function generateFileName(): string;
|
|
13
|
+
export declare function formatError(error: any): any;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatError = exports.generateFileName = exports.generateExternalId = exports.removeTempDir = exports.createTempFile = exports.createTempDir = exports.getFileName = exports.getDir = exports.getHash = exports.normalizePath = exports.excludePath = exports.nullToUndefined = exports.isDefined = void 0;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
const debug_1 = require("./debug");
|
|
13
|
+
const log = debug_1.debug.extend('utils');
|
|
14
|
+
function isDefined(value) {
|
|
15
|
+
return value !== undefined && value !== null;
|
|
16
|
+
}
|
|
17
|
+
exports.isDefined = isDefined;
|
|
18
|
+
function nullToUndefined(value) {
|
|
19
|
+
return value ?? undefined;
|
|
20
|
+
}
|
|
21
|
+
exports.nullToUndefined = nullToUndefined;
|
|
22
|
+
function excludePath(source, toRemove) {
|
|
23
|
+
return source.replace(toRemove, '');
|
|
24
|
+
}
|
|
25
|
+
exports.excludePath = excludePath;
|
|
26
|
+
function normalizePath(path) {
|
|
27
|
+
return (0, path_1.normalize)(path);
|
|
28
|
+
}
|
|
29
|
+
exports.normalizePath = normalizePath;
|
|
30
|
+
function getHash(input) {
|
|
31
|
+
return (0, crypto_1.createHash)('md5').update(input).digest('hex');
|
|
32
|
+
}
|
|
33
|
+
exports.getHash = getHash;
|
|
34
|
+
function getDir(file) {
|
|
35
|
+
return (0, path_1.dirname)(file);
|
|
36
|
+
}
|
|
37
|
+
exports.getDir = getDir;
|
|
38
|
+
function getFileName(file) {
|
|
39
|
+
return (0, path_1.parse)(file).base;
|
|
40
|
+
}
|
|
41
|
+
exports.getFileName = getFileName;
|
|
42
|
+
const dirPrefix = 'testit-';
|
|
43
|
+
let tempDir;
|
|
44
|
+
function createTempDir() {
|
|
45
|
+
log('Creating temp dir');
|
|
46
|
+
tempDir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), dirPrefix));
|
|
47
|
+
log('Created temp dir %s', tempDir);
|
|
48
|
+
}
|
|
49
|
+
exports.createTempDir = createTempDir;
|
|
50
|
+
function createTempFile(name, content) {
|
|
51
|
+
if (!tempDir) {
|
|
52
|
+
throw new Error('Temp dir is not created');
|
|
53
|
+
}
|
|
54
|
+
log('Creating temp file %s in %s', name, tempDir);
|
|
55
|
+
const path = (0, path_1.join)(tempDir, name);
|
|
56
|
+
(0, fs_1.writeFileSync)(path, content);
|
|
57
|
+
return path;
|
|
58
|
+
}
|
|
59
|
+
exports.createTempFile = createTempFile;
|
|
60
|
+
function removeTempDir() {
|
|
61
|
+
if (tempDir) {
|
|
62
|
+
log('Removing temp dir %s', tempDir);
|
|
63
|
+
(0, fs_1.rmSync)(tempDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.removeTempDir = removeTempDir;
|
|
67
|
+
function generateExternalId(path, testName) {
|
|
68
|
+
return getHash(JSON.stringify({
|
|
69
|
+
path: path,
|
|
70
|
+
name: testName,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
exports.generateExternalId = generateExternalId;
|
|
74
|
+
function generateFileName() {
|
|
75
|
+
return `${(0, crypto_1.randomUUID)()}-attachment.txt`;
|
|
76
|
+
}
|
|
77
|
+
exports.generateFileName = generateFileName;
|
|
78
|
+
function formatError(error) {
|
|
79
|
+
return axios_1.default.isAxiosError(error)
|
|
80
|
+
? error.response?.data ?? error.response?.statusText ?? error.message
|
|
81
|
+
: error instanceof Error
|
|
82
|
+
? error.message
|
|
83
|
+
: error;
|
|
84
|
+
}
|
|
85
|
+
exports.formatError = formatError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testit-adapter-jest",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/testitEnvironment.js",
|
|
6
6
|
"scripts": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "ISC",
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"debug": "^4.3.4",
|
|
15
|
-
"testit-api-client": "^1.0.
|
|
15
|
+
"testit-api-client": "^1.0.8"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/debug": "^4.1.7",
|