@supatest/cli 0.0.43 → 0.0.45
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/index.js +533 -95
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,6 +32,34 @@ If no: Run discovery once, then write findings to .supatest/SUPATEST.md:
|
|
|
32
32
|
This ensures discovery happens once and persists across sessions.
|
|
33
33
|
</context>
|
|
34
34
|
|
|
35
|
+
<test_tagging>
|
|
36
|
+
Tag tests with metadata for organization and filtering on the Supatest platform:
|
|
37
|
+
|
|
38
|
+
**Platform Tags** (indexed, fast filtering):
|
|
39
|
+
- @feature:name - Feature area (e.g., auth, checkout, dashboard)
|
|
40
|
+
- @owner:email - Test owner/maintainer
|
|
41
|
+
- @priority:critical|high|medium|low - Test priority
|
|
42
|
+
- @test_type:smoke|e2e|regression|integration|unit - Test category
|
|
43
|
+
- @ticket:PROJ-123 - Related ticket/issue
|
|
44
|
+
- @slow - Flag for long-running tests
|
|
45
|
+
- @flaky - Flag for known flaky tests
|
|
46
|
+
|
|
47
|
+
**Custom Tags** (flexible metadata):
|
|
48
|
+
- @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
|
|
49
|
+
|
|
50
|
+
**Playwright - Use native tag property (preferred):**
|
|
51
|
+
test("User can complete purchase", {
|
|
52
|
+
tag: ['@feature:checkout', '@priority:high', '@test_type:e2e', '@owner:qa@example.com']
|
|
53
|
+
}, async ({ page }) => {
|
|
54
|
+
// test code
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
**WebdriverIO/Other frameworks - Use title tags:**
|
|
58
|
+
it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => {
|
|
59
|
+
// test code
|
|
60
|
+
});
|
|
61
|
+
</test_tagging>
|
|
62
|
+
|
|
35
63
|
<workflow>
|
|
36
64
|
For each test:
|
|
37
65
|
1. **Write** - Create test using the project's framework and patterns
|
|
@@ -163,6 +191,34 @@ You are a Test Fixer Agent that debugs failing tests and fixes issues. You work
|
|
|
163
191
|
Continue until all tests pass.
|
|
164
192
|
</workflow>
|
|
165
193
|
|
|
194
|
+
<test_tagging>
|
|
195
|
+
When creating or fixing tests, add metadata tags for organization and filtering:
|
|
196
|
+
|
|
197
|
+
**Platform Tags** (indexed, fast filtering):
|
|
198
|
+
- @feature:name - Feature area (e.g., auth, checkout, dashboard)
|
|
199
|
+
- @owner:email - Test owner/maintainer
|
|
200
|
+
- @priority:critical|high|medium|low - Test priority
|
|
201
|
+
- @test_type:smoke|e2e|regression|integration|unit - Test category
|
|
202
|
+
- @ticket:PROJ-123 - Related ticket/issue
|
|
203
|
+
- @slow - Flag for long-running tests
|
|
204
|
+
- @flaky - Flag for known flaky tests
|
|
205
|
+
|
|
206
|
+
**Custom Tags** (flexible metadata):
|
|
207
|
+
- @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
|
|
208
|
+
|
|
209
|
+
**Playwright - Use native tag property (preferred):**
|
|
210
|
+
test("User can complete purchase", {
|
|
211
|
+
tag: ['@feature:checkout', '@priority:high', '@test_type:e2e', '@owner:qa@example.com']
|
|
212
|
+
}, async ({ page }) => {
|
|
213
|
+
// test code
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
**WebdriverIO/Other frameworks - Use title tags:**
|
|
217
|
+
it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => {
|
|
218
|
+
// test code
|
|
219
|
+
});
|
|
220
|
+
</test_tagging>
|
|
221
|
+
|
|
166
222
|
<root_causes>
|
|
167
223
|
**Selector** - Element changed or locator is fragile \u2192 update selector, add wait, make more specific
|
|
168
224
|
|
|
@@ -190,6 +246,20 @@ Continue until all tests pass.
|
|
|
190
246
|
- Don't skip or remove tests without understanding the failure
|
|
191
247
|
</fixing_principles>
|
|
192
248
|
|
|
249
|
+
<browser_inspection>
|
|
250
|
+
If available in /mcp commands, use Playwright MCP for live debugging when the failure is unclear from all available assets:
|
|
251
|
+
- Test code, error logs, and stack traces
|
|
252
|
+
- Application code and related files in the repo
|
|
253
|
+
- Configuration and test setup files
|
|
254
|
+
|
|
255
|
+
Execute the test flow with MCP to observe actual behavior:
|
|
256
|
+
- Navigate and interact as the test does
|
|
257
|
+
- Verify element states, attributes, and content
|
|
258
|
+
- Check console errors and runtime issues
|
|
259
|
+
- Test selectors and locators against live DOM
|
|
260
|
+
- Inspect page state at each step
|
|
261
|
+
</browser_inspection>
|
|
262
|
+
|
|
193
263
|
<flakiness>
|
|
194
264
|
After fixing, verify stability by running 2-3 times. Watch for:
|
|
195
265
|
- Inconsistent pass/fail results
|
|
@@ -760,10 +830,39 @@ Never ask about routing, data scope, UI interactions, empty states, or error han
|
|
|
760
830
|
<output_format>
|
|
761
831
|
**Risk Assessment**: [HIGH/MEDIUM/LOW] - one line justification
|
|
762
832
|
**User Journeys**: "User can [action] to [achieve goal]"
|
|
763
|
-
**Test Cases**: Name, assertions, test data needs
|
|
833
|
+
**Test Cases**: Name, assertions, test data needs, suggested tags
|
|
764
834
|
**Not Testing**: What you're skipping and why (shows judgment)
|
|
765
835
|
</output_format>
|
|
766
836
|
|
|
837
|
+
<test_tagging>
|
|
838
|
+
Include metadata tags in test plans for organization and filtering:
|
|
839
|
+
|
|
840
|
+
**Platform Tags** (indexed, fast filtering):
|
|
841
|
+
- @feature:name - Feature area (e.g., auth, checkout, dashboard)
|
|
842
|
+
- @owner:email - Test owner/maintainer
|
|
843
|
+
- @priority:critical|high|medium|low - Test priority (align with risk assessment)
|
|
844
|
+
- @test_type:smoke|e2e|regression|integration|unit - Test category
|
|
845
|
+
- @ticket:PROJ-123 - Related ticket/issue
|
|
846
|
+
- @slow - Flag for long-running tests
|
|
847
|
+
- @flaky - Flag for known flaky tests
|
|
848
|
+
|
|
849
|
+
**Custom Tags** (flexible metadata):
|
|
850
|
+
- @key:value - Any custom metadata (e.g., @browser:chrome, @viewport:mobile)
|
|
851
|
+
|
|
852
|
+
Map risk levels to priority tags:
|
|
853
|
+
- HIGH risk \u2192 @priority:critical or @priority:high
|
|
854
|
+
- MEDIUM risk \u2192 @priority:medium
|
|
855
|
+
- LOW risk \u2192 @priority:low
|
|
856
|
+
|
|
857
|
+
**Playwright - Use native tag property (preferred):**
|
|
858
|
+
test("User can complete purchase", {
|
|
859
|
+
tag: ['@feature:checkout', '@priority:high', '@test_type:e2e']
|
|
860
|
+
}, async ({ page }) => { });
|
|
861
|
+
|
|
862
|
+
**WebdriverIO/Other frameworks - Use title tags:**
|
|
863
|
+
it("@feature:checkout @priority:high @test_type:e2e User can complete purchase", async () => { });
|
|
864
|
+
</test_tagging>
|
|
865
|
+
|
|
767
866
|
<example>
|
|
768
867
|
**Scenario**: Read-only analytics dashboard
|
|
769
868
|
|
|
@@ -1155,7 +1254,7 @@ function getToolGroupCounts(tools) {
|
|
|
1155
1254
|
);
|
|
1156
1255
|
return Object.entries(groups).map(([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count);
|
|
1157
1256
|
}
|
|
1158
|
-
var AVAILABLE_MODELS, DATE_SUFFIX_REGEX, SMALL_COST_MULTIPLIER, MEDIUM_COST_MULTIPLIER, PREMIUM_COST_MULTIPLIER, SMALL_COST_LABEL, MEDIUM_COST_LABEL, PREMIUM_COST_LABEL, MODEL_TIERS, CONTEXT_WINDOWS, util, objectUtil, ZodParsedType, getParsedType, ZodIssueCode, ZodError, errorMap, overrideErrorMap, makeIssue, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, errorUtil, ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, ZodBranded, ZodPipeline, ZodReadonly, ZodFirstPartyTypeKind, stringType, numberType, booleanType, dateType, unknownType, arrayType, objectType, unionType, discriminatedUnionType, recordType, functionType, lazyType, literalType, enumType, promiseType, coerce, MAX_API_KEY_NAME_LENGTH, apiKeySchema, apiKeyUsageSchema, createApiKeyRequestSchema, apiKeyResponseSchema, apiKeyUsageSummarySchema, genericErrorSchema, validationErrorSchema, feedbackCategorySchema, FEEDBACK_CATEGORIES, createFeedbackSchema, feedbackResponseSchema, listFeedbackQuerySchema, feedbackListResponseSchema, healthMetricSchema, healthMetricDailyItemSchema, healthMetricsWithDailySchema, healthAnalyticsPeriodSchema, healthAnalyticsDailyItemSchema, healthAnalyticsResponseSchema, MAX_TIMEZONE_CHAR_LENGTH, organizationSchema, organizationSettingsSchema, textBlockSchema, toolUseBlockSchema, toolResultBlockSchema, thinkingBlockSchema, imageBlockSchema, contentBlockSchema, sessionSchema, createSessionRequestSchema, updateSessionRequestSchema, messageSchema, createMessageRequestSchema, cliEventSchema, createCLISessionRequestSchema, queryResultSchema, queryTurnSchema, queryContentSchema, queryUsageSchema, querySchema, runStatusSchema, testResultStatusSchema, testOutcomeSchema, attachmentKindSchema, stepCategorySchema, runSummarySchema, ciMetadataSchema, gitMetadataSchema, playwrightConfigSchema, errorInfoSchema, locationSchema, sourceSnippetSchema, runSchema, annotationSchema, testSchema, testResultSchema, baseStepSchema, stepSchema, attachmentSchema, listRunsQuerySchema, listTestsQuerySchema, runsListResponseSchema, runDetailResponseSchema, testsListResponseSchema, testDetailResponseSchema, testHistoryItemSchema, testHistoryResponseSchema, topOffenderSchema, topOffendersResponseSchema, trendPointSchema, trendsResponseSchema, errorCategorySchema, failureClusterSchema, newFailureSchema, runInsightsResponseSchema, FailureCategoryEnum, SelectorTypeEnum, FailureCategoryStatsSchema, FailureCategoriesResponseSchema, FailingSelectorStatsSchema, FailingSelectorsResponseSchema, newFailureItemSchema, newFailuresResponseSchema, flakyTestItemSchema, flakyTestsResponseSchema, slowestTestItemSchema, slowestTestsResponseSchema, runSummaryEmailFailureSchema, runSummaryEmailReportSchema, sendRunReportRequestSchema, metricWithTrendSchema, weekOverWeekMetricsSchema, ciComputeTimeSchema, investigationCandidateSchema, failureCategoryBreakdownSchema, stabilityTrendSchema, folderStabilitySchema, managerReportSchema, managerReportQuerySchema, sendManagerReportRequestSchema, reportAttachmentLinkSchema, developerReportRegressionSchema, developerReportFlakyTestSchema, developerReportSlowTestSchema, developerRunSummaryReportSchema, executiveReportStatusSchema, executiveMetricSchema, executiveKeyMetricsSchema, executiveTrendPointSchema, executiveTrendsSchema, executiveFlakyOffenderSchema, executiveSlowestOffenderSchema, executiveTopOffendersSchema, executiveReportSchema, executiveReportQuerySchema, sendExecutiveReportRequestSchema, fixAssignmentStatusSchema, fixAssignmentSchema, testWithAssignmentSchema, listAssignmentsQuerySchema, listTestsWithAssignmentsQuerySchema, assignmentsListResponseSchema, assigneeInfoSchema, assigneesListResponseSchema, assignTestsRequestSchema, assignTestRequestSchema, reassignTestRequestSchema, completeAssignmentsRequestSchema, completeAssignmentRequestSchema, bulkReassignRequestSchema, assignmentResponseSchema, assignTestsResponseSchema, testsWithAssignmentsResponseSchema, bulkReassignResponseSchema, userAssignmentStatsSchema, SECONDS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR;
|
|
1257
|
+
var AVAILABLE_MODELS, DATE_SUFFIX_REGEX, SMALL_COST_MULTIPLIER, MEDIUM_COST_MULTIPLIER, PREMIUM_COST_MULTIPLIER, SMALL_COST_LABEL, MEDIUM_COST_LABEL, PREMIUM_COST_LABEL, MODEL_TIERS, CONTEXT_WINDOWS, util, objectUtil, ZodParsedType, getParsedType, ZodIssueCode, ZodError, errorMap, overrideErrorMap, makeIssue, ParseStatus, INVALID, DIRTY, OK, isAborted, isDirty, isValid, isAsync, errorUtil, ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, ZodBranded, ZodPipeline, ZodReadonly, ZodFirstPartyTypeKind, stringType, numberType, booleanType, dateType, unknownType, arrayType, objectType, unionType, discriminatedUnionType, recordType, functionType, lazyType, literalType, enumType, promiseType, coerce, MAX_API_KEY_NAME_LENGTH, apiKeySchema, apiKeyUsageSchema, createApiKeyRequestSchema, apiKeyResponseSchema, apiKeyUsageSummarySchema, genericErrorSchema, validationErrorSchema, feedbackCategorySchema, FEEDBACK_CATEGORIES, createFeedbackSchema, feedbackResponseSchema, listFeedbackQuerySchema, feedbackListResponseSchema, healthMetricSchema, healthMetricDailyItemSchema, healthMetricsWithDailySchema, healthAnalyticsPeriodSchema, healthAnalyticsDailyItemSchema, healthAnalyticsResponseSchema, MAX_TIMEZONE_CHAR_LENGTH, organizationSchema, organizationSettingsSchema, textBlockSchema, toolUseBlockSchema, toolResultBlockSchema, thinkingBlockSchema, imageBlockSchema, contentBlockSchema, sessionSchema, createSessionRequestSchema, updateSessionRequestSchema, messageSchema, createMessageRequestSchema, cliEventSchema, createCLISessionRequestSchema, queryResultSchema, queryTurnSchema, queryContentSchema, queryUsageSchema, querySchema, runStatusSchema, testResultStatusSchema, testOutcomeSchema, attachmentKindSchema, stepCategorySchema, runSummarySchema, ciMetadataSchema, gitMetadataSchema, playwrightConfigSchema, errorInfoSchema, locationSchema, sourceSnippetSchema, runSchema, annotationSchema, testSchema, testResultSchema, baseStepSchema, stepSchema, attachmentSchema, listRunsQuerySchema, listTestsQuerySchema, runsListResponseSchema, runDetailResponseSchema, coverageTestItemSchema, secondaryTagMetricSchema, tagCoverageSchema, coverageStatsSchema, coverageAlertSchema, coverageDashboardResponseSchema, coverageDashboardQuerySchema, testsListResponseSchema, testDetailResponseSchema, testHistoryItemSchema, testHistoryResponseSchema, topOffenderSchema, topOffendersResponseSchema, trendPointSchema, trendsResponseSchema, errorCategorySchema, failureClusterSchema, newFailureSchema, runInsightsResponseSchema, FailureCategoryEnum, SelectorTypeEnum, FailureCategoryStatsSchema, FailureCategoriesResponseSchema, FailingSelectorStatsSchema, FailingSelectorsResponseSchema, newFailureItemSchema, newFailuresResponseSchema, flakyTestItemSchema, flakyTestsResponseSchema, slowestTestItemSchema, slowestTestsResponseSchema, runSummaryEmailFailureSchema, runSummaryEmailReportSchema, sendRunReportRequestSchema, metricWithTrendSchema, weekOverWeekMetricsSchema, ciComputeTimeSchema, investigationCandidateSchema, failureCategoryBreakdownSchema, stabilityTrendSchema, folderStabilitySchema, managerReportSchema, managerReportQuerySchema, sendManagerReportRequestSchema, reportAttachmentLinkSchema, developerReportRegressionSchema, developerReportFlakyTestSchema, developerReportSlowTestSchema, developerRunSummaryReportSchema, executiveReportStatusSchema, executiveMetricSchema, executiveKeyMetricsSchema, executiveTrendPointSchema, executiveTrendsSchema, executiveFlakyOffenderSchema, executiveSlowestOffenderSchema, executiveTopOffendersSchema, executiveReportSchema, executiveReportQuerySchema, sendExecutiveReportRequestSchema, fixAssignmentStatusSchema, fixAssignmentSchema, testWithAssignmentSchema, listAssignmentsQuerySchema, listTestsWithAssignmentsQuerySchema, assignmentsListResponseSchema, assigneeInfoSchema, assigneesListResponseSchema, assignTestsRequestSchema, assignTestRequestSchema, reassignTestRequestSchema, completeAssignmentsRequestSchema, completeAssignmentRequestSchema, bulkReassignRequestSchema, assignmentResponseSchema, assignTestsResponseSchema, testsWithAssignmentsResponseSchema, bulkReassignResponseSchema, userAssignmentStatsSchema, testCatalogPrioritySchema, testCatalogTypeSchema, testCatalogAssignmentStatusSchema, testCatalogAssignmentSchema, testCatalogDefinitionSchema, testCatalogListItemSchema, testCatalogHistoryEntrySchema, testCatalogListQuerySchema, testCatalogListResponseSchema, testCatalogDetailResponseSchema, testCatalogFilterOptionsSchema, testCatalogAssigneeInfoSchema, testCatalogAssignRequestSchema, testCatalogUpdateAssignmentRequestSchema, testCatalogAssignmentResponseSchema, testCatalogFolderNodeSchema, testCatalogFolderTreeResponseSchema, testCatalogFolderTestsQuerySchema, SECONDS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR;
|
|
1159
1258
|
var init_shared_es = __esm({
|
|
1160
1259
|
"../shared/dist/shared.es.mjs"() {
|
|
1161
1260
|
"use strict";
|
|
@@ -5424,8 +5523,17 @@ var init_shared_es = __esm({
|
|
|
5424
5523
|
status: testResultStatusSchema.optional(),
|
|
5425
5524
|
isFlaky: coerce.boolean().optional(),
|
|
5426
5525
|
file: stringType().optional(),
|
|
5427
|
-
groupByTestId: coerce.boolean().optional()
|
|
5526
|
+
groupByTestId: coerce.boolean().optional(),
|
|
5428
5527
|
// When true, paginate by unique testId (grouped tests)
|
|
5528
|
+
// Tag filters
|
|
5529
|
+
owner: stringType().optional(),
|
|
5530
|
+
priority: stringType().optional(),
|
|
5531
|
+
// Will validate against testCatalogPrioritySchema in backend
|
|
5532
|
+
feature: stringType().optional(),
|
|
5533
|
+
testType: stringType().optional(),
|
|
5534
|
+
// Will validate against testCatalogTypeSchema in backend
|
|
5535
|
+
tags: stringType().optional()
|
|
5536
|
+
// Comma-separated custom tags
|
|
5429
5537
|
});
|
|
5430
5538
|
runsListResponseSchema = objectType({
|
|
5431
5539
|
runs: arrayType(runSchema),
|
|
@@ -5437,6 +5545,86 @@ var init_shared_es = __esm({
|
|
|
5437
5545
|
tests: arrayType(testSchema).optional(),
|
|
5438
5546
|
testsTotal: numberType().optional()
|
|
5439
5547
|
});
|
|
5548
|
+
coverageTestItemSchema = objectType({
|
|
5549
|
+
testId: stringType(),
|
|
5550
|
+
title: stringType(),
|
|
5551
|
+
file: stringType(),
|
|
5552
|
+
status: testResultStatusSchema.nullable(),
|
|
5553
|
+
passRate: numberType().nullable(),
|
|
5554
|
+
// 0-100
|
|
5555
|
+
lastRunAt: stringType().nullable()
|
|
5556
|
+
});
|
|
5557
|
+
secondaryTagMetricSchema = objectType({
|
|
5558
|
+
tag: stringType(),
|
|
5559
|
+
category: stringType(),
|
|
5560
|
+
// e.g., "type", "priority"
|
|
5561
|
+
testCount: numberType(),
|
|
5562
|
+
coverage: numberType()
|
|
5563
|
+
// 0-100 percentage
|
|
5564
|
+
});
|
|
5565
|
+
tagCoverageSchema = objectType({
|
|
5566
|
+
tag: stringType(),
|
|
5567
|
+
testCount: numberType(),
|
|
5568
|
+
passedCount: numberType(),
|
|
5569
|
+
failedCount: numberType(),
|
|
5570
|
+
coverage: numberType(),
|
|
5571
|
+
// 0-100 percentage
|
|
5572
|
+
tests: arrayType(coverageTestItemSchema),
|
|
5573
|
+
secondaryTags: arrayType(secondaryTagMetricSchema).optional()
|
|
5574
|
+
// Secondary metrics like type, priority
|
|
5575
|
+
});
|
|
5576
|
+
coverageStatsSchema = objectType({
|
|
5577
|
+
overallHealth: numberType(),
|
|
5578
|
+
// 0-100 percentage
|
|
5579
|
+
totalTests: numberType()
|
|
5580
|
+
});
|
|
5581
|
+
coverageAlertSchema = objectType({
|
|
5582
|
+
tag: stringType(),
|
|
5583
|
+
previousCoverage: numberType(),
|
|
5584
|
+
currentCoverage: numberType(),
|
|
5585
|
+
changePct: numberType()
|
|
5586
|
+
});
|
|
5587
|
+
coverageDashboardResponseSchema = objectType({
|
|
5588
|
+
stats: coverageStatsSchema,
|
|
5589
|
+
tagCoverages: arrayType(tagCoverageSchema),
|
|
5590
|
+
alerts: arrayType(coverageAlertSchema),
|
|
5591
|
+
period: objectType({
|
|
5592
|
+
start: stringType(),
|
|
5593
|
+
end: stringType(),
|
|
5594
|
+
days: numberType()
|
|
5595
|
+
})
|
|
5596
|
+
});
|
|
5597
|
+
coverageDashboardQuerySchema = objectType({
|
|
5598
|
+
// Option 1: Period-based (e.g., '7d', '14d', '30d')
|
|
5599
|
+
period: stringType().regex(/^\d+d$/, "Period must be in format '7d', '14d', '30d', etc.").optional(),
|
|
5600
|
+
// Option 2: Date range (YYYY-MM-DD format or ISO datetime strings)
|
|
5601
|
+
startDate: stringType().regex(
|
|
5602
|
+
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
|
|
5603
|
+
"startDate must be in format YYYY-MM-DD or ISO datetime"
|
|
5604
|
+
).optional(),
|
|
5605
|
+
endDate: stringType().regex(
|
|
5606
|
+
/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/,
|
|
5607
|
+
"endDate must be in format YYYY-MM-DD or ISO datetime"
|
|
5608
|
+
).optional(),
|
|
5609
|
+
// Optional tag filter to drill down into specific tag
|
|
5610
|
+
tag: stringType().optional()
|
|
5611
|
+
}).refine(
|
|
5612
|
+
(data) => {
|
|
5613
|
+
const hasPeriod = !!data.period;
|
|
5614
|
+
const hasDateRange = !!data.startDate && !!data.endDate;
|
|
5615
|
+
const hasPartialDateRange = !!data.startDate && !data.endDate || !data.startDate && !!data.endDate;
|
|
5616
|
+
if (hasPartialDateRange) {
|
|
5617
|
+
return false;
|
|
5618
|
+
}
|
|
5619
|
+
if (hasPeriod && hasDateRange) {
|
|
5620
|
+
return false;
|
|
5621
|
+
}
|
|
5622
|
+
return true;
|
|
5623
|
+
},
|
|
5624
|
+
{
|
|
5625
|
+
message: "Provide either 'period' OR both 'startDate' and 'endDate', not a mix"
|
|
5626
|
+
}
|
|
5627
|
+
);
|
|
5440
5628
|
testsListResponseSchema = objectType({
|
|
5441
5629
|
tests: arrayType(testSchema),
|
|
5442
5630
|
total: numberType(),
|
|
@@ -5958,7 +6146,7 @@ var init_shared_es = __esm({
|
|
|
5958
6146
|
assigned: numberType(),
|
|
5959
6147
|
completed: numberType(),
|
|
5960
6148
|
failed: numberType(),
|
|
5961
|
-
|
|
6149
|
+
unassigned: numberType()
|
|
5962
6150
|
})
|
|
5963
6151
|
});
|
|
5964
6152
|
assigneeInfoSchema = objectType({
|
|
@@ -6030,7 +6218,7 @@ var init_shared_es = __esm({
|
|
|
6030
6218
|
assigned: numberType(),
|
|
6031
6219
|
completed: numberType(),
|
|
6032
6220
|
failed: numberType(),
|
|
6033
|
-
|
|
6221
|
+
unassigned: numberType()
|
|
6034
6222
|
})
|
|
6035
6223
|
});
|
|
6036
6224
|
bulkReassignResponseSchema = objectType({
|
|
@@ -6049,6 +6237,173 @@ var init_shared_es = __esm({
|
|
|
6049
6237
|
completed: numberType(),
|
|
6050
6238
|
failed: numberType()
|
|
6051
6239
|
});
|
|
6240
|
+
testCatalogPrioritySchema = enumType([
|
|
6241
|
+
"critical",
|
|
6242
|
+
"high",
|
|
6243
|
+
"medium",
|
|
6244
|
+
"low"
|
|
6245
|
+
]);
|
|
6246
|
+
testCatalogTypeSchema = enumType([
|
|
6247
|
+
"smoke",
|
|
6248
|
+
"e2e",
|
|
6249
|
+
"regression",
|
|
6250
|
+
"integration",
|
|
6251
|
+
"unit"
|
|
6252
|
+
]);
|
|
6253
|
+
testCatalogAssignmentStatusSchema = enumType([
|
|
6254
|
+
"assigned",
|
|
6255
|
+
"completed",
|
|
6256
|
+
"failed"
|
|
6257
|
+
]);
|
|
6258
|
+
testCatalogAssignmentSchema = objectType({
|
|
6259
|
+
id: stringType().uuid(),
|
|
6260
|
+
assignedTo: stringType(),
|
|
6261
|
+
assignedAt: stringType(),
|
|
6262
|
+
status: testCatalogAssignmentStatusSchema
|
|
6263
|
+
});
|
|
6264
|
+
testCatalogDefinitionSchema = objectType({
|
|
6265
|
+
id: stringType().uuid(),
|
|
6266
|
+
readableId: stringType(),
|
|
6267
|
+
// TST-123
|
|
6268
|
+
testId: stringType(),
|
|
6269
|
+
// Stable ID from @id: tag or hash
|
|
6270
|
+
file: stringType(),
|
|
6271
|
+
title: stringType(),
|
|
6272
|
+
titlePath: arrayType(stringType()),
|
|
6273
|
+
projectName: stringType().nullable(),
|
|
6274
|
+
// Parsed metadata
|
|
6275
|
+
owner: stringType().nullable(),
|
|
6276
|
+
priority: testCatalogPrioritySchema.nullable(),
|
|
6277
|
+
feature: stringType().nullable(),
|
|
6278
|
+
ticketId: stringType().nullable(),
|
|
6279
|
+
testType: testCatalogTypeSchema.nullable(),
|
|
6280
|
+
isSlow: booleanType(),
|
|
6281
|
+
isFlakyTagged: booleanType(),
|
|
6282
|
+
// Raw data
|
|
6283
|
+
tags: arrayType(stringType()).nullable(),
|
|
6284
|
+
customMetadata: recordType(stringType()).nullable(),
|
|
6285
|
+
// Stats
|
|
6286
|
+
totalRuns: numberType(),
|
|
6287
|
+
passCount: numberType(),
|
|
6288
|
+
failCount: numberType(),
|
|
6289
|
+
flakyCount: numberType(),
|
|
6290
|
+
lastStatus: stringType().nullable(),
|
|
6291
|
+
lastRunAt: stringType().nullable(),
|
|
6292
|
+
lastRunId: stringType().nullable(),
|
|
6293
|
+
avgDurationMs: numberType().nullable(),
|
|
6294
|
+
passRate: numberType().nullable(),
|
|
6295
|
+
// 0-100
|
|
6296
|
+
// Assignment
|
|
6297
|
+
assignment: testCatalogAssignmentSchema.nullable(),
|
|
6298
|
+
// Timestamps
|
|
6299
|
+
createdAt: stringType(),
|
|
6300
|
+
updatedAt: stringType()
|
|
6301
|
+
});
|
|
6302
|
+
testCatalogListItemSchema = objectType({
|
|
6303
|
+
id: stringType().uuid(),
|
|
6304
|
+
readableId: stringType().optional(),
|
|
6305
|
+
testId: stringType(),
|
|
6306
|
+
file: stringType(),
|
|
6307
|
+
title: stringType(),
|
|
6308
|
+
projectName: stringType().nullable(),
|
|
6309
|
+
// Key metadata
|
|
6310
|
+
owner: stringType().nullable(),
|
|
6311
|
+
priority: testCatalogPrioritySchema.nullable(),
|
|
6312
|
+
feature: stringType().nullable(),
|
|
6313
|
+
isSlow: booleanType(),
|
|
6314
|
+
isFlakyTagged: booleanType(),
|
|
6315
|
+
// Stats
|
|
6316
|
+
totalRuns: numberType(),
|
|
6317
|
+
passRate: numberType().nullable(),
|
|
6318
|
+
flakyCount: numberType(),
|
|
6319
|
+
lastStatus: stringType().nullable(),
|
|
6320
|
+
lastRunAt: stringType().nullable(),
|
|
6321
|
+
avgDurationMs: numberType().nullable(),
|
|
6322
|
+
// Assignment
|
|
6323
|
+
assignment: testCatalogAssignmentSchema.nullable()
|
|
6324
|
+
});
|
|
6325
|
+
testCatalogHistoryEntrySchema = objectType({
|
|
6326
|
+
runId: stringType().uuid(),
|
|
6327
|
+
status: stringType(),
|
|
6328
|
+
durationMs: numberType(),
|
|
6329
|
+
date: stringType(),
|
|
6330
|
+
branch: stringType().optional(),
|
|
6331
|
+
errorSummary: stringType().optional()
|
|
6332
|
+
});
|
|
6333
|
+
testCatalogListQuerySchema = objectType({
|
|
6334
|
+
page: coerce.number().int().min(1).default(1),
|
|
6335
|
+
limit: coerce.number().int().min(1).max(100).default(20),
|
|
6336
|
+
status: enumType(["all", "passed", "failed", "flaky", "skipped"]).optional().default("all"),
|
|
6337
|
+
owner: stringType().optional(),
|
|
6338
|
+
assignee: stringType().optional(),
|
|
6339
|
+
feature: stringType().optional(),
|
|
6340
|
+
priority: testCatalogPrioritySchema.optional(),
|
|
6341
|
+
search: stringType().optional(),
|
|
6342
|
+
sortBy: enumType([
|
|
6343
|
+
"lastRunAt",
|
|
6344
|
+
"passRate",
|
|
6345
|
+
"flakyCount",
|
|
6346
|
+
"totalRuns",
|
|
6347
|
+
"title",
|
|
6348
|
+
"avgDurationMs"
|
|
6349
|
+
]).optional().default("lastRunAt"),
|
|
6350
|
+
sortOrder: enumType(["asc", "desc"]).optional().default("desc")
|
|
6351
|
+
});
|
|
6352
|
+
testCatalogListResponseSchema = objectType({
|
|
6353
|
+
tests: arrayType(testCatalogListItemSchema),
|
|
6354
|
+
total: numberType(),
|
|
6355
|
+
page: numberType(),
|
|
6356
|
+
limit: numberType()
|
|
6357
|
+
});
|
|
6358
|
+
testCatalogDetailResponseSchema = objectType({
|
|
6359
|
+
test: testCatalogListItemSchema,
|
|
6360
|
+
history: arrayType(testCatalogHistoryEntrySchema)
|
|
6361
|
+
});
|
|
6362
|
+
testCatalogFilterOptionsSchema = objectType({
|
|
6363
|
+
owners: arrayType(stringType()),
|
|
6364
|
+
features: arrayType(stringType()),
|
|
6365
|
+
priorities: arrayType(testCatalogPrioritySchema),
|
|
6366
|
+
testTypes: arrayType(testCatalogTypeSchema)
|
|
6367
|
+
});
|
|
6368
|
+
testCatalogAssigneeInfoSchema = objectType({
|
|
6369
|
+
id: stringType(),
|
|
6370
|
+
name: stringType(),
|
|
6371
|
+
email: stringType().optional(),
|
|
6372
|
+
activeTests: numberType()
|
|
6373
|
+
});
|
|
6374
|
+
testCatalogAssignRequestSchema = objectType({
|
|
6375
|
+
assignedTo: stringType(),
|
|
6376
|
+
notes: stringType().optional()
|
|
6377
|
+
});
|
|
6378
|
+
testCatalogUpdateAssignmentRequestSchema = objectType({
|
|
6379
|
+
status: enumType(["completed", "failed"]),
|
|
6380
|
+
notes: stringType().optional()
|
|
6381
|
+
});
|
|
6382
|
+
testCatalogAssignmentResponseSchema = objectType({
|
|
6383
|
+
id: stringType().uuid(),
|
|
6384
|
+
testId: stringType().uuid(),
|
|
6385
|
+
assignedTo: stringType(),
|
|
6386
|
+
status: testCatalogAssignmentStatusSchema
|
|
6387
|
+
});
|
|
6388
|
+
testCatalogFolderNodeSchema = objectType({
|
|
6389
|
+
name: stringType(),
|
|
6390
|
+
path: stringType(),
|
|
6391
|
+
type: enumType(["folder", "file"]),
|
|
6392
|
+
testCount: numberType(),
|
|
6393
|
+
hasChildren: booleanType()
|
|
6394
|
+
});
|
|
6395
|
+
testCatalogFolderTreeResponseSchema = objectType({
|
|
6396
|
+
nodes: arrayType(testCatalogFolderNodeSchema)
|
|
6397
|
+
});
|
|
6398
|
+
testCatalogFolderTestsQuerySchema = objectType({
|
|
6399
|
+
folder: stringType(),
|
|
6400
|
+
status: enumType(["all", "passed", "failed", "flaky", "skipped"]).optional().default("all"),
|
|
6401
|
+
owner: stringType().optional(),
|
|
6402
|
+
assignee: stringType().optional(),
|
|
6403
|
+
feature: stringType().optional(),
|
|
6404
|
+
priority: testCatalogPrioritySchema.optional(),
|
|
6405
|
+
search: stringType().optional()
|
|
6406
|
+
});
|
|
6052
6407
|
SECONDS_PER_MINUTE = 60;
|
|
6053
6408
|
SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
|
|
6054
6409
|
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
|
|
@@ -6333,7 +6688,7 @@ var CLI_VERSION;
|
|
|
6333
6688
|
var init_version = __esm({
|
|
6334
6689
|
"src/version.ts"() {
|
|
6335
6690
|
"use strict";
|
|
6336
|
-
CLI_VERSION = "0.0.
|
|
6691
|
+
CLI_VERSION = "0.0.45";
|
|
6337
6692
|
}
|
|
6338
6693
|
});
|
|
6339
6694
|
|
|
@@ -7069,15 +7424,39 @@ var init_api_client = __esm({
|
|
|
7069
7424
|
return data;
|
|
7070
7425
|
}
|
|
7071
7426
|
/**
|
|
7072
|
-
*
|
|
7427
|
+
* Bulk get test details for multiple tests
|
|
7428
|
+
* @param testIds - Array of test IDs
|
|
7429
|
+
* @returns Array of test details (null for not found tests)
|
|
7430
|
+
*/
|
|
7431
|
+
async getTestDetailsBulk(testIds) {
|
|
7432
|
+
const url = `${this.apiUrl}/v1/reporting/tests/bulk`;
|
|
7433
|
+
logger.debug(`Bulk fetching ${testIds.length} test details`);
|
|
7434
|
+
const response = await fetch(url, {
|
|
7435
|
+
method: "POST",
|
|
7436
|
+
headers: {
|
|
7437
|
+
"Content-Type": "application/json",
|
|
7438
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
7439
|
+
},
|
|
7440
|
+
body: JSON.stringify({ testIds })
|
|
7441
|
+
});
|
|
7442
|
+
if (!response.ok) {
|
|
7443
|
+
const errorText = await response.text();
|
|
7444
|
+
throw new ApiError(response.status, response.statusText, errorText);
|
|
7445
|
+
}
|
|
7446
|
+
const data = await response.json();
|
|
7447
|
+
logger.debug(`Fetched ${data.tests.length} test details`);
|
|
7448
|
+
return data.tests;
|
|
7449
|
+
}
|
|
7450
|
+
/**
|
|
7451
|
+
* Assign a test to yourself (or someone else)
|
|
7073
7452
|
* @param params - Assignment parameters
|
|
7074
|
-
* @returns Assignment result
|
|
7453
|
+
* @returns Assignment result
|
|
7075
7454
|
*/
|
|
7076
|
-
async
|
|
7077
|
-
const url = `${this.apiUrl}/v1/
|
|
7078
|
-
logger.debug(`Assigning
|
|
7079
|
-
|
|
7080
|
-
|
|
7455
|
+
async assignTest(params) {
|
|
7456
|
+
const url = `${this.apiUrl}/v1/tests-catalog/assign`;
|
|
7457
|
+
logger.debug(`Assigning test`, {
|
|
7458
|
+
testId: params.testId,
|
|
7459
|
+
assignedTo: params.assignedTo
|
|
7081
7460
|
});
|
|
7082
7461
|
const response = await fetch(url, {
|
|
7083
7462
|
method: "POST",
|
|
@@ -7086,7 +7465,37 @@ var init_api_client = __esm({
|
|
|
7086
7465
|
Authorization: `Bearer ${this.apiKey}`
|
|
7087
7466
|
},
|
|
7088
7467
|
body: JSON.stringify({
|
|
7089
|
-
|
|
7468
|
+
testId: params.testId,
|
|
7469
|
+
assignedTo: params.assignedTo
|
|
7470
|
+
})
|
|
7471
|
+
});
|
|
7472
|
+
if (!response.ok) {
|
|
7473
|
+
const errorText = await response.text();
|
|
7474
|
+
throw new ApiError(response.status, response.statusText, errorText);
|
|
7475
|
+
}
|
|
7476
|
+
const data = await response.json();
|
|
7477
|
+
logger.debug(`Test assigned: ${params.testId} -> ${params.assignedTo}`);
|
|
7478
|
+
return data;
|
|
7479
|
+
}
|
|
7480
|
+
/**
|
|
7481
|
+
* Bulk assign multiple tests to yourself (or someone else)
|
|
7482
|
+
* @param params - Bulk assignment parameters
|
|
7483
|
+
* @returns Bulk assignment result with successful assignments and conflicts
|
|
7484
|
+
*/
|
|
7485
|
+
async assignTestsBulk(params) {
|
|
7486
|
+
const url = `${this.apiUrl}/v1/tests-catalog/assign-bulk`;
|
|
7487
|
+
logger.debug(`Bulk assigning ${params.testIds.length} tests`, {
|
|
7488
|
+
testIds: params.testIds,
|
|
7489
|
+
assignedTo: params.assignedTo
|
|
7490
|
+
});
|
|
7491
|
+
const response = await fetch(url, {
|
|
7492
|
+
method: "POST",
|
|
7493
|
+
headers: {
|
|
7494
|
+
"Content-Type": "application/json",
|
|
7495
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
7496
|
+
},
|
|
7497
|
+
body: JSON.stringify({
|
|
7498
|
+
testIds: params.testIds,
|
|
7090
7499
|
assignedTo: params.assignedTo
|
|
7091
7500
|
})
|
|
7092
7501
|
});
|
|
@@ -7096,18 +7505,18 @@ var init_api_client = __esm({
|
|
|
7096
7505
|
}
|
|
7097
7506
|
const data = await response.json();
|
|
7098
7507
|
logger.debug(
|
|
7099
|
-
`
|
|
7508
|
+
`Bulk assigned ${data.successful.length} tests, ${data.conflicts.length} conflicts`
|
|
7100
7509
|
);
|
|
7101
7510
|
return data;
|
|
7102
7511
|
}
|
|
7103
7512
|
/**
|
|
7104
|
-
* Mark assignment as complete
|
|
7513
|
+
* Mark assignment as complete or failed
|
|
7105
7514
|
* @param params - Completion parameters
|
|
7106
7515
|
* @returns Success status
|
|
7107
7516
|
*/
|
|
7108
7517
|
async completeAssignment(params) {
|
|
7109
|
-
const url = `${this.apiUrl}/v1/
|
|
7110
|
-
logger.debug(`
|
|
7518
|
+
const url = `${this.apiUrl}/v1/tests-catalog/${params.assignmentId}/status`;
|
|
7519
|
+
logger.debug(`Updating assignment status`, {
|
|
7111
7520
|
assignmentId: params.assignmentId,
|
|
7112
7521
|
status: params.status
|
|
7113
7522
|
});
|
|
@@ -7119,7 +7528,7 @@ var init_api_client = __esm({
|
|
|
7119
7528
|
},
|
|
7120
7529
|
body: JSON.stringify({
|
|
7121
7530
|
status: params.status,
|
|
7122
|
-
|
|
7531
|
+
notes: params.notes
|
|
7123
7532
|
})
|
|
7124
7533
|
});
|
|
7125
7534
|
if (!response.ok) {
|
|
@@ -7127,7 +7536,7 @@ var init_api_client = __esm({
|
|
|
7127
7536
|
throw new ApiError(response.status, response.statusText, errorText);
|
|
7128
7537
|
}
|
|
7129
7538
|
const data = await response.json();
|
|
7130
|
-
logger.debug(`Assignment
|
|
7539
|
+
logger.debug(`Assignment updated: ${params.assignmentId} -> ${params.status}`);
|
|
7131
7540
|
return data;
|
|
7132
7541
|
}
|
|
7133
7542
|
/**
|
|
@@ -7136,7 +7545,7 @@ var init_api_client = __esm({
|
|
|
7136
7545
|
* @returns Success status
|
|
7137
7546
|
*/
|
|
7138
7547
|
async releaseAssignment(assignmentId) {
|
|
7139
|
-
const url = `${this.apiUrl}/v1/
|
|
7548
|
+
const url = `${this.apiUrl}/v1/tests-catalog/${assignmentId}`;
|
|
7140
7549
|
logger.debug(`Releasing assignment: ${assignmentId}`);
|
|
7141
7550
|
const response = await fetch(url, {
|
|
7142
7551
|
method: "DELETE",
|
|
@@ -7153,12 +7562,12 @@ var init_api_client = __esm({
|
|
|
7153
7562
|
return data;
|
|
7154
7563
|
}
|
|
7155
7564
|
/**
|
|
7156
|
-
* Get my current assignments
|
|
7157
|
-
* @returns List of current assignments
|
|
7565
|
+
* Get my current work (active test assignments)
|
|
7566
|
+
* @returns List of current assignments with test info
|
|
7158
7567
|
*/
|
|
7159
|
-
async
|
|
7160
|
-
const url = `${this.apiUrl}/v1/
|
|
7161
|
-
logger.debug(`Fetching my assignments`);
|
|
7568
|
+
async getMyWork() {
|
|
7569
|
+
const url = `${this.apiUrl}/v1/tests-catalog/my-work`;
|
|
7570
|
+
logger.debug(`Fetching my work assignments`);
|
|
7162
7571
|
const response = await fetch(url, {
|
|
7163
7572
|
method: "GET",
|
|
7164
7573
|
headers: {
|
|
@@ -7170,17 +7579,22 @@ var init_api_client = __esm({
|
|
|
7170
7579
|
throw new ApiError(response.status, response.statusText, errorText);
|
|
7171
7580
|
}
|
|
7172
7581
|
const data = await response.json();
|
|
7173
|
-
logger.debug(`Fetched ${data.assignments
|
|
7174
|
-
return
|
|
7582
|
+
logger.debug(`Fetched ${data.assignments?.length || 0} active assignments`);
|
|
7583
|
+
return data;
|
|
7175
7584
|
}
|
|
7176
7585
|
/**
|
|
7177
|
-
* Get
|
|
7586
|
+
* Get test catalog tests for a run (to show tests and their assignment status)
|
|
7178
7587
|
* @param runId - The run ID
|
|
7179
|
-
* @
|
|
7588
|
+
* @param query - Optional query parameters for filtering
|
|
7589
|
+
* @returns List of tests with their assignment info
|
|
7180
7590
|
*/
|
|
7181
|
-
async
|
|
7182
|
-
const
|
|
7183
|
-
|
|
7591
|
+
async getRunTestsCatalog(runId, query2) {
|
|
7592
|
+
const urlParams = new URLSearchParams();
|
|
7593
|
+
if (query2?.page) urlParams.set("page", query2.page.toString());
|
|
7594
|
+
if (query2?.limit) urlParams.set("limit", query2.limit.toString());
|
|
7595
|
+
if (query2?.status) urlParams.set("status", query2.status);
|
|
7596
|
+
const url = `${this.apiUrl}/v1/tests-catalog/runs/${runId}?${urlParams.toString()}`;
|
|
7597
|
+
logger.debug(`Fetching tests catalog for run: ${runId}`);
|
|
7184
7598
|
const response = await fetch(url, {
|
|
7185
7599
|
method: "GET",
|
|
7186
7600
|
headers: {
|
|
@@ -7192,14 +7606,10 @@ var init_api_client = __esm({
|
|
|
7192
7606
|
throw new ApiError(response.status, response.statusText, errorText);
|
|
7193
7607
|
}
|
|
7194
7608
|
const data = await response.json();
|
|
7195
|
-
logger.debug(
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
assignedTo: a.assignedTo,
|
|
7200
|
-
assignedAt: a.assignedAt
|
|
7201
|
-
}))
|
|
7202
|
-
};
|
|
7609
|
+
logger.debug(
|
|
7610
|
+
`Fetched ${data.tests?.length || 0} tests for run ${runId}`
|
|
7611
|
+
);
|
|
7612
|
+
return data;
|
|
7203
7613
|
}
|
|
7204
7614
|
};
|
|
7205
7615
|
}
|
|
@@ -12260,36 +12670,22 @@ var init_TestSelector = __esm({
|
|
|
12260
12670
|
run,
|
|
12261
12671
|
onSelect,
|
|
12262
12672
|
onCancel,
|
|
12263
|
-
assignments =
|
|
12673
|
+
assignments = /* @__PURE__ */ new Map()
|
|
12264
12674
|
}) => {
|
|
12265
12675
|
const [allTests, setAllTests] = useState7([]);
|
|
12266
12676
|
const [selectedTests, setSelectedTests] = useState7(/* @__PURE__ */ new Set());
|
|
12267
12677
|
const [cursorIndex, setCursorIndex] = useState7(0);
|
|
12268
12678
|
const [isLoading, setIsLoading] = useState7(false);
|
|
12269
|
-
const [isLoadingAssignments, setIsLoadingAssignments] = useState7(true);
|
|
12270
12679
|
const [hasMore, setHasMore] = useState7(true);
|
|
12271
12680
|
const [totalTests, setTotalTests] = useState7(0);
|
|
12272
12681
|
const [error, setError] = useState7(null);
|
|
12273
12682
|
const [showAvailableOnly, setShowAvailableOnly] = useState7(true);
|
|
12274
12683
|
const [groupByFile, setGroupByFile] = useState7(false);
|
|
12275
|
-
const assignedTestMap =
|
|
12276
|
-
const assignedTestIds = new Set(assignments.
|
|
12684
|
+
const assignedTestMap = assignments;
|
|
12685
|
+
const assignedTestIds = new Set(assignments.keys());
|
|
12277
12686
|
useEffect7(() => {
|
|
12278
12687
|
loadMoreTests();
|
|
12279
12688
|
}, []);
|
|
12280
|
-
useEffect7(() => {
|
|
12281
|
-
fetchAssignments();
|
|
12282
|
-
}, [run.id]);
|
|
12283
|
-
const fetchAssignments = async () => {
|
|
12284
|
-
setIsLoadingAssignments(true);
|
|
12285
|
-
try {
|
|
12286
|
-
const result = await apiClient.getRunAssignments(run.id);
|
|
12287
|
-
} catch (err) {
|
|
12288
|
-
console.error("Failed to load assignments:", err);
|
|
12289
|
-
} finally {
|
|
12290
|
-
setIsLoadingAssignments(false);
|
|
12291
|
-
}
|
|
12292
|
-
};
|
|
12293
12689
|
const loadMoreTests = async () => {
|
|
12294
12690
|
if (isLoading || !hasMore) {
|
|
12295
12691
|
return;
|
|
@@ -12298,15 +12694,16 @@ var init_TestSelector = __esm({
|
|
|
12298
12694
|
setError(null);
|
|
12299
12695
|
try {
|
|
12300
12696
|
const page = Math.floor(allTests.length / PAGE_SIZE2) + 1;
|
|
12301
|
-
const result = await apiClient.
|
|
12697
|
+
const result = await apiClient.getRunTestsCatalog(run.id, {
|
|
12302
12698
|
page,
|
|
12303
12699
|
limit: PAGE_SIZE2,
|
|
12304
12700
|
status: "failed"
|
|
12305
12701
|
// Only fetch failed tests
|
|
12306
12702
|
});
|
|
12307
|
-
setTotalTests(result.total);
|
|
12703
|
+
setTotalTests(result.total ?? result.tests.length);
|
|
12308
12704
|
const loadedCount = allTests.length + result.tests.length;
|
|
12309
|
-
|
|
12705
|
+
const total = result.total ?? loadedCount;
|
|
12706
|
+
setHasMore(result.tests.length === PAGE_SIZE2 && loadedCount < total);
|
|
12310
12707
|
setAllTests((prev) => [...prev, ...result.tests]);
|
|
12311
12708
|
} catch (err) {
|
|
12312
12709
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -12377,7 +12774,7 @@ var init_TestSelector = __esm({
|
|
|
12377
12774
|
setSelectedTests(newSelected);
|
|
12378
12775
|
};
|
|
12379
12776
|
useInput3((input, key) => {
|
|
12380
|
-
if (allTests.length === 0 && !isLoading
|
|
12777
|
+
if (allTests.length === 0 && !isLoading) {
|
|
12381
12778
|
if (key.escape || input === "q") {
|
|
12382
12779
|
onCancel();
|
|
12383
12780
|
}
|
|
@@ -12508,7 +12905,7 @@ var init_TestSelector = __esm({
|
|
|
12508
12905
|
const displayAssignee = assignee.startsWith("cli:") ? assignee.slice(4) : assignee;
|
|
12509
12906
|
return /* @__PURE__ */ React21.createElement(Box18, { key: test.id, marginBottom: 0 }, /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : isAssigned ? theme.text.dim : theme.text.primary }, indicator), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, color: isAssigned ? theme.text.dim : isChecked ? "green" : isSelected ? "black" : theme.text.dim }, isAssigned ? "\u{1F504}" : checkbox), /* @__PURE__ */ React21.createElement(Text16, null, " "), /* @__PURE__ */ React21.createElement(Text16, { backgroundColor: bgColor, bold: isSelected, color: isSelected ? "black" : isAssigned ? theme.text.dim : theme.text.primary }, file, line && /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, ":", line), isAssigned && /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " \u2022 "), /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, displayAssignee)), /* @__PURE__ */ React21.createElement(Text16, { color: isSelected ? "black" : theme.text.dim }, " - "), title));
|
|
12510
12907
|
})
|
|
12511
|
-
)), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1 }, !groupByFile && filteredTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", filteredTests.length, " ", showAvailableOnly ? "available" : "", " tests", hasMore && !isLoading && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " (scroll for more)"))), groupByFile && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", fileGroups.length, " file", fileGroups.length !== 1 ? "s" : "", " \u2022 ", filteredTests.length, " total test", filteredTests.length !== 1 ? "s" : "")), /* @__PURE__ */ React21.createElement(Box18, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "s"), " next 10 \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "f"), " group files \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "t"), " toggle filter \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")),
|
|
12908
|
+
)), /* @__PURE__ */ React21.createElement(Box18, { flexDirection: "column", marginTop: 1 }, !groupByFile && filteredTests.length > VISIBLE_ITEMS2 && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", adjustedStart + 1, "-", adjustedEnd, " of ", filteredTests.length, " ", showAvailableOnly ? "available" : "", " tests", hasMore && !isLoading && /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, " (scroll for more)"))), groupByFile && /* @__PURE__ */ React21.createElement(Box18, { marginBottom: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "yellow" }, "Showing ", fileGroups.length, " file", fileGroups.length !== 1 ? "s" : "", " \u2022 ", filteredTests.length, " total test", filteredTests.length !== 1 ? "s" : "")), /* @__PURE__ */ React21.createElement(Box18, null, /* @__PURE__ */ React21.createElement(Text16, { color: theme.text.dim }, /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "\u2191\u2193"), " navigate \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Space"), " toggle \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "n"), " none \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "s"), " next 10 \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "f"), " group files \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "t"), " toggle filter \u2022 ", /* @__PURE__ */ React21.createElement(Text16, { bold: true }, "Enter"), " fix selected")), selectedTests.size > 0 && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "green" }, selectedTests.size, " test", selectedTests.size !== 1 ? "s" : "", " selected")), isLoading && /* @__PURE__ */ React21.createElement(Box18, { marginTop: 1 }, /* @__PURE__ */ React21.createElement(Text16, { color: "cyan" }, "Loading more tests..."))));
|
|
12512
12909
|
};
|
|
12513
12910
|
}
|
|
12514
12911
|
});
|
|
@@ -12534,7 +12931,8 @@ var init_FixFlow = __esm({
|
|
|
12534
12931
|
const [step, setStep] = useState8(initialRunId ? "select-run" : "select-run");
|
|
12535
12932
|
const [selectedRun, setSelectedRun] = useState8(null);
|
|
12536
12933
|
const [selectedTests, setSelectedTests] = useState8([]);
|
|
12537
|
-
const [assignments, setAssignments] = useState8(
|
|
12934
|
+
const [assignments, setAssignments] = useState8(/* @__PURE__ */ new Map());
|
|
12935
|
+
const [testCatalogMap, setTestCatalogMap] = useState8(/* @__PURE__ */ new Map());
|
|
12538
12936
|
const [assignmentIds, setAssignmentIds] = useState8(/* @__PURE__ */ new Map());
|
|
12539
12937
|
const [loadingProgress, setLoadingProgress] = useState8({ current: 0, total: 0 });
|
|
12540
12938
|
const [loadError, setLoadError] = useState8(null);
|
|
@@ -12558,8 +12956,25 @@ var init_FixFlow = __esm({
|
|
|
12558
12956
|
};
|
|
12559
12957
|
const fetchAssignments = async (runId) => {
|
|
12560
12958
|
try {
|
|
12561
|
-
const result = await apiClient.
|
|
12562
|
-
|
|
12959
|
+
const result = await apiClient.getRunTestsCatalog(runId, {
|
|
12960
|
+
status: "failed",
|
|
12961
|
+
limit: 1e3
|
|
12962
|
+
// Get all failed tests for assignment lookup
|
|
12963
|
+
});
|
|
12964
|
+
const assignmentMap = /* @__PURE__ */ new Map();
|
|
12965
|
+
const catalogMap = /* @__PURE__ */ new Map();
|
|
12966
|
+
for (const test of result.tests) {
|
|
12967
|
+
catalogMap.set(test.id, test.testId);
|
|
12968
|
+
if (test.assignment) {
|
|
12969
|
+
assignmentMap.set(test.id, {
|
|
12970
|
+
testId: test.testId,
|
|
12971
|
+
assignedTo: test.assignment.assignedTo,
|
|
12972
|
+
assignedAt: test.assignment.assignedAt
|
|
12973
|
+
});
|
|
12974
|
+
}
|
|
12975
|
+
}
|
|
12976
|
+
setAssignments(assignmentMap);
|
|
12977
|
+
setTestCatalogMap(catalogMap);
|
|
12563
12978
|
} catch (err) {
|
|
12564
12979
|
console.error("Failed to load assignments:", err);
|
|
12565
12980
|
}
|
|
@@ -12569,16 +12984,46 @@ var init_FixFlow = __esm({
|
|
|
12569
12984
|
setStep("claiming-tests");
|
|
12570
12985
|
setLoadError(null);
|
|
12571
12986
|
try {
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
if (
|
|
12578
|
-
|
|
12579
|
-
|
|
12987
|
+
const assignmentMap = /* @__PURE__ */ new Map();
|
|
12988
|
+
const testCatalogUuids = [];
|
|
12989
|
+
const testRunToCatalogMap = /* @__PURE__ */ new Map();
|
|
12990
|
+
for (const test of tests) {
|
|
12991
|
+
const testCatalogUuid = testCatalogMap.get(test.id);
|
|
12992
|
+
if (!testCatalogUuid) {
|
|
12993
|
+
throw new Error(`Test catalog entry not found for test: ${test.file}:${test.title}`);
|
|
12994
|
+
}
|
|
12995
|
+
testCatalogUuids.push(testCatalogUuid);
|
|
12996
|
+
testRunToCatalogMap.set(testCatalogUuid, test.id);
|
|
12997
|
+
}
|
|
12998
|
+
const result = await apiClient.assignTestsBulk({
|
|
12999
|
+
testIds: testCatalogUuids
|
|
13000
|
+
});
|
|
13001
|
+
for (const assignment of result.successful) {
|
|
13002
|
+
const testRunId = testRunToCatalogMap.get(assignment.testId);
|
|
13003
|
+
if (testRunId) {
|
|
13004
|
+
assignmentMap.set(testRunId, assignment.id);
|
|
13005
|
+
}
|
|
13006
|
+
}
|
|
13007
|
+
const conflicts = [];
|
|
13008
|
+
for (const conflict of result.conflicts) {
|
|
13009
|
+
const testRunId = testRunToCatalogMap.get(conflict.testId);
|
|
13010
|
+
if (testRunId) {
|
|
13011
|
+
const test = tests.find((t) => t.id === testRunId);
|
|
13012
|
+
if (test) {
|
|
13013
|
+
conflicts.push({
|
|
13014
|
+
test,
|
|
13015
|
+
assignee: conflict.assignedTo
|
|
13016
|
+
});
|
|
13017
|
+
}
|
|
13018
|
+
}
|
|
13019
|
+
}
|
|
13020
|
+
if (conflicts.length > 0) {
|
|
13021
|
+
const successfullyClaimed = tests.filter((test) => assignmentMap.has(test.id));
|
|
13022
|
+
if (successfullyClaimed.length === 0) {
|
|
13023
|
+
const conflictList = conflicts.slice(0, 3).map((c) => `${c.test.file}: ${c.test.title} (claimed by ${c.assignee})`).join("\n\u2022 ");
|
|
13024
|
+
const moreCount = conflicts.length - 3;
|
|
12580
13025
|
setLoadError(
|
|
12581
|
-
|
|
13026
|
+
`All selected tests are already claimed by others:
|
|
12582
13027
|
\u2022 ${conflictList}${moreCount > 0 ? `
|
|
12583
13028
|
\u2022 ... and ${moreCount} more` : ""}
|
|
12584
13029
|
|
|
@@ -12587,28 +13032,22 @@ Please select different tests.`
|
|
|
12587
13032
|
setStep("error");
|
|
12588
13033
|
return;
|
|
12589
13034
|
}
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
assignmentMap.set(assignment.testRunId, assignment.id);
|
|
12593
|
-
});
|
|
12594
|
-
setAssignmentIds(assignmentMap);
|
|
13035
|
+
setSelectedTests(successfullyClaimed);
|
|
13036
|
+
console.log(`Skipped ${conflicts.length} already claimed test(s), continuing with ${successfullyClaimed.length} test(s)`);
|
|
12595
13037
|
}
|
|
13038
|
+
setAssignmentIds(assignmentMap);
|
|
13039
|
+
const testsToLoad = conflicts.length > 0 ? tests.filter((test) => assignmentMap.has(test.id)) : tests;
|
|
12596
13040
|
setStep("loading-details");
|
|
12597
|
-
setLoadingProgress({ current: 0, total:
|
|
12598
|
-
const
|
|
12599
|
-
const
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
batch.map((test) => apiClient.getTestDetail(test.id))
|
|
12604
|
-
);
|
|
12605
|
-
testDetails.push(...batchResults);
|
|
12606
|
-
setLoadingProgress({ current: testDetails.length, total: tests.length });
|
|
12607
|
-
}
|
|
13041
|
+
setLoadingProgress({ current: 0, total: testsToLoad.length });
|
|
13042
|
+
const testIds = testsToLoad.map((test) => test.id);
|
|
13043
|
+
const testDetailsArray = await apiClient.getTestDetailsBulk(testIds);
|
|
13044
|
+
const testDetails = testDetailsArray.filter(
|
|
13045
|
+
(detail) => detail !== null
|
|
13046
|
+
);
|
|
12608
13047
|
const testContexts = testDetails.map((test) => ({ test }));
|
|
12609
13048
|
const prompt = buildFixPrompt(testContexts);
|
|
12610
13049
|
setStep("fixing");
|
|
12611
|
-
onStartFix(prompt,
|
|
13050
|
+
onStartFix(prompt, testsToLoad);
|
|
12612
13051
|
} catch (err) {
|
|
12613
13052
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
12614
13053
|
if (errorMessage.includes("network") || errorMessage.includes("fetch")) {
|
|
@@ -12636,7 +13075,7 @@ Press ESC to go back and try again.`);
|
|
|
12636
13075
|
};
|
|
12637
13076
|
const handleTestCancel = () => {
|
|
12638
13077
|
setSelectedRun(null);
|
|
12639
|
-
setAssignments(
|
|
13078
|
+
setAssignments(/* @__PURE__ */ new Map());
|
|
12640
13079
|
setStep("select-run");
|
|
12641
13080
|
};
|
|
12642
13081
|
const markAssignmentsComplete = async (fixSessionId) => {
|
|
@@ -12648,8 +13087,7 @@ Press ESC to go back and try again.`);
|
|
|
12648
13087
|
Array.from(assignmentIds.values()).map(
|
|
12649
13088
|
(assignmentId) => apiClient.completeAssignment({
|
|
12650
13089
|
assignmentId,
|
|
12651
|
-
status: "completed"
|
|
12652
|
-
fixSessionId
|
|
13090
|
+
status: "completed"
|
|
12653
13091
|
})
|
|
12654
13092
|
)
|
|
12655
13093
|
);
|