Implement TeamCity test reporting integration by adding new scripts and documentation. Update package.json to include a new test command for TeamCity. Introduce TeamcityReporter class for formatting service messages and enhance test setup for compatibility with TeamCity environment.
This commit is contained in:
60
tests/TeamcityReporter.ts
Normal file
60
tests/TeamcityReporter.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
export class TeamcityReporter {
|
||||
/**
|
||||
* Escape special characters for TeamCity service messages
|
||||
* https://www.jetbrains.com/help/teamcity/service-messages.html#Escaped+values
|
||||
*/
|
||||
private static escape(str: string): string {
|
||||
return str
|
||||
.replace(/\|/g, "||")
|
||||
.replace(/'/g, "|'")
|
||||
.replace(/\n/g, "|n")
|
||||
.replace(/\r/g, "|r")
|
||||
.replace(/\[/g, "|[")
|
||||
.replace(/]/g, "|]");
|
||||
}
|
||||
|
||||
public static reportSuiteStart(suiteName: string): void {
|
||||
console.log(`##teamcity[testSuiteStarted name='${this.escape(suiteName)}']`);
|
||||
}
|
||||
|
||||
public static reportSuiteEnd(suiteName: string): void {
|
||||
console.log(`##teamcity[testSuiteFinished name='${this.escape(suiteName)}']`);
|
||||
}
|
||||
|
||||
public static reportTestStart(testName: string): void {
|
||||
console.log(`##teamcity[testStarted name='${this.escape(testName)}']`);
|
||||
}
|
||||
|
||||
public static reportTestFailed(testName: string, failureMessage: string, details: string, {comparisonFailure, expected, actual}: {comparisonFailure: boolean, expected: string, actual: string}): void {
|
||||
const attrs = [
|
||||
`name='${this.escape(testName)}'`,
|
||||
`message='${this.escape(failureMessage)}'`,
|
||||
`details='${this.escape(details)}'`
|
||||
];
|
||||
|
||||
if (comparisonFailure) {
|
||||
attrs.push(`type='comparisonFailure'`);
|
||||
attrs.push(`expected='${this.escape(expected)}'`);
|
||||
attrs.push(`actual='${this.escape(actual)}'`);
|
||||
}
|
||||
|
||||
console.log(`##teamcity[testFailed ${attrs.join(' ')}]`);
|
||||
}
|
||||
|
||||
public static reportTestEnd(testName: string, duration?: number): void {
|
||||
const durationAttr = duration !== undefined ? ` duration='${duration}'` : '';
|
||||
console.log(`##teamcity[testFinished name='${this.escape(testName)}'${durationAttr}]`);
|
||||
}
|
||||
|
||||
public static reportTestError(testName: string, error: Error): void {
|
||||
const message = this.escape(error.message || 'Unknown error');
|
||||
const details = this.escape(error.stack || '');
|
||||
console.log(`##teamcity[testFailed name='${this.escape(testName)}' message='${message}' details='${details}']`);
|
||||
}
|
||||
|
||||
public static reportTestIgnored(testName: string, message?: string): void {
|
||||
const msgAttr = message ? ` message='${this.escape(message)}'` : '';
|
||||
console.log(`##teamcity[testIgnored name='${this.escape(testName)}'${msgAttr}]`);
|
||||
}
|
||||
}
|
||||
55
tests/setup.ts
Normal file
55
tests/setup.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { TeamcityReporter } from "./TeamcityReporter.ts";
|
||||
|
||||
// Check if running in TeamCity environment
|
||||
const isTeamCity = process.env.TEAMCITY_VERSION !== undefined;
|
||||
|
||||
// Override console methods to capture test output if needed
|
||||
if (isTeamCity) {
|
||||
// You can add global beforeAll/afterAll if needed
|
||||
console.log("TeamCity reporter enabled");
|
||||
}
|
||||
|
||||
// Export wrapper functions for test suites
|
||||
export function setupTeamCityReporting() {
|
||||
if (!isTeamCity) {
|
||||
return {
|
||||
reportSuiteStart: () => {},
|
||||
reportSuiteEnd: () => {},
|
||||
reportTestStart: () => {},
|
||||
reportTestEnd: () => {},
|
||||
reportTestFailed: () => {},
|
||||
reportTestError: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
reportSuiteStart: (name: string) => {
|
||||
TeamcityReporter.reportSuiteStart(name);
|
||||
},
|
||||
reportSuiteEnd: (name: string) => {
|
||||
TeamcityReporter.reportSuiteEnd(name);
|
||||
},
|
||||
reportTestStart: (name: string) => {
|
||||
TeamcityReporter.reportTestStart(name);
|
||||
},
|
||||
reportTestEnd: (name: string) => {
|
||||
TeamcityReporter.reportTestEnd(name);
|
||||
},
|
||||
reportTestFailed: (
|
||||
name: string,
|
||||
message: string,
|
||||
details: string,
|
||||
comparison?: { expected: string; actual: string }
|
||||
) => {
|
||||
TeamcityReporter.reportTestFailed(name, message, details, {
|
||||
comparisonFailure: !!comparison,
|
||||
expected: comparison?.expected || "",
|
||||
actual: comparison?.actual || "",
|
||||
});
|
||||
},
|
||||
reportTestError: (name: string, error: Error) => {
|
||||
TeamcityReporter.reportTestError(name, error);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user