staklink 0.3.24 → 0.3.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/proxy-server.cjs
CHANGED
|
@@ -34824,7 +34824,7 @@ var SSEManager = class {
|
|
|
34824
34824
|
var sseManager = new SSEManager();
|
|
34825
34825
|
|
|
34826
34826
|
// src/proxy/version.ts
|
|
34827
|
-
var VERSION = "0.3.
|
|
34827
|
+
var VERSION = "0.3.26";
|
|
34828
34828
|
|
|
34829
34829
|
// node_modules/uuid/dist/esm/stringify.js
|
|
34830
34830
|
var byteToHex = [];
|
|
@@ -80367,6 +80367,9 @@ function gitleaksProtect() {
|
|
|
80367
80367
|
var import_child_process4 = require("child_process");
|
|
80368
80368
|
var import_util10 = require("util");
|
|
80369
80369
|
var execAsync = (0, import_util10.promisify)(import_child_process4.exec);
|
|
80370
|
+
function sanitizeGitHubText(text2) {
|
|
80371
|
+
return text2.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
80372
|
+
}
|
|
80370
80373
|
var GitHubCLI = class {
|
|
80371
80374
|
token;
|
|
80372
80375
|
branch;
|
|
@@ -80474,10 +80477,10 @@ Stderr: ${error82.stderr}`
|
|
|
80474
80477
|
"--head",
|
|
80475
80478
|
this.branch,
|
|
80476
80479
|
"--title",
|
|
80477
|
-
`"${options.title}"`
|
|
80480
|
+
`"${sanitizeGitHubText(options.title)}"`
|
|
80478
80481
|
];
|
|
80479
80482
|
if (options.body) {
|
|
80480
|
-
args.push("--body", `"${options.body}"`);
|
|
80483
|
+
args.push("--body", `"${sanitizeGitHubText(options.body)}"`);
|
|
80481
80484
|
}
|
|
80482
80485
|
if (options.base) {
|
|
80483
80486
|
args.push("--base", options.base);
|
|
@@ -80619,10 +80622,10 @@ Stderr: ${error82.stderr}`
|
|
|
80619
80622
|
args.push("--delete-branch");
|
|
80620
80623
|
}
|
|
80621
80624
|
if (commitTitle) {
|
|
80622
|
-
args.push("--subject", `"${commitTitle}"`);
|
|
80625
|
+
args.push("--subject", `"${sanitizeGitHubText(commitTitle)}"`);
|
|
80623
80626
|
}
|
|
80624
80627
|
if (commitBody) {
|
|
80625
|
-
args.push("--body", `"${commitBody}"`);
|
|
80628
|
+
args.push("--body", `"${sanitizeGitHubText(commitBody)}"`);
|
|
80626
80629
|
}
|
|
80627
80630
|
try {
|
|
80628
80631
|
const { stdout } = await this.execGH(args.join(" "));
|
|
@@ -80676,7 +80679,9 @@ Stderr: ${error82.stderr}`
|
|
|
80676
80679
|
*/
|
|
80677
80680
|
async addComment(prNumber, comment) {
|
|
80678
80681
|
try {
|
|
80679
|
-
await this.execGH(
|
|
80682
|
+
await this.execGH(
|
|
80683
|
+
`pr comment ${prNumber} --body "${sanitizeGitHubText(comment)}"`
|
|
80684
|
+
);
|
|
80680
80685
|
} catch (error82) {
|
|
80681
80686
|
throw new Error(`Failed to add comment to PR #${prNumber}: ${error82}`);
|
|
80682
80687
|
}
|
|
@@ -80687,10 +80692,10 @@ Stderr: ${error82.stderr}`
|
|
|
80687
80692
|
async updatePR(prNumber, updates) {
|
|
80688
80693
|
const args = ["pr", "edit", prNumber.toString()];
|
|
80689
80694
|
if (updates.title) {
|
|
80690
|
-
args.push("--title", `"${updates.title}"`);
|
|
80695
|
+
args.push("--title", `"${sanitizeGitHubText(updates.title)}"`);
|
|
80691
80696
|
}
|
|
80692
80697
|
if (updates.body) {
|
|
80693
|
-
args.push("--body", `"${updates.body}"`);
|
|
80698
|
+
args.push("--body", `"${sanitizeGitHubText(updates.body)}"`);
|
|
80694
80699
|
}
|
|
80695
80700
|
try {
|
|
80696
80701
|
await this.execGH(args.join(" "));
|
|
@@ -80751,6 +80756,189 @@ Stderr: ${error82.stderr}`
|
|
|
80751
80756
|
// src/proxy/playwright.ts
|
|
80752
80757
|
var fs10 = __toESM(require("fs/promises"), 1);
|
|
80753
80758
|
var path9 = __toESM(require("path"), 1);
|
|
80759
|
+
var DEFAULT_CONFIG = `import { defineConfig } from "@playwright/test";
|
|
80760
|
+
export default defineConfig({
|
|
80761
|
+
timeout: 60000,
|
|
80762
|
+
workers: 1,
|
|
80763
|
+
fullyParallel: false,
|
|
80764
|
+
reporter: [
|
|
80765
|
+
["list"],
|
|
80766
|
+
["./timestamp-reporter.ts"],
|
|
80767
|
+
],
|
|
80768
|
+
use: {
|
|
80769
|
+
video: "on",
|
|
80770
|
+
headless: true,
|
|
80771
|
+
browserName: "chromium",
|
|
80772
|
+
trace: "on-first-retry",
|
|
80773
|
+
},
|
|
80774
|
+
});
|
|
80775
|
+
`;
|
|
80776
|
+
var TIMESTAMP_REPORTER_CODE = `import {
|
|
80777
|
+
Reporter,
|
|
80778
|
+
TestCase,
|
|
80779
|
+
TestResult,
|
|
80780
|
+
TestStep,
|
|
80781
|
+
FullConfig,
|
|
80782
|
+
Suite,
|
|
80783
|
+
FullResult,
|
|
80784
|
+
} from "@playwright/test/reporter";
|
|
80785
|
+
import * as fs from "fs";
|
|
80786
|
+
import * as path from "path";
|
|
80787
|
+
|
|
80788
|
+
interface TimestampEntry {
|
|
80789
|
+
title: string;
|
|
80790
|
+
category: string;
|
|
80791
|
+
timestamp: string;
|
|
80792
|
+
relativeMs: number;
|
|
80793
|
+
duration: number;
|
|
80794
|
+
location: {
|
|
80795
|
+
file: string;
|
|
80796
|
+
line: number;
|
|
80797
|
+
column: number;
|
|
80798
|
+
};
|
|
80799
|
+
stepPath: string[];
|
|
80800
|
+
sourceCode?: string;
|
|
80801
|
+
error?: {
|
|
80802
|
+
message: string;
|
|
80803
|
+
stack?: string;
|
|
80804
|
+
};
|
|
80805
|
+
}
|
|
80806
|
+
|
|
80807
|
+
class TimestampReporter implements Reporter {
|
|
80808
|
+
private logs: TimestampEntry[] = [];
|
|
80809
|
+
private testStartTime: number = 0;
|
|
80810
|
+
private outputDir: string = "test-results";
|
|
80811
|
+
private sourceCache: Map<string, string[]> = new Map();
|
|
80812
|
+
|
|
80813
|
+
onBegin(config: FullConfig, suite: Suite) {
|
|
80814
|
+
this.outputDir = config.projects[0]?.outputDir || "test-results";
|
|
80815
|
+
console.log("\\n\u{1F3AC} Timestamp Reporter: Recording action timestamps\\n");
|
|
80816
|
+
}
|
|
80817
|
+
|
|
80818
|
+
private readSourceLine(filePath: string, lineNumber: number): string | undefined {
|
|
80819
|
+
try {
|
|
80820
|
+
// Check cache first
|
|
80821
|
+
if (!this.sourceCache.has(filePath)) {
|
|
80822
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
80823
|
+
this.sourceCache.set(filePath, content.split("\\n"));
|
|
80824
|
+
}
|
|
80825
|
+
|
|
80826
|
+
const lines = this.sourceCache.get(filePath);
|
|
80827
|
+
if (lines && lineNumber > 0 && lineNumber <= lines.length) {
|
|
80828
|
+
return lines[lineNumber - 1].trim();
|
|
80829
|
+
}
|
|
80830
|
+
} catch (error) {
|
|
80831
|
+
console.error(\`Error reading source file \${filePath}:\`, error);
|
|
80832
|
+
}
|
|
80833
|
+
return undefined;
|
|
80834
|
+
}
|
|
80835
|
+
|
|
80836
|
+
onTestBegin(test: TestCase, result: TestResult) {
|
|
80837
|
+
this.testStartTime = Date.now();
|
|
80838
|
+
console.log(\`\\n\u{1F4DD} [\${new Date().toISOString()}] Test started: \${test.title}\`);
|
|
80839
|
+
}
|
|
80840
|
+
|
|
80841
|
+
onStepBegin(test: TestCase, result: TestResult, step: TestStep) {
|
|
80842
|
+
// Only log steps that have a location (actual test code)
|
|
80843
|
+
if (!step.location) return;
|
|
80844
|
+
|
|
80845
|
+
const timestamp = new Date().toISOString();
|
|
80846
|
+
const relativeMs = Date.now() - this.testStartTime;
|
|
80847
|
+
const indent = " ".repeat(step.titlePath().length - 1);
|
|
80848
|
+
const sourceCode = this.readSourceLine(step.location.file, step.location.line);
|
|
80849
|
+
|
|
80850
|
+
console.log(
|
|
80851
|
+
\`\${indent}\u23F1\uFE0F [\${timestamp}] +\${relativeMs}ms - \${sourceCode || step.title}\`
|
|
80852
|
+
);
|
|
80853
|
+
}
|
|
80854
|
+
|
|
80855
|
+
onStepEnd(test: TestCase, result: TestResult, step: TestStep) {
|
|
80856
|
+
// Only log steps that have a location (actual test code)
|
|
80857
|
+
if (!step.location) return;
|
|
80858
|
+
|
|
80859
|
+
const timestamp = new Date().toISOString();
|
|
80860
|
+
const relativeMs = Date.now() - this.testStartTime;
|
|
80861
|
+
|
|
80862
|
+
// Read the actual source code line
|
|
80863
|
+
const sourceCode = this.readSourceLine(step.location.file, step.location.line);
|
|
80864
|
+
|
|
80865
|
+
const entry: TimestampEntry = {
|
|
80866
|
+
title: step.title,
|
|
80867
|
+
category: step.category,
|
|
80868
|
+
timestamp: timestamp,
|
|
80869
|
+
relativeMs: relativeMs,
|
|
80870
|
+
duration: step.duration,
|
|
80871
|
+
stepPath: step.titlePath(),
|
|
80872
|
+
location: {
|
|
80873
|
+
file: step.location.file,
|
|
80874
|
+
line: step.location.line,
|
|
80875
|
+
column: step.location.column,
|
|
80876
|
+
},
|
|
80877
|
+
sourceCode: sourceCode,
|
|
80878
|
+
};
|
|
80879
|
+
|
|
80880
|
+
// Add error if present
|
|
80881
|
+
if (step.error) {
|
|
80882
|
+
entry.error = {
|
|
80883
|
+
message: step.error.message || "Unknown error",
|
|
80884
|
+
stack: step.error.stack,
|
|
80885
|
+
};
|
|
80886
|
+
}
|
|
80887
|
+
|
|
80888
|
+
this.logs.push(entry);
|
|
80889
|
+
|
|
80890
|
+
const indent = " ".repeat(step.titlePath().length - 1);
|
|
80891
|
+
const status = step.error ? "\u274C" : "\u2705";
|
|
80892
|
+
console.log(
|
|
80893
|
+
\`\${indent}\${status} [\${timestamp}] \${sourceCode || step.title} (\${step.duration}ms)\`
|
|
80894
|
+
);
|
|
80895
|
+
}
|
|
80896
|
+
|
|
80897
|
+
onTestEnd(test: TestCase, result: TestResult) {
|
|
80898
|
+
const videoAttachment = result.attachments.find((a) => a.name === "video");
|
|
80899
|
+
const videoPath = videoAttachment?.path;
|
|
80900
|
+
|
|
80901
|
+
const output = {
|
|
80902
|
+
testTitle: test.title,
|
|
80903
|
+
testId: test.id,
|
|
80904
|
+
status: result.status,
|
|
80905
|
+
duration: result.duration,
|
|
80906
|
+
startTime: new Date(this.testStartTime).toISOString(),
|
|
80907
|
+
videoPath: videoPath || null,
|
|
80908
|
+
actions: this.logs,
|
|
80909
|
+
};
|
|
80910
|
+
|
|
80911
|
+
// Write to test-results directory
|
|
80912
|
+
const sanitizedTitle = test.title
|
|
80913
|
+
.replace(/[^a-z0-9]/gi, "-")
|
|
80914
|
+
.toLowerCase();
|
|
80915
|
+
const outputPath = path.join(
|
|
80916
|
+
this.outputDir,
|
|
80917
|
+
\`timestamps-\${sanitizedTitle}.json\`
|
|
80918
|
+
);
|
|
80919
|
+
|
|
80920
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
80921
|
+
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
|
|
80922
|
+
|
|
80923
|
+
console.log(\`\\n\u{1F4BE} Timestamps saved to: \${outputPath}\`);
|
|
80924
|
+
if (videoPath) {
|
|
80925
|
+
console.log(\`\u{1F4F9} Video path: \${videoPath}\`);
|
|
80926
|
+
}
|
|
80927
|
+
console.log("");
|
|
80928
|
+
|
|
80929
|
+
// Reset logs for next test
|
|
80930
|
+
this.logs = [];
|
|
80931
|
+
// Clear source cache to free memory
|
|
80932
|
+
this.sourceCache.clear();
|
|
80933
|
+
}
|
|
80934
|
+
|
|
80935
|
+
onEnd(result: FullResult) {
|
|
80936
|
+
console.log(\`\\n\u2705 Test run complete! Status: \${result.status}\\n\`);
|
|
80937
|
+
}
|
|
80938
|
+
}
|
|
80939
|
+
|
|
80940
|
+
export default TimestampReporter;
|
|
80941
|
+
`;
|
|
80754
80942
|
async function findRepositoryLocation(repoName) {
|
|
80755
80943
|
const repoLocation = await findRepoLocation(repoName);
|
|
80756
80944
|
if (!repoLocation) {
|
|
@@ -80785,12 +80973,39 @@ async function findPlaywrightConfig(repoLocation) {
|
|
|
80785
80973
|
}
|
|
80786
80974
|
async function createPlaywrightConfig(repoLocation) {
|
|
80787
80975
|
const configPath = path9.join(repoLocation, "playwright.config.ts");
|
|
80788
|
-
|
|
80976
|
+
await fs10.writeFile(configPath, DEFAULT_CONFIG);
|
|
80977
|
+
console.log(`Created playwright config at ${configPath}`);
|
|
80978
|
+
return configPath;
|
|
80979
|
+
}
|
|
80980
|
+
async function createTimestampReporter(repoLocation) {
|
|
80981
|
+
const reporterPath = path9.join(repoLocation, "timestamp-reporter.ts");
|
|
80982
|
+
await fs10.writeFile(reporterPath, TIMESTAMP_REPORTER_CODE);
|
|
80983
|
+
console.log(`Created timestamp reporter at ${reporterPath}`);
|
|
80984
|
+
return reporterPath;
|
|
80985
|
+
}
|
|
80986
|
+
async function setupPlaywrightConfig(repoLocation) {
|
|
80987
|
+
let configPath = await findPlaywrightConfig(repoLocation);
|
|
80988
|
+
let wasCreated = false;
|
|
80989
|
+
let originalContent = null;
|
|
80990
|
+
let wasModified = false;
|
|
80991
|
+
const reporterPath = await createTimestampReporter(repoLocation);
|
|
80992
|
+
if (!configPath) {
|
|
80993
|
+
configPath = await createPlaywrightConfig(repoLocation);
|
|
80994
|
+
wasCreated = true;
|
|
80995
|
+
console.log("Created new playwright config");
|
|
80996
|
+
} else {
|
|
80997
|
+
originalContent = await fs10.readFile(configPath, "utf-8");
|
|
80998
|
+
wasModified = true;
|
|
80999
|
+
const newConfig = `import { defineConfig } from "@playwright/test";
|
|
80789
81000
|
|
|
80790
81001
|
export default defineConfig({
|
|
80791
81002
|
timeout: 60000,
|
|
80792
81003
|
workers: 1,
|
|
80793
81004
|
fullyParallel: false,
|
|
81005
|
+
reporter: [
|
|
81006
|
+
["list"],
|
|
81007
|
+
["./timestamp-reporter.ts"],
|
|
81008
|
+
],
|
|
80794
81009
|
use: {
|
|
80795
81010
|
video: "on",
|
|
80796
81011
|
headless: true,
|
|
@@ -80799,63 +81014,18 @@ export default defineConfig({
|
|
|
80799
81014
|
},
|
|
80800
81015
|
});
|
|
80801
81016
|
`;
|
|
80802
|
-
|
|
80803
|
-
|
|
80804
|
-
|
|
80805
|
-
}
|
|
80806
|
-
async function ensureVideoEnabled(configPath) {
|
|
80807
|
-
const configContent = await fs10.readFile(configPath, "utf-8");
|
|
80808
|
-
if (configContent.match(/video:\s*["']on["']/)) {
|
|
80809
|
-
console.log("Video already enabled in config");
|
|
80810
|
-
return null;
|
|
80811
|
-
}
|
|
80812
|
-
console.log("Updating config to enable video recording");
|
|
80813
|
-
let updatedConfig = configContent;
|
|
80814
|
-
const useBlockRegex = /use:\s*\{([^}]*)\}/s;
|
|
80815
|
-
const match2 = configContent.match(useBlockRegex);
|
|
80816
|
-
if (match2) {
|
|
80817
|
-
const useBlockContent = match2[1];
|
|
80818
|
-
if (useBlockContent.includes("video:")) {
|
|
80819
|
-
updatedConfig = configContent.replace(
|
|
80820
|
-
/video:\s*["'][^"']*["']/,
|
|
80821
|
-
'video: "on"'
|
|
80822
|
-
);
|
|
80823
|
-
} else {
|
|
80824
|
-
const updatedUseBlock = `use: {
|
|
80825
|
-
video: "on",${useBlockContent}}`;
|
|
80826
|
-
updatedConfig = configContent.replace(useBlockRegex, updatedUseBlock);
|
|
80827
|
-
}
|
|
80828
|
-
} else {
|
|
80829
|
-
const configObjectRegex = /export\s+default\s+defineConfig\(\s*\{/;
|
|
80830
|
-
updatedConfig = configContent.replace(
|
|
80831
|
-
configObjectRegex,
|
|
80832
|
-
`export default defineConfig({
|
|
80833
|
-
use: {
|
|
80834
|
-
video: "on",
|
|
80835
|
-
},`
|
|
81017
|
+
await fs10.writeFile(configPath, newConfig);
|
|
81018
|
+
console.log(
|
|
81019
|
+
`Overwrote existing config at ${configPath} (backed up for cleanup)`
|
|
80836
81020
|
);
|
|
80837
81021
|
}
|
|
80838
|
-
await fs10.writeFile(configPath, updatedConfig);
|
|
80839
|
-
console.log("Config updated to enable video recording");
|
|
80840
|
-
return configContent;
|
|
80841
|
-
}
|
|
80842
|
-
async function setupPlaywrightConfig(repoLocation) {
|
|
80843
|
-
let configPath = await findPlaywrightConfig(repoLocation);
|
|
80844
|
-
let wasCreated = false;
|
|
80845
|
-
let originalContent = null;
|
|
80846
|
-
let wasModified = false;
|
|
80847
|
-
if (!configPath) {
|
|
80848
|
-
configPath = await createPlaywrightConfig(repoLocation);
|
|
80849
|
-
wasCreated = true;
|
|
80850
|
-
} else {
|
|
80851
|
-
originalContent = await ensureVideoEnabled(configPath);
|
|
80852
|
-
wasModified = originalContent !== null;
|
|
80853
|
-
}
|
|
80854
81022
|
return {
|
|
80855
81023
|
configPath,
|
|
80856
81024
|
wasCreated,
|
|
80857
81025
|
originalContent,
|
|
80858
|
-
wasModified
|
|
81026
|
+
wasModified,
|
|
81027
|
+
reporterPath,
|
|
81028
|
+
reporterWasCreated: true
|
|
80859
81029
|
};
|
|
80860
81030
|
}
|
|
80861
81031
|
async function ensureTestResultsInGitignore(repoLocation) {
|
|
@@ -80928,14 +81098,48 @@ async function findVideoFile(repoLocation) {
|
|
|
80928
81098
|
console.log(`Found video at: ${videoPath}`);
|
|
80929
81099
|
return videoPath;
|
|
80930
81100
|
}
|
|
80931
|
-
async function
|
|
81101
|
+
async function findTimestampJsonFile(repoLocation) {
|
|
81102
|
+
const testResultsDir = path9.join(repoLocation, "test-results");
|
|
81103
|
+
const walkDir = async (dir) => {
|
|
81104
|
+
try {
|
|
81105
|
+
const files = await fs10.readdir(dir);
|
|
81106
|
+
for (const file3 of files) {
|
|
81107
|
+
const fullPath = path9.join(dir, file3);
|
|
81108
|
+
const stat4 = await fs10.stat(fullPath);
|
|
81109
|
+
if (stat4.isDirectory()) {
|
|
81110
|
+
const result = await walkDir(fullPath);
|
|
81111
|
+
if (result) {
|
|
81112
|
+
return result;
|
|
81113
|
+
}
|
|
81114
|
+
} else if (file3.startsWith("timestamps-") && file3.endsWith(".json")) {
|
|
81115
|
+
return fullPath;
|
|
81116
|
+
}
|
|
81117
|
+
}
|
|
81118
|
+
} catch (error82) {
|
|
81119
|
+
console.error(`Error walking directory ${dir}:`, error82);
|
|
81120
|
+
}
|
|
81121
|
+
return null;
|
|
81122
|
+
};
|
|
81123
|
+
const jsonPath = await walkDir(testResultsDir);
|
|
81124
|
+
if (!jsonPath) {
|
|
81125
|
+
throw new Error("No timestamp JSON file found in test-results directory");
|
|
81126
|
+
}
|
|
81127
|
+
console.log(`Found timestamp JSON at: ${jsonPath}`);
|
|
81128
|
+
return jsonPath;
|
|
81129
|
+
}
|
|
81130
|
+
async function uploadVideo(videoPath, timestampJsonPath, responseUrl) {
|
|
80932
81131
|
const videoBuffer = await fs10.readFile(videoPath);
|
|
81132
|
+
const jsonBuffer = await fs10.readFile(timestampJsonPath);
|
|
80933
81133
|
const FormData2 = (await Promise.resolve().then(() => __toESM(require_form_data(), 1))).default;
|
|
80934
81134
|
const formData = new FormData2();
|
|
80935
81135
|
formData.append("video", videoBuffer, {
|
|
80936
81136
|
filename: path9.basename(videoPath),
|
|
80937
81137
|
contentType: "video/webm"
|
|
80938
81138
|
});
|
|
81139
|
+
formData.append("timestamps", jsonBuffer, {
|
|
81140
|
+
filename: path9.basename(timestampJsonPath),
|
|
81141
|
+
contentType: "application/json"
|
|
81142
|
+
});
|
|
80939
81143
|
const uploadResponse = await fetch(responseUrl, {
|
|
80940
81144
|
method: "POST",
|
|
80941
81145
|
body: formData,
|
|
@@ -80943,34 +81147,49 @@ async function uploadVideo(videoPath, responseUrl) {
|
|
|
80943
81147
|
});
|
|
80944
81148
|
if (!uploadResponse.ok) {
|
|
80945
81149
|
throw new Error(
|
|
80946
|
-
`Failed to upload
|
|
81150
|
+
`Failed to upload files: ${uploadResponse.status} ${uploadResponse.statusText}`
|
|
80947
81151
|
);
|
|
80948
81152
|
}
|
|
80949
|
-
console.log(`Video uploaded successfully to ${responseUrl}`);
|
|
81153
|
+
console.log(`Video and timestamps uploaded successfully to ${responseUrl}`);
|
|
80950
81154
|
return uploadResponse.status;
|
|
80951
81155
|
}
|
|
80952
|
-
async function
|
|
81156
|
+
async function deleteTestFiles(videoPath, timestampJsonPath) {
|
|
80953
81157
|
try {
|
|
80954
81158
|
await fs10.unlink(videoPath);
|
|
80955
81159
|
console.log(`Deleted video file: ${videoPath}`);
|
|
80956
81160
|
} catch (error82) {
|
|
80957
81161
|
console.error(`Error deleting video file ${videoPath}:`, error82);
|
|
80958
81162
|
}
|
|
81163
|
+
try {
|
|
81164
|
+
await fs10.unlink(timestampJsonPath);
|
|
81165
|
+
console.log(`Deleted timestamp JSON: ${timestampJsonPath}`);
|
|
81166
|
+
} catch (error82) {
|
|
81167
|
+
console.error(`Error deleting timestamp JSON ${timestampJsonPath}:`, error82);
|
|
81168
|
+
}
|
|
80959
81169
|
}
|
|
80960
81170
|
async function cleanupConfig(configState) {
|
|
80961
|
-
if (
|
|
80962
|
-
|
|
81171
|
+
if (configState.configPath) {
|
|
81172
|
+
try {
|
|
81173
|
+
if (configState.wasCreated) {
|
|
81174
|
+
await fs10.unlink(configState.configPath);
|
|
81175
|
+
console.log(
|
|
81176
|
+
`Cleaned up created config file: ${configState.configPath}`
|
|
81177
|
+
);
|
|
81178
|
+
} else if (configState.wasModified && configState.originalContent) {
|
|
81179
|
+
await fs10.writeFile(configState.configPath, configState.originalContent);
|
|
81180
|
+
console.log(`Restored original config: ${configState.configPath}`);
|
|
81181
|
+
}
|
|
81182
|
+
} catch (error82) {
|
|
81183
|
+
console.error("Error cleaning up config:", error82);
|
|
81184
|
+
}
|
|
80963
81185
|
}
|
|
80964
|
-
|
|
80965
|
-
|
|
80966
|
-
await fs10.unlink(configState.
|
|
80967
|
-
console.log(`Cleaned up
|
|
80968
|
-
}
|
|
80969
|
-
|
|
80970
|
-
console.log(`Restored original config: ${configState.configPath}`);
|
|
81186
|
+
if (configState.reporterPath && configState.reporterWasCreated) {
|
|
81187
|
+
try {
|
|
81188
|
+
await fs10.unlink(configState.reporterPath);
|
|
81189
|
+
console.log(`Cleaned up reporter file: ${configState.reporterPath}`);
|
|
81190
|
+
} catch (error82) {
|
|
81191
|
+
console.error("Error cleaning up reporter:", error82);
|
|
80971
81192
|
}
|
|
80972
|
-
} catch (error82) {
|
|
80973
|
-
console.error("Error cleaning up config:", error82);
|
|
80974
81193
|
}
|
|
80975
81194
|
}
|
|
80976
81195
|
async function runPlaywrightTestWithVideo(options) {
|
|
@@ -80983,12 +81202,13 @@ async function runPlaywrightTestWithVideo(options) {
|
|
|
80983
81202
|
await ensureTestResultsInGitignore(repoLocation);
|
|
80984
81203
|
const testResult = await runPlaywrightTest(repoLocation, testFilePath);
|
|
80985
81204
|
const videoPath = await findVideoFile(repoLocation);
|
|
81205
|
+
const timestampJsonPath = await findTimestampJsonFile(repoLocation);
|
|
80986
81206
|
let uploadStatus;
|
|
80987
81207
|
if (responseUrl) {
|
|
80988
|
-
uploadStatus = await uploadVideo(videoPath, responseUrl);
|
|
80989
|
-
await
|
|
81208
|
+
uploadStatus = await uploadVideo(videoPath, timestampJsonPath, responseUrl);
|
|
81209
|
+
await deleteTestFiles(videoPath, timestampJsonPath);
|
|
80990
81210
|
} else {
|
|
80991
|
-
console.log("No responseUrl provided, keeping
|
|
81211
|
+
console.log("No responseUrl provided, keeping files locally");
|
|
80992
81212
|
}
|
|
80993
81213
|
await cleanupConfig(configState);
|
|
80994
81214
|
return {
|
package/dist/staklink-cli.cjs
CHANGED
|
@@ -10905,7 +10905,7 @@ var glob = Object.assign(glob_, {
|
|
|
10905
10905
|
glob.glob = glob;
|
|
10906
10906
|
|
|
10907
10907
|
// src/proxy/version.ts
|
|
10908
|
-
var VERSION = "0.3.
|
|
10908
|
+
var VERSION = "0.3.26";
|
|
10909
10909
|
|
|
10910
10910
|
// src/cli.ts
|
|
10911
10911
|
var STAKLINK_PROXY = "staklink-proxy";
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"testTitle": "YOLO page should display YOLO text",
|
|
3
|
+
"testId": "ea70bc1c4bc8cb3ef066-ef50a3f3fbda7cffd2c6",
|
|
4
|
+
"status": "passed",
|
|
5
|
+
"duration": 2661,
|
|
6
|
+
"startTime": "2025-11-20T05:03:47.154Z",
|
|
7
|
+
"videoPath": "/Users/evanfeenstra/code/sphinx2/staklink/test-results/scripts-demo-test-YOLO-page-should-display-YOLO-text/video.webm",
|
|
8
|
+
"actions": [
|
|
9
|
+
{
|
|
10
|
+
"title": "Navigate to \"/\"",
|
|
11
|
+
"category": "pw:api",
|
|
12
|
+
"timestamp": "2025-11-20T05:03:47.791Z",
|
|
13
|
+
"relativeMs": 637,
|
|
14
|
+
"duration": 505,
|
|
15
|
+
"stepPath": [
|
|
16
|
+
"Navigate to \"/\""
|
|
17
|
+
],
|
|
18
|
+
"location": {
|
|
19
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
20
|
+
"line": 5,
|
|
21
|
+
"column": 14
|
|
22
|
+
},
|
|
23
|
+
"sourceCode": "await page.goto('http://localhost:8080', { waitUntil: 'networkidle' });"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"title": "Wait for load state \"domcontentloaded\"",
|
|
27
|
+
"category": "pw:api",
|
|
28
|
+
"timestamp": "2025-11-20T05:03:47.793Z",
|
|
29
|
+
"relativeMs": 639,
|
|
30
|
+
"duration": 1,
|
|
31
|
+
"stepPath": [
|
|
32
|
+
"Wait for load state \"domcontentloaded\""
|
|
33
|
+
],
|
|
34
|
+
"location": {
|
|
35
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
36
|
+
"line": 8,
|
|
37
|
+
"column": 14
|
|
38
|
+
},
|
|
39
|
+
"sourceCode": "await page.waitForLoadState('domcontentloaded');"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"title": "Expect \"toHaveText\"",
|
|
43
|
+
"category": "expect",
|
|
44
|
+
"timestamp": "2025-11-20T05:03:47.815Z",
|
|
45
|
+
"relativeMs": 661,
|
|
46
|
+
"duration": 21,
|
|
47
|
+
"stepPath": [
|
|
48
|
+
"Expect \"toHaveText\""
|
|
49
|
+
],
|
|
50
|
+
"location": {
|
|
51
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
52
|
+
"line": 11,
|
|
53
|
+
"column": 36
|
|
54
|
+
},
|
|
55
|
+
"sourceCode": "await expect(page.locator('h1')).toHaveText('YOLO');"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"title": "Expect \"toBeVisible\"",
|
|
59
|
+
"category": "expect",
|
|
60
|
+
"timestamp": "2025-11-20T05:03:47.817Z",
|
|
61
|
+
"relativeMs": 663,
|
|
62
|
+
"duration": 2,
|
|
63
|
+
"stepPath": [
|
|
64
|
+
"Expect \"toBeVisible\""
|
|
65
|
+
],
|
|
66
|
+
"location": {
|
|
67
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
68
|
+
"line": 14,
|
|
69
|
+
"column": 40
|
|
70
|
+
},
|
|
71
|
+
"sourceCode": "await expect(page.locator('button')).toBeVisible();"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"title": "Expect \"toHaveText\"",
|
|
75
|
+
"category": "expect",
|
|
76
|
+
"timestamp": "2025-11-20T05:03:47.819Z",
|
|
77
|
+
"relativeMs": 665,
|
|
78
|
+
"duration": 2,
|
|
79
|
+
"stepPath": [
|
|
80
|
+
"Expect \"toHaveText\""
|
|
81
|
+
],
|
|
82
|
+
"location": {
|
|
83
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
84
|
+
"line": 15,
|
|
85
|
+
"column": 40
|
|
86
|
+
},
|
|
87
|
+
"sourceCode": "await expect(page.locator('button')).toHaveText('Test');"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"title": "Wait for timeout",
|
|
91
|
+
"category": "pw:api",
|
|
92
|
+
"timestamp": "2025-11-20T05:03:49.821Z",
|
|
93
|
+
"relativeMs": 2667,
|
|
94
|
+
"duration": 2002,
|
|
95
|
+
"stepPath": [
|
|
96
|
+
"Wait for timeout"
|
|
97
|
+
],
|
|
98
|
+
"location": {
|
|
99
|
+
"file": "/Users/evanfeenstra/code/sphinx2/staklink/scripts/demo-test.spec.ts",
|
|
100
|
+
"line": 18,
|
|
101
|
+
"column": 14
|
|
102
|
+
},
|
|
103
|
+
"sourceCode": "await page.waitForTimeout(2000);"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|