@bbearai/core 0.2.0 → 0.2.1
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.d.mts +222 -1
- package/dist/index.d.ts +222 -1
- package/dist/index.js +492 -0
- package/dist/index.mjs +492 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -117,6 +117,7 @@ var BugBearClient = class {
|
|
|
117
117
|
const { data, error } = await this.supabase.from("test_assignments").select(`
|
|
118
118
|
id,
|
|
119
119
|
status,
|
|
120
|
+
started_at,
|
|
120
121
|
test_case:test_cases(
|
|
121
122
|
id,
|
|
122
123
|
title,
|
|
@@ -144,6 +145,7 @@ var BugBearClient = class {
|
|
|
144
145
|
return (data || []).map((item) => ({
|
|
145
146
|
id: item.id,
|
|
146
147
|
status: item.status,
|
|
148
|
+
startedAt: item.started_at,
|
|
147
149
|
testCase: {
|
|
148
150
|
id: item.test_case.id,
|
|
149
151
|
title: item.test_case.title,
|
|
@@ -169,6 +171,254 @@ var BugBearClient = class {
|
|
|
169
171
|
return [];
|
|
170
172
|
}
|
|
171
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Get assignment by ID with time tracking fields
|
|
176
|
+
*/
|
|
177
|
+
async getAssignment(assignmentId) {
|
|
178
|
+
try {
|
|
179
|
+
const { data, error } = await this.supabase.from("test_assignments").select(`
|
|
180
|
+
id,
|
|
181
|
+
status,
|
|
182
|
+
started_at,
|
|
183
|
+
completed_at,
|
|
184
|
+
duration_seconds,
|
|
185
|
+
test_case:test_cases(
|
|
186
|
+
id,
|
|
187
|
+
title,
|
|
188
|
+
test_key,
|
|
189
|
+
description,
|
|
190
|
+
steps,
|
|
191
|
+
expected_result,
|
|
192
|
+
priority,
|
|
193
|
+
target_route,
|
|
194
|
+
track:qa_tracks(
|
|
195
|
+
id,
|
|
196
|
+
name,
|
|
197
|
+
icon,
|
|
198
|
+
color,
|
|
199
|
+
test_template,
|
|
200
|
+
rubric_mode,
|
|
201
|
+
description
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
`).eq("id", assignmentId).single();
|
|
205
|
+
if (error || !data) return null;
|
|
206
|
+
const testCase = data.test_case;
|
|
207
|
+
if (!testCase) {
|
|
208
|
+
console.error("BugBear: Assignment returned without test_case");
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const track = testCase.track;
|
|
212
|
+
return {
|
|
213
|
+
id: data.id,
|
|
214
|
+
status: data.status,
|
|
215
|
+
startedAt: data.started_at,
|
|
216
|
+
durationSeconds: data.duration_seconds,
|
|
217
|
+
testCase: {
|
|
218
|
+
id: testCase.id,
|
|
219
|
+
title: testCase.title,
|
|
220
|
+
testKey: testCase.test_key,
|
|
221
|
+
description: testCase.description,
|
|
222
|
+
steps: testCase.steps,
|
|
223
|
+
expectedResult: testCase.expected_result,
|
|
224
|
+
priority: testCase.priority,
|
|
225
|
+
targetRoute: testCase.target_route,
|
|
226
|
+
track: track ? {
|
|
227
|
+
id: track.id,
|
|
228
|
+
name: track.name,
|
|
229
|
+
icon: track.icon,
|
|
230
|
+
color: track.color,
|
|
231
|
+
testTemplate: track.test_template,
|
|
232
|
+
rubricMode: track.rubric_mode || "pass_fail",
|
|
233
|
+
description: track.description
|
|
234
|
+
} : void 0
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
} catch (err) {
|
|
238
|
+
console.error("BugBear: Error fetching assignment", err);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Update assignment status with automatic time tracking
|
|
244
|
+
* - Sets started_at when status changes to 'in_progress'
|
|
245
|
+
* - Calculates duration_seconds when status changes to 'passed'/'failed'/'blocked'
|
|
246
|
+
* - Optionally include feedback when completing a test
|
|
247
|
+
*/
|
|
248
|
+
async updateAssignmentStatus(assignmentId, status, options) {
|
|
249
|
+
try {
|
|
250
|
+
const { data: currentAssignment, error: fetchError } = await this.supabase.from("test_assignments").select("status, started_at").eq("id", assignmentId).single();
|
|
251
|
+
if (fetchError || !currentAssignment) {
|
|
252
|
+
return { success: false, error: "Assignment not found" };
|
|
253
|
+
}
|
|
254
|
+
const updateData = { status };
|
|
255
|
+
let durationSeconds;
|
|
256
|
+
if (status === "in_progress" && currentAssignment.status !== "in_progress") {
|
|
257
|
+
updateData.started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
258
|
+
}
|
|
259
|
+
if (["passed", "failed", "blocked"].includes(status)) {
|
|
260
|
+
updateData.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
261
|
+
if (currentAssignment.started_at) {
|
|
262
|
+
const startedAt = new Date(currentAssignment.started_at);
|
|
263
|
+
const completedAt = /* @__PURE__ */ new Date();
|
|
264
|
+
durationSeconds = Math.round((completedAt.getTime() - startedAt.getTime()) / 1e3);
|
|
265
|
+
updateData.duration_seconds = durationSeconds;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (options?.notes) {
|
|
269
|
+
updateData.notes = options.notes;
|
|
270
|
+
}
|
|
271
|
+
if (options?.testResult) {
|
|
272
|
+
updateData.test_result = options.testResult;
|
|
273
|
+
}
|
|
274
|
+
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
275
|
+
if (error) {
|
|
276
|
+
console.error("BugBear: Failed to update assignment status", error);
|
|
277
|
+
return { success: false, error: error.message };
|
|
278
|
+
}
|
|
279
|
+
if (options?.feedback && ["passed", "failed", "blocked"].includes(status)) {
|
|
280
|
+
const { data: assignmentData, error: fetchError2 } = await this.supabase.from("test_assignments").select("test_case_id").eq("id", assignmentId).single();
|
|
281
|
+
if (fetchError2) {
|
|
282
|
+
console.error("BugBear: Failed to fetch assignment for feedback", fetchError2);
|
|
283
|
+
} else if (assignmentData?.test_case_id) {
|
|
284
|
+
const feedbackResult = await this.submitTestFeedback({
|
|
285
|
+
testCaseId: assignmentData.test_case_id,
|
|
286
|
+
assignmentId,
|
|
287
|
+
feedback: options.feedback,
|
|
288
|
+
timeToCompleteSeconds: durationSeconds
|
|
289
|
+
});
|
|
290
|
+
if (!feedbackResult.success) {
|
|
291
|
+
console.error("BugBear: Failed to submit feedback", feedbackResult.error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return { success: true, durationSeconds };
|
|
296
|
+
} catch (err) {
|
|
297
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
298
|
+
console.error("BugBear: Error updating assignment status", err);
|
|
299
|
+
return { success: false, error: message };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Submit feedback on a test case to help improve test quality
|
|
304
|
+
* This empowers testers to shape better tests over time
|
|
305
|
+
*/
|
|
306
|
+
async submitTestFeedback(options) {
|
|
307
|
+
try {
|
|
308
|
+
const testerInfo = await this.getTesterInfo();
|
|
309
|
+
if (!testerInfo) {
|
|
310
|
+
return { success: false, error: "Not authenticated as tester" };
|
|
311
|
+
}
|
|
312
|
+
const { testCaseId, assignmentId, feedback, timeToCompleteSeconds } = options;
|
|
313
|
+
if (feedback.rating < 1 || feedback.rating > 5) {
|
|
314
|
+
return { success: false, error: "Rating must be between 1 and 5" };
|
|
315
|
+
}
|
|
316
|
+
const { error: feedbackError } = await this.supabase.from("test_feedback").insert({
|
|
317
|
+
project_id: this.config.projectId,
|
|
318
|
+
test_case_id: testCaseId,
|
|
319
|
+
assignment_id: assignmentId || null,
|
|
320
|
+
tester_id: testerInfo.id,
|
|
321
|
+
rating: feedback.rating,
|
|
322
|
+
clarity_rating: feedback.clarityRating || null,
|
|
323
|
+
steps_rating: feedback.stepsRating || null,
|
|
324
|
+
relevance_rating: feedback.relevanceRating || null,
|
|
325
|
+
feedback_note: feedback.feedbackNote?.trim() || null,
|
|
326
|
+
suggested_improvement: feedback.suggestedImprovement?.trim() || null,
|
|
327
|
+
is_outdated: feedback.isOutdated || false,
|
|
328
|
+
needs_more_detail: feedback.needsMoreDetail || false,
|
|
329
|
+
steps_unclear: feedback.stepsUnclear || false,
|
|
330
|
+
expected_result_unclear: feedback.expectedResultUnclear || false,
|
|
331
|
+
platform: this.getDeviceInfo().platform,
|
|
332
|
+
time_to_complete_seconds: timeToCompleteSeconds || null
|
|
333
|
+
});
|
|
334
|
+
if (feedbackError) {
|
|
335
|
+
console.error("BugBear: Failed to submit feedback", feedbackError);
|
|
336
|
+
return { success: false, error: feedbackError.message };
|
|
337
|
+
}
|
|
338
|
+
if (assignmentId) {
|
|
339
|
+
const { error: assignmentError } = await this.supabase.from("test_assignments").update({
|
|
340
|
+
feedback_rating: feedback.rating,
|
|
341
|
+
feedback_note: feedback.feedbackNote?.trim() || null,
|
|
342
|
+
feedback_submitted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
343
|
+
}).eq("id", assignmentId);
|
|
344
|
+
if (assignmentError) {
|
|
345
|
+
console.error("BugBear: Failed to update assignment feedback fields", assignmentError);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return { success: true };
|
|
349
|
+
} catch (err) {
|
|
350
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
351
|
+
console.error("BugBear: Error submitting feedback", err);
|
|
352
|
+
return { success: false, error: message };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Get the currently active (in_progress) assignment for the tester
|
|
357
|
+
*/
|
|
358
|
+
async getActiveAssignment() {
|
|
359
|
+
try {
|
|
360
|
+
const testerInfo = await this.getTesterInfo();
|
|
361
|
+
if (!testerInfo) return null;
|
|
362
|
+
const { data, error } = await this.supabase.from("test_assignments").select(`
|
|
363
|
+
id,
|
|
364
|
+
status,
|
|
365
|
+
started_at,
|
|
366
|
+
test_case:test_cases(
|
|
367
|
+
id,
|
|
368
|
+
title,
|
|
369
|
+
test_key,
|
|
370
|
+
description,
|
|
371
|
+
steps,
|
|
372
|
+
expected_result,
|
|
373
|
+
priority,
|
|
374
|
+
target_route,
|
|
375
|
+
track:qa_tracks(
|
|
376
|
+
id,
|
|
377
|
+
name,
|
|
378
|
+
icon,
|
|
379
|
+
color,
|
|
380
|
+
test_template,
|
|
381
|
+
rubric_mode,
|
|
382
|
+
description
|
|
383
|
+
)
|
|
384
|
+
)
|
|
385
|
+
`).eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).eq("status", "in_progress").order("started_at", { ascending: false }).limit(1).maybeSingle();
|
|
386
|
+
if (error || !data) return null;
|
|
387
|
+
const testCase = data.test_case;
|
|
388
|
+
if (!testCase) {
|
|
389
|
+
console.error("BugBear: Active assignment returned without test_case");
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
const track = testCase.track;
|
|
393
|
+
return {
|
|
394
|
+
id: data.id,
|
|
395
|
+
status: data.status,
|
|
396
|
+
startedAt: data.started_at,
|
|
397
|
+
testCase: {
|
|
398
|
+
id: testCase.id,
|
|
399
|
+
title: testCase.title,
|
|
400
|
+
testKey: testCase.test_key,
|
|
401
|
+
description: testCase.description,
|
|
402
|
+
steps: testCase.steps,
|
|
403
|
+
expectedResult: testCase.expected_result,
|
|
404
|
+
priority: testCase.priority,
|
|
405
|
+
targetRoute: testCase.target_route,
|
|
406
|
+
track: track ? {
|
|
407
|
+
id: track.id,
|
|
408
|
+
name: track.name,
|
|
409
|
+
icon: track.icon,
|
|
410
|
+
color: track.color,
|
|
411
|
+
testTemplate: track.test_template,
|
|
412
|
+
rubricMode: track.rubric_mode || "pass_fail",
|
|
413
|
+
description: track.description
|
|
414
|
+
} : void 0
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
} catch (err) {
|
|
418
|
+
console.error("BugBear: Error fetching active assignment", err);
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
172
422
|
/**
|
|
173
423
|
* Get current tester info
|
|
174
424
|
* Looks up tester by email from the host app's authenticated user
|
|
@@ -719,6 +969,248 @@ var BugBearClient = class {
|
|
|
719
969
|
return { success: false, error: message };
|
|
720
970
|
}
|
|
721
971
|
}
|
|
972
|
+
// ============================================
|
|
973
|
+
// QA Sessions (Sprint 1)
|
|
974
|
+
// ============================================
|
|
975
|
+
/**
|
|
976
|
+
* Start a new QA session for exploratory testing
|
|
977
|
+
*/
|
|
978
|
+
async startSession(options = {}) {
|
|
979
|
+
try {
|
|
980
|
+
const testerInfo = await this.getTesterInfo();
|
|
981
|
+
if (!testerInfo) {
|
|
982
|
+
return { success: false, error: "Not authenticated as a tester" };
|
|
983
|
+
}
|
|
984
|
+
const activeSession = await this.getActiveSession();
|
|
985
|
+
if (activeSession) {
|
|
986
|
+
return { success: false, error: "You already have an active session. End it before starting a new one." };
|
|
987
|
+
}
|
|
988
|
+
const { data, error } = await this.supabase.rpc("start_qa_session", {
|
|
989
|
+
p_project_id: this.config.projectId,
|
|
990
|
+
p_tester_id: testerInfo.id,
|
|
991
|
+
p_focus_area: options.focusArea || null,
|
|
992
|
+
p_track: options.track || null,
|
|
993
|
+
p_platform: options.platform || null
|
|
994
|
+
});
|
|
995
|
+
if (error) {
|
|
996
|
+
console.error("BugBear: Failed to start session", error);
|
|
997
|
+
return { success: false, error: error.message };
|
|
998
|
+
}
|
|
999
|
+
const session = await this.getSession(data);
|
|
1000
|
+
if (!session) {
|
|
1001
|
+
return { success: false, error: "Session created but could not be fetched" };
|
|
1002
|
+
}
|
|
1003
|
+
return { success: true, session };
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1006
|
+
console.error("BugBear: Error starting session", err);
|
|
1007
|
+
return { success: false, error: message };
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* End the current QA session
|
|
1012
|
+
*/
|
|
1013
|
+
async endSession(sessionId, options = {}) {
|
|
1014
|
+
try {
|
|
1015
|
+
const { data, error } = await this.supabase.rpc("end_qa_session", {
|
|
1016
|
+
p_session_id: sessionId,
|
|
1017
|
+
p_notes: options.notes || null,
|
|
1018
|
+
p_routes_covered: options.routesCovered || null
|
|
1019
|
+
});
|
|
1020
|
+
if (error) {
|
|
1021
|
+
console.error("BugBear: Failed to end session", error);
|
|
1022
|
+
return { success: false, error: error.message };
|
|
1023
|
+
}
|
|
1024
|
+
const session = this.transformSession(data);
|
|
1025
|
+
return { success: true, session };
|
|
1026
|
+
} catch (err) {
|
|
1027
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1028
|
+
console.error("BugBear: Error ending session", err);
|
|
1029
|
+
return { success: false, error: message };
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Get the current active session for the tester
|
|
1034
|
+
*/
|
|
1035
|
+
async getActiveSession() {
|
|
1036
|
+
try {
|
|
1037
|
+
const testerInfo = await this.getTesterInfo();
|
|
1038
|
+
if (!testerInfo) return null;
|
|
1039
|
+
const { data, error } = await this.supabase.from("qa_sessions").select("*").eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).eq("status", "active").order("started_at", { ascending: false }).limit(1).maybeSingle();
|
|
1040
|
+
if (error || !data) return null;
|
|
1041
|
+
return this.transformSession(data);
|
|
1042
|
+
} catch (err) {
|
|
1043
|
+
console.error("BugBear: Error fetching active session", err);
|
|
1044
|
+
return null;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Get a session by ID
|
|
1049
|
+
*/
|
|
1050
|
+
async getSession(sessionId) {
|
|
1051
|
+
try {
|
|
1052
|
+
const { data, error } = await this.supabase.from("qa_sessions").select("*").eq("id", sessionId).single();
|
|
1053
|
+
if (error || !data) return null;
|
|
1054
|
+
return this.transformSession(data);
|
|
1055
|
+
} catch (err) {
|
|
1056
|
+
console.error("BugBear: Error fetching session", err);
|
|
1057
|
+
return null;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Get session history for the tester
|
|
1062
|
+
*/
|
|
1063
|
+
async getSessionHistory(limit = 10) {
|
|
1064
|
+
try {
|
|
1065
|
+
const testerInfo = await this.getTesterInfo();
|
|
1066
|
+
if (!testerInfo) return [];
|
|
1067
|
+
const { data, error } = await this.supabase.from("qa_sessions").select("*").eq("project_id", this.config.projectId).eq("tester_id", testerInfo.id).order("started_at", { ascending: false }).limit(limit);
|
|
1068
|
+
if (error) {
|
|
1069
|
+
console.error("BugBear: Failed to fetch session history", error);
|
|
1070
|
+
return [];
|
|
1071
|
+
}
|
|
1072
|
+
return (data || []).map((s) => this.transformSession(s));
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
console.error("BugBear: Error fetching session history", err);
|
|
1075
|
+
return [];
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Add a finding during a session
|
|
1080
|
+
*/
|
|
1081
|
+
async addFinding(sessionId, options) {
|
|
1082
|
+
try {
|
|
1083
|
+
const { data, error } = await this.supabase.rpc("add_session_finding", {
|
|
1084
|
+
p_session_id: sessionId,
|
|
1085
|
+
p_type: options.type,
|
|
1086
|
+
p_title: options.title,
|
|
1087
|
+
p_description: options.description || null,
|
|
1088
|
+
p_severity: options.severity || "observation",
|
|
1089
|
+
p_route: options.route || null,
|
|
1090
|
+
p_screenshot_url: options.screenshotUrl || null,
|
|
1091
|
+
p_console_logs: options.consoleLogs || null,
|
|
1092
|
+
p_network_snapshot: options.networkSnapshot || null,
|
|
1093
|
+
p_device_info: options.deviceInfo || null,
|
|
1094
|
+
p_app_context: options.appContext || null
|
|
1095
|
+
});
|
|
1096
|
+
if (error) {
|
|
1097
|
+
console.error("BugBear: Failed to add finding", error);
|
|
1098
|
+
return { success: false, error: error.message };
|
|
1099
|
+
}
|
|
1100
|
+
const finding = this.transformFinding(data);
|
|
1101
|
+
return { success: true, finding };
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1104
|
+
console.error("BugBear: Error adding finding", err);
|
|
1105
|
+
return { success: false, error: message };
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Get findings for a session
|
|
1110
|
+
*/
|
|
1111
|
+
async getSessionFindings(sessionId) {
|
|
1112
|
+
try {
|
|
1113
|
+
const { data, error } = await this.supabase.from("qa_findings").select("*").eq("session_id", sessionId).order("created_at", { ascending: true });
|
|
1114
|
+
if (error) {
|
|
1115
|
+
console.error("BugBear: Failed to fetch findings", error);
|
|
1116
|
+
return [];
|
|
1117
|
+
}
|
|
1118
|
+
return (data || []).map((f) => this.transformFinding(f));
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
console.error("BugBear: Error fetching findings", err);
|
|
1121
|
+
return [];
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Convert a finding to a bug report
|
|
1126
|
+
*/
|
|
1127
|
+
async convertFindingToBug(findingId) {
|
|
1128
|
+
try {
|
|
1129
|
+
const { data, error } = await this.supabase.rpc("convert_finding_to_bug", {
|
|
1130
|
+
p_finding_id: findingId
|
|
1131
|
+
});
|
|
1132
|
+
if (error) {
|
|
1133
|
+
console.error("BugBear: Failed to convert finding", error);
|
|
1134
|
+
return { success: false, error: error.message };
|
|
1135
|
+
}
|
|
1136
|
+
return { success: true, bugId: data };
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1139
|
+
console.error("BugBear: Error converting finding", err);
|
|
1140
|
+
return { success: false, error: message };
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Dismiss a finding
|
|
1145
|
+
*/
|
|
1146
|
+
async dismissFinding(findingId, reason) {
|
|
1147
|
+
try {
|
|
1148
|
+
const { error } = await this.supabase.from("qa_findings").update({
|
|
1149
|
+
dismissed: true,
|
|
1150
|
+
dismissed_reason: reason || null,
|
|
1151
|
+
dismissed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1152
|
+
}).eq("id", findingId);
|
|
1153
|
+
if (error) {
|
|
1154
|
+
console.error("BugBear: Failed to dismiss finding", error);
|
|
1155
|
+
return { success: false, error: error.message };
|
|
1156
|
+
}
|
|
1157
|
+
return { success: true };
|
|
1158
|
+
} catch (err) {
|
|
1159
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1160
|
+
console.error("BugBear: Error dismissing finding", err);
|
|
1161
|
+
return { success: false, error: message };
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Transform database session to QASession type
|
|
1166
|
+
*/
|
|
1167
|
+
transformSession(data) {
|
|
1168
|
+
return {
|
|
1169
|
+
id: data.id,
|
|
1170
|
+
projectId: data.project_id,
|
|
1171
|
+
testerId: data.tester_id,
|
|
1172
|
+
focusArea: data.focus_area,
|
|
1173
|
+
track: data.track,
|
|
1174
|
+
platform: data.platform,
|
|
1175
|
+
startedAt: data.started_at,
|
|
1176
|
+
endedAt: data.ended_at,
|
|
1177
|
+
notes: data.notes,
|
|
1178
|
+
routesCovered: data.routes_covered || [],
|
|
1179
|
+
status: data.status,
|
|
1180
|
+
durationMinutes: data.duration_minutes,
|
|
1181
|
+
findingsCount: data.findings_count || 0,
|
|
1182
|
+
bugsFiled: data.bugs_filed || 0,
|
|
1183
|
+
createdAt: data.created_at,
|
|
1184
|
+
updatedAt: data.updated_at
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Transform database finding to QAFinding type
|
|
1189
|
+
*/
|
|
1190
|
+
transformFinding(data) {
|
|
1191
|
+
return {
|
|
1192
|
+
id: data.id,
|
|
1193
|
+
sessionId: data.session_id,
|
|
1194
|
+
projectId: data.project_id,
|
|
1195
|
+
type: data.type,
|
|
1196
|
+
severity: data.severity,
|
|
1197
|
+
title: data.title,
|
|
1198
|
+
description: data.description,
|
|
1199
|
+
route: data.route,
|
|
1200
|
+
screenshotUrl: data.screenshot_url,
|
|
1201
|
+
consoleLogs: data.console_logs,
|
|
1202
|
+
networkSnapshot: data.network_snapshot,
|
|
1203
|
+
deviceInfo: data.device_info,
|
|
1204
|
+
appContext: data.app_context,
|
|
1205
|
+
convertedToBugId: data.converted_to_bug_id,
|
|
1206
|
+
convertedToTestId: data.converted_to_test_id,
|
|
1207
|
+
dismissed: data.dismissed || false,
|
|
1208
|
+
dismissedReason: data.dismissed_reason,
|
|
1209
|
+
dismissedAt: data.dismissed_at,
|
|
1210
|
+
createdAt: data.created_at,
|
|
1211
|
+
updatedAt: data.updated_at
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
722
1214
|
};
|
|
723
1215
|
function createBugBear(config) {
|
|
724
1216
|
return new BugBearClient(config);
|