@testream/vitest-reporter 1.1.0 → 1.2.0
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/README.md +4 -0
- package/dist/cjs/ctrf-builder.d.ts +2 -2
- package/dist/cjs/ctrf-builder.d.ts.map +1 -1
- package/dist/cjs/index.d.ts +3 -3
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/reporter.d.ts +6 -5
- package/dist/cjs/reporter.d.ts.map +1 -1
- package/dist/cjs/types.d.ts +5 -5
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/uploader.d.ts +3 -3
- package/dist/cjs/uploader.d.ts.map +1 -1
- package/dist/ctrf-builder.d.ts +2 -2
- package/dist/ctrf-builder.d.ts.map +1 -1
- package/dist/esm/index.mjs +12 -1
- package/dist/index.d.ts +3 -3
- package/dist/reporter.d.ts +6 -5
- package/dist/reporter.d.ts.map +1 -1
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/uploader.d.ts +3 -3
- package/dist/uploader.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,4 +25,8 @@ export default defineConfig({
|
|
|
25
25
|
})
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
The reporter enables Vitest `includeTaskLocation` automatically so generated
|
|
29
|
+
CTRF reports include `line` metadata and shared snippet enrichment can populate
|
|
30
|
+
`snippet` for JS/TS tests.
|
|
31
|
+
|
|
28
32
|
Need more configuration options? See the full guide at https://docs.testream.app/reporters/vitest.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TestModule } from
|
|
2
|
-
import type { CTRFReport, VitestReporterConfig } from
|
|
1
|
+
import type { TestModule } from "vitest/node";
|
|
2
|
+
import type { CTRFReport, VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Build a CTRF report from Vitest TestModules
|
|
5
5
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/ctrf-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAY,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/ctrf-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAY,oBAAoB,EAAE,MAAM,SAAS,CAAC;AA4F1E;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,MAAM,EAAE,oBAAoB,EAC5B,cAAc,EAAE,MAAM,GACrB,UAAU,CA6DZ"}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Vitest reporter that generates CTRF-format test reports and
|
|
5
5
|
* automatically uploads them to the Testream backend.
|
|
6
6
|
*/
|
|
7
|
-
export { TestreamVitestReporter as default } from
|
|
8
|
-
export { TestreamVitestReporter } from
|
|
9
|
-
export type { VitestReporterConfig } from
|
|
7
|
+
export { TestreamVitestReporter as default } from "./reporter";
|
|
8
|
+
export { TestreamVitestReporter } from "./reporter";
|
|
9
|
+
export type { VitestReporterConfig } from "./types";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e={406:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true});t.detectCIContext=detectCIContext;function removePrefix(e,t){if(!e){return undefined}return e.startsWith(t)?e.slice(t.length):e}function readEnvironment(){const e=globalThis;return e.process?.env??{}}function buildGithubRepositoryUrl(e){if(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY){return undefined}return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}`}function buildGithubBuildUrl(e){if(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY||!e.GITHUB_RUN_ID){return undefined}return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`}function detectGitHubBranch(e){if(e.GITHUB_HEAD_REF){return e.GITHUB_HEAD_REF}if(e.GITHUB_REF?.startsWith("refs/heads/")){return e.GITHUB_REF_NAME??removePrefix(e.GITHUB_REF,"refs/heads/")}return undefined}function detectGitHubActionsContext(e){return{branch:detectGitHubBranch(e),commitSha:e.GITHUB_SHA,repositoryUrl:buildGithubRepositoryUrl(e),buildNumber:e.GITHUB_RUN_NUMBER,buildUrl:buildGithubBuildUrl(e)}}function detectGitLabContext(e){return{branch:e.CI_COMMIT_BRANCH||e.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:e.CI_COMMIT_SHA,repositoryUrl:e.CI_PROJECT_URL,buildNumber:e.CI_PIPELINE_IID,buildUrl:e.CI_PIPELINE_URL}}function detectAzurePipelinesContext(e){return{branch:removePrefix(e.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:e.BUILD_SOURCEVERSION,repositoryUrl:e.BUILD_REPOSITORY_URI,buildNumber:e.BUILD_BUILDNUMBER,buildUrl:e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&e.SYSTEM_TEAMPROJECT&&e.BUILD_BUILDID?`${e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${e.SYSTEM_TEAMPROJECT}/_build/results?buildId=${e.BUILD_BUILDID}`:undefined}}function detectCircleCIContext(e){return{branch:e.CIRCLE_BRANCH,commitSha:e.CIRCLE_SHA1,repositoryUrl:e.CIRCLE_REPOSITORY_URL,buildNumber:e.CIRCLE_BUILD_NUM,buildUrl:e.CIRCLE_BUILD_URL}}function detectJenkinsContext(e){return{branch:removePrefix(e.GIT_BRANCH,"origin/"),commitSha:e.GIT_COMMIT,repositoryUrl:e.GIT_URL,buildNumber:e.BUILD_NUMBER,buildUrl:e.BUILD_URL}}function detectBitbucketContext(e){return{branch:e.BITBUCKET_BRANCH,commitSha:e.BITBUCKET_COMMIT,repositoryUrl:e.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:e.BITBUCKET_BUILD_NUMBER,buildUrl:e.BITBUCKET_REPO_FULL_NAME&&e.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${e.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${e.BITBUCKET_BUILD_NUMBER}`:undefined}}const r=[{isMatch:e=>e.GITHUB_ACTIONS==="true",detect:detectGitHubActionsContext},{isMatch:e=>e.GITLAB_CI==="true",detect:detectGitLabContext},{isMatch:e=>e.TF_BUILD==="True",detect:detectAzurePipelinesContext},{isMatch:e=>e.CIRCLECI==="true",detect:detectCircleCIContext},{isMatch:e=>Boolean(e.JENKINS_URL),detect:detectJenkinsContext},{isMatch:e=>Boolean(e.BITBUCKET_BUILD_NUMBER),detect:detectBitbucketContext}];function detectCIContext(){const e=readEnvironment();for(const t of r){if(t.isMatch(e)){return t.detect(e)}}return{}}},827:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true})},322:function(e,t,r){var o=this&&this.__createBinding||(Object.create?function(e,t,r,o){if(o===undefined)o=r;var n=Object.getOwnPropertyDescriptor(t,r);if(!n||("get"in n?!t.__esModule:n.writable||n.configurable)){n={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,o,n)}:function(e,t,r,o){if(o===undefined)o=r;e[o]=t[r]});var n=this&&this.__exportStar||function(e,t){for(var r in e)if(r!=="default"&&!Object.prototype.hasOwnProperty.call(t,r))o(t,e,r)};Object.defineProperty(t,"__esModule",{value:true});t.ensureReportId=t.mapAttachmentsToTestResults=t.uploadArtifacts=t.uploadTestRun=t.detectCIContext=void 0;n(r(827),t);var s=r(406);Object.defineProperty(t,"detectCIContext",{enumerable:true,get:function(){return s.detectCIContext}});var i=r(969);Object.defineProperty(t,"uploadTestRun",{enumerable:true,get:function(){return i.uploadTestRun}});Object.defineProperty(t,"uploadArtifacts",{enumerable:true,get:function(){return i.uploadArtifacts}});Object.defineProperty(t,"mapAttachmentsToTestResults",{enumerable:true,get:function(){return i.mapAttachmentsToTestResults}});Object.defineProperty(t,"ensureReportId",{enumerable:true,get:function(){return i.ensureReportId}})},969:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:true});t.ensureReportId=ensureReportId;t.uploadTestRun=uploadTestRun;t.mapAttachmentsToTestResults=mapAttachmentsToTestResults;t.uploadArtifacts=uploadArtifacts;const o=r(406);const n="https://test-manager-backend.fly.dev";function ensureReportId(e){if(typeof e.reportId==="string"&&e.reportId.trim().length>0){return e.reportId}const t=crypto.randomUUID();e.reportId=t;return t}function resolveApiUrl(e){const t=normalizeApiUrl(e);if(t){return t}const r=getEnvApiUrl();if(r){return r}return n}function getEnvApiUrl(){if(typeof process==="undefined"||!process?.env){return undefined}return normalizeApiUrl(process.env.TESTREAM_API_URL)}function normalizeApiUrl(e){if(!e){return undefined}const t=e.trim();if(!t){return undefined}return t.replace(/\/+$/,"")}function isReportAlreadyExistsConflict(e){return e.errorCode==="report_already_exists"}function formatUploadError(e){const t=e.detail||e.title||e.rawBody||"Unknown error";const r=e.errorCode?`, code=${e.errorCode}`:"";return`Upload failed (HTTP ${e.statusCode}${r}): ${t}`}async function parseHttpError(e){const t=await e.text();const r=e.headers.get("content-type")||"";if(r.toLowerCase().includes("json")&&t.trim().length>0){try{const r=JSON.parse(t);return{statusCode:e.status,title:r.title,detail:r.detail||r.details||r.error,errorCode:r.errorCode,rawBody:t}}catch{}}return{statusCode:e.status,rawBody:t}}function resolveUploadContext(e){const t=(0,o.detectCIContext)();return{commitSha:e.commitSha??t.commitSha,branch:e.branch??t.branch,repositoryUrl:e.repositoryUrl??t.repositoryUrl,buildName:e.buildName,buildNumber:e.buildNumber??t.buildNumber,buildUrl:e.buildUrl??t.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async function uploadTestRun(e){const{report:t,apiKey:r}=e;const o=resolveApiUrl(e.apiUrl);const n=ensureReportId(t);const s=resolveUploadContext(e);const i={report:t,reportId:n,...s};console.log("Uploading test results...");let a;try{a=await fetch(`${o}/api/v1/ingest`,{method:"POST",headers:{"X-API-KEY":r,"Content-Type":"application/json"},body:JSON.stringify(i)})}catch(e){const t=e instanceof Error?e.message:String(e);const r=`Connection failed: ${t}`;console.error(r);return{success:false,reportId:n,error:r}}if(!a.ok){const e=await parseHttpError(a);if(a.status===409&&isReportAlreadyExistsConflict(e)){console.warn("Report already exists (workflow may have been re-run)");return{success:true,reportId:n,summary:{passed:t.results.summary.passed,failed:t.results.summary.failed,skipped:t.results.summary.skipped,total:t.results.summary.tests},alreadyExists:true,statusCode:e.statusCode,errorCode:e.errorCode}}const r=formatUploadError(e);console.error(r);return{success:false,reportId:n,error:r,statusCode:e.statusCode,errorCode:e.errorCode,errorDetail:e.detail||e.rawBody}}const c=await a.json();console.log(`✓ Test results uploaded successfully`);console.log(` Report ID: ${c.reportId}`);console.log(` Test Run ID: ${c.testRunId}`);console.log(` Tests: ${c.summary.passed}/${c.summary.total} passed`);return{success:true,reportId:c.reportId,testRunId:c.testRunId,summary:{passed:c.summary.passed,failed:c.summary.failed,skipped:c.summary.skipped,total:c.summary.total},testResults:c.testResults}}function mapAttachmentsToTestResults(e,t){const r=new Map;for(const e of t){const t=r.get(e.name)??[];t.push(e.id);r.set(e.name,t)}const o=[];for(const t of e){const e=r.get(t.name);const n=e?.shift();if(!t.attachments||t.attachments.length===0){continue}if(!n){console.warn(`Skipping artifact upload: could not match test result for "${t.name}"`);continue}o.push({testResultId:n,attachments:t.attachments})}return o}async function uploadArtifacts(e){const{reportId:t,apiKey:r,testResults:o}=e;const n=resolveApiUrl(e.apiUrl);let s=0;for(const e of o){for(const o of e.attachments){try{const i=await uploadSingleArtifact({testResultId:e.testResultId,attachment:o,reportId:t,apiKey:r,apiUrl:n});if(i)s++}catch(e){const t=e instanceof Error?e.message:String(e);console.error(`Failed to upload artifact ${o.name}: ${t}`)}}}if(s>0){console.log(`✓ Uploaded ${s} artifact(s)`)}return s}async function uploadSingleArtifact(e){const{testResultId:t,attachment:o,reportId:n,apiKey:s,apiUrl:i}=e;const a=await Promise.resolve().then(r.t.bind(r,943,23));const c=await Promise.resolve().then(r.t.bind(r,928,23));const l=c.resolve(o.path);try{await a.access(l)}catch{console.warn(`Artifact not found: ${c.basename(l)}`);return false}let u;let d;const p=c.basename(l);const f=o.contentType||"application/octet-stream";try{u=await a.readFile(l);d=u.byteLength}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Failed to read file: ${t}`)}try{return await uploadWithPresignedUrl({testResultId:t,reportId:n,apiKey:s,apiUrl:i,attachmentName:o.name,fileName:p,contentType:f,sizeBytes:d,fileBuffer:u})}catch(e){if(!(e instanceof LegacyUploadRequiredError)){throw e}return await uploadWithLegacyEndpoint({testResultId:t,attachmentName:o.name,reportId:n,apiKey:s,apiUrl:i,fileName:p,contentType:f,fileBuffer:u})}}class LegacyUploadRequiredError extends Error{constructor(){super("Legacy upload endpoint required")}}async function uploadWithPresignedUrl(e){const{testResultId:t,reportId:r,apiKey:o,apiUrl:n,attachmentName:s,fileName:i,contentType:a,sizeBytes:c,fileBuffer:l}=e;const u={testResultId:t,ctrfAttachmentName:s,fileName:i,contentType:a,sizeBytes:c};const d=await fetch(`${n}/api/v1/artifacts/${r}/upload-url`,{method:"POST",headers:{"X-API-KEY":o,"Content-Type":"application/json"},body:JSON.stringify(u)});if(shouldFallbackToLegacyUpload(d.status)){throw new LegacyUploadRequiredError}if(!d.ok){const e=await d.text();throw new Error(`Failed to create direct upload URL (HTTP ${d.status}): ${e}`)}const p=await d.json();const f={...p.requiredHeaders??{}};if(!hasHeaderIgnoreCase(f,"Content-Type")){f["Content-Type"]=a}const m=await fetch(p.uploadUrl,{method:"PUT",headers:f,body:l});if(!m.ok){const e=await m.text();throw new Error(`Direct artifact upload failed (HTTP ${m.status}): ${e}`)}const h={testResultId:t,ctrfAttachmentName:s,fileName:i,contentType:a,sizeBytes:c,storageKey:p.storageKey};const _=await fetch(`${n}/api/v1/artifacts/${r}/complete`,{method:"POST",headers:{"X-API-KEY":o,"Content-Type":"application/json"},body:JSON.stringify(h)});if(!_.ok){const e=await _.text();throw new Error(`Failed to finalize artifact upload (HTTP ${_.status}): ${e}`)}return true}async function uploadWithLegacyEndpoint(e){const{testResultId:t,attachmentName:r,reportId:o,apiKey:n,apiUrl:s,fileName:i,contentType:a,fileBuffer:c}=e;const l=new Blob([new Uint8Array(c)],{type:a});const u=new FormData;u.append("testResultId",t);u.append("ctrfAttachmentName",r);u.append("file",l,i);const d=await fetch(`${s}/api/v1/artifacts/${o}`,{method:"POST",headers:{"X-API-KEY":n},body:u});if(!d.ok){const e=await d.text();throw new Error(`Legacy artifact upload failed (HTTP ${d.status}): ${e}`)}return true}function shouldFallbackToLegacyUpload(e){return e===404||e===405||e===501}function hasHeaderIgnoreCase(e,t){const r=t.toLowerCase();return Object.keys(e).some((e=>e.toLowerCase()===r))}},943:e=>{e.exports=require("fs/promises")},928:e=>{e.exports=require("path")}};var t={};function __nccwpck_require__(r){var o=t[r];if(o!==undefined){return o.exports}var n=t[r]={exports:{}};var s=true;try{e[r].call(n.exports,n,n.exports,__nccwpck_require__);s=false}finally{if(s)delete t[r]}return n.exports}(()=>{var e=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;var t;__nccwpck_require__.t=function(r,o){if(o&1)r=this(r);if(o&8)return r;if(typeof r==="object"&&r){if(o&4&&r.__esModule)return r;if(o&16&&typeof r.then==="function")return r}var n=Object.create(null);__nccwpck_require__.r(n);var s={};t=t||[null,e({}),e([]),e(e)];for(var i=o&2&&r;typeof i=="object"&&!~t.indexOf(i);i=e(i)){Object.getOwnPropertyNames(i).forEach((e=>s[e]=()=>r[e]))}s["default"]=()=>r;__nccwpck_require__.d(n,s);return n}})();(()=>{__nccwpck_require__.d=(e,t)=>{for(var r in t){if(__nccwpck_require__.o(t,r)&&!__nccwpck_require__.o(e,r)){Object.defineProperty(e,r,{enumerable:true,get:t[r]})}}}})();(()=>{__nccwpck_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})();(()=>{__nccwpck_require__.r=e=>{if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(e,"__esModule",{value:true})}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r={};__nccwpck_require__.r(r);__nccwpck_require__.d(r,{TestreamVitestReporter:()=>TestreamVitestReporter,default:()=>TestreamVitestReporter});var o=__nccwpck_require__(943);var n=__nccwpck_require__(928);var s=__nccwpck_require__(322);function mapStatus(e){switch(e){case"passed":return"passed";case"failed":return"failed";case"skipped":return"skipped";default:return"pending"}}function buildSuiteName(e){const t=[];let r=e.parent;while(r&&r.type==="suite"){t.unshift(r.name);r=r.parent}return t.join(" > ")}function collectTests(e){const t=[];for(const r of e){if(r.type==="test"){t.push(r)}else if(r.type==="suite"){t.push(...collectTests(r.children))}}return t}function buildCTRFReport(e,t,r){const o=Date.now();const n=[];const s=new Set;for(const o of e){const e=collectTests(o.children);for(const o of e){const e=o.result();const i=o.diagnostic();const a=e.state;const c=mapStatus(a);const l=Math.round(i?.duration??0);const u=i?.startTime??r;const d=u+l;const p=i?.retryCount??0;const f=i?.flaky??false;const m=buildSuiteName(o);if(m){s.add(m)}let h;let _;const b=e.errors;if(b&&b.length>0){const e=b[0];h=e.message;const t=e.stackTrace??e.stack;_=typeof t==="string"?t:undefined}const y={name:o.name,status:c,duration:l,start:u,stop:d,rawStatus:a,tags:[],type:t.testType||"unit",filePath:o.module.moduleId,retries:p,flaky:f,steps:[],suite:m||undefined,stdout:[],stderr:[],message:h,trace:_};n.push(y)}}const i={tests:n.length,passed:n.filter((e=>e.status==="passed")).length,failed:n.filter((e=>e.status==="failed")).length,skipped:n.filter((e=>e.status==="skipped")).length,pending:n.filter((e=>e.status==="pending")).length,other:n.filter((e=>e.status==="other")).length,suites:s.size,start:r,stop:o};const a={reportFormat:"CTRF",specVersion:"0.0.1",timestamp:new Date(r).toISOString(),generatedBy:"@testream/vitest-reporter",extra:{branch:t.branch,commitSha:t.commitSha},results:{tool:{name:"vitest"},summary:i,tests:n,environment:{...t.testEnvironment?{testEnvironment:t.testEnvironment}:{},...t.appName?{appName:t.appName}:{},...t.appVersion?{appVersion:t.appVersion}:{},...t.buildName?{buildName:t.buildName}:{},...t.buildNumber?{buildNumber:t.buildNumber}:{},...t.buildUrl?{buildUrl:t.buildUrl}:{}}}};return a}class ReportUploader{constructor(e){this.config={apiKey:e.apiKey,branch:e.branch,commitSha:e.commitSha,repositoryUrl:e.repositoryUrl,failOnUploadError:e.failOnUploadError??false,buildName:e.buildName,buildNumber:e.buildNumber,buildUrl:e.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async uploadReport(e){try{const t=await(0,s.uploadTestRun)({report:e,apiKey:this.config.apiKey,commitSha:this.config.commitSha,branch:this.config.branch,repositoryUrl:this.config.repositoryUrl,buildName:this.config.buildName,buildNumber:this.config.buildNumber,buildUrl:this.config.buildUrl,testEnvironment:this.config.testEnvironment,appName:this.config.appName,appVersion:this.config.appVersion,testType:this.config.testType});if(!t.success){if(this.config.failOnUploadError){throw new Error(t.error||"Upload failed")}return t}let r=0;if(!t.alreadyExists&&t.testRunId&&t.testResults){const o=(0,s.mapAttachmentsToTestResults)(e.results.tests,t.testResults);if(o.length>0){r=await(0,s.uploadArtifacts)({reportId:t.reportId,apiKey:this.config.apiKey,testResults:o})}}return{...t,artifactCount:r}}catch(t){const r=t instanceof Error?t.message:String(t);if(this.config.failOnUploadError){throw new Error(`Failed to upload report: ${r}`)}return{success:false,reportId:(0,s.ensureReportId)(e),error:r}}}}class TestreamVitestReporter{constructor(e){this.uploader=null;this.startTimestamp=0;if(!e.apiKey){throw new Error("TestreamVitestReporter: apiKey is required")}this.config={uploadEnabled:true,outputFile:"ctrf-report.json",outputDir:"ctrf",failOnUploadError:false,testType:"unit",...e};const t=(0,s.detectCIContext)();if(!this.config.branch&&t.branch){this.config.branch=t.branch}if(!this.config.commitSha&&t.commitSha){this.config.commitSha=t.commitSha}if(!this.config.repositoryUrl&&t.repositoryUrl){this.config.repositoryUrl=t.repositoryUrl}if(!this.config.buildNumber&&t.buildNumber){this.config.buildNumber=t.buildNumber}if(!this.config.buildUrl&&t.buildUrl){this.config.buildUrl=t.buildUrl}this.reportPath=n.join(this.config.outputDir,this.config.outputFile);if(this.config.uploadEnabled){this.uploader=new ReportUploader(this.config)}}onTestRunStart(e){this.startTimestamp=Date.now();console.log("");console.log("=".repeat(60));console.log("Vitest Testream Reporter");console.log("=".repeat(60));if(this.config.uploadEnabled){if(this.config.branch)console.log(`Branch: ${this.config.branch}`);if(this.config.commitSha)console.log(`Commit: ${this.config.commitSha.substring(0,7)}`);if(this.config.repositoryUrl)console.log(`Repository: ${this.config.repositoryUrl}`)}else{console.log("Upload: Disabled")}console.log(`Report: ${this.reportPath}`);console.log("=".repeat(60));console.log("")}async onTestRunEnd(e,t,r){const n=buildCTRFReport(e,this.config,this.startTimestamp);try{await o.mkdir(this.config.outputDir,{recursive:true});await o.writeFile(this.reportPath,JSON.stringify(n,null,2))}catch(e){const t=e instanceof Error?e.message:String(e);console.error(`Failed to write CTRF report: ${t}`)}if(!this.config.uploadEnabled||!this.uploader){console.log("");console.log("CTRF report generated");console.log(` ${this.reportPath}`);return}console.log("");console.log("=".repeat(60));console.log("Uploading Test Results");console.log("=".repeat(60));try{const e=await this.uploader.uploadReport(n);if(e.success){console.log("=".repeat(60));console.log("Upload Complete");console.log("=".repeat(60));console.log("")}else{console.error("Upload completed with errors");if(e.error){console.error(`Error: ${e.error}`)}if(e.errorCode){console.error(`Error code: ${e.errorCode}`)}console.error("")}}catch(e){const t=e instanceof Error?e.message:String(e);console.error("");console.error("=".repeat(60));console.error("Upload Failed");console.error("=".repeat(60));console.error(`Error: ${t}`);console.error("");if(this.config.failOnUploadError){throw e}}}}const i=null&&TestreamVitestReporter;module.exports=r})();
|
|
1
|
+
(()=>{"use strict";var e={406:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true});t.detectCIContext=detectCIContext;function removePrefix(e,t){if(!e){return undefined}return e.startsWith(t)?e.slice(t.length):e}function readEnvironment(){const e=globalThis;return e.process?.env??{}}function buildGithubRepositoryUrl(e){if(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY){return undefined}return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}`}function buildGithubBuildUrl(e){if(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY||!e.GITHUB_RUN_ID){return undefined}return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`}function detectGitHubBranch(e){if(e.GITHUB_HEAD_REF){return e.GITHUB_HEAD_REF}if(e.GITHUB_REF?.startsWith("refs/heads/")){return e.GITHUB_REF_NAME??removePrefix(e.GITHUB_REF,"refs/heads/")}return undefined}function detectGitHubActionsContext(e){return{branch:detectGitHubBranch(e),commitSha:e.GITHUB_SHA,repositoryUrl:buildGithubRepositoryUrl(e),buildNumber:e.GITHUB_RUN_NUMBER,buildUrl:buildGithubBuildUrl(e)}}function detectGitLabContext(e){return{branch:e.CI_COMMIT_BRANCH||e.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:e.CI_COMMIT_SHA,repositoryUrl:e.CI_PROJECT_URL,buildNumber:e.CI_PIPELINE_IID,buildUrl:e.CI_PIPELINE_URL}}function detectAzurePipelinesContext(e){return{branch:removePrefix(e.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:e.BUILD_SOURCEVERSION,repositoryUrl:e.BUILD_REPOSITORY_URI,buildNumber:e.BUILD_BUILDNUMBER,buildUrl:e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&e.SYSTEM_TEAMPROJECT&&e.BUILD_BUILDID?`${e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${e.SYSTEM_TEAMPROJECT}/_build/results?buildId=${e.BUILD_BUILDID}`:undefined}}function detectCircleCIContext(e){return{branch:e.CIRCLE_BRANCH,commitSha:e.CIRCLE_SHA1,repositoryUrl:e.CIRCLE_REPOSITORY_URL,buildNumber:e.CIRCLE_BUILD_NUM,buildUrl:e.CIRCLE_BUILD_URL}}function detectJenkinsContext(e){return{branch:removePrefix(e.GIT_BRANCH,"origin/"),commitSha:e.GIT_COMMIT,repositoryUrl:e.GIT_URL,buildNumber:e.BUILD_NUMBER,buildUrl:e.BUILD_URL}}function detectBitbucketContext(e){return{branch:e.BITBUCKET_BRANCH,commitSha:e.BITBUCKET_COMMIT,repositoryUrl:e.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:e.BITBUCKET_BUILD_NUMBER,buildUrl:e.BITBUCKET_REPO_FULL_NAME&&e.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${e.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${e.BITBUCKET_BUILD_NUMBER}`:undefined}}const r=[{isMatch:e=>e.GITHUB_ACTIONS==="true",detect:detectGitHubActionsContext},{isMatch:e=>e.GITLAB_CI==="true",detect:detectGitLabContext},{isMatch:e=>e.TF_BUILD==="True",detect:detectAzurePipelinesContext},{isMatch:e=>e.CIRCLECI==="true",detect:detectCircleCIContext},{isMatch:e=>Boolean(e.JENKINS_URL),detect:detectJenkinsContext},{isMatch:e=>Boolean(e.BITBUCKET_BUILD_NUMBER),detect:detectBitbucketContext}];function detectCIContext(){const e=readEnvironment();for(const t of r){if(t.isMatch(e)){return t.detect(e)}}return{}}},827:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true})},322:function(e,t,r){var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var o=Object.getOwnPropertyDescriptor(t,r);if(!o||("get"in o?!t.__esModule:o.writable||o.configurable)){o={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,o)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var o=this&&this.__exportStar||function(e,t){for(var r in e)if(r!=="default"&&!Object.prototype.hasOwnProperty.call(t,r))n(t,e,r)};Object.defineProperty(t,"__esModule",{value:true});t.createTestLocationCollector=t.enrichReportWithJsTestNameSourceSnippets=t.resolveSourceSnippetOptions=t.enrichReportWithSourceSnippets=t.ensureReportId=t.mapAttachmentsToTestResults=t.uploadArtifacts=t.uploadTestRun=t.detectCIContext=void 0;o(r(827),t);var i=r(406);Object.defineProperty(t,"detectCIContext",{enumerable:true,get:function(){return i.detectCIContext}});var s=r(969);Object.defineProperty(t,"uploadTestRun",{enumerable:true,get:function(){return s.uploadTestRun}});Object.defineProperty(t,"uploadArtifacts",{enumerable:true,get:function(){return s.uploadArtifacts}});Object.defineProperty(t,"mapAttachmentsToTestResults",{enumerable:true,get:function(){return s.mapAttachmentsToTestResults}});Object.defineProperty(t,"ensureReportId",{enumerable:true,get:function(){return s.ensureReportId}});var a=r(304);Object.defineProperty(t,"enrichReportWithSourceSnippets",{enumerable:true,get:function(){return a.enrichReportWithSourceSnippets}});Object.defineProperty(t,"resolveSourceSnippetOptions",{enumerable:true,get:function(){return a.resolveSourceSnippetOptions}});var c=r(913);Object.defineProperty(t,"enrichReportWithJsTestNameSourceSnippets",{enumerable:true,get:function(){return c.enrichReportWithJsTestNameSourceSnippets}});var l=r(293);Object.defineProperty(t,"createTestLocationCollector",{enumerable:true,get:function(){return l.createTestLocationCollector}})},913:function(e,t,r){var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:true});t.enrichReportWithJsTestNameSourceSnippets=enrichReportWithJsTestNameSourceSnippets;const o=r(455);const i=n(r(760));const s=r(304);const a=3;const c=/\b(describe|it|test)(?:\.(only|skip))?\s*\(\s*(['"`])/g;async function enrichReportWithJsTestNameSourceSnippets(e,t){const r=(0,s.resolveSourceSnippetOptions)(t);const n=new Map;await Promise.all(e.results.tests.map((async e=>{if(e.snippet||!e.filePath){return}const t=i.default.resolve(r.sourceRoot,e.filePath);if(!isInsideSourceRoot(t,r.sourceRoot)){return}const o=await getCachedJsTestCandidates(t,n);if(!o){return}const s=rankCandidatesForTest(e,o).slice(0,a);if(s.length===0){return}e.line??(e.line=s[0].line);e.snippet=formatCandidateSnippet(s,r)})))}function getCachedJsTestCandidates(e,t){let r=t.get(e);if(!r){r=(0,o.readFile)(e,"utf-8").then((e=>scanJsTestCandidates(e))).catch((()=>undefined));t.set(e,r)}return r}function scanJsTestCandidates(e){const t=buildLineOffsets(e);const r=scanJsTestBlocks(e,t);const n=r.filter((e=>e.kind==="describe"));return r.filter((e=>e.kind==="test")).map((e=>{const t=n.filter((t=>t.startIndex<e.startIndex&&t.endIndex>=e.endIndex)).sort(((e,t)=>e.startIndex-t.startIndex)).map((e=>e.title));return{title:e.title,describeTitles:t,fullName:[...t,e.title].join(" ").trim(),line:e.startLine,snippet:e.snippet}}))}function scanJsTestBlocks(e,t){const r=[];c.lastIndex=0;let n;while((n=c.exec(e))!==null){if(isCommentedLine(e,n.index)){continue}const o=readQuotedTitle(e,n.index+n[0].length,n[3]);if(!o){continue}const i=skipWhitespaceAndFindComma(e,o.endIndex+1);if(i==null){continue}const s=n[1]==="describe"?"describe":"test";const a=n.index;const c=findCallbackOpenBrace(e,i+1);if(c==null){continue}const l=findMatchingBrace(e,c);if(l==null){continue}const u=findSnippetEndIndex(e,l);const d=e.slice(a,u).trim();if(!d){continue}r.push({kind:s,title:o.value.trim(),startIndex:a,endIndex:u,startLine:getLineNumber(t,a),snippet:d})}return r}function rankCandidatesForTest(e,t){const r=normalizeWhitespace(e.name);const n=normalizeDescribeChain(e.suite);const o=t.filter((e=>normalizeWhitespace(e.fullName)===r));if(o.length>0){return o}if(n){const e=t.filter((e=>normalizeWhitespace(e.title)===r&&normalizeWhitespace(e.describeTitles.join(" "))===n));if(e.length>0){return e}}const i=t.filter((e=>normalizeWhitespace(e.title)===r));if(i.length>0){return i}return t.filter((e=>{const t=normalizeWhitespace(e.title);if(!r.endsWith(t)){return false}const n=r.slice(0,r.length-t.length).trim();return n.length>0&&normalizeWhitespace(e.describeTitles.join(" "))===n}))}function formatCandidateSnippet(e,t){const r=e.length===1?e[0].snippet:e.map(((e,t)=>`Candidate ${t+1} (line ${e.line})\n${e.snippet}`)).join("\n\n");const n=r.split(/\r?\n/).slice(0,t.maxLines).join("\n").trim();if(n.length<=t.maxChars){return n}return n.slice(0,t.maxChars)}function findCallbackOpenBrace(e,t){for(let r=t;r<e.length;r++){const t=e[r];if(t==="'"||t==='"'||t==="`"){r=skipQuotedString(e,r);continue}if(t==="/"&&e[r+1]==="/"){r=skipLineComment(e,r+2);continue}if(t==="/"&&e[r+1]==="*"){r=skipBlockComment(e,r+2);continue}if(e.startsWith("=>",r)){return findNextBlockBrace(e,r+2)}if(startsWithWord(e,r,"function")){return findNextBlockBrace(e,r+"function".length)}if(t===";"){return undefined}}return undefined}function findNextBlockBrace(e,t){for(let r=t;r<e.length;r++){const t=e[r];if(t==="'"||t==='"'||t==="`"){r=skipQuotedString(e,r);continue}if(t==="{"){return r}if(t==="\n"&&looksLikeLineTerminator(e,r+1)){return undefined}}return undefined}function findMatchingBrace(e,t){let r=0;for(let n=t;n<e.length;n++){const t=e[n];if(t==="'"||t==='"'||t==="`"){n=skipQuotedString(e,n);continue}if(t==="/"&&e[n+1]==="/"){n=skipLineComment(e,n+2);continue}if(t==="/"&&e[n+1]==="*"){n=skipBlockComment(e,n+2);continue}if(t==="{"){r++;continue}if(t==="}"){r--;if(r===0){return n}}}return undefined}function readQuotedTitle(e,t,r){let n="";for(let o=t;o<e.length;o++){const t=e[o];if(t==="\\"){n+=t;if(o+1<e.length){o++;n+=e[o]}continue}if(t===r){return{value:n,endIndex:o}}if(t==="\n"&&r!=="`"){return undefined}n+=t}return undefined}function skipWhitespaceAndFindComma(e,t){for(let r=t;r<e.length;r++){const t=e[r];if(/\s/.test(t)){continue}return t===","?r:undefined}return undefined}function findSnippetEndIndex(e,t){let r=t+1;while(r<e.length){const t=e[r];if(t==="\r"||t==="\n"){return r}r++}return e.length}function skipQuotedString(e,t){const r=e[t];for(let n=t+1;n<e.length;n++){const t=e[n];if(t==="\\"){n++;continue}if(t===r){return n}}return e.length-1}function skipLineComment(e,t){for(let r=t;r<e.length;r++){if(e[r]==="\n"){return r}}return e.length-1}function skipBlockComment(e,t){for(let r=t;r<e.length-1;r++){if(e[r]==="*"&&e[r+1]==="/"){return r+1}}return e.length-1}function looksLikeLineTerminator(e,t){for(let r=t;r<e.length;r++){const t=e[r];if(!/\s/.test(t)){return t!=="."&&t!=="("}}return false}function buildLineOffsets(e){const t=[0];for(let r=0;r<e.length;r++){if(e[r]==="\n"){t.push(r+1)}}return t}function getLineNumber(e,t){let r=0;for(let n=0;n<e.length;n++){if(e[n]>t){break}r=n}return r+1}function isCommentedLine(e,t){const r=e.lastIndexOf("\n",t-1)+1;const n=e.slice(r,t).trimStart();return n.startsWith("//")||n.startsWith("*")}function startsWithWord(e,t,r){if(!e.startsWith(r,t)){return false}const n=t===0?"":e[t-1];const o=e[t+r.length]??"";return!isIdentifierChar(n)&&!isIdentifierChar(o)}function isIdentifierChar(e){return/[A-Za-z0-9_$]/.test(e)}function normalizeWhitespace(e){return(e??"").trim().replace(/\s+/g," ")}function normalizeDescribeChain(e){if(!e){return""}const t=e.split(">").map((e=>e.trim())).filter(Boolean);if(t.length===0){return""}const r=t[0].includes(".");const n=r?t.slice(1):t;return normalizeWhitespace(n.join(" "))}function isInsideSourceRoot(e,t){const r=i.default.relative(t,e);return r.length>0&&!r.startsWith("..")&&!i.default.isAbsolute(r)}},304:function(e,t,r){var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:true});t.resolveSourceSnippetOptions=resolveSourceSnippetOptions;t.enrichReportWithSourceSnippets=enrichReportWithSourceSnippets;const o=r(455);const i=n(r(760));const s=2e3;const a=40;function resolveSourceSnippetOptions(e){return{sourceRoot:i.default.resolve(e?.sourceRoot??process.cwd()),maxChars:normalizePositiveInt(e?.maxChars,s),maxLines:normalizePositiveInt(e?.maxLines,a)}}async function enrichReportWithSourceSnippets(e,t){const r=resolveSourceSnippetOptions(t);const n=new Map;await Promise.all(e.results.tests.map((async e=>{if(e.snippet||!e.filePath||!e.line){return}const t=await tryExtractSnippet(e,r,n);if(t){e.snippet=t}})))}async function tryExtractSnippet(e,t,r){const n=i.default.resolve(t.sourceRoot,e.filePath);if(!isInsideSourceRoot(n,t.sourceRoot)){return undefined}const o=await getCachedFileContent(n,r);if(!o){return undefined}return extractEnclosingTestBlock(o,e.line,t)}function getCachedFileContent(e,t){let r=t.get(e);if(!r){r=(0,o.readFile)(e,"utf-8").catch((()=>undefined));t.set(e,r)}return r}function extractEnclosingTestBlock(e,t,r){const n=e.split(/\r?\n/);const o=Math.max(0,Math.min(n.length-1,t-1));const i=findTestStart(n,o);if(i==null){return undefined}const s=[];let a=0;let c=false;for(let e=i;e<n.length&&s.length<r.maxLines;e++){const t=n[e];s.push(t);for(const e of t){if(e==="{"){a++;c=true}else if(e==="}"){a--}}if(c&&a<=0&&isJsTestBlockTerminator(t)){break}}const l=s.join("\n").trim();if(!l){return undefined}return l.length<=r.maxChars?l:l.slice(0,r.maxChars)}function findTestStart(e,t){for(let r=t;r>=0;r--){if(/\b(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/.test(e[r])){return r}}return undefined}function isJsTestBlockTerminator(e){let t=e.length-1;while(t>=0&&/\s/.test(e[t])){t--}if(t>=0&&e[t]===";"){t--}while(t>=0&&/\s/.test(e[t])){t--}if(t<1||e[t]!==")"){return false}t--;while(t>=0&&/\s/.test(e[t])){t--}return t>=0&&e[t]==="}"}function isInsideSourceRoot(e,t){const r=i.default.relative(t,e);return r.length>0&&!r.startsWith("..")&&!i.default.isAbsolute(r)}function normalizePositiveInt(e,t){return typeof e==="number"&&Number.isInteger(e)&&e>0?e:t}},293:(e,t)=>{Object.defineProperty(t,"__esModule",{value:true});t.createTestLocationCollector=createTestLocationCollector;function createTestLocationCollector(){const e=new Map;return{add(t,r){if(!t||!isValidLocation(r)){return}const n=e.get(t)??[];n.push(r);e.set(t,n)},applyToReport(t){const r=new Map([...e.entries()].map((([e,t])=>[e,[...t]])));for(const e of t.results.tests){const t=r.get(e.name);const n=t?.shift();if(!n){continue}e.filePath??(e.filePath=n.filePath);e.line??(e.line=n.line)}}}}function isValidLocation(e){return Boolean(e.filePath)&&Number.isInteger(e.line)&&e.line>0}},969:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:true});t.ensureReportId=ensureReportId;t.uploadTestRun=uploadTestRun;t.mapAttachmentsToTestResults=mapAttachmentsToTestResults;t.uploadArtifacts=uploadArtifacts;const n=r(406);const o=r(304);const i="https://api.testream.app";function ensureReportId(e){if(typeof e.reportId==="string"&&e.reportId.trim().length>0){return e.reportId}const t=crypto.randomUUID();e.reportId=t;return t}function resolveApiUrl(e){const t=normalizeApiUrl(e);if(t){return t}const r=getEnvApiUrl();if(r){return r}return i}function getEnvApiUrl(){if(typeof process==="undefined"||!process?.env){return undefined}return normalizeApiUrl(process.env.TESTREAM_API_URL)}function normalizeApiUrl(e){if(!e){return undefined}const t=e.trim();if(!t){return undefined}let r=t;while(r.endsWith("/")){r=r.slice(0,-1)}return r}function isReportAlreadyExistsConflict(e){return e.errorCode==="report_already_exists"}function formatUploadError(e){const t=e.detail||e.title||e.rawBody||"Unknown error";const r=e.errorCode?`, code=${e.errorCode}`:"";return`Upload failed (HTTP ${e.statusCode}${r}): ${t}`}async function parseHttpError(e){const t=await e.text();const r=e.headers.get("content-type")||"";if(r.toLowerCase().includes("json")&&t.trim().length>0){try{const r=JSON.parse(t);return{statusCode:e.status,title:r.title,detail:r.detail||r.details||r.error,errorCode:r.errorCode,rawBody:t}}catch{}}return{statusCode:e.status,rawBody:t}}function resolveUploadContext(e){const t=(0,n.detectCIContext)();return{commitSha:e.commitSha??t.commitSha,branch:e.branch??t.branch,repositoryUrl:e.repositoryUrl??t.repositoryUrl,buildName:e.buildName,buildNumber:e.buildNumber??t.buildNumber,buildUrl:e.buildUrl??t.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async function uploadTestRun(e){const{report:t,apiKey:r}=e;const n=resolveApiUrl(e.apiUrl);const i=ensureReportId(t);const s=resolveUploadContext(e);await(0,o.enrichReportWithSourceSnippets)(t);const a={report:t,reportId:i,...s};console.log("Uploading test results...");let c;try{c=await fetch(`${n}/api/v1/ingest`,{method:"POST",headers:{"X-API-KEY":r,"Content-Type":"application/json"},body:JSON.stringify(a)})}catch(e){const t=e instanceof Error?e.message:String(e);const r=`Connection failed: ${t}`;console.error(r);return{success:false,reportId:i,error:r}}if(!c.ok){const e=await parseHttpError(c);if(c.status===409&&isReportAlreadyExistsConflict(e)){console.warn("Report already exists (workflow may have been re-run)");return{success:true,reportId:i,summary:{passed:t.results.summary.passed,failed:t.results.summary.failed,skipped:t.results.summary.skipped,total:t.results.summary.tests},alreadyExists:true,statusCode:e.statusCode,errorCode:e.errorCode}}const r=formatUploadError(e);console.error(r);return{success:false,reportId:i,error:r,statusCode:e.statusCode,errorCode:e.errorCode,errorDetail:e.detail||e.rawBody}}const l=await c.json();console.log(`✓ Test results uploaded successfully`);console.log(` Report ID: ${l.reportId}`);console.log(` Test Run ID: ${l.testRunId}`);console.log(` Tests: ${l.summary.passed}/${l.summary.total} passed`);return{success:true,reportId:l.reportId,testRunId:l.testRunId,summary:{passed:l.summary.passed,failed:l.summary.failed,skipped:l.summary.skipped,total:l.summary.total},testResults:l.testResults}}function mapAttachmentsToTestResults(e,t){const r=new Map;for(const e of t){const t=r.get(e.name)??[];t.push(e.id);r.set(e.name,t)}const n=[];for(const t of e){const e=r.get(t.name);const o=e?.shift();if(!t.attachments||t.attachments.length===0){continue}if(!o){console.warn(`Skipping artifact upload: could not match test result for "${t.name}"`);continue}n.push({testResultId:o,attachments:t.attachments})}return n}async function uploadArtifacts(e){const{reportId:t,apiKey:r,testResults:n}=e;const o=resolveApiUrl(e.apiUrl);let i=0;for(const e of n){for(const n of e.attachments){try{const s=await uploadSingleArtifact({testResultId:e.testResultId,attachment:n,reportId:t,apiKey:r,apiUrl:o});if(s)i++}catch(e){const t=e instanceof Error?e.message:String(e);console.error(`Failed to upload artifact ${n.name}: ${t}`)}}}if(i>0){console.log(`✓ Uploaded ${i} artifact(s)`)}return i}async function uploadSingleArtifact(e){const{testResultId:t,attachment:n,reportId:o,apiKey:i,apiUrl:s}=e;const a=await Promise.resolve().then(r.t.bind(r,455,23));const c=await Promise.resolve().then(r.t.bind(r,760,23));const l=c.resolve(n.path);try{await a.access(l)}catch{console.warn(`Artifact not found: ${c.basename(l)}`);return false}let u;let d;const p=c.basename(l);const f=n.contentType||"application/octet-stream";try{u=await a.readFile(l);d=u.byteLength}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Failed to read file: ${t}`)}try{return await uploadWithPresignedUrl({testResultId:t,reportId:o,apiKey:i,apiUrl:s,attachmentName:n.name,fileName:p,contentType:f,sizeBytes:d,fileBuffer:u})}catch(e){if(!(e instanceof LegacyUploadRequiredError)){throw e}return await uploadWithLegacyEndpoint({testResultId:t,attachmentName:n.name,reportId:o,apiKey:i,apiUrl:s,fileName:p,contentType:f,fileBuffer:u})}}class LegacyUploadRequiredError extends Error{constructor(){super("Legacy upload endpoint required")}}async function uploadWithPresignedUrl(e){const{testResultId:t,reportId:r,apiKey:n,apiUrl:o,attachmentName:i,fileName:s,contentType:a,sizeBytes:c,fileBuffer:l}=e;const u={testResultId:t,ctrfAttachmentName:i,fileName:s,contentType:a,sizeBytes:c};const d=await fetch(`${o}/api/v1/artifacts/${r}/upload-url`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(u)});if(shouldFallbackToLegacyUpload(d.status)){throw new LegacyUploadRequiredError}if(!d.ok){const e=await d.text();throw new Error(`Failed to create direct upload URL (HTTP ${d.status}): ${e}`)}const p=await d.json();const f={...p.requiredHeaders};if(!hasHeaderIgnoreCase(f,"Content-Type")){f["Content-Type"]=a}const h=await fetch(p.uploadUrl,{method:"PUT",headers:f,body:l});if(!h.ok){const e=await h.text();throw new Error(`Direct artifact upload failed (HTTP ${h.status}): ${e}`)}const m={testResultId:t,ctrfAttachmentName:i,fileName:s,contentType:a,sizeBytes:c,storageKey:p.storageKey};const g=await fetch(`${o}/api/v1/artifacts/${r}/complete`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(m)});if(!g.ok){const e=await g.text();throw new Error(`Failed to finalize artifact upload (HTTP ${g.status}): ${e}`)}return true}async function uploadWithLegacyEndpoint(e){const{testResultId:t,attachmentName:r,reportId:n,apiKey:o,apiUrl:i,fileName:s,contentType:a,fileBuffer:c}=e;const l=new Blob([new Uint8Array(c)],{type:a});const u=new FormData;u.append("testResultId",t);u.append("ctrfAttachmentName",r);u.append("file",l,s);const d=await fetch(`${i}/api/v1/artifacts/${n}`,{method:"POST",headers:{"X-API-KEY":o},body:u});if(!d.ok){const e=await d.text();throw new Error(`Legacy artifact upload failed (HTTP ${d.status}): ${e}`)}return true}function shouldFallbackToLegacyUpload(e){return e===404||e===405||e===501}function hasHeaderIgnoreCase(e,t){const r=t.toLowerCase();return Object.keys(e).some((e=>e.toLowerCase()===r))}},455:e=>{e.exports=require("node:fs/promises")},760:e=>{e.exports=require("node:path")}};var t={};function __nccwpck_require__(r){var n=t[r];if(n!==undefined){return n.exports}var o=t[r]={exports:{}};var i=true;try{e[r].call(o.exports,o,o.exports,__nccwpck_require__);i=false}finally{if(i)delete t[r]}return o.exports}(()=>{var e=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;var t;__nccwpck_require__.t=function(r,n){if(n&1)r=this(r);if(n&8)return r;if(typeof r==="object"&&r){if(n&4&&r.__esModule)return r;if(n&16&&typeof r.then==="function")return r}var o=Object.create(null);__nccwpck_require__.r(o);var i={};t=t||[null,e({}),e([]),e(e)];for(var s=n&2&&r;typeof s=="object"&&!~t.indexOf(s);s=e(s)){Object.getOwnPropertyNames(s).forEach((e=>i[e]=()=>r[e]))}i["default"]=()=>r;__nccwpck_require__.d(o,i);return o}})();(()=>{__nccwpck_require__.d=(e,t)=>{for(var r in t){if(__nccwpck_require__.o(t,r)&&!__nccwpck_require__.o(e,r)){Object.defineProperty(e,r,{enumerable:true,get:t[r]})}}}})();(()=>{__nccwpck_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})();(()=>{__nccwpck_require__.r=e=>{if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(e,"__esModule",{value:true})}})();if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r={};__nccwpck_require__.r(r);__nccwpck_require__.d(r,{TestreamVitestReporter:()=>TestreamVitestReporter,default:()=>TestreamVitestReporter});var n=__nccwpck_require__(455);var o=__nccwpck_require__(760);var i=__nccwpck_require__(322);function mapStatus(e){switch(e){case"passed":return"passed";case"failed":return"failed";case"skipped":return"skipped";default:return"pending"}}function buildSuiteName(e){const t=[];let r=e.parent;while(r?.type==="suite"){t.unshift(r.name);r=r.parent}return t.join(" > ")}function collectTests(e){const t=[];for(const r of e){if(r.type==="test"){t.push(r)}else if(r.type==="suite"){t.push(...collectTests(r.children))}}return t}function extractErrorInfo(e){if(!e||e.length===0)return{message:undefined,trace:undefined};const t=e[0];const r=t?.message;const n=t?.stackTrace??t?.stack;const o=typeof n==="string"?n:undefined;return{message:r,trace:o}}function createCtrfTest(e,t,r){const n=e.result();const o=e.diagnostic();const i=n.state;const s=mapStatus(i);const a=Math.round(o?.duration??0);const c=o?.startTime??r;const l=c+a;const u=o?.retryCount??0;const d=o?.flaky??false;const p=buildSuiteName(e);const{message:f,trace:h}=extractErrorInfo(n.errors);const m={name:e.name,status:s,duration:a,start:c,stop:l,rawStatus:i,tags:[],type:t.testType||"unit",filePath:e.module.moduleId,line:e.location?.line,retries:u,flaky:d,steps:[],suite:p||undefined,stdout:[],stderr:[],message:f,trace:h};return{ctrfTest:m,suiteName:p}}function buildCTRFReport(e,t,r){const n=Date.now();const o=[];const i=new Set;for(const n of e){const e=collectTests(n.children);for(const n of e){const{ctrfTest:e,suiteName:s}=createCtrfTest(n,t,r);if(s)i.add(s);o.push(e)}}const s={tests:o.length,passed:o.filter((e=>e.status==="passed")).length,failed:o.filter((e=>e.status==="failed")).length,skipped:o.filter((e=>e.status==="skipped")).length,pending:o.filter((e=>e.status==="pending")).length,other:o.filter((e=>e.status==="other")).length,suites:i.size,start:r,stop:n};const a={reportFormat:"CTRF",specVersion:"0.0.1",timestamp:new Date(r).toISOString(),generatedBy:"@testream/vitest-reporter",extra:{branch:t.branch,commitSha:t.commitSha},results:{tool:{name:"vitest"},summary:s,tests:o,environment:{...t.testEnvironment?{testEnvironment:t.testEnvironment}:{},...t.appName?{appName:t.appName}:{},...t.appVersion?{appVersion:t.appVersion}:{},...t.buildName?{buildName:t.buildName}:{},...t.buildNumber?{buildNumber:t.buildNumber}:{},...t.buildUrl?{buildUrl:t.buildUrl}:{}}}};return a}class ReportUploader{constructor(e){if(!e.apiKey){throw new Error("ReportUploader requires an apiKey")}this.config={apiKey:e.apiKey,branch:e.branch,commitSha:e.commitSha,repositoryUrl:e.repositoryUrl,failOnUploadError:e.failOnUploadError??false,buildName:e.buildName,buildNumber:e.buildNumber,buildUrl:e.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async uploadReport(e){try{const t=await(0,i.uploadTestRun)({report:e,apiKey:this.config.apiKey,commitSha:this.config.commitSha,branch:this.config.branch,repositoryUrl:this.config.repositoryUrl,buildName:this.config.buildName,buildNumber:this.config.buildNumber,buildUrl:this.config.buildUrl,testEnvironment:this.config.testEnvironment,appName:this.config.appName,appVersion:this.config.appVersion,testType:this.config.testType});if(!t.success){if(this.config.failOnUploadError){throw new Error(t.error||"Upload failed")}return t}let r=0;if(!t.alreadyExists&&t.testRunId&&t.testResults){const n=(0,i.mapAttachmentsToTestResults)(e.results.tests,t.testResults);if(n.length>0){r=await(0,i.uploadArtifacts)({reportId:t.reportId,apiKey:this.config.apiKey,testResults:n})}}return{...t,artifactCount:r}}catch(t){const r=t instanceof Error?t.message:String(t);if(this.config.failOnUploadError){throw new Error(`Failed to upload report: ${r}`)}return{success:false,reportId:(0,i.ensureReportId)(e),error:r}}}}class TestreamVitestReporter{constructor(e){this.uploader=null;this.startTimestamp=0;this.config={uploadEnabled:true,outputFile:"ctrf-report.json",outputDir:"ctrf",failOnUploadError:false,testType:"unit",...e};if(this.config.uploadEnabled&&!this.config.apiKey){throw new Error("TestreamVitestReporter: apiKey is required when upload is enabled")}const t=(0,i.detectCIContext)();if(!this.config.branch&&t.branch){this.config.branch=t.branch}if(!this.config.commitSha&&t.commitSha){this.config.commitSha=t.commitSha}if(!this.config.repositoryUrl&&t.repositoryUrl){this.config.repositoryUrl=t.repositoryUrl}if(!this.config.buildNumber&&t.buildNumber){this.config.buildNumber=t.buildNumber}if(!this.config.buildUrl&&t.buildUrl){this.config.buildUrl=t.buildUrl}this.reportPath=o.join(this.config.outputDir,this.config.outputFile);if(this.config.uploadEnabled){this.uploader=new ReportUploader(this.config)}}onInit(e){if(e.config.includeTaskLocation===true){return}e.config.includeTaskLocation=true}onTestRunStart(e){this.startTimestamp=Date.now();console.log("");console.log("=".repeat(60));console.log("Vitest Testream Reporter");console.log("=".repeat(60));if(this.config.uploadEnabled){if(this.config.branch)console.log(`Branch: ${this.config.branch}`);if(this.config.commitSha)console.log(`Commit: ${this.config.commitSha.substring(0,7)}`);if(this.config.repositoryUrl)console.log(`Repository: ${this.config.repositoryUrl}`)}else{console.log("Upload: Disabled")}console.log(`Report: ${this.reportPath}`);console.log("=".repeat(60));console.log("")}async onTestRunEnd(e,t,r){const o=buildCTRFReport(e,this.config,this.startTimestamp);await(0,i.enrichReportWithSourceSnippets)(o);try{await n.mkdir(this.config.outputDir,{recursive:true});await n.writeFile(this.reportPath,JSON.stringify(o,null,2))}catch(e){const t=e instanceof Error?e.message:String(e);console.error(`Failed to write CTRF report: ${t}`)}if(!this.config.uploadEnabled||!this.uploader){console.log("");console.log("CTRF report generated");console.log(` ${this.reportPath}`);return}console.log("");console.log("=".repeat(60));console.log("Uploading Test Results");console.log("=".repeat(60));try{const e=await this.uploader.uploadReport(o);if(e.success){console.log("=".repeat(60));console.log("Upload Complete");console.log("=".repeat(60));console.log("")}else{console.error("Upload completed with errors");if(e.error){console.error(`Error: ${e.error}`)}if(e.errorCode){console.error(`Error code: ${e.errorCode}`)}console.error("")}}catch(e){const t=e instanceof Error?e.message:String(e);console.error("");console.error("=".repeat(60));console.error("Upload Failed");console.error("=".repeat(60));console.error(`Error: ${t}`);console.error("");if(this.config.failOnUploadError){throw e}}}}const s=null&&TestreamVitestReporter;module.exports=r})();
|
package/dist/cjs/reporter.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import type { Reporter, TestModule, TestSpecification, SerializedError, TestRunEndReason } from
|
|
2
|
-
import { VitestReporterConfig } from
|
|
1
|
+
import type { Reporter, TestModule, TestSpecification, SerializedError, TestRunEndReason, Vitest } from "vitest/node";
|
|
2
|
+
import { VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Vitest Reporter that generates CTRF reports and uploads them to Testream
|
|
5
5
|
*/
|
|
6
6
|
export declare class TestreamVitestReporter implements Reporter {
|
|
7
|
-
private config;
|
|
8
|
-
private uploader;
|
|
9
|
-
private reportPath;
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly uploader;
|
|
9
|
+
private readonly reportPath;
|
|
10
10
|
private startTimestamp;
|
|
11
11
|
constructor(config: VitestReporterConfig);
|
|
12
|
+
onInit(vitest: Vitest): void;
|
|
12
13
|
onTestRunStart(_specifications: ReadonlyArray<TestSpecification>): void;
|
|
13
14
|
onTestRunEnd(testModules: ReadonlyArray<TestModule>, _unhandledErrors: ReadonlyArray<SerializedError>, _reason: TestRunEndReason): Promise<void>;
|
|
14
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,MAAM,EACP,MAAM,aAAa,CAAC;AAOrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI/C;;GAEG;AACH,qBAAa,sBAAuB,YAAW,QAAQ;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,cAAc,CAAa;gBAEvB,MAAM,EAAE,oBAAoB;IA6CxC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU5B,cAAc,CAAC,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAqBjE,YAAY,CAChB,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,gBAAgB,EAAE,aAAa,CAAC,eAAe,CAAC,EAChD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC;CAiEjB;AAED,eAAe,sBAAsB,CAAC"}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Re-export CTRF types from shared-types package
|
|
3
3
|
*/
|
|
4
|
-
export type { CTRFReport, CTRFTest, CTRFSummary, CTRFResults, CTRFAttachment, CTRFStep, } from
|
|
4
|
+
export type { CTRFReport, CTRFTest, CTRFSummary, CTRFResults, CTRFAttachment, CTRFStep, } from "@jira-test-manager/shared-types";
|
|
5
5
|
/**
|
|
6
6
|
* Re-export API types from shared-types package
|
|
7
7
|
*/
|
|
8
|
-
export type { UploadResult
|
|
8
|
+
export type { UploadResult } from "@jira-test-manager/shared-types";
|
|
9
9
|
/**
|
|
10
10
|
* Configuration options for the Vitest Testream Reporter
|
|
11
11
|
*/
|
|
12
12
|
export interface VitestReporterConfig {
|
|
13
13
|
/**
|
|
14
|
-
* API key for authentication with Testream
|
|
15
|
-
*
|
|
14
|
+
* API key for authentication with Testream.
|
|
15
|
+
* Required when uploadEnabled is true.
|
|
16
16
|
*/
|
|
17
|
-
apiKey
|
|
17
|
+
apiKey?: string;
|
|
18
18
|
/**
|
|
19
19
|
* Git branch name (auto-detected from CI environment if not provided)
|
|
20
20
|
*/
|
package/dist/cjs/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,cAAc,EACd,QAAQ,GACT,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,YAAY,
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,cAAc,EACd,QAAQ,GACT,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,YAAY,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/cjs/uploader.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { CTRFReport, UploadResult } from
|
|
2
|
-
import { VitestReporterConfig } from
|
|
1
|
+
import { CTRFReport, UploadResult } from "@jira-test-manager/shared-types";
|
|
2
|
+
import { VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Upload CTRF report and artifacts to the Testream backend API
|
|
5
5
|
*/
|
|
6
6
|
export declare class ReportUploader {
|
|
7
|
-
private config;
|
|
7
|
+
private readonly config;
|
|
8
8
|
constructor(config: VitestReporterConfig);
|
|
9
9
|
/**
|
|
10
10
|
* Upload CTRF report to the backend
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/uploader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EAKb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/jira-test-manager/jira-test-manager/packages/vitest-reporter/src/uploader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EAKb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAenB;gBAEQ,MAAM,EAAE,oBAAoB;IAqBxC;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CA4D9D"}
|
package/dist/ctrf-builder.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TestModule } from
|
|
2
|
-
import type { CTRFReport, VitestReporterConfig } from
|
|
1
|
+
import type { TestModule } from "vitest/node";
|
|
2
|
+
import type { CTRFReport, VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Build a CTRF report from Vitest TestModules
|
|
5
5
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ctrf-builder.d.ts","sourceRoot":"","sources":["../src/ctrf-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAY,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ctrf-builder.d.ts","sourceRoot":"","sources":["../src/ctrf-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAY,oBAAoB,EAAE,MAAM,SAAS,CAAC;AA4F1E;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,MAAM,EAAE,oBAAoB,EAC5B,cAAc,EAAE,MAAM,GACrB,UAAU,CA6DZ"}
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
var Q=Object.create;var H=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var et=Object.getPrototypeOf,rt=Object.prototype.hasOwnProperty;var I=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ot=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of tt(e))!rt.call(t,o)&&o!==r&&H(t,o,{get:()=>e[o],enumerable:!(s=Z(e,o))||s.enumerable});return t};var x=(t,e,r)=>(r=t!=null?Q(et(t)):{},ot(e||!t||!t.__esModule?H(r,"default",{value:t,enumerable:!0}):r,t));var G=I(F=>{"use strict";Object.defineProperty(F,"__esModule",{value:!0})});var A=I(P=>{"use strict";Object.defineProperty(P,"__esModule",{value:!0});P.detectCIContext=ht;function O(t,e){if(t)return t.startsWith(e)?t.slice(e.length):t}function st(){return globalThis.process?.env??{}}function it(t){if(!(!t.GITHUB_SERVER_URL||!t.GITHUB_REPOSITORY))return`${t.GITHUB_SERVER_URL}/${t.GITHUB_REPOSITORY}`}function nt(t){if(!(!t.GITHUB_SERVER_URL||!t.GITHUB_REPOSITORY||!t.GITHUB_RUN_ID))return`${t.GITHUB_SERVER_URL}/${t.GITHUB_REPOSITORY}/actions/runs/${t.GITHUB_RUN_ID}`}function at(t){if(t.GITHUB_HEAD_REF)return t.GITHUB_HEAD_REF;if(t.GITHUB_REF?.startsWith("refs/heads/"))return t.GITHUB_REF_NAME??O(t.GITHUB_REF,"refs/heads/")}function ct(t){return{branch:at(t),commitSha:t.GITHUB_SHA,repositoryUrl:it(t),buildNumber:t.GITHUB_RUN_NUMBER,buildUrl:nt(t)}}function lt(t){return{branch:t.CI_COMMIT_BRANCH||t.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:t.CI_COMMIT_SHA,repositoryUrl:t.CI_PROJECT_URL,buildNumber:t.CI_PIPELINE_IID,buildUrl:t.CI_PIPELINE_URL}}function ut(t){return{branch:O(t.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:t.BUILD_SOURCEVERSION,repositoryUrl:t.BUILD_REPOSITORY_URI,buildNumber:t.BUILD_BUILDNUMBER,buildUrl:t.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&t.SYSTEM_TEAMPROJECT&&t.BUILD_BUILDID?`${t.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${t.SYSTEM_TEAMPROJECT}/_build/results?buildId=${t.BUILD_BUILDID}`:void 0}}function dt(t){return{branch:t.CIRCLE_BRANCH,commitSha:t.CIRCLE_SHA1,repositoryUrl:t.CIRCLE_REPOSITORY_URL,buildNumber:t.CIRCLE_BUILD_NUM,buildUrl:t.CIRCLE_BUILD_URL}}function pt(t){return{branch:O(t.GIT_BRANCH,"origin/"),commitSha:t.GIT_COMMIT,repositoryUrl:t.GIT_URL,buildNumber:t.BUILD_NUMBER,buildUrl:t.BUILD_URL}}function ft(t){return{branch:t.BITBUCKET_BRANCH,commitSha:t.BITBUCKET_COMMIT,repositoryUrl:t.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:t.BITBUCKET_BUILD_NUMBER,buildUrl:t.BITBUCKET_REPO_FULL_NAME&&t.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${t.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${t.BITBUCKET_BUILD_NUMBER}`:void 0}}var mt=[{isMatch:t=>t.GITHUB_ACTIONS==="true",detect:ct},{isMatch:t=>t.GITLAB_CI==="true",detect:lt},{isMatch:t=>t.TF_BUILD==="True",detect:ut},{isMatch:t=>t.CIRCLECI==="true",detect:dt},{isMatch:t=>!!t.JENKINS_URL,detect:pt},{isMatch:t=>!!t.BITBUCKET_BUILD_NUMBER,detect:ft}];function ht(){let t=st();for(let e of mt)if(e.isMatch(t))return e.detect(t);return{}}});var k=I(U=>{"use strict";Object.defineProperty(U,"__esModule",{value:!0});U.ensureReportId=K;U.uploadTestRun=Et;U.mapAttachmentsToTestResults=Ct;U.uploadArtifacts=_t;var Tt=A(),Rt="https://test-manager-backend.fly.dev";function K(t){if(typeof t.reportId=="string"&&t.reportId.trim().length>0)return t.reportId;let e=crypto.randomUUID();return t.reportId=e,e}function V(t){let e=j(t);if(e)return e;let r=yt();return r||Rt}function yt(){if(!(typeof process>"u"||!process?.env))return j(process.env.TESTREAM_API_URL)}function j(t){if(!t)return;let e=t.trim();if(e)return e.replace(/\/+$/,"")}function Ut(t){return t.errorCode==="report_already_exists"}function bt(t){let e=t.detail||t.title||t.rawBody||"Unknown error",r=t.errorCode?`, code=${t.errorCode}`:"";return`Upload failed (HTTP ${t.statusCode}${r}): ${e}`}async function It(t){let e=await t.text();if((t.headers.get("content-type")||"").toLowerCase().includes("json")&&e.trim().length>0)try{let s=JSON.parse(e);return{statusCode:t.status,title:s.title,detail:s.detail||s.details||s.error,errorCode:s.errorCode,rawBody:e}}catch{}return{statusCode:t.status,rawBody:e}}function gt(t){let e=(0,Tt.detectCIContext)();return{commitSha:t.commitSha??e.commitSha,branch:t.branch??e.branch,repositoryUrl:t.repositoryUrl??e.repositoryUrl,buildName:t.buildName,buildNumber:t.buildNumber??e.buildNumber,buildUrl:t.buildUrl??e.buildUrl,testEnvironment:t.testEnvironment,appName:t.appName,appVersion:t.appVersion,testType:t.testType}}async function Et(t){let{report:e,apiKey:r}=t,s=V(t.apiUrl),o=K(e),n=gt(t),c={report:e,reportId:o,...n};console.log("Uploading test results...");let l;try{l=await fetch(`${s}/api/v1/ingest`,{method:"POST",headers:{"X-API-KEY":r,"Content-Type":"application/json"},body:JSON.stringify(c)})}catch(a){let d=`Connection failed: ${a instanceof Error?a.message:String(a)}`;return console.error(d),{success:!1,reportId:o,error:d}}if(!l.ok){let a=await It(l);if(l.status===409&&Ut(a))return console.warn("Report already exists (workflow may have been re-run)"),{success:!0,reportId:o,summary:{passed:e.results.summary.passed,failed:e.results.summary.failed,skipped:e.results.summary.skipped,total:e.results.summary.tests},alreadyExists:!0,statusCode:a.statusCode,errorCode:a.errorCode};let u=bt(a);return console.error(u),{success:!1,reportId:o,error:u,statusCode:a.statusCode,errorCode:a.errorCode,errorDetail:a.detail||a.rawBody}}let i=await l.json();return console.log("\u2713 Test results uploaded successfully"),console.log(` Report ID: ${i.reportId}`),console.log(` Test Run ID: ${i.testRunId}`),console.log(` Tests: ${i.summary.passed}/${i.summary.total} passed`),{success:!0,reportId:i.reportId,testRunId:i.testRunId,summary:{passed:i.summary.passed,failed:i.summary.failed,skipped:i.summary.skipped,total:i.summary.total},testResults:i.testResults}}function Ct(t,e){let r=new Map;for(let o of e){let n=r.get(o.name)??[];n.push(o.id),r.set(o.name,n)}let s=[];for(let o of t){let c=r.get(o.name)?.shift();if(!(!o.attachments||o.attachments.length===0)){if(!c){console.warn(`Skipping artifact upload: could not match test result for "${o.name}"`);continue}s.push({testResultId:c,attachments:o.attachments})}}return s}async function _t(t){let{reportId:e,apiKey:r,testResults:s}=t,o=V(t.apiUrl),n=0;for(let c of s)for(let l of c.attachments)try{await Nt({testResultId:c.testResultId,attachment:l,reportId:e,apiKey:r,apiUrl:o})&&n++}catch(i){let a=i instanceof Error?i.message:String(i);console.error(`Failed to upload artifact ${l.name}: ${a}`)}return n>0&&console.log(`\u2713 Uploaded ${n} artifact(s)`),n}async function Nt(t){let{testResultId:e,attachment:r,reportId:s,apiKey:o,apiUrl:n}=t,c=await import("fs/promises"),l=await import("path"),i=l.resolve(r.path);try{await c.access(i)}catch{return console.warn(`Artifact not found: ${l.basename(i)}`),!1}let a,u,d=l.basename(i),f=r.contentType||"application/octet-stream";try{a=await c.readFile(i),u=a.byteLength}catch(m){let T=m instanceof Error?m.message:String(m);throw new Error(`Failed to read file: ${T}`)}try{return await Bt({testResultId:e,reportId:s,apiKey:o,apiUrl:n,attachmentName:r.name,fileName:d,contentType:f,sizeBytes:u,fileBuffer:a})}catch(m){if(!(m instanceof g))throw m;return await St({testResultId:e,attachmentName:r.name,reportId:s,apiKey:o,apiUrl:n,fileName:d,contentType:f,fileBuffer:a})}}var g=class extends Error{constructor(){super("Legacy upload endpoint required")}};async function Bt(t){let{testResultId:e,reportId:r,apiKey:s,apiUrl:o,attachmentName:n,fileName:c,contentType:l,sizeBytes:i,fileBuffer:a}=t,u={testResultId:e,ctrfAttachmentName:n,fileName:c,contentType:l,sizeBytes:i},d=await fetch(`${o}/api/v1/artifacts/${r}/upload-url`,{method:"POST",headers:{"X-API-KEY":s,"Content-Type":"application/json"},body:JSON.stringify(u)});if(wt(d.status))throw new g;if(!d.ok){let R=await d.text();throw new Error(`Failed to create direct upload URL (HTTP ${d.status}): ${R}`)}let f=await d.json(),m={...f.requiredHeaders??{}};Ot(m,"Content-Type")||(m["Content-Type"]=l);let T=await fetch(f.uploadUrl,{method:"PUT",headers:m,body:a});if(!T.ok){let R=await T.text();throw new Error(`Direct artifact upload failed (HTTP ${T.status}): ${R}`)}let b={testResultId:e,ctrfAttachmentName:n,fileName:c,contentType:l,sizeBytes:i,storageKey:f.storageKey},y=await fetch(`${o}/api/v1/artifacts/${r}/complete`,{method:"POST",headers:{"X-API-KEY":s,"Content-Type":"application/json"},body:JSON.stringify(b)});if(!y.ok){let R=await y.text();throw new Error(`Failed to finalize artifact upload (HTTP ${y.status}): ${R}`)}return!0}async function St(t){let{testResultId:e,attachmentName:r,reportId:s,apiKey:o,apiUrl:n,fileName:c,contentType:l,fileBuffer:i}=t,a=new Blob([new Uint8Array(i)],{type:l}),u=new FormData;u.append("testResultId",e),u.append("ctrfAttachmentName",r),u.append("file",a,c);let d=await fetch(`${n}/api/v1/artifacts/${s}`,{method:"POST",headers:{"X-API-KEY":o},body:u});if(!d.ok){let f=await d.text();throw new Error(`Legacy artifact upload failed (HTTP ${d.status}): ${f}`)}return!0}function wt(t){return t===404||t===405||t===501}function Ot(t,e){let r=e.toLowerCase();return Object.keys(t).some(s=>s.toLowerCase()===r)}});var L=I(p=>{"use strict";var Pt=p&&p.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var o=Object.getOwnPropertyDescriptor(e,r);(!o||("get"in o?!e.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,o)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),At=p&&p.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&Pt(e,t,r)};Object.defineProperty(p,"__esModule",{value:!0});p.ensureReportId=p.mapAttachmentsToTestResults=p.uploadArtifacts=p.uploadTestRun=p.detectCIContext=void 0;At(G(),p);var Lt=A();Object.defineProperty(p,"detectCIContext",{enumerable:!0,get:function(){return Lt.detectCIContext}});var E=k();Object.defineProperty(p,"uploadTestRun",{enumerable:!0,get:function(){return E.uploadTestRun}});Object.defineProperty(p,"uploadArtifacts",{enumerable:!0,get:function(){return E.uploadArtifacts}});Object.defineProperty(p,"mapAttachmentsToTestResults",{enumerable:!0,get:function(){return E.mapAttachmentsToTestResults}});Object.defineProperty(p,"ensureReportId",{enumerable:!0,get:function(){return E.ensureReportId}})});var z=x(L());import*as N from"fs/promises";import*as J from"path";function Mt(t){switch(t){case"passed":return"passed";case"failed":return"failed";case"skipped":return"skipped";default:return"pending"}}function $t(t){let e=[],r=t.parent;for(;r&&r.type==="suite";)e.unshift(r.name),r=r.parent;return e.join(" > ")}function Y(t){let e=[];for(let r of t)r.type==="test"?e.push(r):r.type==="suite"&&e.push(...Y(r.children));return e}function q(t,e,r){let s=Date.now(),o=[],n=new Set;for(let i of t){let a=Y(i.children);for(let u of a){let d=u.result(),f=u.diagnostic(),m=d.state,T=Mt(m),b=Math.round(f?.duration??0),y=f?.startTime??r,R=y+b,W=f?.retryCount??0,X=f?.flaky??!1,B=$t(u);B&&n.add(B);let M,$,S=d.errors;if(S&&S.length>0){let w=S[0];M=w.message;let D=w.stackTrace??w.stack;$=typeof D=="string"?D:void 0}let v={name:u.name,status:T,duration:b,start:y,stop:R,rawStatus:m,tags:[],type:e.testType||"unit",filePath:u.module.moduleId,retries:W,flaky:X,steps:[],suite:B||void 0,stdout:[],stderr:[],message:M,trace:$};o.push(v)}}let c={tests:o.length,passed:o.filter(i=>i.status==="passed").length,failed:o.filter(i=>i.status==="failed").length,skipped:o.filter(i=>i.status==="skipped").length,pending:o.filter(i=>i.status==="pending").length,other:o.filter(i=>i.status==="other").length,suites:n.size,start:r,stop:s};return{reportFormat:"CTRF",specVersion:"0.0.1",timestamp:new Date(r).toISOString(),generatedBy:"@testream/vitest-reporter",extra:{branch:e.branch,commitSha:e.commitSha},results:{tool:{name:"vitest"},summary:c,tests:o,environment:{...e.testEnvironment?{testEnvironment:e.testEnvironment}:{},...e.appName?{appName:e.appName}:{},...e.appVersion?{appVersion:e.appVersion}:{},...e.buildName?{buildName:e.buildName}:{},...e.buildNumber?{buildNumber:e.buildNumber}:{},...e.buildUrl?{buildUrl:e.buildUrl}:{}}}}}var h=x(L()),C=class{constructor(e){this.config={apiKey:e.apiKey,branch:e.branch,commitSha:e.commitSha,repositoryUrl:e.repositoryUrl,failOnUploadError:e.failOnUploadError??!1,buildName:e.buildName,buildNumber:e.buildNumber,buildUrl:e.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async uploadReport(e){try{let r=await(0,h.uploadTestRun)({report:e,apiKey:this.config.apiKey,commitSha:this.config.commitSha,branch:this.config.branch,repositoryUrl:this.config.repositoryUrl,buildName:this.config.buildName,buildNumber:this.config.buildNumber,buildUrl:this.config.buildUrl,testEnvironment:this.config.testEnvironment,appName:this.config.appName,appVersion:this.config.appVersion,testType:this.config.testType});if(!r.success){if(this.config.failOnUploadError)throw new Error(r.error||"Upload failed");return r}let s=0;if(!r.alreadyExists&&r.testRunId&&r.testResults){let o=(0,h.mapAttachmentsToTestResults)(e.results.tests,r.testResults);o.length>0&&(s=await(0,h.uploadArtifacts)({reportId:r.reportId,apiKey:this.config.apiKey,testResults:o}))}return{...r,artifactCount:s}}catch(r){let s=r instanceof Error?r.message:String(r);if(this.config.failOnUploadError)throw new Error(`Failed to upload report: ${s}`);return{success:!1,reportId:(0,h.ensureReportId)(e),error:s}}}};var _=class{constructor(e){this.uploader=null;this.startTimestamp=0;if(!e.apiKey)throw new Error("TestreamVitestReporter: apiKey is required");this.config={uploadEnabled:!0,outputFile:"ctrf-report.json",outputDir:"ctrf",failOnUploadError:!1,testType:"unit",...e};let r=(0,z.detectCIContext)();!this.config.branch&&r.branch&&(this.config.branch=r.branch),!this.config.commitSha&&r.commitSha&&(this.config.commitSha=r.commitSha),!this.config.repositoryUrl&&r.repositoryUrl&&(this.config.repositoryUrl=r.repositoryUrl),!this.config.buildNumber&&r.buildNumber&&(this.config.buildNumber=r.buildNumber),!this.config.buildUrl&&r.buildUrl&&(this.config.buildUrl=r.buildUrl),this.reportPath=J.join(this.config.outputDir,this.config.outputFile),this.config.uploadEnabled&&(this.uploader=new C(this.config))}onTestRunStart(e){this.startTimestamp=Date.now(),console.log(""),console.log("=".repeat(60)),console.log("Vitest Testream Reporter"),console.log("=".repeat(60)),this.config.uploadEnabled?(this.config.branch&&console.log(`Branch: ${this.config.branch}`),this.config.commitSha&&console.log(`Commit: ${this.config.commitSha.substring(0,7)}`),this.config.repositoryUrl&&console.log(`Repository: ${this.config.repositoryUrl}`)):console.log("Upload: Disabled"),console.log(`Report: ${this.reportPath}`),console.log("=".repeat(60)),console.log("")}async onTestRunEnd(e,r,s){let o=q(e,this.config,this.startTimestamp);try{await N.mkdir(this.config.outputDir,{recursive:!0}),await N.writeFile(this.reportPath,JSON.stringify(o,null,2))}catch(n){let c=n instanceof Error?n.message:String(n);console.error(`Failed to write CTRF report: ${c}`)}if(!this.config.uploadEnabled||!this.uploader){console.log(""),console.log("CTRF report generated"),console.log(` ${this.reportPath}`);return}console.log(""),console.log("=".repeat(60)),console.log("Uploading Test Results"),console.log("=".repeat(60));try{let n=await this.uploader.uploadReport(o);n.success?(console.log("=".repeat(60)),console.log("Upload Complete"),console.log("=".repeat(60)),console.log("")):(console.error("Upload completed with errors"),n.error&&console.error(`Error: ${n.error}`),n.errorCode&&console.error(`Error code: ${n.errorCode}`),console.error(""))}catch(n){let c=n instanceof Error?n.message:String(n);if(console.error(""),console.error("=".repeat(60)),console.error("Upload Failed"),console.error("=".repeat(60)),console.error(`Error: ${c}`),console.error(""),this.config.failOnUploadError)throw n}}};export{_ as TestreamVitestReporter,_ as default};
|
|
1
|
+
var ue=Object.create;var j=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var _=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var R=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var fe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of le(t))!pe.call(e,i)&&i!==r&&j(e,i,{get:()=>t[i],enumerable:!(n=ce(t,i))||n.enumerable});return e};var V=(e,t,r)=>(r=e!=null?ue(de(e)):{},fe(t||!e||!e.__esModule?j(r,"default",{value:e,enumerable:!0}):r,e));var G=R(K=>{"use strict";Object.defineProperty(K,"__esModule",{value:!0})});var M=R(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.detectCIContext=Ee;function P(e,t){if(e)return e.startsWith(t)?e.slice(t.length):e}function he(){return globalThis.process?.env??{}}function me(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}`}function Te(e){if(!(!e.GITHUB_SERVER_URL||!e.GITHUB_REPOSITORY||!e.GITHUB_RUN_ID))return`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`}function ge(e){if(e.GITHUB_HEAD_REF)return e.GITHUB_HEAD_REF;if(e.GITHUB_REF?.startsWith("refs/heads/"))return e.GITHUB_REF_NAME??P(e.GITHUB_REF,"refs/heads/")}function Re(e){return{branch:ge(e),commitSha:e.GITHUB_SHA,repositoryUrl:me(e),buildNumber:e.GITHUB_RUN_NUMBER,buildUrl:Te(e)}}function be(e){return{branch:e.CI_COMMIT_BRANCH||e.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,commitSha:e.CI_COMMIT_SHA,repositoryUrl:e.CI_PROJECT_URL,buildNumber:e.CI_PIPELINE_IID,buildUrl:e.CI_PIPELINE_URL}}function ye(e){return{branch:P(e.BUILD_SOURCEBRANCH,"refs/heads/"),commitSha:e.BUILD_SOURCEVERSION,repositoryUrl:e.BUILD_REPOSITORY_URI,buildNumber:e.BUILD_BUILDNUMBER,buildUrl:e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI&&e.SYSTEM_TEAMPROJECT&&e.BUILD_BUILDID?`${e.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI}${e.SYSTEM_TEAMPROJECT}/_build/results?buildId=${e.BUILD_BUILDID}`:void 0}}function Ie(e){return{branch:e.CIRCLE_BRANCH,commitSha:e.CIRCLE_SHA1,repositoryUrl:e.CIRCLE_REPOSITORY_URL,buildNumber:e.CIRCLE_BUILD_NUM,buildUrl:e.CIRCLE_BUILD_URL}}function Ce(e){return{branch:P(e.GIT_BRANCH,"origin/"),commitSha:e.GIT_COMMIT,repositoryUrl:e.GIT_URL,buildNumber:e.BUILD_NUMBER,buildUrl:e.BUILD_URL}}function _e(e){return{branch:e.BITBUCKET_BRANCH,commitSha:e.BITBUCKET_COMMIT,repositoryUrl:e.BITBUCKET_GIT_HTTP_ORIGIN,buildNumber:e.BITBUCKET_BUILD_NUMBER,buildUrl:e.BITBUCKET_REPO_FULL_NAME&&e.BITBUCKET_BUILD_NUMBER?`https://bitbucket.org/${e.BITBUCKET_REPO_FULL_NAME}/pipelines/results/${e.BITBUCKET_BUILD_NUMBER}`:void 0}}var Ue=[{isMatch:e=>e.GITHUB_ACTIONS==="true",detect:Re},{isMatch:e=>e.GITLAB_CI==="true",detect:be},{isMatch:e=>e.TF_BUILD==="True",detect:ye},{isMatch:e=>e.CIRCLECI==="true",detect:Ie},{isMatch:e=>!!e.JENKINS_URL,detect:Ce},{isMatch:e=>!!e.BITBUCKET_BUILD_NUMBER,detect:_e}];function Ee(){let e=he();for(let t of Ue)if(t.isMatch(e))return t.detect(e);return{}}});var E=R(b=>{"use strict";var Se=b&&b.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(b,"__esModule",{value:!0});b.resolveSourceSnippetOptions=v;b.enrichReportWithSourceSnippets=Le;var Ne=_("node:fs/promises"),U=Se(_("node:path")),Be=2e3,we=40;function v(e){return{sourceRoot:U.default.resolve(e?.sourceRoot??process.cwd()),maxChars:W(e?.maxChars,Be),maxLines:W(e?.maxLines,we)}}async function Le(e,t){let r=v(t),n=new Map;await Promise.all(e.results.tests.map(async i=>{if(i.snippet||!i.filePath||!i.line)return;let o=await Oe(i,r,n);o&&(i.snippet=o)}))}async function Oe(e,t,r){let n=U.default.resolve(t.sourceRoot,e.filePath);if(!De(n,t.sourceRoot))return;let i=await xe(n,r);if(i)return Pe(i,e.line,t)}function xe(e,t){let r=t.get(e);return r||(r=(0,Ne.readFile)(e,"utf-8").catch(()=>{}),t.set(e,r)),r}function Pe(e,t,r){let n=e.split(/\r?\n/),i=Math.max(0,Math.min(n.length-1,t-1)),o=Ae(n,i);if(o==null)return;let a=[],u=0,s=!1;for(let p=o;p<n.length&&a.length<r.maxLines;p++){let l=n[p];a.push(l);for(let f of l)f==="{"?(u++,s=!0):f==="}"&&u--;if(s&&u<=0&&Me(l))break}let c=a.join(`
|
|
2
|
+
`).trim();if(c)return c.length<=r.maxChars?c:c.slice(0,r.maxChars)}function Ae(e,t){for(let r=t;r>=0;r--)if(/\b(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/.test(e[r]))return r}function Me(e){let t=e.length-1;for(;t>=0&&/\s/.test(e[t]);)t--;for(t>=0&&e[t]===";"&&t--;t>=0&&/\s/.test(e[t]);)t--;if(t<1||e[t]!==")")return!1;for(t--;t>=0&&/\s/.test(e[t]);)t--;return t>=0&&e[t]==="}"}function De(e,t){let r=U.default.relative(t,e);return r.length>0&&!r.startsWith("..")&&!U.default.isAbsolute(r)}function W(e,t){return typeof e=="number"&&Number.isInteger(e)&&e>0?e:t}});var Y=R(y=>{"use strict";Object.defineProperty(y,"__esModule",{value:!0});y.ensureReportId=q;y.uploadTestRun=We;y.mapAttachmentsToTestResults=ve;y.uploadArtifacts=qe;var $e=M(),Fe=E(),ke="https://api.testream.app";function q(e){if(typeof e.reportId=="string"&&e.reportId.trim().length>0)return e.reportId;let t=crypto.randomUUID();return e.reportId=t,t}function J(e){let t=z(e);if(t)return t;let r=He();return r||ke}function He(){if(!(typeof process>"u"||!process?.env))return z(process.env.TESTREAM_API_URL)}function z(e){if(!e)return;let t=e.trim();if(!t)return;let r=t;for(;r.endsWith("/");)r=r.slice(0,-1);return r}function je(e){return e.errorCode==="report_already_exists"}function Ve(e){let t=e.detail||e.title||e.rawBody||"Unknown error",r=e.errorCode?`, code=${e.errorCode}`:"";return`Upload failed (HTTP ${e.statusCode}${r}): ${t}`}async function Ke(e){let t=await e.text();if((e.headers.get("content-type")||"").toLowerCase().includes("json")&&t.trim().length>0)try{let n=JSON.parse(t);return{statusCode:e.status,title:n.title,detail:n.detail||n.details||n.error,errorCode:n.errorCode,rawBody:t}}catch{}return{statusCode:e.status,rawBody:t}}function Ge(e){let t=(0,$e.detectCIContext)();return{commitSha:e.commitSha??t.commitSha,branch:e.branch??t.branch,repositoryUrl:e.repositoryUrl??t.repositoryUrl,buildName:e.buildName,buildNumber:e.buildNumber??t.buildNumber,buildUrl:e.buildUrl??t.buildUrl,testEnvironment:e.testEnvironment,appName:e.appName,appVersion:e.appVersion,testType:e.testType}}async function We(e){let{report:t,apiKey:r}=e,n=J(e.apiUrl),i=q(t),o=Ge(e);await(0,Fe.enrichReportWithSourceSnippets)(t);let a={report:t,reportId:i,...o};console.log("Uploading test results...");let u;try{u=await fetch(`${n}/api/v1/ingest`,{method:"POST",headers:{"X-API-KEY":r,"Content-Type":"application/json"},body:JSON.stringify(a)})}catch(c){let l=`Connection failed: ${c instanceof Error?c.message:String(c)}`;return console.error(l),{success:!1,reportId:i,error:l}}if(!u.ok){let c=await Ke(u);if(u.status===409&&je(c))return console.warn("Report already exists (workflow may have been re-run)"),{success:!0,reportId:i,summary:{passed:t.results.summary.passed,failed:t.results.summary.failed,skipped:t.results.summary.skipped,total:t.results.summary.tests},alreadyExists:!0,statusCode:c.statusCode,errorCode:c.errorCode};let p=Ve(c);return console.error(p),{success:!1,reportId:i,error:p,statusCode:c.statusCode,errorCode:c.errorCode,errorDetail:c.detail||c.rawBody}}let s=await u.json();return console.log("\u2713 Test results uploaded successfully"),console.log(` Report ID: ${s.reportId}`),console.log(` Test Run ID: ${s.testRunId}`),console.log(` Tests: ${s.summary.passed}/${s.summary.total} passed`),{success:!0,reportId:s.reportId,testRunId:s.testRunId,summary:{passed:s.summary.passed,failed:s.summary.failed,skipped:s.summary.skipped,total:s.summary.total},testResults:s.testResults}}function ve(e,t){let r=new Map;for(let i of t){let o=r.get(i.name)??[];o.push(i.id),r.set(i.name,o)}let n=[];for(let i of e){let a=r.get(i.name)?.shift();if(!(!i.attachments||i.attachments.length===0)){if(!a){console.warn(`Skipping artifact upload: could not match test result for "${i.name}"`);continue}n.push({testResultId:a,attachments:i.attachments})}}return n}async function qe(e){let{reportId:t,apiKey:r,testResults:n}=e,i=J(e.apiUrl),o=0;for(let a of n)for(let u of a.attachments)try{await Je({testResultId:a.testResultId,attachment:u,reportId:t,apiKey:r,apiUrl:i})&&o++}catch(s){let c=s instanceof Error?s.message:String(s);console.error(`Failed to upload artifact ${u.name}: ${c}`)}return o>0&&console.log(`\u2713 Uploaded ${o} artifact(s)`),o}async function Je(e){let{testResultId:t,attachment:r,reportId:n,apiKey:i,apiUrl:o}=e,a=await import("node:fs/promises"),u=await import("node:path"),s=u.resolve(r.path);try{await a.access(s)}catch{return console.warn(`Artifact not found: ${u.basename(s)}`),!1}let c,p,l=u.basename(s),f=r.contentType||"application/octet-stream";try{c=await a.readFile(s),p=c.byteLength}catch(h){let g=h instanceof Error?h.message:String(h);throw new Error(`Failed to read file: ${g}`)}try{return await ze({testResultId:t,reportId:n,apiKey:i,apiUrl:o,attachmentName:r.name,fileName:l,contentType:f,sizeBytes:p,fileBuffer:c})}catch(h){if(!(h instanceof S))throw h;return await Ye({testResultId:t,attachmentName:r.name,reportId:n,apiKey:i,apiUrl:o,fileName:l,contentType:f,fileBuffer:c})}}var S=class extends Error{constructor(){super("Legacy upload endpoint required")}};async function ze(e){let{testResultId:t,reportId:r,apiKey:n,apiUrl:i,attachmentName:o,fileName:a,contentType:u,sizeBytes:s,fileBuffer:c}=e,p={testResultId:t,ctrfAttachmentName:o,fileName:a,contentType:u,sizeBytes:s},l=await fetch(`${i}/api/v1/artifacts/${r}/upload-url`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(p)});if(Xe(l.status))throw new S;if(!l.ok){let I=await l.text();throw new Error(`Failed to create direct upload URL (HTTP ${l.status}): ${I}`)}let f=await l.json(),h={...f.requiredHeaders};Qe(h,"Content-Type")||(h["Content-Type"]=u);let g=await fetch(f.uploadUrl,{method:"PUT",headers:h,body:c});if(!g.ok){let I=await g.text();throw new Error(`Direct artifact upload failed (HTTP ${g.status}): ${I}`)}let H={testResultId:t,ctrfAttachmentName:o,fileName:a,contentType:u,sizeBytes:s,storageKey:f.storageKey},x=await fetch(`${i}/api/v1/artifacts/${r}/complete`,{method:"POST",headers:{"X-API-KEY":n,"Content-Type":"application/json"},body:JSON.stringify(H)});if(!x.ok){let I=await x.text();throw new Error(`Failed to finalize artifact upload (HTTP ${x.status}): ${I}`)}return!0}async function Ye(e){let{testResultId:t,attachmentName:r,reportId:n,apiKey:i,apiUrl:o,fileName:a,contentType:u,fileBuffer:s}=e,c=new Blob([new Uint8Array(s)],{type:u}),p=new FormData;p.append("testResultId",t),p.append("ctrfAttachmentName",r),p.append("file",c,a);let l=await fetch(`${o}/api/v1/artifacts/${n}`,{method:"POST",headers:{"X-API-KEY":i},body:p});if(!l.ok){let f=await l.text();throw new Error(`Legacy artifact upload failed (HTTP ${l.status}): ${f}`)}return!0}function Xe(e){return e===404||e===405||e===501}function Qe(e,t){let r=t.toLowerCase();return Object.keys(e).some(n=>n.toLowerCase()===r)}});var re=R(C=>{"use strict";var Ze=C&&C.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(C,"__esModule",{value:!0});C.enrichReportWithJsTestNameSourceSnippets=nt;var et=_("node:fs/promises"),D=Ze(_("node:path")),tt=E(),rt=3,X=/\b(describe|it|test)(?:\.(only|skip))?\s*\(\s*(['"`])/g;async function nt(e,t){let r=(0,tt.resolveSourceSnippetOptions)(t),n=new Map;await Promise.all(e.results.tests.map(async i=>{if(i.snippet||!i.filePath)return;let o=D.default.resolve(r.sourceRoot,i.filePath);if(!yt(o,r.sourceRoot))return;let a=await it(o,n);if(!a)return;let u=at(i,a).slice(0,rt);u.length!==0&&(i.line??(i.line=u[0].line),i.snippet=ut(u,r))}))}function it(e,t){let r=t.get(e);return r||(r=(0,et.readFile)(e,"utf-8").then(n=>ot(n)).catch(()=>{}),t.set(e,r)),r}function ot(e){let t=mt(e),r=st(e,t),n=r.filter(i=>i.kind==="describe");return r.filter(i=>i.kind==="test").map(i=>{let o=n.filter(a=>a.startIndex<i.startIndex&&a.endIndex>=i.endIndex).sort((a,u)=>a.startIndex-u.startIndex).map(a=>a.title);return{title:i.title,describeTitles:o,fullName:[...o,i.title].join(" ").trim(),line:i.startLine,snippet:i.snippet}})}function st(e,t){let r=[];X.lastIndex=0;let n;for(;(n=X.exec(e))!==null;){if(gt(e,n.index))continue;let i=dt(e,n.index+n[0].length,n[3]);if(!i)continue;let o=pt(e,i.endIndex+1);if(o==null)continue;let a=n[1]==="describe"?"describe":"test",u=n.index,s=ct(e,o+1);if(s==null)continue;let c=lt(e,s);if(c==null)continue;let p=ft(e,c),l=e.slice(u,p).trim();l&&r.push({kind:a,title:i.value.trim(),startIndex:u,endIndex:p,startLine:Tt(t,u),snippet:l})}return r}function at(e,t){let r=m(e.name),n=bt(e.suite),i=t.filter(a=>m(a.fullName)===r);if(i.length>0)return i;if(n){let a=t.filter(u=>m(u.title)===r&&m(u.describeTitles.join(" "))===n);if(a.length>0)return a}let o=t.filter(a=>m(a.title)===r);return o.length>0?o:t.filter(a=>{let u=m(a.title);if(!r.endsWith(u))return!1;let s=r.slice(0,r.length-u.length).trim();return s.length>0&&m(a.describeTitles.join(" "))===s})}function ut(e,t){let n=(e.length===1?e[0].snippet:e.map((i,o)=>`Candidate ${o+1} (line ${i.line})
|
|
3
|
+
${i.snippet}`).join(`
|
|
4
|
+
|
|
5
|
+
`)).split(/\r?\n/).slice(0,t.maxLines).join(`
|
|
6
|
+
`).trim();return n.length<=t.maxChars?n:n.slice(0,t.maxChars)}function ct(e,t){for(let r=t;r<e.length;r++){let n=e[r];if(n==="'"||n==='"'||n==="`"){r=$(e,r);continue}if(n==="/"&&e[r+1]==="/"){r=ee(e,r+2);continue}if(n==="/"&&e[r+1]==="*"){r=te(e,r+2);continue}if(e.startsWith("=>",r))return Q(e,r+2);if(Rt(e,r,"function"))return Q(e,r+8);if(n===";")return}}function Q(e,t){for(let r=t;r<e.length;r++){let n=e[r];if(n==="'"||n==='"'||n==="`"){r=$(e,r);continue}if(n==="{")return r;if(n===`
|
|
7
|
+
`&&ht(e,r+1))return}}function lt(e,t){let r=0;for(let n=t;n<e.length;n++){let i=e[n];if(i==="'"||i==='"'||i==="`"){n=$(e,n);continue}if(i==="/"&&e[n+1]==="/"){n=ee(e,n+2);continue}if(i==="/"&&e[n+1]==="*"){n=te(e,n+2);continue}if(i==="{"){r++;continue}if(i==="}"&&(r--,r===0))return n}}function dt(e,t,r){let n="";for(let i=t;i<e.length;i++){let o=e[i];if(o==="\\"){n+=o,i+1<e.length&&(i++,n+=e[i]);continue}if(o===r)return{value:n,endIndex:i};if(o===`
|
|
8
|
+
`&&r!=="`")return;n+=o}}function pt(e,t){for(let r=t;r<e.length;r++){let n=e[r];if(!/\s/.test(n))return n===","?r:void 0}}function ft(e,t){let r=t+1;for(;r<e.length;){let n=e[r];if(n==="\r"||n===`
|
|
9
|
+
`)return r;r++}return e.length}function $(e,t){let r=e[t];for(let n=t+1;n<e.length;n++){let i=e[n];if(i==="\\"){n++;continue}if(i===r)return n}return e.length-1}function ee(e,t){for(let r=t;r<e.length;r++)if(e[r]===`
|
|
10
|
+
`)return r;return e.length-1}function te(e,t){for(let r=t;r<e.length-1;r++)if(e[r]==="*"&&e[r+1]==="/")return r+1;return e.length-1}function ht(e,t){for(let r=t;r<e.length;r++){let n=e[r];if(!/\s/.test(n))return n!=="."&&n!=="("}return!1}function mt(e){let t=[0];for(let r=0;r<e.length;r++)e[r]===`
|
|
11
|
+
`&&t.push(r+1);return t}function Tt(e,t){let r=0;for(let n=0;n<e.length&&!(e[n]>t);n++)r=n;return r+1}function gt(e,t){let r=e.lastIndexOf(`
|
|
12
|
+
`,t-1)+1,n=e.slice(r,t).trimStart();return n.startsWith("//")||n.startsWith("*")}function Rt(e,t,r){if(!e.startsWith(r,t))return!1;let n=t===0?"":e[t-1],i=e[t+r.length]??"";return!Z(n)&&!Z(i)}function Z(e){return/[A-Za-z0-9_$]/.test(e)}function m(e){return(e??"").trim().replace(/\s+/g," ")}function bt(e){if(!e)return"";let t=e.split(">").map(i=>i.trim()).filter(Boolean);if(t.length===0)return"";let n=t[0].includes(".")?t.slice(1):t;return m(n.join(" "))}function yt(e,t){let r=D.default.relative(t,e);return r.length>0&&!r.startsWith("..")&&!D.default.isAbsolute(r)}});var ne=R(F=>{"use strict";Object.defineProperty(F,"__esModule",{value:!0});F.createTestLocationCollector=It;function It(){let e=new Map;return{add(t,r){if(!t||!Ct(r))return;let n=e.get(t)??[];n.push(r),e.set(t,n)},applyToReport(t){let r=new Map([...e.entries()].map(([n,i])=>[n,[...i]]));for(let n of t.results.tests){let o=r.get(n.name)?.shift();o&&(n.filePath??(n.filePath=o.filePath),n.line??(n.line=o.line))}}}}function Ct(e){return!!e.filePath&&Number.isInteger(e.line)&&e.line>0}});var k=R(d=>{"use strict";var _t=d&&d.__createBinding||(Object.create?function(e,t,r,n){n===void 0&&(n=r);var i=Object.getOwnPropertyDescriptor(t,r);(!i||("get"in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,i)}:function(e,t,r,n){n===void 0&&(n=r),e[n]=t[r]}),Ut=d&&d.__exportStar||function(e,t){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(t,r)&&_t(t,e,r)};Object.defineProperty(d,"__esModule",{value:!0});d.createTestLocationCollector=d.enrichReportWithJsTestNameSourceSnippets=d.resolveSourceSnippetOptions=d.enrichReportWithSourceSnippets=d.ensureReportId=d.mapAttachmentsToTestResults=d.uploadArtifacts=d.uploadTestRun=d.detectCIContext=void 0;Ut(G(),d);var Et=M();Object.defineProperty(d,"detectCIContext",{enumerable:!0,get:function(){return Et.detectCIContext}});var N=Y();Object.defineProperty(d,"uploadTestRun",{enumerable:!0,get:function(){return N.uploadTestRun}});Object.defineProperty(d,"uploadArtifacts",{enumerable:!0,get:function(){return N.uploadArtifacts}});Object.defineProperty(d,"mapAttachmentsToTestResults",{enumerable:!0,get:function(){return N.mapAttachmentsToTestResults}});Object.defineProperty(d,"ensureReportId",{enumerable:!0,get:function(){return N.ensureReportId}});var ie=E();Object.defineProperty(d,"enrichReportWithSourceSnippets",{enumerable:!0,get:function(){return ie.enrichReportWithSourceSnippets}});Object.defineProperty(d,"resolveSourceSnippetOptions",{enumerable:!0,get:function(){return ie.resolveSourceSnippetOptions}});var St=re();Object.defineProperty(d,"enrichReportWithJsTestNameSourceSnippets",{enumerable:!0,get:function(){return St.enrichReportWithJsTestNameSourceSnippets}});var Nt=ne();Object.defineProperty(d,"createTestLocationCollector",{enumerable:!0,get:function(){return Nt.createTestLocationCollector}})});var O=V(k());import*as L from"node:fs/promises";import*as ae from"node:path";function Bt(e){switch(e){case"passed":return"passed";case"failed":return"failed";case"skipped":return"skipped";default:return"pending"}}function wt(e){let t=[],r=e.parent;for(;r?.type==="suite";)t.unshift(r.name),r=r.parent;return t.join(" > ")}function oe(e){let t=[];for(let r of e)r.type==="test"?t.push(r):r.type==="suite"&&t.push(...oe(r.children));return t}function Lt(e){if(!e||e.length===0)return{message:void 0,trace:void 0};let t=e[0],r=t?.message,n=t?.stackTrace??t?.stack;return{message:r,trace:typeof n=="string"?n:void 0}}function Ot(e,t,r){let n=e.result(),i=e.diagnostic(),o=n.state,a=Bt(o),u=Math.round(i?.duration??0),s=i?.startTime??r,c=s+u,p=i?.retryCount??0,l=i?.flaky??!1,f=wt(e),{message:h,trace:g}=Lt(n.errors);return{ctrfTest:{name:e.name,status:a,duration:u,start:s,stop:c,rawStatus:o,tags:[],type:t.testType||"unit",filePath:e.module.moduleId,line:e.location?.line,retries:p,flaky:l,steps:[],suite:f||void 0,stdout:[],stderr:[],message:h,trace:g},suiteName:f}}function se(e,t,r){let n=Date.now(),i=[],o=new Set;for(let s of e){let c=oe(s.children);for(let p of c){let{ctrfTest:l,suiteName:f}=Ot(p,t,r);f&&o.add(f),i.push(l)}}let a={tests:i.length,passed:i.filter(s=>s.status==="passed").length,failed:i.filter(s=>s.status==="failed").length,skipped:i.filter(s=>s.status==="skipped").length,pending:i.filter(s=>s.status==="pending").length,other:i.filter(s=>s.status==="other").length,suites:o.size,start:r,stop:n};return{reportFormat:"CTRF",specVersion:"0.0.1",timestamp:new Date(r).toISOString(),generatedBy:"@testream/vitest-reporter",extra:{branch:t.branch,commitSha:t.commitSha},results:{tool:{name:"vitest"},summary:a,tests:i,environment:{...t.testEnvironment?{testEnvironment:t.testEnvironment}:{},...t.appName?{appName:t.appName}:{},...t.appVersion?{appVersion:t.appVersion}:{},...t.buildName?{buildName:t.buildName}:{},...t.buildNumber?{buildNumber:t.buildNumber}:{},...t.buildUrl?{buildUrl:t.buildUrl}:{}}}}}var T=V(k()),B=class{constructor(t){if(!t.apiKey)throw new Error("ReportUploader requires an apiKey");this.config={apiKey:t.apiKey,branch:t.branch,commitSha:t.commitSha,repositoryUrl:t.repositoryUrl,failOnUploadError:t.failOnUploadError??!1,buildName:t.buildName,buildNumber:t.buildNumber,buildUrl:t.buildUrl,testEnvironment:t.testEnvironment,appName:t.appName,appVersion:t.appVersion,testType:t.testType}}async uploadReport(t){try{let r=await(0,T.uploadTestRun)({report:t,apiKey:this.config.apiKey,commitSha:this.config.commitSha,branch:this.config.branch,repositoryUrl:this.config.repositoryUrl,buildName:this.config.buildName,buildNumber:this.config.buildNumber,buildUrl:this.config.buildUrl,testEnvironment:this.config.testEnvironment,appName:this.config.appName,appVersion:this.config.appVersion,testType:this.config.testType});if(!r.success){if(this.config.failOnUploadError)throw new Error(r.error||"Upload failed");return r}let n=0;if(!r.alreadyExists&&r.testRunId&&r.testResults){let i=(0,T.mapAttachmentsToTestResults)(t.results.tests,r.testResults);i.length>0&&(n=await(0,T.uploadArtifacts)({reportId:r.reportId,apiKey:this.config.apiKey,testResults:i}))}return{...r,artifactCount:n}}catch(r){let n=r instanceof Error?r.message:String(r);if(this.config.failOnUploadError)throw new Error(`Failed to upload report: ${n}`);return{success:!1,reportId:(0,T.ensureReportId)(t),error:n}}}};var w=class{constructor(t){this.uploader=null;this.startTimestamp=0;if(this.config={uploadEnabled:!0,outputFile:"ctrf-report.json",outputDir:"ctrf",failOnUploadError:!1,testType:"unit",...t},this.config.uploadEnabled&&!this.config.apiKey)throw new Error("TestreamVitestReporter: apiKey is required when upload is enabled");let r=(0,O.detectCIContext)();!this.config.branch&&r.branch&&(this.config.branch=r.branch),!this.config.commitSha&&r.commitSha&&(this.config.commitSha=r.commitSha),!this.config.repositoryUrl&&r.repositoryUrl&&(this.config.repositoryUrl=r.repositoryUrl),!this.config.buildNumber&&r.buildNumber&&(this.config.buildNumber=r.buildNumber),!this.config.buildUrl&&r.buildUrl&&(this.config.buildUrl=r.buildUrl),this.reportPath=ae.join(this.config.outputDir,this.config.outputFile),this.config.uploadEnabled&&(this.uploader=new B(this.config))}onInit(t){t.config.includeTaskLocation!==!0&&(t.config.includeTaskLocation=!0)}onTestRunStart(t){this.startTimestamp=Date.now(),console.log(""),console.log("=".repeat(60)),console.log("Vitest Testream Reporter"),console.log("=".repeat(60)),this.config.uploadEnabled?(this.config.branch&&console.log(`Branch: ${this.config.branch}`),this.config.commitSha&&console.log(`Commit: ${this.config.commitSha.substring(0,7)}`),this.config.repositoryUrl&&console.log(`Repository: ${this.config.repositoryUrl}`)):console.log("Upload: Disabled"),console.log(`Report: ${this.reportPath}`),console.log("=".repeat(60)),console.log("")}async onTestRunEnd(t,r,n){let i=se(t,this.config,this.startTimestamp);await(0,O.enrichReportWithSourceSnippets)(i);try{await L.mkdir(this.config.outputDir,{recursive:!0}),await L.writeFile(this.reportPath,JSON.stringify(i,null,2))}catch(o){let a=o instanceof Error?o.message:String(o);console.error(`Failed to write CTRF report: ${a}`)}if(!this.config.uploadEnabled||!this.uploader){console.log(""),console.log("CTRF report generated"),console.log(` ${this.reportPath}`);return}console.log(""),console.log("=".repeat(60)),console.log("Uploading Test Results"),console.log("=".repeat(60));try{let o=await this.uploader.uploadReport(i);o.success?(console.log("=".repeat(60)),console.log("Upload Complete"),console.log("=".repeat(60)),console.log("")):(console.error("Upload completed with errors"),o.error&&console.error(`Error: ${o.error}`),o.errorCode&&console.error(`Error code: ${o.errorCode}`),console.error(""))}catch(o){let a=o instanceof Error?o.message:String(o);if(console.error(""),console.error("=".repeat(60)),console.error("Upload Failed"),console.error("=".repeat(60)),console.error(`Error: ${a}`),console.error(""),this.config.failOnUploadError)throw o}}};export{w as TestreamVitestReporter,w as default};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Vitest reporter that generates CTRF-format test reports and
|
|
5
5
|
* automatically uploads them to the Testream backend.
|
|
6
6
|
*/
|
|
7
|
-
export { TestreamVitestReporter as default } from
|
|
8
|
-
export { TestreamVitestReporter } from
|
|
9
|
-
export type { VitestReporterConfig } from
|
|
7
|
+
export { TestreamVitestReporter as default } from "./reporter";
|
|
8
|
+
export { TestreamVitestReporter } from "./reporter";
|
|
9
|
+
export type { VitestReporterConfig } from "./types";
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/reporter.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import type { Reporter, TestModule, TestSpecification, SerializedError, TestRunEndReason } from
|
|
2
|
-
import { VitestReporterConfig } from
|
|
1
|
+
import type { Reporter, TestModule, TestSpecification, SerializedError, TestRunEndReason, Vitest } from "vitest/node";
|
|
2
|
+
import { VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Vitest Reporter that generates CTRF reports and uploads them to Testream
|
|
5
5
|
*/
|
|
6
6
|
export declare class TestreamVitestReporter implements Reporter {
|
|
7
|
-
private config;
|
|
8
|
-
private uploader;
|
|
9
|
-
private reportPath;
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly uploader;
|
|
9
|
+
private readonly reportPath;
|
|
10
10
|
private startTimestamp;
|
|
11
11
|
constructor(config: VitestReporterConfig);
|
|
12
|
+
onInit(vitest: Vitest): void;
|
|
12
13
|
onTestRunStart(_specifications: ReadonlyArray<TestSpecification>): void;
|
|
13
14
|
onTestRunEnd(testModules: ReadonlyArray<TestModule>, _unhandledErrors: ReadonlyArray<SerializedError>, _reason: TestRunEndReason): Promise<void>;
|
|
14
15
|
}
|
package/dist/reporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,MAAM,EACP,MAAM,aAAa,CAAC;AAOrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI/C;;GAEG;AACH,qBAAa,sBAAuB,YAAW,QAAQ;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,cAAc,CAAa;gBAEvB,MAAM,EAAE,oBAAoB;IA6CxC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU5B,cAAc,CAAC,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAqBjE,YAAY,CAChB,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,EACtC,gBAAgB,EAAE,aAAa,CAAC,eAAe,CAAC,EAChD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC;CAiEjB;AAED,eAAe,sBAAsB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Re-export CTRF types from shared-types package
|
|
3
3
|
*/
|
|
4
|
-
export type { CTRFReport, CTRFTest, CTRFSummary, CTRFResults, CTRFAttachment, CTRFStep, } from
|
|
4
|
+
export type { CTRFReport, CTRFTest, CTRFSummary, CTRFResults, CTRFAttachment, CTRFStep, } from "@jira-test-manager/shared-types";
|
|
5
5
|
/**
|
|
6
6
|
* Re-export API types from shared-types package
|
|
7
7
|
*/
|
|
8
|
-
export type { UploadResult
|
|
8
|
+
export type { UploadResult } from "@jira-test-manager/shared-types";
|
|
9
9
|
/**
|
|
10
10
|
* Configuration options for the Vitest Testream Reporter
|
|
11
11
|
*/
|
|
12
12
|
export interface VitestReporterConfig {
|
|
13
13
|
/**
|
|
14
|
-
* API key for authentication with Testream
|
|
15
|
-
*
|
|
14
|
+
* API key for authentication with Testream.
|
|
15
|
+
* Required when uploadEnabled is true.
|
|
16
16
|
*/
|
|
17
|
-
apiKey
|
|
17
|
+
apiKey?: string;
|
|
18
18
|
/**
|
|
19
19
|
* Git branch name (auto-detected from CI environment if not provided)
|
|
20
20
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,cAAc,EACd,QAAQ,GACT,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,YAAY,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,cAAc,EACd,QAAQ,GACT,MAAM,iCAAiC,CAAC;AAEzC;;GAEG;AACH,YAAY,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/uploader.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { CTRFReport, UploadResult } from
|
|
2
|
-
import { VitestReporterConfig } from
|
|
1
|
+
import { CTRFReport, UploadResult } from "@jira-test-manager/shared-types";
|
|
2
|
+
import { VitestReporterConfig } from "./types";
|
|
3
3
|
/**
|
|
4
4
|
* Upload CTRF report and artifacts to the Testream backend API
|
|
5
5
|
*/
|
|
6
6
|
export declare class ReportUploader {
|
|
7
|
-
private config;
|
|
7
|
+
private readonly config;
|
|
8
8
|
constructor(config: VitestReporterConfig);
|
|
9
9
|
/**
|
|
10
10
|
* Upload CTRF report to the backend
|
package/dist/uploader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../src/uploader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EAKb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../src/uploader.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,YAAY,EAKb,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAenB;gBAEQ,MAAM,EAAE,oBAAoB;IAqBxC;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;CA4D9D"}
|