@qawolf/cli 1.36.0 → 1.38.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/dist/cli.js +322 -26
- package/dist/runner-sdk.js +320 -24
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +8 -3
- package/skills/qawolf-cli/references/run-results.md +12 -4
package/dist/cli.js
CHANGED
|
@@ -16617,6 +16617,10 @@ var publicRunStatusValues = [
|
|
|
16617
16617
|
"failed",
|
|
16618
16618
|
"canceled"
|
|
16619
16619
|
];
|
|
16620
|
+
var publicRunSummaryStatusValues = [
|
|
16621
|
+
...publicRunStatusValues,
|
|
16622
|
+
"superseded"
|
|
16623
|
+
];
|
|
16620
16624
|
var makeRunSummaryFields = (ids) => ({
|
|
16621
16625
|
completedAt: exports_iso.datetime().optional().describe("When the run finished executing. Absent while queued or running, and also absent for a terminal run that never completed execution (e.g. every flow was canceled or skipped)."),
|
|
16622
16626
|
createdAt: exports_iso.datetime(),
|
|
@@ -16628,7 +16632,11 @@ var makeRunSummaryFields = (ids) => ({
|
|
|
16628
16632
|
}).describe("The branch and commit under test. The fields are present when a deploy notification started the run, and absent for runs started another way, for example manually or with run.create."),
|
|
16629
16633
|
needsReview: boolean2().optional().describe("True once every flow has finished its attempts and at least one failed flow still has no diagnosis, including one whose investigation carried over to a later run. `status` stays `running` until that failure is diagnosed, so a caller that is not waiting for a diagnosis can stop polling here and read the run's failed flows."),
|
|
16630
16634
|
runId: ids.run,
|
|
16631
|
-
status: _enum(
|
|
16635
|
+
status: _enum(publicRunSummaryStatusValues).describe("Whole-run status, and the value to gate a pipeline on. Terminal statuses are passed, failed, canceled, and superseded; poll until one is reached. `failed` means the run found a bug that is still open and serious enough to block — a lower-priority bug, or one since resolved, reads `passed`, and the per-flow diagnoses are still in `flows`. The run stays `running` while any investigation is unresolved, including one that carried over to a later run, so a terminal status always means a settled answer, and `needsReview` tells such a run apart from one that is still executing. `superseded` means a newer run replaced this one before it finished: it is not a pass, this run will never change again, and the verdict belongs to the run in `supersededBy`."),
|
|
16636
|
+
supersededBy: object({
|
|
16637
|
+
runId: ids.run,
|
|
16638
|
+
url: url().describe("Absolute URL of the replacement run's page.")
|
|
16639
|
+
}).optional().describe("The run that replaced this one, present only when `status` is `superseded`. A newer deployment to the same branch and environment (and service, when the deployment named one) cancels the older run's unfinished flows and takes over. Deduplication ignores the commit, so the replacement may be testing a later commit than this run did. Only the direct replacement is named; that run can itself be superseded.")
|
|
16632
16640
|
});
|
|
16633
16641
|
|
|
16634
16642
|
// node_modules/@qawolf/api-contracts/dist/v1/deployment/didNotRunReason.js
|
|
@@ -16843,6 +16851,7 @@ var defaultIdSchemas = {
|
|
|
16843
16851
|
issue: string2().min(1).describe("The id of the issue."),
|
|
16844
16852
|
legacyTrigger: string2().min(1).describe("The id of the legacy trigger, from legacyTrigger.find."),
|
|
16845
16853
|
run: string2().min(1).describe("The id of the run."),
|
|
16854
|
+
runAttempt: string2().min(1).describe("The id of the run attempt."),
|
|
16846
16855
|
trigger: string2().min(1).describe("The id of the trigger."),
|
|
16847
16856
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
16848
16857
|
};
|
|
@@ -16894,6 +16903,72 @@ var makeCreateRunContract = (ids) => {
|
|
|
16894
16903
|
};
|
|
16895
16904
|
};
|
|
16896
16905
|
|
|
16906
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/listScreenshotComparisons.js
|
|
16907
|
+
var maxListedScreenshotAttempts = 20;
|
|
16908
|
+
var makeListScreenshotComparisonsContract = (ids) => {
|
|
16909
|
+
const input = object({
|
|
16910
|
+
flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").optional().describe("Only list the comparisons of these flows. Each flow must have a result in the run. Omit to list every failed flow of the run."),
|
|
16911
|
+
runId: ids.run
|
|
16912
|
+
});
|
|
16913
|
+
const imageUrl = (image) => url().describe(`Signed URL of the full-size ${image} PNG. It stops working at expiresAt.`);
|
|
16914
|
+
const previewUrl = (image) => url().optional().describe(`Signed URL of a JPEG copy of the ${image} image, scaled down so its long edge is at most 1568 pixels. ` + "Fetch this one to look at the image: it is small enough to view inline, while the full-size PNG can be too large. " + "It stops working at expiresAt. Absent when QA Wolf could not make the copy, for example because the full-size image is gone.");
|
|
16915
|
+
const passedEnvironment = object({
|
|
16916
|
+
environmentId: ids.environment,
|
|
16917
|
+
lastPassedAt: exports_iso.datetime().describe("When the latest passing comparison in this environment ran.")
|
|
16918
|
+
});
|
|
16919
|
+
const passingElsewhere = discriminatedUnion("status", [
|
|
16920
|
+
object({
|
|
16921
|
+
status: literal("not-tracked").describe("QA Wolf does not record screenshot comparisons for this workspace, so it cannot tell.")
|
|
16922
|
+
}),
|
|
16923
|
+
object({
|
|
16924
|
+
environments: array(passedEnvironment).describe("Other environments where the current baseline passed this screenshot in the last 14 days, most recent first. " + "Empty when it passed nowhere else, or when the baseline no longer exists."),
|
|
16925
|
+
status: literal("tracked")
|
|
16926
|
+
})
|
|
16927
|
+
]).describe("Whether the current baseline still passes in other environments. " + "A baseline that passes elsewhere points to a difference in this environment rather than an outdated baseline.");
|
|
16928
|
+
const comparison = object({
|
|
16929
|
+
actualPreviewUrl: previewUrl("actual"),
|
|
16930
|
+
actualUrl: imageUrl("actual (the screenshot the flow took)"),
|
|
16931
|
+
attemptCompletedAt: exports_iso.datetime().describe("When the run attempt that made the comparison finished."),
|
|
16932
|
+
baselineStatus: _enum([
|
|
16933
|
+
"unchanged",
|
|
16934
|
+
"accepted",
|
|
16935
|
+
"changed-since-run",
|
|
16936
|
+
"deleted",
|
|
16937
|
+
"unknown"
|
|
16938
|
+
]).describe('How the current baseline relates to the expected image this comparison used. "unchanged": the baseline is still the expected image. ' + `"accepted": the baseline is now this comparison's actual screenshot, because someone accepted it, so a reattempt should pass. ` + '"changed-since-run": someone replaced the baseline with another image after this run, so rerun the flow before deciding anything. ' + '"deleted": the baseline no longer exists, and the next run will save its screenshot as the new baseline. ' + `"unknown": the run's copy of the expected image is gone, so QA Wolf cannot compare.`),
|
|
16939
|
+
comparisonId: string2().describe("Identifies this comparison: the run attempt id and the position of the comparison in that attempt."),
|
|
16940
|
+
diffPreviewUrl: previewUrl("diff"),
|
|
16941
|
+
diffUrl: imageUrl("diff (the pixels that differ are highlighted)"),
|
|
16942
|
+
expectedPreviewUrl: previewUrl("expected"),
|
|
16943
|
+
expectedUrl: imageUrl("expected (the baseline as it was when the flow ran)"),
|
|
16944
|
+
filePath: string2().optional().describe("The flow file that made the comparison."),
|
|
16945
|
+
flowId: ids.flow,
|
|
16946
|
+
lineNumber: number2().int().optional().describe("The line of filePath that made the comparison."),
|
|
16947
|
+
name: string2().describe("The screenshot name the flow passed to toHaveScreenshot. The baseline is stored as _screenshots_/<name>.png in team storage."),
|
|
16948
|
+
passingElsewhere,
|
|
16949
|
+
runAttemptId: string2(),
|
|
16950
|
+
similarity: number2().describe("How much of the actual image matches the expected image, in percent."),
|
|
16951
|
+
sizeMismatch: boolean2().describe("The actual and expected images have different dimensions. That fails the comparison whatever the pixels show, and similarity reads 0.")
|
|
16952
|
+
});
|
|
16953
|
+
const output = object({
|
|
16954
|
+
comparisons: array(comparison).describe(`Each screenshot comparison that failed its flow, from the ${maxListedScreenshotAttempts} most recent failed attempts of the selected flows, oldest attempt first.`),
|
|
16955
|
+
expiresAt: exports_iso.datetime().describe("When the image URLs stop working. Call run.listScreenshotComparisons again for fresh ones after it."),
|
|
16956
|
+
truncated: boolean2().describe(`True when the selected flows have more than ${maxListedScreenshotAttempts} failed attempts. Only the ${maxListedScreenshotAttempts} most recent are listed, and the older attempts cannot be listed.`)
|
|
16957
|
+
});
|
|
16958
|
+
return {
|
|
16959
|
+
annotations: {
|
|
16960
|
+
destructiveHint: false,
|
|
16961
|
+
openWorldHint: false,
|
|
16962
|
+
readOnlyHint: false
|
|
16963
|
+
},
|
|
16964
|
+
description: "List the screenshot comparisons that failed a run's flows, with the expected, actual and diff images of each. " + "Only comparisons that caused a failure are listed: a screenshot that differs within tolerance, or that differs on a line that did not fail, is left out. " + "Each comparison tells whether its baseline changed since the run and whether the baseline still passes in other environments. " + "The image URLs expire after a few minutes; fetch the preview URLs to look at the images. " + "The first call for an image makes its missing JPEG preview and keeps it in team storage, so later calls reuse it.",
|
|
16965
|
+
input,
|
|
16966
|
+
kind: "read",
|
|
16967
|
+
name: "run.listScreenshotComparisons",
|
|
16968
|
+
output
|
|
16969
|
+
};
|
|
16970
|
+
};
|
|
16971
|
+
|
|
16897
16972
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/actionSequence.js
|
|
16898
16973
|
var maxActionsPerRequest = 10;
|
|
16899
16974
|
var screenshotModes = ["none", "final", "each"];
|
|
@@ -18959,11 +19034,22 @@ var makeGetIssueContract = (ids) => {
|
|
|
18959
19034
|
var investigationFindingStateDescription = 'What the investigation concluded about the cause. Known values: "investigating", "fixed", "fix-proposed", "reported", "report-proposed", "flake", "question" and "dismissed". New values can appear.';
|
|
18960
19035
|
var makeInvestigationFindingSchema = (ids) => object({
|
|
18961
19036
|
actual: string2().optional(),
|
|
18962
|
-
commitHash: string2().optional(),
|
|
19037
|
+
commitHash: string2().optional().describe("The commit of a commit fix. Same as `fix.commitHash`."),
|
|
18963
19038
|
decidedBy: _enum(["agent", "user"]).optional().describe("Who decided: the AI on its own, or a person who approved or dismissed it. Absent until someone decides."),
|
|
18964
19039
|
disputeReason: string2().optional().describe("Why a person disputed what the AI did. Present on a proposal the AI made again after that dispute."),
|
|
18965
19040
|
expected: string2().optional(),
|
|
18966
19041
|
findingId: string2(),
|
|
19042
|
+
fix: discriminatedUnion("type", [
|
|
19043
|
+
object({
|
|
19044
|
+
commitHash: string2().describe("The commit that changes the flow code."),
|
|
19045
|
+
type: literal("commit")
|
|
19046
|
+
}),
|
|
19047
|
+
object({
|
|
19048
|
+
baselineChangeId: string2().optional().describe('The baseline change that made the new screenshot the baseline, on a "fixed" finding. `run restoreScreenshotBaseline` undoes it.'),
|
|
19049
|
+
comparisonId: string2().describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run listScreenshotComparisons` names it."),
|
|
19050
|
+
type: literal("baseline")
|
|
19051
|
+
})
|
|
19052
|
+
]).optional().describe('The fix of a "fixed" or "fix-proposed" finding: a commit to the flow code, or a new screenshot baseline.'),
|
|
18967
19053
|
flowIds: array(ids.flow),
|
|
18968
19054
|
headline: string2().optional(),
|
|
18969
19055
|
issueId: ids.issue.optional(),
|
|
@@ -18974,8 +19060,9 @@ var makeInvestigationFindingSchema = (ids) => object({
|
|
|
18974
19060
|
answers: array(object({
|
|
18975
19061
|
description: string2().optional(),
|
|
18976
19062
|
title: string2(),
|
|
18977
|
-
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance" and "
|
|
19063
|
+
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance", "bug" and "baseline". New values can appear.')
|
|
18978
19064
|
})),
|
|
19065
|
+
comparisonId: string2().optional().describe('The failed screenshot comparison a screenshot question is about, as `run listScreenshotComparisons` names it. Its answers are "bug" (the old screenshot is right), "maintenance" (both are right) and "baseline" (the new screenshot is right).'),
|
|
18979
19066
|
text: string2()
|
|
18980
19067
|
}).optional().describe("The question waiting for a person, with the answers offered."),
|
|
18981
19068
|
response: object({
|
|
@@ -18995,6 +19082,7 @@ var makeInvestigationFindingSchema = (ids) => object({
|
|
|
18995
19082
|
var makeGetInvestigationContract = (ids) => {
|
|
18996
19083
|
const input = object({ runId: ids.run });
|
|
18997
19084
|
const output = resource({
|
|
19085
|
+
baselineChanges: _enum(["automatic", "needs-approval"]).describe('How the investigation can make a new screenshot the baseline. "automatic": it can accept a baseline on its own. ' + '"needs-approval": it proposes the baseline on a fix-proposed finding, and accepts it only after a person applies the proposal.'),
|
|
18998
19086
|
findings: array(makeInvestigationFindingSchema(ids)),
|
|
18999
19087
|
runId: ids.run,
|
|
19000
19088
|
sessionId: ids.chatSession.optional().describe("The investigation session. Absent when the run has none."),
|
|
@@ -19045,7 +19133,7 @@ var makeAddFlowsToIssueContract = (ids) => {
|
|
|
19045
19133
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/create.js
|
|
19046
19134
|
var makeCreateIssueContract = (ids) => {
|
|
19047
19135
|
const commonFields = {
|
|
19048
|
-
description: string2().optional().describe("The issue description
|
|
19136
|
+
description: string2().optional().describe("The issue description in Markdown, which is stored as rich text. Text without Markdown is stored as written, one paragraph per line."),
|
|
19049
19137
|
name: string2().trim().min(1).max(255),
|
|
19050
19138
|
priority: issuePrioritySchema.optional().describe('Defaults to "unprioritized" for bug reports and coverage requests.'),
|
|
19051
19139
|
workspaceId: ids.workspace.optional().describe("The workspace to create the issue in. Required when authenticating with an organization or user API key.")
|
|
@@ -19088,7 +19176,8 @@ var makeCreateIssueContract = (ids) => {
|
|
|
19088
19176
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/removeFlows.js
|
|
19089
19177
|
var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
19090
19178
|
const input = object({
|
|
19091
|
-
|
|
19179
|
+
environmentId: ids.environment.optional().describe("The environment whose bug or maintenance reproductions to remove. Required when a selected flow is linked in more than one environment."),
|
|
19180
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows to remove from the issue."),
|
|
19092
19181
|
issueId: ids.issue
|
|
19093
19182
|
});
|
|
19094
19183
|
const output = object({
|
|
@@ -19097,10 +19186,10 @@ var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
|
19097
19186
|
return {
|
|
19098
19187
|
annotations: {
|
|
19099
19188
|
destructiveHint: true,
|
|
19100
|
-
openWorldHint:
|
|
19189
|
+
openWorldHint: true,
|
|
19101
19190
|
readOnlyHint: false
|
|
19102
19191
|
},
|
|
19103
|
-
description: "Remove flows from a coverage request
|
|
19192
|
+
description: "Remove flows from a coverage request or remove bug/maintenance reproductions in an environment. " + "Unlinked flows are left alone. Reports auto-close when no active reproductions remain and auto-close is enabled. " + "For reports, omit environmentId only when each selected flow is linked in at most one environment.",
|
|
19104
19193
|
input,
|
|
19105
19194
|
kind: "write",
|
|
19106
19195
|
name: "issue.removeFlows",
|
|
@@ -19110,7 +19199,7 @@ var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
|
19110
19199
|
|
|
19111
19200
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/update.js
|
|
19112
19201
|
var makeUpdateIssueContract = (ids) => {
|
|
19113
|
-
const descriptionSchema = string2().describe("The issue description
|
|
19202
|
+
const descriptionSchema = string2().describe("The issue description in Markdown, which is stored as rich text. Text without Markdown is stored as written, one paragraph per line.");
|
|
19114
19203
|
const nameSchema = string2().trim().min(1).max(255);
|
|
19115
19204
|
const input = object({
|
|
19116
19205
|
description: descriptionSchema.optional(),
|
|
@@ -19260,6 +19349,49 @@ var makeLegacyTriggerContracts = (ids) => ({
|
|
|
19260
19349
|
resume: makeResumeLegacyTriggerContract(ids)
|
|
19261
19350
|
});
|
|
19262
19351
|
|
|
19352
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/investigationSessionId.js
|
|
19353
|
+
var investigationSessionId = string2().trim().min(1).max(100).optional();
|
|
19354
|
+
|
|
19355
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/acceptScreenshotBaseline.js
|
|
19356
|
+
var makeAcceptScreenshotBaselineContract = (ids) => {
|
|
19357
|
+
const input = object({
|
|
19358
|
+
chatSessionId: investigationSessionId.describe("The chat session of the investigation that accepts the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
|
|
19359
|
+
comparisonId: string2().trim().min(1).max(100).describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run.listScreenshotComparisons` names it."),
|
|
19360
|
+
runId: ids.run
|
|
19361
|
+
});
|
|
19362
|
+
const output = discriminatedUnion("outcome", [
|
|
19363
|
+
object({
|
|
19364
|
+
baselineChangeId: string2().describe("The baseline change. Record it on the fixed finding, and pass it to `run.restoreScreenshotBaseline` with this runId to put the old baseline back."),
|
|
19365
|
+
name: string2().describe("The screenshot name whose baseline changed."),
|
|
19366
|
+
outcome: literal("accepted").describe("The new screenshot is now the baseline. The old baseline is kept, so the change can be restored.")
|
|
19367
|
+
}),
|
|
19368
|
+
object({
|
|
19369
|
+
outcome: literal("baseline-changed").describe("The baseline is no longer the one the run compared with: someone changed or deleted it since. Nothing changed. List the comparisons again to see the current baseline.")
|
|
19370
|
+
}),
|
|
19371
|
+
object({
|
|
19372
|
+
outcome: literal("needs-approval").describe("Only a person can approve this change. Nothing changed. Propose the new baseline on a fix-proposed finding and wait for a person to apply it.")
|
|
19373
|
+
}),
|
|
19374
|
+
object({
|
|
19375
|
+
outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
|
|
19376
|
+
}),
|
|
19377
|
+
object({
|
|
19378
|
+
outcome: literal("nothing-to-accept").describe("The comparison did not fail, or has no new screenshot to accept. Nothing changed.")
|
|
19379
|
+
})
|
|
19380
|
+
]);
|
|
19381
|
+
return {
|
|
19382
|
+
annotations: {
|
|
19383
|
+
destructiveHint: true,
|
|
19384
|
+
openWorldHint: false,
|
|
19385
|
+
readOnlyHint: false
|
|
19386
|
+
},
|
|
19387
|
+
description: "Make the new screenshot of a failed screenshot comparison the baseline, so later runs compare with it. " + "Use it only when the difference is an intended change of the app, not a bug, noise, or a page that was not ready. " + "Every later run of every environment of the workspace compares with the new baseline. " + "Refuses without changing anything when the baseline changed since the run.",
|
|
19388
|
+
input,
|
|
19389
|
+
kind: "write",
|
|
19390
|
+
name: "run.acceptScreenshotBaseline",
|
|
19391
|
+
output
|
|
19392
|
+
};
|
|
19393
|
+
};
|
|
19394
|
+
|
|
19263
19395
|
// node_modules/@qawolf/api-contracts/dist/v1/run/diagnose.js
|
|
19264
19396
|
var makeDiagnoseRunContract = (ids) => {
|
|
19265
19397
|
const input = object({
|
|
@@ -19276,7 +19408,7 @@ var makeDiagnoseRunContract = (ids) => {
|
|
|
19276
19408
|
openWorldHint: true,
|
|
19277
19409
|
readOnlyHint: false
|
|
19278
19410
|
},
|
|
19279
|
-
description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed moves to this issue. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
|
|
19411
|
+
description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed in the run moves to this issue, and may stay linked to other open reports. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
|
|
19280
19412
|
input,
|
|
19281
19413
|
kind: "write",
|
|
19282
19414
|
name: "run.diagnose",
|
|
@@ -19294,9 +19426,11 @@ var makeFindRunsContract = (ids) => {
|
|
|
19294
19426
|
});
|
|
19295
19427
|
const output = object({
|
|
19296
19428
|
nextCursor: nextCursorSchema,
|
|
19297
|
-
runs: array(resource(
|
|
19298
|
-
|
|
19299
|
-
|
|
19429
|
+
runs: array(resource({
|
|
19430
|
+
...makeRunSummaryFields(ids),
|
|
19431
|
+
failedAttemptCount: number2().int().nonnegative().optional(),
|
|
19432
|
+
hasFailedAttempts: boolean2().optional()
|
|
19433
|
+
}, { urlFieldDescription: "Absolute URL of the run page." })).describe("The environment's runs, newest first. Per-flow results are available via run.get.")
|
|
19300
19434
|
});
|
|
19301
19435
|
return {
|
|
19302
19436
|
annotations: {
|
|
@@ -19304,7 +19438,7 @@ var makeFindRunsContract = (ids) => {
|
|
|
19304
19438
|
openWorldHint: false,
|
|
19305
19439
|
readOnlyHint: true
|
|
19306
19440
|
},
|
|
19307
|
-
description: "List an environment's recent runs, newest first.",
|
|
19441
|
+
description: "List an environment's recent runs, newest first, including failed-attempt discovery metadata.",
|
|
19308
19442
|
input,
|
|
19309
19443
|
kind: "read",
|
|
19310
19444
|
name: "run.find",
|
|
@@ -19312,6 +19446,22 @@ var makeFindRunsContract = (ids) => {
|
|
|
19312
19446
|
};
|
|
19313
19447
|
};
|
|
19314
19448
|
|
|
19449
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/flowFailure.js
|
|
19450
|
+
var makeFlowFailureSchema = (ids) => {
|
|
19451
|
+
const diagnosis = object({
|
|
19452
|
+
issueId: ids.issue,
|
|
19453
|
+
type: _enum(["bug", "maintenance"])
|
|
19454
|
+
}).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict, and absent when " + "the flow was opted out of investigation. Pass issueId to issue.get " + "for details.");
|
|
19455
|
+
const optedOutOfInvestigation = object({
|
|
19456
|
+
by: _enum(["user", "system"]).describe("Who stopped the investigation: `user` is a person, in the app or " + "with a user API key, or the workspace's automation user for a " + "team or organization API key, for example through " + "run.optOutOfInvestigation; `system` is QA Wolf, when the " + "investigation expired.")
|
|
19457
|
+
}).optional().describe('Present when the failure was marked "do not investigate" (DNI): ' + "it will get no bug or maintenance verdict.");
|
|
19458
|
+
return object({
|
|
19459
|
+
diagnosis,
|
|
19460
|
+
error: string2(),
|
|
19461
|
+
optedOutOfInvestigation
|
|
19462
|
+
});
|
|
19463
|
+
};
|
|
19464
|
+
|
|
19315
19465
|
// node_modules/@qawolf/api-contracts/dist/v1/run/get.js
|
|
19316
19466
|
var makeGetRunContract = (ids) => {
|
|
19317
19467
|
const flowStatus = _enum(publicRunStatusValues);
|
|
@@ -19328,6 +19478,7 @@ var makeGetRunContract = (ids) => {
|
|
|
19328
19478
|
const automatedAttempt = discriminatedUnion("status", [
|
|
19329
19479
|
object({
|
|
19330
19480
|
...artifactUrls,
|
|
19481
|
+
attemptId: ids.runAttempt.optional(),
|
|
19331
19482
|
completedAt: exports_iso.datetime(),
|
|
19332
19483
|
kind: automatedKind,
|
|
19333
19484
|
startedAt: exports_iso.datetime(),
|
|
@@ -19335,12 +19486,14 @@ var makeGetRunContract = (ids) => {
|
|
|
19335
19486
|
}),
|
|
19336
19487
|
object({
|
|
19337
19488
|
...artifactUrls,
|
|
19489
|
+
attemptId: ids.runAttempt.optional(),
|
|
19338
19490
|
completedAt: exports_iso.datetime(),
|
|
19339
19491
|
kind: automatedKind,
|
|
19340
19492
|
startedAt: exports_iso.datetime().optional().describe("Absent when the attempt failed before it could start."),
|
|
19341
19493
|
status: literal("failed")
|
|
19342
19494
|
}),
|
|
19343
19495
|
object({
|
|
19496
|
+
attemptId: ids.runAttempt.optional(),
|
|
19344
19497
|
completedAt: exports_iso.datetime().optional(),
|
|
19345
19498
|
kind: automatedKind,
|
|
19346
19499
|
startedAt: exports_iso.datetime().optional(),
|
|
@@ -19348,6 +19501,7 @@ var makeGetRunContract = (ids) => {
|
|
|
19348
19501
|
})
|
|
19349
19502
|
]);
|
|
19350
19503
|
const manualAttempt = object({
|
|
19504
|
+
attemptId: ids.runAttempt.optional(),
|
|
19351
19505
|
completedAt: exports_iso.datetime(),
|
|
19352
19506
|
kind: literal("manual").describe("The attempt ran by hand in the Wolf Browser."),
|
|
19353
19507
|
startedAt: exports_iso.datetime(),
|
|
@@ -19355,16 +19509,9 @@ var makeGetRunContract = (ids) => {
|
|
|
19355
19509
|
});
|
|
19356
19510
|
const attempt = union([automatedAttempt, manualAttempt]);
|
|
19357
19511
|
const attempts = array(attempt).optional().describe("The flow's finished execution attempts, oldest first, including " + "manual Wolf Browser attempts. Present once at least one attempt has " + "finished, so a flow that passed after retries also lists its failed " + "attempts. Artifact URLs appear only on automated attempts that " + "reached a verdict, stay valid for at least a day (call run.get " + "again for fresh ones), and can return 404 when the attempt did not " + "produce that artifact.");
|
|
19358
|
-
const diagnosis = object({
|
|
19359
|
-
issueId: ids.issue,
|
|
19360
|
-
type: _enum(["bug", "maintenance"])
|
|
19361
|
-
}).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict. Pass issueId to " + "issue.get for details.");
|
|
19362
19512
|
const failedFlow = object({
|
|
19363
19513
|
attempts,
|
|
19364
|
-
failure:
|
|
19365
|
-
diagnosis,
|
|
19366
|
-
error: string2()
|
|
19367
|
-
}),
|
|
19514
|
+
failure: makeFlowFailureSchema(ids),
|
|
19368
19515
|
flowId: ids.flow,
|
|
19369
19516
|
name: string2(),
|
|
19370
19517
|
status: literal("failed")
|
|
@@ -19396,6 +19543,107 @@ var makeGetRunContract = (ids) => {
|
|
|
19396
19543
|
};
|
|
19397
19544
|
};
|
|
19398
19545
|
|
|
19546
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/getAttemptArtifacts.js
|
|
19547
|
+
var makeGetRunAttemptArtifactsContract = (ids) => {
|
|
19548
|
+
const input = object({ attemptId: ids.runAttempt });
|
|
19549
|
+
const attemptStatus = _enum([
|
|
19550
|
+
"passed",
|
|
19551
|
+
"failed",
|
|
19552
|
+
"canceled",
|
|
19553
|
+
"aborted",
|
|
19554
|
+
"skipped"
|
|
19555
|
+
]);
|
|
19556
|
+
const attemptNeighbor = object({
|
|
19557
|
+
attemptId: ids.runAttempt,
|
|
19558
|
+
status: attemptStatus
|
|
19559
|
+
});
|
|
19560
|
+
const response = object({
|
|
19561
|
+
flowId: ids.flow,
|
|
19562
|
+
flowStatus: _enum(publicRunStatusValues),
|
|
19563
|
+
retryContext: object({
|
|
19564
|
+
currentOrdinal: number2().int().min(1),
|
|
19565
|
+
next: attemptNeighbor.optional(),
|
|
19566
|
+
previous: attemptNeighbor.optional(),
|
|
19567
|
+
total: number2().int().min(1)
|
|
19568
|
+
}),
|
|
19569
|
+
runId: ids.run,
|
|
19570
|
+
runStatus: _enum(publicRunSummaryStatusValues)
|
|
19571
|
+
});
|
|
19572
|
+
const attempt = object({
|
|
19573
|
+
attemptId: ids.runAttempt,
|
|
19574
|
+
completedAt: exports_iso.datetime().optional(),
|
|
19575
|
+
createdAt: exports_iso.datetime(),
|
|
19576
|
+
error: string2().optional(),
|
|
19577
|
+
startedAt: exports_iso.datetime().optional()
|
|
19578
|
+
});
|
|
19579
|
+
const output = discriminatedUnion("artifactStatus", [
|
|
19580
|
+
response.extend({
|
|
19581
|
+
artifacts: object({
|
|
19582
|
+
logsUrl: url().optional(),
|
|
19583
|
+
traceUrl: url().optional(),
|
|
19584
|
+
videoUrl: url().optional()
|
|
19585
|
+
}),
|
|
19586
|
+
artifactStatus: literal("signed"),
|
|
19587
|
+
attempt: attempt.extend({
|
|
19588
|
+
kind: literal("automated"),
|
|
19589
|
+
status: attemptStatus
|
|
19590
|
+
})
|
|
19591
|
+
}),
|
|
19592
|
+
response.extend({
|
|
19593
|
+
artifacts: object({}).strict(),
|
|
19594
|
+
artifactStatus: literal("signing-failed"),
|
|
19595
|
+
attempt: attempt.extend({
|
|
19596
|
+
kind: literal("automated"),
|
|
19597
|
+
status: attemptStatus
|
|
19598
|
+
})
|
|
19599
|
+
}),
|
|
19600
|
+
response.extend({
|
|
19601
|
+
artifacts: object({}).strict(),
|
|
19602
|
+
artifactStatus: literal("not-captured"),
|
|
19603
|
+
attempt: attempt.extend({
|
|
19604
|
+
kind: literal("manual"),
|
|
19605
|
+
status: literal("passed")
|
|
19606
|
+
})
|
|
19607
|
+
})
|
|
19608
|
+
]);
|
|
19609
|
+
return {
|
|
19610
|
+
annotations: {
|
|
19611
|
+
destructiveHint: false,
|
|
19612
|
+
openWorldHint: false,
|
|
19613
|
+
readOnlyHint: true
|
|
19614
|
+
},
|
|
19615
|
+
description: "Get metadata and signed artifact URLs for one finished run attempt.",
|
|
19616
|
+
input,
|
|
19617
|
+
kind: "read",
|
|
19618
|
+
name: "run.getAttemptArtifacts",
|
|
19619
|
+
output
|
|
19620
|
+
};
|
|
19621
|
+
};
|
|
19622
|
+
|
|
19623
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/optOutOfInvestigation.js
|
|
19624
|
+
var makeOptOutOfInvestigationRunContract = (ids) => {
|
|
19625
|
+
const input = object({
|
|
19626
|
+
flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The failed flows to stop investigating. Every named flow must be " + "eligible or the whole request is rejected."),
|
|
19627
|
+
runId: ids.run
|
|
19628
|
+
});
|
|
19629
|
+
const output = resource({
|
|
19630
|
+
optedOutFlowIds: array(ids.flow).describe("The flows that no longer need investigation."),
|
|
19631
|
+
runId: ids.run
|
|
19632
|
+
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
19633
|
+
return {
|
|
19634
|
+
annotations: {
|
|
19635
|
+
destructiveHint: true,
|
|
19636
|
+
openWorldHint: true,
|
|
19637
|
+
readOnlyHint: false
|
|
19638
|
+
},
|
|
19639
|
+
description: 'Mark failed flows in a run as "do not investigate" (DNI): the failures need no bug or maintenance report. ' + "Each flow must have failed in the run and still be under investigation. " + "A flow that already has a diagnosis cannot be opted out. " + "A team or organization key records the opt-out as the workspace's automation user. " + "To link a failure to a report instead, use run.diagnose.",
|
|
19640
|
+
input,
|
|
19641
|
+
kind: "write",
|
|
19642
|
+
name: "run.optOutOfInvestigation",
|
|
19643
|
+
output
|
|
19644
|
+
};
|
|
19645
|
+
};
|
|
19646
|
+
|
|
19399
19647
|
// node_modules/@qawolf/api-contracts/dist/v1/run/reattempt.js
|
|
19400
19648
|
var makeReattemptRunContract = (ids) => {
|
|
19401
19649
|
const input = object({
|
|
@@ -19420,6 +19668,45 @@ var makeReattemptRunContract = (ids) => {
|
|
|
19420
19668
|
};
|
|
19421
19669
|
};
|
|
19422
19670
|
|
|
19671
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/restoreScreenshotBaseline.js
|
|
19672
|
+
var makeRestoreScreenshotBaselineContract = (ids) => {
|
|
19673
|
+
const input = object({
|
|
19674
|
+
baselineChangeId: string2().trim().min(1).max(100).describe("The baseline change to undo, as `run.acceptScreenshotBaseline` returned it for this run."),
|
|
19675
|
+
chatSessionId: investigationSessionId.describe("The chat session of the investigation that restores the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
|
|
19676
|
+
runId: ids.run
|
|
19677
|
+
});
|
|
19678
|
+
const output = discriminatedUnion("outcome", [
|
|
19679
|
+
object({
|
|
19680
|
+
name: string2().describe("The screenshot name whose baseline changed."),
|
|
19681
|
+
outcome: literal("restored").describe("The baseline the change replaced is the baseline again.")
|
|
19682
|
+
}),
|
|
19683
|
+
object({
|
|
19684
|
+
outcome: literal("baseline-changed").describe("The baseline changed again after this change, so restoring it would undo someone else's change. Nothing changed.")
|
|
19685
|
+
}),
|
|
19686
|
+
object({
|
|
19687
|
+
outcome: literal("needs-dispute").describe("Only a person can restore this change, unless a person disputed the finding that made it. Nothing changed.")
|
|
19688
|
+
}),
|
|
19689
|
+
object({
|
|
19690
|
+
outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
|
|
19691
|
+
}),
|
|
19692
|
+
object({
|
|
19693
|
+
outcome: literal("nothing-to-restore").describe("The change was already restored, the name had no baseline before it, or the kept copy of the old baseline is missing or is not the baseline the change replaced. Nothing changed.")
|
|
19694
|
+
})
|
|
19695
|
+
]);
|
|
19696
|
+
return {
|
|
19697
|
+
annotations: {
|
|
19698
|
+
destructiveHint: true,
|
|
19699
|
+
openWorldHint: false,
|
|
19700
|
+
readOnlyHint: false
|
|
19701
|
+
},
|
|
19702
|
+
description: "Undo a screenshot baseline change that accepted a failed comparison of the run: put back the baseline it replaced, so later runs compare with the old baseline again. " + "Use it when a person disputes a baseline the AI accepted. " + "Refuses without changing anything when the baseline changed again since.",
|
|
19703
|
+
input,
|
|
19704
|
+
kind: "write",
|
|
19705
|
+
name: "run.restoreScreenshotBaseline",
|
|
19706
|
+
output
|
|
19707
|
+
};
|
|
19708
|
+
};
|
|
19709
|
+
|
|
19423
19710
|
// node_modules/@qawolf/api-contracts/dist/v1/run/stop.js
|
|
19424
19711
|
var makeStopRunContract = (ids) => {
|
|
19425
19712
|
const input = object({ runId: ids.run });
|
|
@@ -19740,7 +20027,7 @@ var makeRunFlowOnRunnerContract = (ids) => {
|
|
|
19740
20027
|
env: runEnvironmentSchema.optional().describe("Environment variables to make available to the run."),
|
|
19741
20028
|
environmentId: ids.environmentRef.optional().describe("A QA Wolf environment whose variables the run is given, by id or alias. QA Wolf reads and decrypts them itself, so they never travel in the request and the count and length limits on `env` do not apply to them. Send this or `env`, not both."),
|
|
19742
20029
|
files: runFilesSchema.describe("Every file the run needs keyed by its path — the flow file, everything it imports, package.json and tsconfig.json. A runner holds no copy of your project, so what runs is exactly what is sent here."),
|
|
19743
|
-
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both.
|
|
20030
|
+
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both. Omitted, the flow whose file is at `entryPointPath` on the named environment's flow-code branch stands in; a file not in QA Wolf yet, or a run given no environment, leaves the run with no `QAWOLF_WORKFLOW_ID`."),
|
|
19744
20031
|
id: runnerIdSchema.describe("Id of the runner to run the flow on."),
|
|
19745
20032
|
selection: runSelectionSchema.optional().describe("Run only these lines, inside the page the runner is already on, instead of running the whole flow from a fresh browser. Omit to run the whole entry point."),
|
|
19746
20033
|
unchangedFiles: unchangedFilesSchema.optional().describe("Files this runner already holds from an earlier run, keyed by path with a hex SHA-256 of the content it should hold. Send this to make `files` only what changed. The runner refuses with `needs-full-sync` if it holds none of a referenced path, so it never runs something other than what was asked for. Omit it to send every file."),
|
|
@@ -19956,7 +20243,11 @@ var makeListTagsContract = (ids) => {
|
|
|
19956
20243
|
|
|
19957
20244
|
// node_modules/@qawolf/api-contracts/dist/v1/index.js
|
|
19958
20245
|
var makeContractsV1 = (ids) => {
|
|
19959
|
-
const resolvedIds = {
|
|
20246
|
+
const resolvedIds = {
|
|
20247
|
+
...defaultIdSchemas,
|
|
20248
|
+
...ids,
|
|
20249
|
+
runAttempt: ids.runAttempt ?? defaultIdSchemas.runAttempt
|
|
20250
|
+
};
|
|
19960
20251
|
return {
|
|
19961
20252
|
agent: {
|
|
19962
20253
|
get: makeAgentGetContract(resolvedIds),
|
|
@@ -20003,11 +20294,16 @@ var makeContractsV1 = (ids) => {
|
|
|
20003
20294
|
},
|
|
20004
20295
|
legacyTrigger: makeLegacyTriggerContracts(resolvedIds),
|
|
20005
20296
|
run: {
|
|
20297
|
+
acceptScreenshotBaseline: makeAcceptScreenshotBaselineContract(resolvedIds),
|
|
20006
20298
|
create: makeCreateRunContract(resolvedIds),
|
|
20007
20299
|
diagnose: makeDiagnoseRunContract(resolvedIds),
|
|
20008
20300
|
find: makeFindRunsContract(resolvedIds),
|
|
20009
20301
|
get: makeGetRunContract(resolvedIds),
|
|
20302
|
+
getAttemptArtifacts: makeGetRunAttemptArtifactsContract(resolvedIds),
|
|
20303
|
+
listScreenshotComparisons: makeListScreenshotComparisonsContract(resolvedIds),
|
|
20304
|
+
optOutOfInvestigation: makeOptOutOfInvestigationRunContract(resolvedIds),
|
|
20010
20305
|
reattempt: makeReattemptRunContract(resolvedIds),
|
|
20306
|
+
restoreScreenshotBaseline: makeRestoreScreenshotBaselineContract(resolvedIds),
|
|
20011
20307
|
stop: makeStopRunContract(resolvedIds)
|
|
20012
20308
|
},
|
|
20013
20309
|
runner: makeRunnerContracts(resolvedIds),
|
|
@@ -22524,7 +22820,7 @@ function startUpdateCheck(deps) {
|
|
|
22524
22820
|
// package.json
|
|
22525
22821
|
var package_default = {
|
|
22526
22822
|
name: "@qawolf/cli",
|
|
22527
|
-
version: "1.
|
|
22823
|
+
version: "1.38.0",
|
|
22528
22824
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
22529
22825
|
keywords: [
|
|
22530
22826
|
"automation",
|
|
@@ -22595,7 +22891,7 @@ var package_default = {
|
|
|
22595
22891
|
"@clack/prompts": "1.5.1",
|
|
22596
22892
|
"@napi-rs/keyring": "1.3.0",
|
|
22597
22893
|
"@oxc-node/core": "0.1.0",
|
|
22598
|
-
"@qawolf/api-contracts": "0.
|
|
22894
|
+
"@qawolf/api-contracts": "0.77.0",
|
|
22599
22895
|
"@qawolf/emails": "1.1.1",
|
|
22600
22896
|
"@qawolf/flow-targets": "1.0.0",
|
|
22601
22897
|
"@qawolf/flows": "0.1.4",
|
|
@@ -38846,4 +39142,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
38846
39142
|
process.exitCode = 1;
|
|
38847
39143
|
}).finally(() => exitWhenIdle(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
38848
39144
|
|
|
38849
|
-
//# debugId=
|
|
39145
|
+
//# debugId=4535AB8728B9D01A64756E2164756E21
|
package/dist/runner-sdk.js
CHANGED
|
@@ -6979,6 +6979,10 @@ var publicRunStatusValues = [
|
|
|
6979
6979
|
"failed",
|
|
6980
6980
|
"canceled"
|
|
6981
6981
|
];
|
|
6982
|
+
var publicRunSummaryStatusValues = [
|
|
6983
|
+
...publicRunStatusValues,
|
|
6984
|
+
"superseded"
|
|
6985
|
+
];
|
|
6982
6986
|
var makeRunSummaryFields = (ids) => ({
|
|
6983
6987
|
completedAt: exports_iso.datetime().optional().describe("When the run finished executing. Absent while queued or running, and also absent for a terminal run that never completed execution (e.g. every flow was canceled or skipped)."),
|
|
6984
6988
|
createdAt: exports_iso.datetime(),
|
|
@@ -6990,7 +6994,11 @@ var makeRunSummaryFields = (ids) => ({
|
|
|
6990
6994
|
}).describe("The branch and commit under test. The fields are present when a deploy notification started the run, and absent for runs started another way, for example manually or with run.create."),
|
|
6991
6995
|
needsReview: boolean2().optional().describe("True once every flow has finished its attempts and at least one failed flow still has no diagnosis, including one whose investigation carried over to a later run. `status` stays `running` until that failure is diagnosed, so a caller that is not waiting for a diagnosis can stop polling here and read the run's failed flows."),
|
|
6992
6996
|
runId: ids.run,
|
|
6993
|
-
status: _enum(
|
|
6997
|
+
status: _enum(publicRunSummaryStatusValues).describe("Whole-run status, and the value to gate a pipeline on. Terminal statuses are passed, failed, canceled, and superseded; poll until one is reached. `failed` means the run found a bug that is still open and serious enough to block — a lower-priority bug, or one since resolved, reads `passed`, and the per-flow diagnoses are still in `flows`. The run stays `running` while any investigation is unresolved, including one that carried over to a later run, so a terminal status always means a settled answer, and `needsReview` tells such a run apart from one that is still executing. `superseded` means a newer run replaced this one before it finished: it is not a pass, this run will never change again, and the verdict belongs to the run in `supersededBy`."),
|
|
6998
|
+
supersededBy: object({
|
|
6999
|
+
runId: ids.run,
|
|
7000
|
+
url: url().describe("Absolute URL of the replacement run's page.")
|
|
7001
|
+
}).optional().describe("The run that replaced this one, present only when `status` is `superseded`. A newer deployment to the same branch and environment (and service, when the deployment named one) cancels the older run's unfinished flows and takes over. Deduplication ignores the commit, so the replacement may be testing a later commit than this run did. Only the direct replacement is named; that run can itself be superseded.")
|
|
6994
7002
|
});
|
|
6995
7003
|
|
|
6996
7004
|
// node_modules/@qawolf/api-contracts/dist/v1/deployment/didNotRunReason.js
|
|
@@ -7205,6 +7213,7 @@ var defaultIdSchemas = {
|
|
|
7205
7213
|
issue: string2().min(1).describe("The id of the issue."),
|
|
7206
7214
|
legacyTrigger: string2().min(1).describe("The id of the legacy trigger, from legacyTrigger.find."),
|
|
7207
7215
|
run: string2().min(1).describe("The id of the run."),
|
|
7216
|
+
runAttempt: string2().min(1).describe("The id of the run attempt."),
|
|
7208
7217
|
trigger: string2().min(1).describe("The id of the trigger."),
|
|
7209
7218
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
7210
7219
|
};
|
|
@@ -7256,6 +7265,72 @@ var makeCreateRunContract = (ids) => {
|
|
|
7256
7265
|
};
|
|
7257
7266
|
};
|
|
7258
7267
|
|
|
7268
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/listScreenshotComparisons.js
|
|
7269
|
+
var maxListedScreenshotAttempts = 20;
|
|
7270
|
+
var makeListScreenshotComparisonsContract = (ids) => {
|
|
7271
|
+
const input = object({
|
|
7272
|
+
flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").optional().describe("Only list the comparisons of these flows. Each flow must have a result in the run. Omit to list every failed flow of the run."),
|
|
7273
|
+
runId: ids.run
|
|
7274
|
+
});
|
|
7275
|
+
const imageUrl = (image) => url().describe(`Signed URL of the full-size ${image} PNG. It stops working at expiresAt.`);
|
|
7276
|
+
const previewUrl = (image) => url().optional().describe(`Signed URL of a JPEG copy of the ${image} image, scaled down so its long edge is at most 1568 pixels. ` + "Fetch this one to look at the image: it is small enough to view inline, while the full-size PNG can be too large. " + "It stops working at expiresAt. Absent when QA Wolf could not make the copy, for example because the full-size image is gone.");
|
|
7277
|
+
const passedEnvironment = object({
|
|
7278
|
+
environmentId: ids.environment,
|
|
7279
|
+
lastPassedAt: exports_iso.datetime().describe("When the latest passing comparison in this environment ran.")
|
|
7280
|
+
});
|
|
7281
|
+
const passingElsewhere = discriminatedUnion("status", [
|
|
7282
|
+
object({
|
|
7283
|
+
status: literal("not-tracked").describe("QA Wolf does not record screenshot comparisons for this workspace, so it cannot tell.")
|
|
7284
|
+
}),
|
|
7285
|
+
object({
|
|
7286
|
+
environments: array(passedEnvironment).describe("Other environments where the current baseline passed this screenshot in the last 14 days, most recent first. " + "Empty when it passed nowhere else, or when the baseline no longer exists."),
|
|
7287
|
+
status: literal("tracked")
|
|
7288
|
+
})
|
|
7289
|
+
]).describe("Whether the current baseline still passes in other environments. " + "A baseline that passes elsewhere points to a difference in this environment rather than an outdated baseline.");
|
|
7290
|
+
const comparison = object({
|
|
7291
|
+
actualPreviewUrl: previewUrl("actual"),
|
|
7292
|
+
actualUrl: imageUrl("actual (the screenshot the flow took)"),
|
|
7293
|
+
attemptCompletedAt: exports_iso.datetime().describe("When the run attempt that made the comparison finished."),
|
|
7294
|
+
baselineStatus: _enum([
|
|
7295
|
+
"unchanged",
|
|
7296
|
+
"accepted",
|
|
7297
|
+
"changed-since-run",
|
|
7298
|
+
"deleted",
|
|
7299
|
+
"unknown"
|
|
7300
|
+
]).describe('How the current baseline relates to the expected image this comparison used. "unchanged": the baseline is still the expected image. ' + `"accepted": the baseline is now this comparison's actual screenshot, because someone accepted it, so a reattempt should pass. ` + '"changed-since-run": someone replaced the baseline with another image after this run, so rerun the flow before deciding anything. ' + '"deleted": the baseline no longer exists, and the next run will save its screenshot as the new baseline. ' + `"unknown": the run's copy of the expected image is gone, so QA Wolf cannot compare.`),
|
|
7301
|
+
comparisonId: string2().describe("Identifies this comparison: the run attempt id and the position of the comparison in that attempt."),
|
|
7302
|
+
diffPreviewUrl: previewUrl("diff"),
|
|
7303
|
+
diffUrl: imageUrl("diff (the pixels that differ are highlighted)"),
|
|
7304
|
+
expectedPreviewUrl: previewUrl("expected"),
|
|
7305
|
+
expectedUrl: imageUrl("expected (the baseline as it was when the flow ran)"),
|
|
7306
|
+
filePath: string2().optional().describe("The flow file that made the comparison."),
|
|
7307
|
+
flowId: ids.flow,
|
|
7308
|
+
lineNumber: number2().int().optional().describe("The line of filePath that made the comparison."),
|
|
7309
|
+
name: string2().describe("The screenshot name the flow passed to toHaveScreenshot. The baseline is stored as _screenshots_/<name>.png in team storage."),
|
|
7310
|
+
passingElsewhere,
|
|
7311
|
+
runAttemptId: string2(),
|
|
7312
|
+
similarity: number2().describe("How much of the actual image matches the expected image, in percent."),
|
|
7313
|
+
sizeMismatch: boolean2().describe("The actual and expected images have different dimensions. That fails the comparison whatever the pixels show, and similarity reads 0.")
|
|
7314
|
+
});
|
|
7315
|
+
const output = object({
|
|
7316
|
+
comparisons: array(comparison).describe(`Each screenshot comparison that failed its flow, from the ${maxListedScreenshotAttempts} most recent failed attempts of the selected flows, oldest attempt first.`),
|
|
7317
|
+
expiresAt: exports_iso.datetime().describe("When the image URLs stop working. Call run.listScreenshotComparisons again for fresh ones after it."),
|
|
7318
|
+
truncated: boolean2().describe(`True when the selected flows have more than ${maxListedScreenshotAttempts} failed attempts. Only the ${maxListedScreenshotAttempts} most recent are listed, and the older attempts cannot be listed.`)
|
|
7319
|
+
});
|
|
7320
|
+
return {
|
|
7321
|
+
annotations: {
|
|
7322
|
+
destructiveHint: false,
|
|
7323
|
+
openWorldHint: false,
|
|
7324
|
+
readOnlyHint: false
|
|
7325
|
+
},
|
|
7326
|
+
description: "List the screenshot comparisons that failed a run's flows, with the expected, actual and diff images of each. " + "Only comparisons that caused a failure are listed: a screenshot that differs within tolerance, or that differs on a line that did not fail, is left out. " + "Each comparison tells whether its baseline changed since the run and whether the baseline still passes in other environments. " + "The image URLs expire after a few minutes; fetch the preview URLs to look at the images. " + "The first call for an image makes its missing JPEG preview and keeps it in team storage, so later calls reuse it.",
|
|
7327
|
+
input,
|
|
7328
|
+
kind: "read",
|
|
7329
|
+
name: "run.listScreenshotComparisons",
|
|
7330
|
+
output
|
|
7331
|
+
};
|
|
7332
|
+
};
|
|
7333
|
+
|
|
7259
7334
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/actionSequence.js
|
|
7260
7335
|
var maxActionsPerRequest = 10;
|
|
7261
7336
|
var screenshotModes = ["none", "final", "each"];
|
|
@@ -9328,11 +9403,22 @@ var makeGetIssueContract = (ids) => {
|
|
|
9328
9403
|
var investigationFindingStateDescription = 'What the investigation concluded about the cause. Known values: "investigating", "fixed", "fix-proposed", "reported", "report-proposed", "flake", "question" and "dismissed". New values can appear.';
|
|
9329
9404
|
var makeInvestigationFindingSchema = (ids) => object({
|
|
9330
9405
|
actual: string2().optional(),
|
|
9331
|
-
commitHash: string2().optional(),
|
|
9406
|
+
commitHash: string2().optional().describe("The commit of a commit fix. Same as `fix.commitHash`."),
|
|
9332
9407
|
decidedBy: _enum(["agent", "user"]).optional().describe("Who decided: the AI on its own, or a person who approved or dismissed it. Absent until someone decides."),
|
|
9333
9408
|
disputeReason: string2().optional().describe("Why a person disputed what the AI did. Present on a proposal the AI made again after that dispute."),
|
|
9334
9409
|
expected: string2().optional(),
|
|
9335
9410
|
findingId: string2(),
|
|
9411
|
+
fix: discriminatedUnion("type", [
|
|
9412
|
+
object({
|
|
9413
|
+
commitHash: string2().describe("The commit that changes the flow code."),
|
|
9414
|
+
type: literal("commit")
|
|
9415
|
+
}),
|
|
9416
|
+
object({
|
|
9417
|
+
baselineChangeId: string2().optional().describe('The baseline change that made the new screenshot the baseline, on a "fixed" finding. `run restoreScreenshotBaseline` undoes it.'),
|
|
9418
|
+
comparisonId: string2().describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run listScreenshotComparisons` names it."),
|
|
9419
|
+
type: literal("baseline")
|
|
9420
|
+
})
|
|
9421
|
+
]).optional().describe('The fix of a "fixed" or "fix-proposed" finding: a commit to the flow code, or a new screenshot baseline.'),
|
|
9336
9422
|
flowIds: array(ids.flow),
|
|
9337
9423
|
headline: string2().optional(),
|
|
9338
9424
|
issueId: ids.issue.optional(),
|
|
@@ -9343,8 +9429,9 @@ var makeInvestigationFindingSchema = (ids) => object({
|
|
|
9343
9429
|
answers: array(object({
|
|
9344
9430
|
description: string2().optional(),
|
|
9345
9431
|
title: string2(),
|
|
9346
|
-
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance" and "
|
|
9432
|
+
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance", "bug" and "baseline". New values can appear.')
|
|
9347
9433
|
})),
|
|
9434
|
+
comparisonId: string2().optional().describe('The failed screenshot comparison a screenshot question is about, as `run listScreenshotComparisons` names it. Its answers are "bug" (the old screenshot is right), "maintenance" (both are right) and "baseline" (the new screenshot is right).'),
|
|
9348
9435
|
text: string2()
|
|
9349
9436
|
}).optional().describe("The question waiting for a person, with the answers offered."),
|
|
9350
9437
|
response: object({
|
|
@@ -9364,6 +9451,7 @@ var makeInvestigationFindingSchema = (ids) => object({
|
|
|
9364
9451
|
var makeGetInvestigationContract = (ids) => {
|
|
9365
9452
|
const input = object({ runId: ids.run });
|
|
9366
9453
|
const output = resource({
|
|
9454
|
+
baselineChanges: _enum(["automatic", "needs-approval"]).describe('How the investigation can make a new screenshot the baseline. "automatic": it can accept a baseline on its own. ' + '"needs-approval": it proposes the baseline on a fix-proposed finding, and accepts it only after a person applies the proposal.'),
|
|
9367
9455
|
findings: array(makeInvestigationFindingSchema(ids)),
|
|
9368
9456
|
runId: ids.run,
|
|
9369
9457
|
sessionId: ids.chatSession.optional().describe("The investigation session. Absent when the run has none."),
|
|
@@ -9414,7 +9502,7 @@ var makeAddFlowsToIssueContract = (ids) => {
|
|
|
9414
9502
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/create.js
|
|
9415
9503
|
var makeCreateIssueContract = (ids) => {
|
|
9416
9504
|
const commonFields = {
|
|
9417
|
-
description: string2().optional().describe("The issue description
|
|
9505
|
+
description: string2().optional().describe("The issue description in Markdown, which is stored as rich text. Text without Markdown is stored as written, one paragraph per line."),
|
|
9418
9506
|
name: string2().trim().min(1).max(255),
|
|
9419
9507
|
priority: issuePrioritySchema.optional().describe('Defaults to "unprioritized" for bug reports and coverage requests.'),
|
|
9420
9508
|
workspaceId: ids.workspace.optional().describe("The workspace to create the issue in. Required when authenticating with an organization or user API key.")
|
|
@@ -9457,7 +9545,8 @@ var makeCreateIssueContract = (ids) => {
|
|
|
9457
9545
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/removeFlows.js
|
|
9458
9546
|
var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
9459
9547
|
const input = object({
|
|
9460
|
-
|
|
9548
|
+
environmentId: ids.environment.optional().describe("The environment whose bug or maintenance reproductions to remove. Required when a selected flow is linked in more than one environment."),
|
|
9549
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows to remove from the issue."),
|
|
9461
9550
|
issueId: ids.issue
|
|
9462
9551
|
});
|
|
9463
9552
|
const output = object({
|
|
@@ -9466,10 +9555,10 @@ var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
|
9466
9555
|
return {
|
|
9467
9556
|
annotations: {
|
|
9468
9557
|
destructiveHint: true,
|
|
9469
|
-
openWorldHint:
|
|
9558
|
+
openWorldHint: true,
|
|
9470
9559
|
readOnlyHint: false
|
|
9471
9560
|
},
|
|
9472
|
-
description: "Remove flows from a coverage request
|
|
9561
|
+
description: "Remove flows from a coverage request or remove bug/maintenance reproductions in an environment. " + "Unlinked flows are left alone. Reports auto-close when no active reproductions remain and auto-close is enabled. " + "For reports, omit environmentId only when each selected flow is linked in at most one environment.",
|
|
9473
9562
|
input,
|
|
9474
9563
|
kind: "write",
|
|
9475
9564
|
name: "issue.removeFlows",
|
|
@@ -9479,7 +9568,7 @@ var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
|
9479
9568
|
|
|
9480
9569
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/update.js
|
|
9481
9570
|
var makeUpdateIssueContract = (ids) => {
|
|
9482
|
-
const descriptionSchema = string2().describe("The issue description
|
|
9571
|
+
const descriptionSchema = string2().describe("The issue description in Markdown, which is stored as rich text. Text without Markdown is stored as written, one paragraph per line.");
|
|
9483
9572
|
const nameSchema = string2().trim().min(1).max(255);
|
|
9484
9573
|
const input = object({
|
|
9485
9574
|
description: descriptionSchema.optional(),
|
|
@@ -9629,6 +9718,49 @@ var makeLegacyTriggerContracts = (ids) => ({
|
|
|
9629
9718
|
resume: makeResumeLegacyTriggerContract(ids)
|
|
9630
9719
|
});
|
|
9631
9720
|
|
|
9721
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/investigationSessionId.js
|
|
9722
|
+
var investigationSessionId = string2().trim().min(1).max(100).optional();
|
|
9723
|
+
|
|
9724
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/acceptScreenshotBaseline.js
|
|
9725
|
+
var makeAcceptScreenshotBaselineContract = (ids) => {
|
|
9726
|
+
const input = object({
|
|
9727
|
+
chatSessionId: investigationSessionId.describe("The chat session of the investigation that accepts the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
|
|
9728
|
+
comparisonId: string2().trim().min(1).max(100).describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run.listScreenshotComparisons` names it."),
|
|
9729
|
+
runId: ids.run
|
|
9730
|
+
});
|
|
9731
|
+
const output = discriminatedUnion("outcome", [
|
|
9732
|
+
object({
|
|
9733
|
+
baselineChangeId: string2().describe("The baseline change. Record it on the fixed finding, and pass it to `run.restoreScreenshotBaseline` with this runId to put the old baseline back."),
|
|
9734
|
+
name: string2().describe("The screenshot name whose baseline changed."),
|
|
9735
|
+
outcome: literal("accepted").describe("The new screenshot is now the baseline. The old baseline is kept, so the change can be restored.")
|
|
9736
|
+
}),
|
|
9737
|
+
object({
|
|
9738
|
+
outcome: literal("baseline-changed").describe("The baseline is no longer the one the run compared with: someone changed or deleted it since. Nothing changed. List the comparisons again to see the current baseline.")
|
|
9739
|
+
}),
|
|
9740
|
+
object({
|
|
9741
|
+
outcome: literal("needs-approval").describe("Only a person can approve this change. Nothing changed. Propose the new baseline on a fix-proposed finding and wait for a person to apply it.")
|
|
9742
|
+
}),
|
|
9743
|
+
object({
|
|
9744
|
+
outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
|
|
9745
|
+
}),
|
|
9746
|
+
object({
|
|
9747
|
+
outcome: literal("nothing-to-accept").describe("The comparison did not fail, or has no new screenshot to accept. Nothing changed.")
|
|
9748
|
+
})
|
|
9749
|
+
]);
|
|
9750
|
+
return {
|
|
9751
|
+
annotations: {
|
|
9752
|
+
destructiveHint: true,
|
|
9753
|
+
openWorldHint: false,
|
|
9754
|
+
readOnlyHint: false
|
|
9755
|
+
},
|
|
9756
|
+
description: "Make the new screenshot of a failed screenshot comparison the baseline, so later runs compare with it. " + "Use it only when the difference is an intended change of the app, not a bug, noise, or a page that was not ready. " + "Every later run of every environment of the workspace compares with the new baseline. " + "Refuses without changing anything when the baseline changed since the run.",
|
|
9757
|
+
input,
|
|
9758
|
+
kind: "write",
|
|
9759
|
+
name: "run.acceptScreenshotBaseline",
|
|
9760
|
+
output
|
|
9761
|
+
};
|
|
9762
|
+
};
|
|
9763
|
+
|
|
9632
9764
|
// node_modules/@qawolf/api-contracts/dist/v1/run/diagnose.js
|
|
9633
9765
|
var makeDiagnoseRunContract = (ids) => {
|
|
9634
9766
|
const input = object({
|
|
@@ -9645,7 +9777,7 @@ var makeDiagnoseRunContract = (ids) => {
|
|
|
9645
9777
|
openWorldHint: true,
|
|
9646
9778
|
readOnlyHint: false
|
|
9647
9779
|
},
|
|
9648
|
-
description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed moves to this issue. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
|
|
9780
|
+
description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed in the run moves to this issue, and may stay linked to other open reports. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
|
|
9649
9781
|
input,
|
|
9650
9782
|
kind: "write",
|
|
9651
9783
|
name: "run.diagnose",
|
|
@@ -9663,9 +9795,11 @@ var makeFindRunsContract = (ids) => {
|
|
|
9663
9795
|
});
|
|
9664
9796
|
const output = object({
|
|
9665
9797
|
nextCursor: nextCursorSchema,
|
|
9666
|
-
runs: array(resource(
|
|
9667
|
-
|
|
9668
|
-
|
|
9798
|
+
runs: array(resource({
|
|
9799
|
+
...makeRunSummaryFields(ids),
|
|
9800
|
+
failedAttemptCount: number2().int().nonnegative().optional(),
|
|
9801
|
+
hasFailedAttempts: boolean2().optional()
|
|
9802
|
+
}, { urlFieldDescription: "Absolute URL of the run page." })).describe("The environment's runs, newest first. Per-flow results are available via run.get.")
|
|
9669
9803
|
});
|
|
9670
9804
|
return {
|
|
9671
9805
|
annotations: {
|
|
@@ -9673,7 +9807,7 @@ var makeFindRunsContract = (ids) => {
|
|
|
9673
9807
|
openWorldHint: false,
|
|
9674
9808
|
readOnlyHint: true
|
|
9675
9809
|
},
|
|
9676
|
-
description: "List an environment's recent runs, newest first.",
|
|
9810
|
+
description: "List an environment's recent runs, newest first, including failed-attempt discovery metadata.",
|
|
9677
9811
|
input,
|
|
9678
9812
|
kind: "read",
|
|
9679
9813
|
name: "run.find",
|
|
@@ -9681,6 +9815,22 @@ var makeFindRunsContract = (ids) => {
|
|
|
9681
9815
|
};
|
|
9682
9816
|
};
|
|
9683
9817
|
|
|
9818
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/flowFailure.js
|
|
9819
|
+
var makeFlowFailureSchema = (ids) => {
|
|
9820
|
+
const diagnosis = object({
|
|
9821
|
+
issueId: ids.issue,
|
|
9822
|
+
type: _enum(["bug", "maintenance"])
|
|
9823
|
+
}).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict, and absent when " + "the flow was opted out of investigation. Pass issueId to issue.get " + "for details.");
|
|
9824
|
+
const optedOutOfInvestigation = object({
|
|
9825
|
+
by: _enum(["user", "system"]).describe("Who stopped the investigation: `user` is a person, in the app or " + "with a user API key, or the workspace's automation user for a " + "team or organization API key, for example through " + "run.optOutOfInvestigation; `system` is QA Wolf, when the " + "investigation expired.")
|
|
9826
|
+
}).optional().describe('Present when the failure was marked "do not investigate" (DNI): ' + "it will get no bug or maintenance verdict.");
|
|
9827
|
+
return object({
|
|
9828
|
+
diagnosis,
|
|
9829
|
+
error: string2(),
|
|
9830
|
+
optedOutOfInvestigation
|
|
9831
|
+
});
|
|
9832
|
+
};
|
|
9833
|
+
|
|
9684
9834
|
// node_modules/@qawolf/api-contracts/dist/v1/run/get.js
|
|
9685
9835
|
var makeGetRunContract = (ids) => {
|
|
9686
9836
|
const flowStatus = _enum(publicRunStatusValues);
|
|
@@ -9697,6 +9847,7 @@ var makeGetRunContract = (ids) => {
|
|
|
9697
9847
|
const automatedAttempt = discriminatedUnion("status", [
|
|
9698
9848
|
object({
|
|
9699
9849
|
...artifactUrls,
|
|
9850
|
+
attemptId: ids.runAttempt.optional(),
|
|
9700
9851
|
completedAt: exports_iso.datetime(),
|
|
9701
9852
|
kind: automatedKind,
|
|
9702
9853
|
startedAt: exports_iso.datetime(),
|
|
@@ -9704,12 +9855,14 @@ var makeGetRunContract = (ids) => {
|
|
|
9704
9855
|
}),
|
|
9705
9856
|
object({
|
|
9706
9857
|
...artifactUrls,
|
|
9858
|
+
attemptId: ids.runAttempt.optional(),
|
|
9707
9859
|
completedAt: exports_iso.datetime(),
|
|
9708
9860
|
kind: automatedKind,
|
|
9709
9861
|
startedAt: exports_iso.datetime().optional().describe("Absent when the attempt failed before it could start."),
|
|
9710
9862
|
status: literal("failed")
|
|
9711
9863
|
}),
|
|
9712
9864
|
object({
|
|
9865
|
+
attemptId: ids.runAttempt.optional(),
|
|
9713
9866
|
completedAt: exports_iso.datetime().optional(),
|
|
9714
9867
|
kind: automatedKind,
|
|
9715
9868
|
startedAt: exports_iso.datetime().optional(),
|
|
@@ -9717,6 +9870,7 @@ var makeGetRunContract = (ids) => {
|
|
|
9717
9870
|
})
|
|
9718
9871
|
]);
|
|
9719
9872
|
const manualAttempt = object({
|
|
9873
|
+
attemptId: ids.runAttempt.optional(),
|
|
9720
9874
|
completedAt: exports_iso.datetime(),
|
|
9721
9875
|
kind: literal("manual").describe("The attempt ran by hand in the Wolf Browser."),
|
|
9722
9876
|
startedAt: exports_iso.datetime(),
|
|
@@ -9724,16 +9878,9 @@ var makeGetRunContract = (ids) => {
|
|
|
9724
9878
|
});
|
|
9725
9879
|
const attempt = union([automatedAttempt, manualAttempt]);
|
|
9726
9880
|
const attempts = array(attempt).optional().describe("The flow's finished execution attempts, oldest first, including " + "manual Wolf Browser attempts. Present once at least one attempt has " + "finished, so a flow that passed after retries also lists its failed " + "attempts. Artifact URLs appear only on automated attempts that " + "reached a verdict, stay valid for at least a day (call run.get " + "again for fresh ones), and can return 404 when the attempt did not " + "produce that artifact.");
|
|
9727
|
-
const diagnosis = object({
|
|
9728
|
-
issueId: ids.issue,
|
|
9729
|
-
type: _enum(["bug", "maintenance"])
|
|
9730
|
-
}).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict. Pass issueId to " + "issue.get for details.");
|
|
9731
9881
|
const failedFlow = object({
|
|
9732
9882
|
attempts,
|
|
9733
|
-
failure:
|
|
9734
|
-
diagnosis,
|
|
9735
|
-
error: string2()
|
|
9736
|
-
}),
|
|
9883
|
+
failure: makeFlowFailureSchema(ids),
|
|
9737
9884
|
flowId: ids.flow,
|
|
9738
9885
|
name: string2(),
|
|
9739
9886
|
status: literal("failed")
|
|
@@ -9765,6 +9912,107 @@ var makeGetRunContract = (ids) => {
|
|
|
9765
9912
|
};
|
|
9766
9913
|
};
|
|
9767
9914
|
|
|
9915
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/getAttemptArtifacts.js
|
|
9916
|
+
var makeGetRunAttemptArtifactsContract = (ids) => {
|
|
9917
|
+
const input = object({ attemptId: ids.runAttempt });
|
|
9918
|
+
const attemptStatus = _enum([
|
|
9919
|
+
"passed",
|
|
9920
|
+
"failed",
|
|
9921
|
+
"canceled",
|
|
9922
|
+
"aborted",
|
|
9923
|
+
"skipped"
|
|
9924
|
+
]);
|
|
9925
|
+
const attemptNeighbor = object({
|
|
9926
|
+
attemptId: ids.runAttempt,
|
|
9927
|
+
status: attemptStatus
|
|
9928
|
+
});
|
|
9929
|
+
const response = object({
|
|
9930
|
+
flowId: ids.flow,
|
|
9931
|
+
flowStatus: _enum(publicRunStatusValues),
|
|
9932
|
+
retryContext: object({
|
|
9933
|
+
currentOrdinal: number2().int().min(1),
|
|
9934
|
+
next: attemptNeighbor.optional(),
|
|
9935
|
+
previous: attemptNeighbor.optional(),
|
|
9936
|
+
total: number2().int().min(1)
|
|
9937
|
+
}),
|
|
9938
|
+
runId: ids.run,
|
|
9939
|
+
runStatus: _enum(publicRunSummaryStatusValues)
|
|
9940
|
+
});
|
|
9941
|
+
const attempt = object({
|
|
9942
|
+
attemptId: ids.runAttempt,
|
|
9943
|
+
completedAt: exports_iso.datetime().optional(),
|
|
9944
|
+
createdAt: exports_iso.datetime(),
|
|
9945
|
+
error: string2().optional(),
|
|
9946
|
+
startedAt: exports_iso.datetime().optional()
|
|
9947
|
+
});
|
|
9948
|
+
const output = discriminatedUnion("artifactStatus", [
|
|
9949
|
+
response.extend({
|
|
9950
|
+
artifacts: object({
|
|
9951
|
+
logsUrl: url().optional(),
|
|
9952
|
+
traceUrl: url().optional(),
|
|
9953
|
+
videoUrl: url().optional()
|
|
9954
|
+
}),
|
|
9955
|
+
artifactStatus: literal("signed"),
|
|
9956
|
+
attempt: attempt.extend({
|
|
9957
|
+
kind: literal("automated"),
|
|
9958
|
+
status: attemptStatus
|
|
9959
|
+
})
|
|
9960
|
+
}),
|
|
9961
|
+
response.extend({
|
|
9962
|
+
artifacts: object({}).strict(),
|
|
9963
|
+
artifactStatus: literal("signing-failed"),
|
|
9964
|
+
attempt: attempt.extend({
|
|
9965
|
+
kind: literal("automated"),
|
|
9966
|
+
status: attemptStatus
|
|
9967
|
+
})
|
|
9968
|
+
}),
|
|
9969
|
+
response.extend({
|
|
9970
|
+
artifacts: object({}).strict(),
|
|
9971
|
+
artifactStatus: literal("not-captured"),
|
|
9972
|
+
attempt: attempt.extend({
|
|
9973
|
+
kind: literal("manual"),
|
|
9974
|
+
status: literal("passed")
|
|
9975
|
+
})
|
|
9976
|
+
})
|
|
9977
|
+
]);
|
|
9978
|
+
return {
|
|
9979
|
+
annotations: {
|
|
9980
|
+
destructiveHint: false,
|
|
9981
|
+
openWorldHint: false,
|
|
9982
|
+
readOnlyHint: true
|
|
9983
|
+
},
|
|
9984
|
+
description: "Get metadata and signed artifact URLs for one finished run attempt.",
|
|
9985
|
+
input,
|
|
9986
|
+
kind: "read",
|
|
9987
|
+
name: "run.getAttemptArtifacts",
|
|
9988
|
+
output
|
|
9989
|
+
};
|
|
9990
|
+
};
|
|
9991
|
+
|
|
9992
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/optOutOfInvestigation.js
|
|
9993
|
+
var makeOptOutOfInvestigationRunContract = (ids) => {
|
|
9994
|
+
const input = object({
|
|
9995
|
+
flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The failed flows to stop investigating. Every named flow must be " + "eligible or the whole request is rejected."),
|
|
9996
|
+
runId: ids.run
|
|
9997
|
+
});
|
|
9998
|
+
const output = resource({
|
|
9999
|
+
optedOutFlowIds: array(ids.flow).describe("The flows that no longer need investigation."),
|
|
10000
|
+
runId: ids.run
|
|
10001
|
+
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
10002
|
+
return {
|
|
10003
|
+
annotations: {
|
|
10004
|
+
destructiveHint: true,
|
|
10005
|
+
openWorldHint: true,
|
|
10006
|
+
readOnlyHint: false
|
|
10007
|
+
},
|
|
10008
|
+
description: 'Mark failed flows in a run as "do not investigate" (DNI): the failures need no bug or maintenance report. ' + "Each flow must have failed in the run and still be under investigation. " + "A flow that already has a diagnosis cannot be opted out. " + "A team or organization key records the opt-out as the workspace's automation user. " + "To link a failure to a report instead, use run.diagnose.",
|
|
10009
|
+
input,
|
|
10010
|
+
kind: "write",
|
|
10011
|
+
name: "run.optOutOfInvestigation",
|
|
10012
|
+
output
|
|
10013
|
+
};
|
|
10014
|
+
};
|
|
10015
|
+
|
|
9768
10016
|
// node_modules/@qawolf/api-contracts/dist/v1/run/reattempt.js
|
|
9769
10017
|
var makeReattemptRunContract = (ids) => {
|
|
9770
10018
|
const input = object({
|
|
@@ -9789,6 +10037,45 @@ var makeReattemptRunContract = (ids) => {
|
|
|
9789
10037
|
};
|
|
9790
10038
|
};
|
|
9791
10039
|
|
|
10040
|
+
// node_modules/@qawolf/api-contracts/dist/v1/run/restoreScreenshotBaseline.js
|
|
10041
|
+
var makeRestoreScreenshotBaselineContract = (ids) => {
|
|
10042
|
+
const input = object({
|
|
10043
|
+
baselineChangeId: string2().trim().min(1).max(100).describe("The baseline change to undo, as `run.acceptScreenshotBaseline` returned it for this run."),
|
|
10044
|
+
chatSessionId: investigationSessionId.describe("The chat session of the investigation that restores the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
|
|
10045
|
+
runId: ids.run
|
|
10046
|
+
});
|
|
10047
|
+
const output = discriminatedUnion("outcome", [
|
|
10048
|
+
object({
|
|
10049
|
+
name: string2().describe("The screenshot name whose baseline changed."),
|
|
10050
|
+
outcome: literal("restored").describe("The baseline the change replaced is the baseline again.")
|
|
10051
|
+
}),
|
|
10052
|
+
object({
|
|
10053
|
+
outcome: literal("baseline-changed").describe("The baseline changed again after this change, so restoring it would undo someone else's change. Nothing changed.")
|
|
10054
|
+
}),
|
|
10055
|
+
object({
|
|
10056
|
+
outcome: literal("needs-dispute").describe("Only a person can restore this change, unless a person disputed the finding that made it. Nothing changed.")
|
|
10057
|
+
}),
|
|
10058
|
+
object({
|
|
10059
|
+
outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
|
|
10060
|
+
}),
|
|
10061
|
+
object({
|
|
10062
|
+
outcome: literal("nothing-to-restore").describe("The change was already restored, the name had no baseline before it, or the kept copy of the old baseline is missing or is not the baseline the change replaced. Nothing changed.")
|
|
10063
|
+
})
|
|
10064
|
+
]);
|
|
10065
|
+
return {
|
|
10066
|
+
annotations: {
|
|
10067
|
+
destructiveHint: true,
|
|
10068
|
+
openWorldHint: false,
|
|
10069
|
+
readOnlyHint: false
|
|
10070
|
+
},
|
|
10071
|
+
description: "Undo a screenshot baseline change that accepted a failed comparison of the run: put back the baseline it replaced, so later runs compare with the old baseline again. " + "Use it when a person disputes a baseline the AI accepted. " + "Refuses without changing anything when the baseline changed again since.",
|
|
10072
|
+
input,
|
|
10073
|
+
kind: "write",
|
|
10074
|
+
name: "run.restoreScreenshotBaseline",
|
|
10075
|
+
output
|
|
10076
|
+
};
|
|
10077
|
+
};
|
|
10078
|
+
|
|
9792
10079
|
// node_modules/@qawolf/api-contracts/dist/v1/run/stop.js
|
|
9793
10080
|
var makeStopRunContract = (ids) => {
|
|
9794
10081
|
const input = object({ runId: ids.run });
|
|
@@ -10109,7 +10396,7 @@ var makeRunFlowOnRunnerContract = (ids) => {
|
|
|
10109
10396
|
env: runEnvironmentSchema.optional().describe("Environment variables to make available to the run."),
|
|
10110
10397
|
environmentId: ids.environmentRef.optional().describe("A QA Wolf environment whose variables the run is given, by id or alias. QA Wolf reads and decrypts them itself, so they never travel in the request and the count and length limits on `env` do not apply to them. Send this or `env`, not both."),
|
|
10111
10398
|
files: runFilesSchema.describe("Every file the run needs keyed by its path — the flow file, everything it imports, package.json and tsconfig.json. A runner holds no copy of your project, so what runs is exactly what is sent here."),
|
|
10112
|
-
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both.
|
|
10399
|
+
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both. Omitted, the flow whose file is at `entryPointPath` on the named environment's flow-code branch stands in; a file not in QA Wolf yet, or a run given no environment, leaves the run with no `QAWOLF_WORKFLOW_ID`."),
|
|
10113
10400
|
id: runnerIdSchema.describe("Id of the runner to run the flow on."),
|
|
10114
10401
|
selection: runSelectionSchema.optional().describe("Run only these lines, inside the page the runner is already on, instead of running the whole flow from a fresh browser. Omit to run the whole entry point."),
|
|
10115
10402
|
unchangedFiles: unchangedFilesSchema.optional().describe("Files this runner already holds from an earlier run, keyed by path with a hex SHA-256 of the content it should hold. Send this to make `files` only what changed. The runner refuses with `needs-full-sync` if it holds none of a referenced path, so it never runs something other than what was asked for. Omit it to send every file."),
|
|
@@ -10325,7 +10612,11 @@ var makeListTagsContract = (ids) => {
|
|
|
10325
10612
|
|
|
10326
10613
|
// node_modules/@qawolf/api-contracts/dist/v1/index.js
|
|
10327
10614
|
var makeContractsV1 = (ids) => {
|
|
10328
|
-
const resolvedIds = {
|
|
10615
|
+
const resolvedIds = {
|
|
10616
|
+
...defaultIdSchemas,
|
|
10617
|
+
...ids,
|
|
10618
|
+
runAttempt: ids.runAttempt ?? defaultIdSchemas.runAttempt
|
|
10619
|
+
};
|
|
10329
10620
|
return {
|
|
10330
10621
|
agent: {
|
|
10331
10622
|
get: makeAgentGetContract(resolvedIds),
|
|
@@ -10372,11 +10663,16 @@ var makeContractsV1 = (ids) => {
|
|
|
10372
10663
|
},
|
|
10373
10664
|
legacyTrigger: makeLegacyTriggerContracts(resolvedIds),
|
|
10374
10665
|
run: {
|
|
10666
|
+
acceptScreenshotBaseline: makeAcceptScreenshotBaselineContract(resolvedIds),
|
|
10375
10667
|
create: makeCreateRunContract(resolvedIds),
|
|
10376
10668
|
diagnose: makeDiagnoseRunContract(resolvedIds),
|
|
10377
10669
|
find: makeFindRunsContract(resolvedIds),
|
|
10378
10670
|
get: makeGetRunContract(resolvedIds),
|
|
10671
|
+
getAttemptArtifacts: makeGetRunAttemptArtifactsContract(resolvedIds),
|
|
10672
|
+
listScreenshotComparisons: makeListScreenshotComparisonsContract(resolvedIds),
|
|
10673
|
+
optOutOfInvestigation: makeOptOutOfInvestigationRunContract(resolvedIds),
|
|
10379
10674
|
reattempt: makeReattemptRunContract(resolvedIds),
|
|
10675
|
+
restoreScreenshotBaseline: makeRestoreScreenshotBaselineContract(resolvedIds),
|
|
10380
10676
|
stop: makeStopRunContract(resolvedIds)
|
|
10381
10677
|
},
|
|
10382
10678
|
runner: makeRunnerContracts(resolvedIds),
|
|
@@ -15011,4 +15307,4 @@ export {
|
|
|
15011
15307
|
createRunnerSdk
|
|
15012
15308
|
};
|
|
15013
15309
|
|
|
15014
|
-
//# debugId=
|
|
15310
|
+
//# debugId=6A1EED78FDDC38F864756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qawolf/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@clack/prompts": "1.5.1",
|
|
72
72
|
"@napi-rs/keyring": "1.3.0",
|
|
73
73
|
"@oxc-node/core": "0.1.0",
|
|
74
|
-
"@qawolf/api-contracts": "0.
|
|
74
|
+
"@qawolf/api-contracts": "0.77.0",
|
|
75
75
|
"@qawolf/emails": "1.1.1",
|
|
76
76
|
"@qawolf/flow-targets": "1.0.0",
|
|
77
77
|
"@qawolf/flows": "0.1.4",
|
|
@@ -171,16 +171,21 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
171
171
|
| `qawolf issue create` | write | Create a bug report, maintenance report, or coverage request issue for the caller's team. A user can create a maintenance report only when they can see the workspace's maintenance reports; a team or organization API key credits it to the workspace's automation user. Link its failed flows afterwards with run.diagnose. |
|
|
172
172
|
| `qawolf issue find` | read | List the team's bug reports, maintenance reports, or coverage requests, newest first. |
|
|
173
173
|
| `qawolf issue get` | read | Get an issue by id. |
|
|
174
|
-
| `qawolf issue removeFlows` | write | Remove flows from a coverage request
|
|
174
|
+
| `qawolf issue removeFlows` | write | Remove flows from a coverage request or remove bug/maintenance reproductions in an environment. Unlinked flows are left alone. Reports auto-close when no active reproductions remain and auto-close is enabled. For reports, omit environmentId only when each selected flow is linked in at most one environment. |
|
|
175
175
|
| `qawolf issue update` | write | Update an issue owned by the caller's team. Omitted fields remain unchanged. |
|
|
176
176
|
| `qawolf legacyTrigger find` | read | List a workspace's legacy per-environment triggers; trigger.find lists the current ones. For migration only; it goes when legacy triggers go. adaptiveFlowSelection becomes a generativeSuite action, which takes no tags. |
|
|
177
177
|
| `qawolf legacyTrigger pause` | write | Pause one legacy trigger, the older per-environment kind, so it stops firing; use trigger.pause for a current one. Its copies in pull request environments pause too. For migration only; it goes when legacy triggers go. |
|
|
178
178
|
| `qawolf legacyTrigger resume` | write | Resume one legacy trigger, the older per-environment kind; use trigger.resume for a current one. Its copies in pull request environments resume too, and a scheduled one jumps to the next upcoming slot even if it was not paused. For migration only; it goes when legacy triggers go. |
|
|
179
|
+
| `qawolf run acceptScreenshotBaseline` | write | Make the new screenshot of a failed screenshot comparison the baseline, so later runs compare with it. Use it only when the difference is an intended change of the app, not a bug, noise, or a page that was not ready. Every later run of every environment of the workspace compares with the new baseline. Refuses without changing anything when the baseline changed since the run. |
|
|
179
180
|
| `qawolf run create` | write | Create a run for the selected flows and/or tags in an environment. |
|
|
180
|
-
| `qawolf run diagnose` | write | Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. The issue's type selects the diagnosis. Each flow must have failed in the run. A flow that is already diagnosed moves to this issue. The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead. |
|
|
181
|
-
| `qawolf run find` | read | List an environment's recent runs, newest first. |
|
|
181
|
+
| `qawolf run diagnose` | write | Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. The issue's type selects the diagnosis. Each flow must have failed in the run. A flow that is already diagnosed in the run moves to this issue, and may stay linked to other open reports. The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead. |
|
|
182
|
+
| `qawolf run find` | read | List an environment's recent runs, newest first, including failed-attempt discovery metadata. |
|
|
182
183
|
| `qawolf run get` | read | Get a run's status, per-flow results, links, and how many of its bugs are blocking. |
|
|
184
|
+
| `qawolf run getAttemptArtifacts` | read | Get metadata and signed artifact URLs for one finished run attempt. |
|
|
185
|
+
| `qawolf run listScreenshotComparisons` | read | List the screenshot comparisons that failed a run's flows, with the expected, actual and diff images of each. Only comparisons that caused a failure are listed: a screenshot that differs within tolerance, or that differs on a line that did not fail, is left out. Each comparison tells whether its baseline changed since the run and whether the baseline still passes in other environments. The image URLs expire after a few minutes; fetch the preview URLs to look at the images. The first call for an image makes its missing JPEG preview and keeps it in team storage, so later calls reuse it. |
|
|
186
|
+
| `qawolf run optOutOfInvestigation` | write | Mark failed flows in a run as "do not investigate" (DNI): the failures need no bug or maintenance report. Each flow must have failed in the run and still be under investigation. A flow that already has a diagnosis cannot be opted out. A team or organization key records the opt-out as the workspace's automation user. To link a failure to a report instead, use run.diagnose. |
|
|
183
187
|
| `qawolf run reattempt` | write | Request new attempts for a run's flows, in the same run. A flow is eligible once its result is failed or canceled and QA Wolf's automatic retries have finished. A fully investigated run no longer accepts reattempts. Attempts run with the latest flow code. Poll run.get for results. |
|
|
188
|
+
| `qawolf run restoreScreenshotBaseline` | write | Undo a screenshot baseline change that accepted a failed comparison of the run: put back the baseline it replaced, so later runs compare with the old baseline again. Use it when a person disputes a baseline the AI accepted. Refuses without changing anything when the baseline changed again since. |
|
|
184
189
|
| `qawolf run stop` | write | Stop a run, including its queued flows and automatic retries. Stopping is asynchronous and can update run-status messages and commit statuses in connected integrations. Repeated requests are safe, and finished runs keep their results. A run that is still being created returns not found; retry once run.get returns the run. If run.get returns a different runId, use that ID. Poll run.get for results. |
|
|
185
190
|
| `qawolf runner act` | write | Perform one raw action on a runner's screen. A browser runner takes click, double_click, scroll, move, drag, keypress, navigate and type; a mobile runner takes tap, swipe, fill and type. A browser runner answers mobile actions with action-not-supported-on-browser; a mobile runner answers the other browser actions with action-not-supported-on-mobile. Use - to read a whole action as JSON from stdin |
|
|
186
191
|
| `qawolf runner actions` | write | Perform a sequence of up to ten raw actions on a runner's screen in one request, as a JSON array of the same actions `runner act` takes. Use - to read the array from stdin. Actions run back to back, so batch only steps whose targets are on the screen you last saw, and end the sequence at the step that changes the page. Each result carries an effect: performed, not-performed, or unknown when the runner stopped answering and the action may have landed |
|
|
@@ -59,8 +59,10 @@ A run that has been requested but not yet created answers exit `8` too, and
|
|
|
59
59
|
says it is still being created. That one clears on its own, so read the message
|
|
60
60
|
rather than the code before deciding whether to poll.
|
|
61
61
|
|
|
62
|
-
Poll `status` until it reaches `passed`, `failed` or `
|
|
63
|
-
|
|
62
|
+
Poll `status` until it reaches `passed`, `failed`, `canceled` or `superseded`.
|
|
63
|
+
When it is `superseded`, this run will never change again. Read the replacement
|
|
64
|
+
run in `supersededBy.runId` for the verdict. `queued` and `running` mean the run
|
|
65
|
+
is still going.
|
|
64
66
|
|
|
65
67
|
## Fields a passing run does not show you
|
|
66
68
|
|
|
@@ -185,19 +187,25 @@ Every documented field of the `run.get` response. `[]` marks an array, so
|
|
|
185
187
|
- `git.commitUrl` — Link to the commit on the code host.
|
|
186
188
|
- `needsReview` — True once every flow has finished its attempts and at least one failed flow still has no diagnosis, including one whose investigation carried over to a later run. `status` stays `running` until that failure is diagnosed, so a caller that is not waiting for a diagnosis can stop polling here and read the run's failed flows.
|
|
187
189
|
- `runId` — The run this response describes. Treat it as canonical: it can differ from the id you asked for. A deploy notification returns a run id before the run exists, and if a second notification for the same commit is folded into an earlier run, that id resolves to the earlier run instead.
|
|
188
|
-
- `status` — One of: queued, running, passed, failed, canceled
|
|
190
|
+
- `status` — One of: queued, running, passed, failed, canceled, superseded
|
|
191
|
+
- `supersededBy` — The run that replaced this one, present only when `status` is `superseded`. A newer deployment to the same branch and environment (and service, when the deployment named one) cancels the older run's unfinished flows and takes over. Deduplication ignores the commit, so the replacement may be testing a later commit than this run did. Only the direct replacement is named; that run can itself be superseded.
|
|
192
|
+
- `supersededBy.runId` — The id of the run.
|
|
193
|
+
- `supersededBy.url` — Absolute URL of the replacement run's page.
|
|
189
194
|
- `blockingBugCount` — How many bugs this run found are blocking: still open, and priority urgent, high, or unprioritized — unprioritized counts because nobody has ruled it out yet. This is what `failed` is derived from, so it explains a failure rather than adding a second verdict: gate on `status`, then read this to say how many bugs are holding the build. It counts a bug filed against a later run by an investigation that carried over from this one, and it drops a bug once that bug is resolved.
|
|
190
195
|
- `flows` — The run's flows, ordered alphabetically by name. Only the flows matching flowStatuses when the request set it.
|
|
191
196
|
- `flows[].attempts` — The flow's finished execution attempts, oldest first, including manual Wolf Browser attempts. Present once at least one attempt has finished, so a flow that passed after retries also lists its failed attempts. Artifact URLs appear only on automated attempts that reached a verdict, stay valid for at least a day (call run.get again for fresh ones), and can return 404 when the attempt did not produce that artifact.
|
|
192
197
|
- `flows[].attempts[].logsUrl` — Signed URL for the attempt's execution logs.
|
|
193
198
|
- `flows[].attempts[].traceUrl` — Signed URL for the attempt's Playwright trace (a trace.zip; open it with `npx playwright show-trace`).
|
|
194
199
|
- `flows[].attempts[].videoUrl` — Signed URL for the attempt's screen recording.
|
|
200
|
+
- `flows[].attempts[].attemptId` — The id of the run attempt.
|
|
195
201
|
- `flows[].attempts[].kind` — One of: automated, manual
|
|
196
202
|
- `flows[].attempts[].startedAt` — Absent when the attempt failed before it could start.
|
|
197
203
|
- `flows[].attempts[].status` — One of: passed, failed, canceled
|
|
198
|
-
- `flows[].failure.diagnosis` — QA Wolf's investigation verdict for the failure: `bug` means the application is broken, `maintenance` means the test needed an update and the failure does not indicate an application problem. Absent until the investigation reaches a verdict. Pass issueId to issue.get for details.
|
|
204
|
+
- `flows[].failure.diagnosis` — QA Wolf's investigation verdict for the failure: `bug` means the application is broken, `maintenance` means the test needed an update and the failure does not indicate an application problem. Absent until the investigation reaches a verdict, and absent when the flow was opted out of investigation. Pass issueId to issue.get for details.
|
|
199
205
|
- `flows[].failure.diagnosis.issueId` — The id of the issue.
|
|
200
206
|
- `flows[].failure.diagnosis.type` — One of: bug, maintenance
|
|
207
|
+
- `flows[].failure.optedOutOfInvestigation` — Present when the failure was marked "do not investigate" (DNI): it will get no bug or maintenance verdict.
|
|
208
|
+
- `flows[].failure.optedOutOfInvestigation.by` — One of: user, system
|
|
201
209
|
- `flows[].flowId` — The id of the flow.
|
|
202
210
|
- `flows[].status` — One of: failed, queued, running, passed, canceled
|
|
203
211
|
- `url` — Absolute URL of the run page.
|