@iblai/iblai-js 1.26.9 → 1.26.11
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/data-layer/playwright/human-support-tab-helpers.d.ts +262 -0
- package/dist/data-layer/playwright/index.d.ts +1 -0
- package/dist/data-layer/security/index.d.ts +1 -0
- package/dist/data-layer/security/next.d.ts +1 -0
- package/dist/playwright/index.cjs +597 -41
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.ts +264 -2
- package/dist/playwright/index.esm.js +559 -42
- package/dist/playwright/index.esm.js.map +1 -1
- package/dist/playwright/playwright/human-support-tab-helpers.d.ts +262 -0
- package/dist/playwright/playwright/index.d.ts +1 -0
- package/dist/playwright/security/index.d.ts +1 -0
- package/dist/playwright/security/next.d.ts +1 -0
- package/dist/security/data-layer/index.d.ts +1 -0
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.esm.js +2 -0
- package/dist/security/index.esm.js.map +1 -0
- package/dist/security/index.js +13 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/next.d.ts +1 -0
- package/dist/security/next.esm.js +2 -0
- package/dist/security/next.esm.js.map +1 -0
- package/dist/security/next.js +13 -0
- package/dist/security/next.js.map +1 -0
- package/dist/security/playwright/audit-log-helpers.d.ts +119 -0
- package/dist/security/playwright/auth-flow-builder.d.ts +13 -0
- package/dist/security/playwright/auth-helpers.d.ts +10 -0
- package/dist/security/playwright/auth-setup.d.ts +34 -0
- package/dist/security/playwright/billing-tab-helpers.d.ts +88 -0
- package/dist/security/playwright/chat-privacy-helpers.d.ts +127 -0
- package/dist/security/playwright/claw-sandbox-helpers.d.ts +266 -0
- package/dist/security/playwright/credit-balance-helpers.d.ts +73 -0
- package/dist/security/playwright/custom-reporter.d.ts +12 -0
- package/dist/security/playwright/env-config.d.ts +24 -0
- package/dist/security/playwright/evaluation-tab-helpers.d.ts +396 -0
- package/dist/security/playwright/helpers.d.ts +11 -0
- package/dist/security/playwright/human-support-tab-helpers.d.ts +262 -0
- package/dist/security/playwright/index.d.ts +40 -0
- package/dist/security/playwright/logger.d.ts +3 -0
- package/dist/security/playwright/lti-tab-helpers.d.ts +270 -0
- package/dist/security/playwright/mail-client.d.ts +46 -0
- package/dist/security/playwright/memory-test-helpers.d.ts +66 -0
- package/dist/security/playwright/navigation.d.ts +26 -0
- package/dist/security/playwright/page-helpers.d.ts +38 -0
- package/dist/security/playwright/playwright-config.d.ts +81 -0
- package/dist/security/playwright/privacy-tab-helpers.d.ts +95 -0
- package/dist/security/playwright/report-download.d.ts +71 -0
- package/dist/security/playwright/screenshare-tab-helpers.d.ts +57 -0
- package/dist/security/playwright/shared-test-helpers.d.ts +37 -0
- package/dist/security/playwright/tasks-tab-helpers.d.ts +177 -0
- package/dist/security/playwright/voice-tab-helpers.d.ts +194 -0
- package/dist/security/security/index.d.ts +1 -0
- package/dist/security/security/next.d.ts +1 -0
- package/dist/security/web-containers/index.d.ts +1 -0
- package/dist/security/web-containers/next.d.ts +1 -0
- package/dist/security/web-containers/sso.d.ts +1 -0
- package/dist/security/web-utils/auth.d.ts +1 -0
- package/dist/security/web-utils/index.d.ts +1 -0
- package/dist/web-containers/playwright/human-support-tab-helpers.d.ts +262 -0
- package/dist/web-containers/playwright/index.d.ts +1 -0
- package/dist/web-containers/security/index.d.ts +1 -0
- package/dist/web-containers/security/next.d.ts +1 -0
- package/dist/web-containers/source/index.esm.js +216 -0
- package/dist/web-containers/source/next/index.esm.js +666 -15
- package/dist/web-utils/playwright/human-support-tab-helpers.d.ts +262 -0
- package/dist/web-utils/playwright/index.d.ts +1 -0
- package/dist/web-utils/security/index.d.ts +1 -0
- package/dist/web-utils/security/next.d.ts +1 -0
- package/package.json +15 -5
|
@@ -3165,7 +3165,7 @@ const PRIVACY_LABELS = {
|
|
|
3165
3165
|
* reach DOM that Radix renders outside the dialog subtree (popovers,
|
|
3166
3166
|
* select options, etc.).
|
|
3167
3167
|
*/
|
|
3168
|
-
function asPage$
|
|
3168
|
+
function asPage$7(scope) {
|
|
3169
3169
|
return 'page' in scope ? scope.page() : scope;
|
|
3170
3170
|
}
|
|
3171
3171
|
/**
|
|
@@ -3226,7 +3226,7 @@ async function selectPrivacyAction(scope, action) {
|
|
|
3226
3226
|
await trigger.click();
|
|
3227
3227
|
// Radix Select renders options in a portal at the document root, so we
|
|
3228
3228
|
// always look them up on the Page — never on the dialog Locator.
|
|
3229
|
-
const option = asPage$
|
|
3229
|
+
const option = asPage$7(scope).getByRole('option', {
|
|
3230
3230
|
name: PRIVACY_LABELS.actionOptions[action],
|
|
3231
3231
|
});
|
|
3232
3232
|
await test$1.expect(option).toBeVisible({ timeout: 5000 });
|
|
@@ -3338,7 +3338,7 @@ const CHAT_PRIVACY_LABELS = {
|
|
|
3338
3338
|
rowLabel: 'Allow users to control chat privacy',
|
|
3339
3339
|
},
|
|
3340
3340
|
};
|
|
3341
|
-
function asPage$
|
|
3341
|
+
function asPage$6(scope) {
|
|
3342
3342
|
return 'page' in scope ? scope.page() : scope;
|
|
3343
3343
|
}
|
|
3344
3344
|
// ──────────────────────────────────────────────────────────────────────
|
|
@@ -3410,7 +3410,7 @@ async function clickChatPrivacyToggle(scope) {
|
|
|
3410
3410
|
// ── Mid-session confirm dialog ────────────────────────────────────────
|
|
3411
3411
|
/** Locator for the AlertDialog content that the mid-session enable opens. */
|
|
3412
3412
|
function getChatPrivacyConfirmDialog(scope) {
|
|
3413
|
-
return asPage$
|
|
3413
|
+
return asPage$6(scope).getByTestId('chat-privacy-confirm-dialog');
|
|
3414
3414
|
}
|
|
3415
3415
|
async function expectChatPrivacyConfirmDialogOpen(scope, open) {
|
|
3416
3416
|
if (open) {
|
|
@@ -3429,7 +3429,7 @@ async function expectChatPrivacyConfirmDialogOpen(scope, open) {
|
|
|
3429
3429
|
*/
|
|
3430
3430
|
async function confirmEnableChatPrivacyMidSession(scope) {
|
|
3431
3431
|
await clickChatPrivacyToggle(scope);
|
|
3432
|
-
const page = asPage$
|
|
3432
|
+
const page = asPage$6(scope);
|
|
3433
3433
|
await expectChatPrivacyConfirmDialogOpen(page, true);
|
|
3434
3434
|
const action = page.getByTestId('chat-privacy-confirm-action');
|
|
3435
3435
|
await test$1.expect(action).toBeVisible({ timeout: 10000 });
|
|
@@ -3440,7 +3440,7 @@ async function confirmEnableChatPrivacyMidSession(scope) {
|
|
|
3440
3440
|
}
|
|
3441
3441
|
/** Cancel the confirm dialog without enabling. */
|
|
3442
3442
|
async function cancelEnableChatPrivacyMidSession(scope) {
|
|
3443
|
-
const page = asPage$
|
|
3443
|
+
const page = asPage$6(scope);
|
|
3444
3444
|
const cancel = page.getByTestId('chat-privacy-confirm-cancel');
|
|
3445
3445
|
await test$1.expect(cancel).toBeVisible({ timeout: 10000 });
|
|
3446
3446
|
await cancel.click();
|
|
@@ -3627,7 +3627,7 @@ const VOICE_LABELS = {
|
|
|
3627
3627
|
* reach DOM that Radix renders outside the dialog subtree (popovers,
|
|
3628
3628
|
* select options, etc.).
|
|
3629
3629
|
*/
|
|
3630
|
-
function asPage$
|
|
3630
|
+
function asPage$5(scope) {
|
|
3631
3631
|
return 'page' in scope ? scope.page() : scope;
|
|
3632
3632
|
}
|
|
3633
3633
|
// ─── Tab navigation ──────────────────────────────────────────────────────
|
|
@@ -3709,7 +3709,7 @@ async function openMentorVoicePicker(scope) {
|
|
|
3709
3709
|
const openBtn = scope.getByTestId('mentor-voice-trigger-open');
|
|
3710
3710
|
await test$1.expect(openBtn).toBeVisible({ timeout: 10000 });
|
|
3711
3711
|
await openBtn.click();
|
|
3712
|
-
await test$1.expect(asPage$
|
|
3712
|
+
await test$1.expect(asPage$5(scope).getByTestId('voice-picker-modal')).toBeVisible({
|
|
3713
3713
|
timeout: 10000,
|
|
3714
3714
|
});
|
|
3715
3715
|
}
|
|
@@ -3721,7 +3721,7 @@ async function openCallConfigVoicePicker(scope) {
|
|
|
3721
3721
|
const openBtn = scope.getByTestId('call-config-voice-trigger-open');
|
|
3722
3722
|
await test$1.expect(openBtn).toBeVisible({ timeout: 10000 });
|
|
3723
3723
|
await openBtn.click();
|
|
3724
|
-
await test$1.expect(asPage$
|
|
3724
|
+
await test$1.expect(asPage$5(scope).getByTestId('voice-picker-modal')).toBeVisible({
|
|
3725
3725
|
timeout: 10000,
|
|
3726
3726
|
});
|
|
3727
3727
|
}
|
|
@@ -3834,7 +3834,7 @@ async function selectCallMode(scope, mode) {
|
|
|
3834
3834
|
const trigger = scope.getByRole('combobox', { name: VOICE_LABELS.callConfigFields.mode });
|
|
3835
3835
|
await test$1.expect(trigger).toBeVisible({ timeout: 10000 });
|
|
3836
3836
|
await trigger.click();
|
|
3837
|
-
const option = asPage$
|
|
3837
|
+
const option = asPage$5(scope).getByRole('option', { name: VOICE_LABELS.modeOptions[mode] });
|
|
3838
3838
|
await test$1.expect(option).toBeVisible({ timeout: 5000 });
|
|
3839
3839
|
await option.click();
|
|
3840
3840
|
await test$1.expect(trigger).toHaveText(new RegExp(VOICE_LABELS.modeOptions[mode]));
|
|
@@ -3850,7 +3850,7 @@ async function selectFromCombobox(scope, triggerName, optionName) {
|
|
|
3850
3850
|
const trigger = scope.getByRole('combobox', { name: triggerName });
|
|
3851
3851
|
await test$1.expect(trigger).toBeVisible({ timeout: 10000 });
|
|
3852
3852
|
await trigger.click();
|
|
3853
|
-
const option = asPage$
|
|
3853
|
+
const option = asPage$5(scope).getByRole('option', { name: optionName });
|
|
3854
3854
|
await test$1.expect(option).toBeVisible({ timeout: 5000 });
|
|
3855
3855
|
await option.click();
|
|
3856
3856
|
}
|
|
@@ -3947,7 +3947,7 @@ const SCREENSHARE_LABELS = {
|
|
|
3947
3947
|
},
|
|
3948
3948
|
saveButton: 'Save',
|
|
3949
3949
|
};
|
|
3950
|
-
function asPage$
|
|
3950
|
+
function asPage$4(scope) {
|
|
3951
3951
|
return 'page' in scope ? scope.page() : scope;
|
|
3952
3952
|
}
|
|
3953
3953
|
/**
|
|
@@ -3987,7 +3987,7 @@ async function openScreenSharePromptEditor(scope, field) {
|
|
|
3987
3987
|
const btn = scope.getByRole('button', { name: `Edit ${label}` });
|
|
3988
3988
|
await test$1.expect(btn).toBeVisible({ timeout: 10000 });
|
|
3989
3989
|
await btn.click();
|
|
3990
|
-
await test$1.expect(asPage$
|
|
3990
|
+
await test$1.expect(asPage$4(scope).getByText(`Edit ${label}`)).toBeVisible({ timeout: 10000 });
|
|
3991
3991
|
logger.info(`Opened screen-share ${field} editor`);
|
|
3992
3992
|
}
|
|
3993
3993
|
/**
|
|
@@ -3997,7 +3997,7 @@ async function openScreenSharePromptEditor(scope, field) {
|
|
|
3997
3997
|
*/
|
|
3998
3998
|
async function setScreenSharePrompt(scope, field, text) {
|
|
3999
3999
|
await openScreenSharePromptEditor(scope, field);
|
|
4000
|
-
const page = asPage$
|
|
4000
|
+
const page = asPage$4(scope);
|
|
4001
4001
|
const editor = page.getByRole('dialog').locator('[contenteditable="true"]').first();
|
|
4002
4002
|
await test$1.expect(editor).toBeVisible({ timeout: 10000 });
|
|
4003
4003
|
await editor.click();
|
|
@@ -4328,7 +4328,7 @@ const TASKS_LABELS = {
|
|
|
4328
4328
|
* reach DOM that Radix renders outside the dialog subtree (popovers,
|
|
4329
4329
|
* select options, the schedule / delete / log-details dialogs, etc.).
|
|
4330
4330
|
*/
|
|
4331
|
-
function asPage$
|
|
4331
|
+
function asPage$3(scope) {
|
|
4332
4332
|
return 'page' in scope ? scope.page() : scope;
|
|
4333
4333
|
}
|
|
4334
4334
|
// ── Tab navigation ─────────────────────────────────────────────────────
|
|
@@ -4438,7 +4438,7 @@ async function searchTasks(scope, query) {
|
|
|
4438
4438
|
* shares an accessible name with the dialog's submit button.
|
|
4439
4439
|
*/
|
|
4440
4440
|
function getScheduleTaskDialog(scope) {
|
|
4441
|
-
return asPage$
|
|
4441
|
+
return asPage$3(scope).getByRole('dialog', { name: TASKS_LABELS.scheduleDialog.dialogName });
|
|
4442
4442
|
}
|
|
4443
4443
|
/** Open the Schedule Task dialog and wait for it to be interactive. */
|
|
4444
4444
|
async function openScheduleTaskDialog(scope) {
|
|
@@ -4457,7 +4457,7 @@ async function openScheduleTaskDialog(scope) {
|
|
|
4457
4457
|
*/
|
|
4458
4458
|
async function scheduleTask(scope, opts) {
|
|
4459
4459
|
await openScheduleTaskDialog(scope);
|
|
4460
|
-
const page = asPage$
|
|
4460
|
+
const page = asPage$3(scope);
|
|
4461
4461
|
// Scope every query to the dialog: the toolbar "Schedule Task" button shares
|
|
4462
4462
|
// an accessible name with the dialog's submit button, so an unscoped
|
|
4463
4463
|
// getByRole('button', { name: 'Schedule Task' }) matches two elements.
|
|
@@ -4492,13 +4492,13 @@ async function scheduleTask(scope, opts) {
|
|
|
4492
4492
|
}
|
|
4493
4493
|
/** Asserts the in-dialog past-time error is currently shown. */
|
|
4494
4494
|
async function expectScheduleStartTimeInPastError(scope) {
|
|
4495
|
-
await test$1.expect(asPage$
|
|
4495
|
+
await test$1.expect(asPage$3(scope).getByText(TASKS_LABELS.scheduleDialog.startTimeInPast)).toBeVisible({
|
|
4496
4496
|
timeout: 5000,
|
|
4497
4497
|
});
|
|
4498
4498
|
}
|
|
4499
4499
|
// ── Delete flow ────────────────────────────────────────────────────────
|
|
4500
4500
|
function getDeleteTaskDialog(scope) {
|
|
4501
|
-
return asPage$
|
|
4501
|
+
return asPage$3(scope).locator(`[role="dialog"][aria-label="${TASKS_LABELS.deleteDialog.dialogName}"]`);
|
|
4502
4502
|
}
|
|
4503
4503
|
/**
|
|
4504
4504
|
* Click the trash icon on a task row and confirm the delete in the
|
|
@@ -4519,7 +4519,7 @@ async function deleteTask(scope, taskName) {
|
|
|
4519
4519
|
}
|
|
4520
4520
|
// ── Logs panel + log details ───────────────────────────────────────────
|
|
4521
4521
|
function getLogDetailsDialog(scope) {
|
|
4522
|
-
return asPage$
|
|
4522
|
+
return asPage$3(scope).locator(`[role="dialog"][aria-label="${TASKS_LABELS.logDetails.dialogName}"]`);
|
|
4523
4523
|
}
|
|
4524
4524
|
/**
|
|
4525
4525
|
* Wait for the logs panel to finish loading and assert that the selected
|
|
@@ -4713,7 +4713,7 @@ const EVALS_LABELS = {
|
|
|
4713
4713
|
* toasts) — those queries must run on the page, never on the tab pane or a
|
|
4714
4714
|
* parent dialog.
|
|
4715
4715
|
*/
|
|
4716
|
-
function asPage$
|
|
4716
|
+
function asPage$2(scope) {
|
|
4717
4717
|
return 'page' in scope ? scope.page() : scope;
|
|
4718
4718
|
}
|
|
4719
4719
|
/** Escape a user-supplied string (run / benchmark names) for use in a RegExp. */
|
|
@@ -4722,7 +4722,7 @@ function escapeRegExp(value) {
|
|
|
4722
4722
|
}
|
|
4723
4723
|
/** Attribute-based dialog locator — immune to title renames and to Radix's `aria-labelledby` name precedence. */
|
|
4724
4724
|
function dialogByName(scope, dialogName) {
|
|
4725
|
-
return asPage$
|
|
4725
|
+
return asPage$2(scope).locator(`[role="dialog"][aria-label="${dialogName}"]`);
|
|
4726
4726
|
}
|
|
4727
4727
|
// ── Tab navigation ─────────────────────────────────────────────────────
|
|
4728
4728
|
/**
|
|
@@ -4809,7 +4809,7 @@ async function expectNoBenchmarksNotice(scope) {
|
|
|
4809
4809
|
function getRunRow(scope, runName) {
|
|
4810
4810
|
return scope
|
|
4811
4811
|
.getByRole('row')
|
|
4812
|
-
.filter({ has: asPage$
|
|
4812
|
+
.filter({ has: asPage$2(scope).getByRole('cell', { name: runName, exact: true }) });
|
|
4813
4813
|
}
|
|
4814
4814
|
async function expectRunInTable(scope, runName) {
|
|
4815
4815
|
await test$1.expect(getRunRow(scope, runName)).toBeVisible({ timeout: 15000 });
|
|
@@ -4836,7 +4836,7 @@ async function openRunActionsMenu(scope, runName) {
|
|
|
4836
4836
|
await getRunRow(scope, runName)
|
|
4837
4837
|
.getByRole('button', { name: `Actions for ${runName}`, exact: true })
|
|
4838
4838
|
.click();
|
|
4839
|
-
const menu = asPage$
|
|
4839
|
+
const menu = asPage$2(scope).getByRole('menu');
|
|
4840
4840
|
await test$1.expect(menu).toBeVisible({ timeout: 5000 });
|
|
4841
4841
|
return menu;
|
|
4842
4842
|
}
|
|
@@ -4873,7 +4873,7 @@ async function openNewReviewForRun(scope, runName) {
|
|
|
4873
4873
|
* design (the item prevents default), so we close it with Escape.
|
|
4874
4874
|
*/
|
|
4875
4875
|
async function checkRunStatus(scope, runName) {
|
|
4876
|
-
const page = asPage$
|
|
4876
|
+
const page = asPage$2(scope);
|
|
4877
4877
|
const menu = await openRunActionsMenu(scope, runName);
|
|
4878
4878
|
await menu.getByRole('menuitem', { name: EVALS_LABELS.actions.checkStatus }).click();
|
|
4879
4879
|
const toasts = EVALS_LABELS.checkStatusToast;
|
|
@@ -4895,7 +4895,7 @@ async function checkRunStatus(scope, runName) {
|
|
|
4895
4895
|
* suggested filename (`<benchmark>_<run>_results.csv`).
|
|
4896
4896
|
*/
|
|
4897
4897
|
async function exportRunCsv(scope, runName) {
|
|
4898
|
-
const page = asPage$
|
|
4898
|
+
const page = asPage$2(scope);
|
|
4899
4899
|
const menu = await openRunActionsMenu(scope, runName);
|
|
4900
4900
|
const item = menu.getByRole('menuitem', { name: EVALS_LABELS.actions.exportCsv });
|
|
4901
4901
|
await test$1.expect(item).toBeEnabled({ timeout: 5000 });
|
|
@@ -4991,7 +4991,7 @@ function getLlmPickerDialog(scope) {
|
|
|
4991
4991
|
* title text since it has no aria-label). Both pickers close on selection.
|
|
4992
4992
|
*/
|
|
4993
4993
|
async function selectJudgeLlm(scope, providerName, modelName) {
|
|
4994
|
-
const page = asPage$
|
|
4994
|
+
const page = asPage$2(scope);
|
|
4995
4995
|
const judgeDialog = getLlmJudgeDialog(scope);
|
|
4996
4996
|
await judgeDialog
|
|
4997
4997
|
.getByRole('button', { name: EVALS_LABELS.judgeDialog.selectorAriaLabel })
|
|
@@ -5116,9 +5116,9 @@ async function removeTraceScore(scope, scoreName) {
|
|
|
5116
5116
|
const dialog = getEvaluationDetailDialog(scope);
|
|
5117
5117
|
const chip = dialog
|
|
5118
5118
|
.locator('div')
|
|
5119
|
-
.filter({ has: asPage$
|
|
5119
|
+
.filter({ has: asPage$2(scope).getByText(scoreName, { exact: true }) })
|
|
5120
5120
|
.filter({
|
|
5121
|
-
has: asPage$
|
|
5121
|
+
has: asPage$2(scope).getByRole('button', {
|
|
5122
5122
|
name: EVALS_LABELS.detailDialog.removeScoreAriaLabel,
|
|
5123
5123
|
}),
|
|
5124
5124
|
})
|
|
@@ -5158,7 +5158,7 @@ async function expandReview(scope, scoreName) {
|
|
|
5158
5158
|
/** Close the detail dialog via Escape and wait for it to be gone. */
|
|
5159
5159
|
async function closeEvaluationDetailDialog(scope) {
|
|
5160
5160
|
const dialog = getEvaluationDetailDialog(scope);
|
|
5161
|
-
await asPage$
|
|
5161
|
+
await asPage$2(scope).keyboard.press('Escape');
|
|
5162
5162
|
await test$1.expect(dialog).toBeHidden({ timeout: 10000 });
|
|
5163
5163
|
}
|
|
5164
5164
|
// ── Manage benchmarks dialog (embedded tenant Benchmarks) ──────────────
|
|
@@ -5340,13 +5340,13 @@ async function deleteQaItem(scope, questionText) {
|
|
|
5340
5340
|
/** Close the benchmark items dialog via Escape and wait for it to be gone. */
|
|
5341
5341
|
async function closeBenchmarkItemsDialog(scope) {
|
|
5342
5342
|
const dialog = getBenchmarkItemsDialog(scope);
|
|
5343
|
-
await asPage$
|
|
5343
|
+
await asPage$2(scope).keyboard.press('Escape');
|
|
5344
5344
|
await test$1.expect(dialog).toBeHidden({ timeout: 10000 });
|
|
5345
5345
|
}
|
|
5346
5346
|
/** Close the Manage benchmarks dialog via Escape and wait for it to be gone. */
|
|
5347
5347
|
async function closeManageBenchmarksDialog(scope) {
|
|
5348
5348
|
const dialog = getManageBenchmarksDialog(scope);
|
|
5349
|
-
await asPage$
|
|
5349
|
+
await asPage$2(scope).keyboard.press('Escape');
|
|
5350
5350
|
await test$1.expect(dialog).toBeHidden({ timeout: 10000 });
|
|
5351
5351
|
}
|
|
5352
5352
|
|
|
@@ -5473,7 +5473,7 @@ const LTI_TEST_IDS = {
|
|
|
5473
5473
|
* DOM that Radix renders in a portal outside the dialog subtree (dropdown
|
|
5474
5474
|
* menus, select options).
|
|
5475
5475
|
*/
|
|
5476
|
-
function asPage(scope) {
|
|
5476
|
+
function asPage$1(scope) {
|
|
5477
5477
|
return 'page' in scope ? scope.page() : scope;
|
|
5478
5478
|
}
|
|
5479
5479
|
// ── Tab navigation ─────────────────────────────────────────────────────
|
|
@@ -5545,7 +5545,7 @@ function getLinkCopyTargetUriButton(scope) {
|
|
|
5545
5545
|
return scope.getByRole('button', { name: 'Copy target link URI' });
|
|
5546
5546
|
}
|
|
5547
5547
|
function getLinkModal(scope) {
|
|
5548
|
-
return asPage(scope).getByTestId(LTI_TEST_IDS.links.modal);
|
|
5548
|
+
return asPage$1(scope).getByTestId(LTI_TEST_IDS.links.modal);
|
|
5549
5549
|
}
|
|
5550
5550
|
function getLinkNameInput(scope) {
|
|
5551
5551
|
return getLinkModal(scope).getByTestId(LTI_TEST_IDS.links.nameInput);
|
|
@@ -5621,13 +5621,13 @@ function getKeyActionsTrigger(scope, name) {
|
|
|
5621
5621
|
/** Open a key's three-dots menu and return the open menu (portal-rendered). */
|
|
5622
5622
|
async function openKeyActionsMenu(scope, name) {
|
|
5623
5623
|
await getKeyActionsTrigger(scope, name).click();
|
|
5624
|
-
const menu = asPage(scope).getByRole('menu');
|
|
5624
|
+
const menu = asPage$1(scope).getByRole('menu');
|
|
5625
5625
|
await test$1.expect(menu).toBeVisible({ timeout: 5000 });
|
|
5626
5626
|
return menu;
|
|
5627
5627
|
}
|
|
5628
5628
|
// — Key: create —
|
|
5629
5629
|
function getKeyCreateModal(scope) {
|
|
5630
|
-
return asPage(scope).getByTestId(LTI_TEST_IDS.keys.createModal);
|
|
5630
|
+
return asPage$1(scope).getByTestId(LTI_TEST_IDS.keys.createModal);
|
|
5631
5631
|
}
|
|
5632
5632
|
function getKeyCreateNameInput(scope) {
|
|
5633
5633
|
return getKeyCreateModal(scope).getByTestId(LTI_TEST_IDS.keys.createNameInput);
|
|
@@ -5647,7 +5647,7 @@ async function createKey(scope, name) {
|
|
|
5647
5647
|
}
|
|
5648
5648
|
// — Key: edit / detail —
|
|
5649
5649
|
function getKeyDetailModal(scope) {
|
|
5650
|
-
return asPage(scope).getByTestId(LTI_TEST_IDS.keys.detailModal);
|
|
5650
|
+
return asPage$1(scope).getByTestId(LTI_TEST_IDS.keys.detailModal);
|
|
5651
5651
|
}
|
|
5652
5652
|
function getKeyDetailNameInput(scope) {
|
|
5653
5653
|
return getKeyDetailModal(scope).getByTestId(LTI_TEST_IDS.keys.detailNameInput);
|
|
@@ -5691,7 +5691,7 @@ async function closeKeyDetail(scope) {
|
|
|
5691
5691
|
}
|
|
5692
5692
|
// — Key: delete —
|
|
5693
5693
|
function getKeyDeleteModal(scope) {
|
|
5694
|
-
return asPage(scope).getByTestId(LTI_TEST_IDS.keys.deleteModal);
|
|
5694
|
+
return asPage$1(scope).getByTestId(LTI_TEST_IDS.keys.deleteModal);
|
|
5695
5695
|
}
|
|
5696
5696
|
/** Open the delete confirmation for a key via its actions menu → Delete. */
|
|
5697
5697
|
async function openKeyDelete(scope, name) {
|
|
@@ -5722,7 +5722,7 @@ async function deleteKey(scope, name) {
|
|
|
5722
5722
|
* delete-modal convention); the modal stays open so the user can cancel.
|
|
5723
5723
|
*/
|
|
5724
5724
|
async function expectKeyDeleteError(scope, message) {
|
|
5725
|
-
const page = asPage(scope);
|
|
5725
|
+
const page = asPage$1(scope);
|
|
5726
5726
|
await test$1.expect(page.getByText(message, { exact: false }).first()).toBeVisible({ timeout: 15000 });
|
|
5727
5727
|
await test$1.expect(getKeyDeleteModal(scope)).toBeVisible();
|
|
5728
5728
|
}
|
|
@@ -5754,7 +5754,7 @@ function getToolEditButton(scope, name) {
|
|
|
5754
5754
|
return scope.getByRole('button', { name: `Edit ${name}` });
|
|
5755
5755
|
}
|
|
5756
5756
|
function getToolModal(scope) {
|
|
5757
|
-
return asPage(scope).getByTestId(LTI_TEST_IDS.tools.modal);
|
|
5757
|
+
return asPage$1(scope).getByTestId(LTI_TEST_IDS.tools.modal);
|
|
5758
5758
|
}
|
|
5759
5759
|
/** Field locators inside the (open) tool modal. */
|
|
5760
5760
|
const toolFields = {
|
|
@@ -5787,7 +5787,7 @@ async function selectToolKeySetMode(scope, mode) {
|
|
|
5787
5787
|
/** Pick a signing key by name from the Radix select in the open tool modal. */
|
|
5788
5788
|
async function selectToolSigningKey(scope, name) {
|
|
5789
5789
|
await getToolKeySelect(scope).click();
|
|
5790
|
-
await asPage(scope).getByRole('option', { name }).click();
|
|
5790
|
+
await asPage$1(scope).getByRole('option', { name }).click();
|
|
5791
5791
|
}
|
|
5792
5792
|
/** Submit button inside the tool modal ("Create" or "Save"). */
|
|
5793
5793
|
function getToolSubmitButton(scope) {
|
|
@@ -5880,6 +5880,523 @@ async function expectAllEndpointsVisible(scope) {
|
|
|
5880
5880
|
}
|
|
5881
5881
|
}
|
|
5882
5882
|
|
|
5883
|
+
/**
|
|
5884
|
+
* Support tab helpers — Playwright bindings for the `AgentHumanSupportTab`
|
|
5885
|
+
* component from `@iblai/web-containers` (Edit Agent modal → Runtime →
|
|
5886
|
+
* Support).
|
|
5887
|
+
*
|
|
5888
|
+
* All UI strings below mirror `AGENT_HUMAN_SUPPORT_TAB_LABELS` from
|
|
5889
|
+
* `@iblai/web-containers/next`. If a consumer renames a label via the
|
|
5890
|
+
* `labels` prop, override these constants per spec — don't edit this file.
|
|
5891
|
+
*
|
|
5892
|
+
* Scoping rule (see playwright-testing skill §12): capture the Edit Agent
|
|
5893
|
+
* dialog FIRST via `getEditAgentDialog(page)`, then resolve every in-panel
|
|
5894
|
+
* locator from that dialog. Radix portals (select option lists, popover
|
|
5895
|
+
* contents) render OUTSIDE the dialog subtree — those queries intentionally
|
|
5896
|
+
* run on the `page` and are commented as such.
|
|
5897
|
+
*/
|
|
5898
|
+
const SUPPORT_LABELS = {
|
|
5899
|
+
/** Sidebar segment label (host app) + tab panel value. */
|
|
5900
|
+
tabName: 'Support',
|
|
5901
|
+
/** The host sidebar trigger's `aria-controls` panel id suffix. */
|
|
5902
|
+
panelValue: 'human_support',
|
|
5903
|
+
/** Category strip pill that hosts the Support segment. */
|
|
5904
|
+
navCategory: 'Runtime',
|
|
5905
|
+
header: {
|
|
5906
|
+
title: 'Support',
|
|
5907
|
+
description: 'Review and respond to support requests submitted for this agent.',
|
|
5908
|
+
},
|
|
5909
|
+
toggle: {
|
|
5910
|
+
/** `aria-label` on the availability switch in the info box. */
|
|
5911
|
+
enable: 'Enable support',
|
|
5912
|
+
},
|
|
5913
|
+
filters: {
|
|
5914
|
+
searchUser: 'Search for User',
|
|
5915
|
+
searchUsersPlaceholder: 'Search users...',
|
|
5916
|
+
allUsers: 'All Users',
|
|
5917
|
+
allStatuses: 'All Statuses',
|
|
5918
|
+
},
|
|
5919
|
+
status: {
|
|
5920
|
+
open: 'Open',
|
|
5921
|
+
inProgress: 'In Progress',
|
|
5922
|
+
closed: 'Closed',
|
|
5923
|
+
},
|
|
5924
|
+
list: {
|
|
5925
|
+
noTickets: 'No support tickets found',
|
|
5926
|
+
untitled: 'Support request',
|
|
5927
|
+
/** `aria-label` of the ticket-list region. */
|
|
5928
|
+
regionLabel: 'Support ticket list',
|
|
5929
|
+
},
|
|
5930
|
+
detail: {
|
|
5931
|
+
selectPrompt: 'Select a ticket to view details.',
|
|
5932
|
+
statusLabel: 'Status',
|
|
5933
|
+
requestSection: 'Request',
|
|
5934
|
+
conversationSection: 'Conversation',
|
|
5935
|
+
supportTeam: 'Support Team',
|
|
5936
|
+
noMessages: 'No replies yet.',
|
|
5937
|
+
replyPlaceholder: 'Write a reply to the user…',
|
|
5938
|
+
sendReply: 'Send Reply',
|
|
5939
|
+
closedNotice: 'This ticket is closed. Set it back to Open or In Progress to reply.',
|
|
5940
|
+
/** `aria-label` of the ticket-detail region. */
|
|
5941
|
+
regionLabel: 'Support ticket details',
|
|
5942
|
+
},
|
|
5943
|
+
testIds: {
|
|
5944
|
+
infoBox: 'human-support-info-box',
|
|
5945
|
+
toggle: 'human-support-toggle',
|
|
5946
|
+
ticketList: 'human-support-ticket-list',
|
|
5947
|
+
ticketDetail: 'human-support-ticket-detail',
|
|
5948
|
+
ticketDescription: 'human-support-ticket-description',
|
|
5949
|
+
/** Ticket rows render as `human-support-ticket-item-<id>`. */
|
|
5950
|
+
ticketItemPrefix: 'human-support-ticket-item-',
|
|
5951
|
+
},
|
|
5952
|
+
chat: {
|
|
5953
|
+
/** Accessible name of the chat textbox in the host app. */
|
|
5954
|
+
inputName: 'Ask anything',
|
|
5955
|
+
sendButton: 'Send message',
|
|
5956
|
+
/** Stable class markers from `CSS_CLASS_NAMES.CHAT` in web-containers. */
|
|
5957
|
+
userQueryClass: '.chat-user-message-query',
|
|
5958
|
+
aiResponseClass: '.chat-ai-message-response',
|
|
5959
|
+
stopStreamingClass: '.chat-stop-streaming-button',
|
|
5960
|
+
},
|
|
5961
|
+
};
|
|
5962
|
+
/**
|
|
5963
|
+
* Resolve a Page from either a Page or a Locator. Used when we need to
|
|
5964
|
+
* reach DOM that Radix renders outside the dialog subtree (select option
|
|
5965
|
+
* lists, popover contents).
|
|
5966
|
+
*/
|
|
5967
|
+
function asPage(scope) {
|
|
5968
|
+
return 'page' in scope ? scope.page() : scope;
|
|
5969
|
+
}
|
|
5970
|
+
// ── Dialog capture ─────────────────────────────────────────────────────
|
|
5971
|
+
/**
|
|
5972
|
+
* Capture the Edit Agent dialog itself. Every other helper resolves its
|
|
5973
|
+
* locators from this dialog, so in-panel controls never collide with
|
|
5974
|
+
* elements mounted on the page behind the modal.
|
|
5975
|
+
*
|
|
5976
|
+
* The dialog carries no stable test id in the host, so it is identified by
|
|
5977
|
+
* its visible title ("Edit Agent" by default — override for hosts that
|
|
5978
|
+
* rename the modal).
|
|
5979
|
+
*/
|
|
5980
|
+
function getEditAgentDialog(page, dialogTitle = 'Edit Agent') {
|
|
5981
|
+
return page.getByRole('dialog').filter({ hasText: dialogTitle });
|
|
5982
|
+
}
|
|
5983
|
+
// ── Tab navigation ─────────────────────────────────────────────────────
|
|
5984
|
+
/**
|
|
5985
|
+
* Check whether the Support tab is currently reachable in the Edit Agent
|
|
5986
|
+
* dialog. Returns false instead of throwing so callers can guard
|
|
5987
|
+
* permission-gated hosts (the segment is admin-only).
|
|
5988
|
+
*/
|
|
5989
|
+
async function isSupportTabVisible(page) {
|
|
5990
|
+
const dialog = getEditAgentDialog(page);
|
|
5991
|
+
try {
|
|
5992
|
+
await switchToRuntimeCategory(dialog);
|
|
5993
|
+
await test$1.expect(getSupportTabTrigger(dialog)).toBeVisible({ timeout: 5000 });
|
|
5994
|
+
return true;
|
|
5995
|
+
}
|
|
5996
|
+
catch (_a) {
|
|
5997
|
+
return false;
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
/**
|
|
6001
|
+
* The host sidebar trigger for the Support segment. Matched by its
|
|
6002
|
+
* `aria-controls="panel-human_support"` (stable across label renames);
|
|
6003
|
+
* `:visible` excludes the hidden responsive twin the host renders for the
|
|
6004
|
+
* other breakpoint.
|
|
6005
|
+
*/
|
|
6006
|
+
function getSupportTabTrigger(dialog) {
|
|
6007
|
+
return dialog
|
|
6008
|
+
.locator(`[role="tab"][aria-controls="panel-${SUPPORT_LABELS.panelValue}"]:visible`)
|
|
6009
|
+
.first();
|
|
6010
|
+
}
|
|
6011
|
+
/**
|
|
6012
|
+
* Best-effort switch to the "Runtime" category strip that hosts the
|
|
6013
|
+
* Support segment. The strip only renders when more than one category has
|
|
6014
|
+
* items, so a missing pill is not an error — the segment is then already
|
|
6015
|
+
* mounted in the single visible list.
|
|
6016
|
+
*/
|
|
6017
|
+
async function switchToRuntimeCategory(dialog) {
|
|
6018
|
+
const pill = dialog
|
|
6019
|
+
.getByRole('tab', { name: SUPPORT_LABELS.navCategory, exact: true })
|
|
6020
|
+
.and(dialog.locator(':visible'))
|
|
6021
|
+
.first();
|
|
6022
|
+
const hasStrip = await pill
|
|
6023
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
6024
|
+
.then(() => true)
|
|
6025
|
+
.catch(() => false);
|
|
6026
|
+
if (!hasStrip)
|
|
6027
|
+
return;
|
|
6028
|
+
if ((await pill.getAttribute('data-state').catch(() => null)) !== 'active') {
|
|
6029
|
+
await pill.click();
|
|
6030
|
+
await test$1.expect(pill).toHaveAttribute('data-state', 'active', { timeout: 5000 });
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
/**
|
|
6034
|
+
* Switch to the Support tab. Assumes the Edit Agent dialog is open.
|
|
6035
|
+
* Returns the dialog locator so callers can keep every follow-up query
|
|
6036
|
+
* scoped without re-capturing it.
|
|
6037
|
+
*/
|
|
6038
|
+
async function switchToSupportTab(page) {
|
|
6039
|
+
const dialog = getEditAgentDialog(page);
|
|
6040
|
+
await test$1.expect(dialog).toBeVisible({ timeout: 15000 });
|
|
6041
|
+
await switchToRuntimeCategory(dialog);
|
|
6042
|
+
const trigger = getSupportTabTrigger(dialog);
|
|
6043
|
+
await test$1.expect(trigger).toBeVisible({ timeout: 10000 });
|
|
6044
|
+
await trigger.click();
|
|
6045
|
+
// The info box is unique to the Support pane and mounts immediately
|
|
6046
|
+
// (unlike the ticket list, which waits on network).
|
|
6047
|
+
await test$1.expect(dialog.getByTestId(SUPPORT_LABELS.testIds.infoBox)).toBeVisible({
|
|
6048
|
+
timeout: 10000,
|
|
6049
|
+
});
|
|
6050
|
+
logger.info('Switched to Support tab');
|
|
6051
|
+
return dialog;
|
|
6052
|
+
}
|
|
6053
|
+
// ── Info box + availability toggle ─────────────────────────────────────
|
|
6054
|
+
/** The info box at the top of the pane (conversational description). */
|
|
6055
|
+
function getSupportInfoBox(dialog) {
|
|
6056
|
+
return dialog.getByTestId(SUPPORT_LABELS.testIds.infoBox);
|
|
6057
|
+
}
|
|
6058
|
+
/**
|
|
6059
|
+
* The availability switch inside the info box — the same "human support"
|
|
6060
|
+
* tool toggle exposed on the Tools tab. Hidden when the tenant's tool
|
|
6061
|
+
* catalog has no human-support tool.
|
|
6062
|
+
*/
|
|
6063
|
+
function getSupportToggle(dialog) {
|
|
6064
|
+
return dialog.getByTestId(SUPPORT_LABELS.testIds.toggle);
|
|
6065
|
+
}
|
|
6066
|
+
/** Read the current on/off state of the availability toggle. */
|
|
6067
|
+
async function isSupportEnabled(dialog) {
|
|
6068
|
+
const toggle = getSupportToggle(dialog);
|
|
6069
|
+
await test$1.expect(toggle).toBeVisible({ timeout: 10000 });
|
|
6070
|
+
return (await toggle.getAttribute('aria-checked')) === 'true';
|
|
6071
|
+
}
|
|
6072
|
+
/**
|
|
6073
|
+
* Flip the availability toggle to the requested state (no-op when already
|
|
6074
|
+
* there). Waits for `aria-checked` to settle, which tracks the persisted
|
|
6075
|
+
* mentor-settings round trip.
|
|
6076
|
+
*/
|
|
6077
|
+
async function setSupportEnabled(dialog, enabled) {
|
|
6078
|
+
const toggle = getSupportToggle(dialog);
|
|
6079
|
+
await test$1.expect(toggle).toBeVisible({ timeout: 10000 });
|
|
6080
|
+
const current = (await toggle.getAttribute('aria-checked')) === 'true';
|
|
6081
|
+
if (current === enabled) {
|
|
6082
|
+
logger.info(`Support already ${enabled ? 'enabled' : 'disabled'}`);
|
|
6083
|
+
return;
|
|
6084
|
+
}
|
|
6085
|
+
await test$1.expect(toggle).toBeEnabled({ timeout: 10000 });
|
|
6086
|
+
await toggle.click();
|
|
6087
|
+
// Re-locate on every retry — the switch re-renders after the save.
|
|
6088
|
+
await test$1.expect(getSupportToggle(dialog)).toHaveAttribute('aria-checked', String(enabled), {
|
|
6089
|
+
timeout: 15000,
|
|
6090
|
+
});
|
|
6091
|
+
logger.info(`Support ${enabled ? 'enabled' : 'disabled'}`);
|
|
6092
|
+
}
|
|
6093
|
+
/** Turn the support tool on. */
|
|
6094
|
+
async function enableSupport(dialog) {
|
|
6095
|
+
await setSupportEnabled(dialog, true);
|
|
6096
|
+
}
|
|
6097
|
+
/** Turn the support tool off. */
|
|
6098
|
+
async function disableSupport(dialog) {
|
|
6099
|
+
await setSupportEnabled(dialog, false);
|
|
6100
|
+
}
|
|
6101
|
+
// ── Ticket list ────────────────────────────────────────────────────────
|
|
6102
|
+
/** The ticket-list region. Only mounted when at least one ticket exists. */
|
|
6103
|
+
function getTicketList(dialog) {
|
|
6104
|
+
return dialog.getByTestId(SUPPORT_LABELS.testIds.ticketList);
|
|
6105
|
+
}
|
|
6106
|
+
/**
|
|
6107
|
+
* A ticket row matched by (a substring of) its subject. Rows carry
|
|
6108
|
+
* `data-testid="human-support-ticket-item-<id>"`; the id is server-side,
|
|
6109
|
+
* so text matching within the list is the stable route for specs.
|
|
6110
|
+
*/
|
|
6111
|
+
function getTicketRow(dialog, subject) {
|
|
6112
|
+
return getTicketList(dialog)
|
|
6113
|
+
.locator(`[data-testid^="${SUPPORT_LABELS.testIds.ticketItemPrefix}"]`)
|
|
6114
|
+
.filter({ hasText: subject })
|
|
6115
|
+
.first();
|
|
6116
|
+
}
|
|
6117
|
+
/** A ticket row by its zero-based position in the list. */
|
|
6118
|
+
function getTicketRowByIndex(dialog, index) {
|
|
6119
|
+
return getTicketList(dialog)
|
|
6120
|
+
.locator(`[data-testid^="${SUPPORT_LABELS.testIds.ticketItemPrefix}"]`)
|
|
6121
|
+
.nth(index);
|
|
6122
|
+
}
|
|
6123
|
+
/** Assert a ticket with the given subject text is listed. */
|
|
6124
|
+
async function expectTicketInList(dialog, subject, timeoutMs = 15000) {
|
|
6125
|
+
await test$1.expect(getTicketRow(dialog, subject)).toBeVisible({ timeout: timeoutMs });
|
|
6126
|
+
}
|
|
6127
|
+
/** Assert the empty state ("No support tickets found") is shown. */
|
|
6128
|
+
async function expectNoTickets(dialog) {
|
|
6129
|
+
await test$1.expect(dialog.getByText(SUPPORT_LABELS.list.noTickets)).toBeVisible({
|
|
6130
|
+
timeout: 15000,
|
|
6131
|
+
});
|
|
6132
|
+
}
|
|
6133
|
+
/** Assert a listed ticket row shows the expected status badge. */
|
|
6134
|
+
async function expectTicketStatusInList(dialog, subject, status) {
|
|
6135
|
+
await test$1.expect(getTicketRow(dialog, subject).getByText(SUPPORT_LABELS.status[status], { exact: true })).toBeVisible({ timeout: 10000 });
|
|
6136
|
+
}
|
|
6137
|
+
// ── Filters ────────────────────────────────────────────────────────────
|
|
6138
|
+
/** The status-filter trigger next to the user search. */
|
|
6139
|
+
function getStatusFilter(dialog) {
|
|
6140
|
+
// The SDK labels the trigger "Filter by status" (i18n key
|
|
6141
|
+
// tabsHumanSupportTab.filterByStatus); fall back cheaply to the displayed
|
|
6142
|
+
// "All Statuses" placeholder if a host overrides the aria-label.
|
|
6143
|
+
return dialog
|
|
6144
|
+
.getByRole('combobox', { name: 'Filter by status' })
|
|
6145
|
+
.or(dialog.getByRole('combobox').filter({ hasText: SUPPORT_LABELS.filters.allStatuses }))
|
|
6146
|
+
.first();
|
|
6147
|
+
}
|
|
6148
|
+
/**
|
|
6149
|
+
* Filter the list by ticket status ('all' clears the filter). Changing
|
|
6150
|
+
* the filter re-queries the backend, so this doubles as a refresh hook.
|
|
6151
|
+
*/
|
|
6152
|
+
async function filterTicketsByStatus(dialog, status) {
|
|
6153
|
+
const label = status === 'all' ? SUPPORT_LABELS.filters.allStatuses : SUPPORT_LABELS.status[status];
|
|
6154
|
+
await getStatusFilter(dialog).click();
|
|
6155
|
+
// Radix renders the option list in a portal outside the dialog subtree.
|
|
6156
|
+
await asPage(dialog).getByRole('option', { name: label, exact: true }).click();
|
|
6157
|
+
logger.info(`Filtered tickets by status: ${label}`);
|
|
6158
|
+
}
|
|
6159
|
+
/** The "Search for User" combobox trigger (opens the requester popover). */
|
|
6160
|
+
function getUserFilter(dialog) {
|
|
6161
|
+
return dialog.getByRole('combobox', { name: SUPPORT_LABELS.filters.searchUser });
|
|
6162
|
+
}
|
|
6163
|
+
/**
|
|
6164
|
+
* Filter the list by requester. Types `search` into the popover's search
|
|
6165
|
+
* box, then clicks the entry whose label (email, else username) matches
|
|
6166
|
+
* `optionText`.
|
|
6167
|
+
*/
|
|
6168
|
+
async function filterTicketsByUser(dialog, search, optionText = search) {
|
|
6169
|
+
await getUserFilter(dialog).click();
|
|
6170
|
+
// The popover renders in place (`portalled={false}`) so it stays inside
|
|
6171
|
+
// the host dialog's focus trap — queries stay dialog-scoped.
|
|
6172
|
+
const searchBox = dialog.getByPlaceholder(SUPPORT_LABELS.filters.searchUsersPlaceholder);
|
|
6173
|
+
await test$1.expect(searchBox).toBeVisible({ timeout: 10000 });
|
|
6174
|
+
await searchBox.fill(search);
|
|
6175
|
+
await dialog.getByText(optionText).first().click();
|
|
6176
|
+
logger.info(`Filtered tickets by user: ${search}`);
|
|
6177
|
+
}
|
|
6178
|
+
/** Clear the requester filter via the "All Users" popover entry. */
|
|
6179
|
+
async function clearUserFilter(dialog) {
|
|
6180
|
+
await getUserFilter(dialog).click();
|
|
6181
|
+
// In-place popover (see filterTicketsByUser) — dialog-scoped.
|
|
6182
|
+
await dialog.getByText(SUPPORT_LABELS.filters.allUsers, { exact: true }).first().click();
|
|
6183
|
+
}
|
|
6184
|
+
/**
|
|
6185
|
+
* Force the ticket list to re-query by bouncing the status filter
|
|
6186
|
+
* (all → open → all). Each argument change issues a fresh request for
|
|
6187
|
+
* uncached filter combinations, which is how specs pick up tickets
|
|
6188
|
+
* created out-of-band (e.g. by the agent during a chat).
|
|
6189
|
+
*/
|
|
6190
|
+
async function refreshTickets(dialog) {
|
|
6191
|
+
await filterTicketsByStatus(dialog, 'open');
|
|
6192
|
+
await filterTicketsByStatus(dialog, 'all');
|
|
6193
|
+
}
|
|
6194
|
+
/**
|
|
6195
|
+
* Wait for a ticket to appear in the list, refreshing between polls.
|
|
6196
|
+
* Agent-created tickets land after the chat tool call completes
|
|
6197
|
+
* server-side, so allow a generous deadline.
|
|
6198
|
+
*
|
|
6199
|
+
* Pass `opts.refresh` to override the default status-filter bounce with a
|
|
6200
|
+
* stronger strategy (e.g. close and re-open the modal, or reload the page
|
|
6201
|
+
* and navigate back) — the callback runs between polls and must leave the
|
|
6202
|
+
* Support tab open.
|
|
6203
|
+
*/
|
|
6204
|
+
async function waitForTicketInList(dialog, subject, opts = {}) {
|
|
6205
|
+
var _a;
|
|
6206
|
+
const timeoutMs = (_a = opts.timeoutMs) !== null && _a !== void 0 ? _a : 90000;
|
|
6207
|
+
const deadline = Date.now() + timeoutMs;
|
|
6208
|
+
for (;;) {
|
|
6209
|
+
try {
|
|
6210
|
+
await test$1.expect(getTicketRow(dialog, subject)).toBeVisible({ timeout: 10000 });
|
|
6211
|
+
logger.info(`Ticket visible in list: ${subject}`);
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
6214
|
+
catch (error) {
|
|
6215
|
+
if (Date.now() >= deadline) {
|
|
6216
|
+
throw error;
|
|
6217
|
+
}
|
|
6218
|
+
logger.info(`Ticket not yet listed, refreshing: ${subject}`);
|
|
6219
|
+
if (opts.refresh) {
|
|
6220
|
+
await opts.refresh();
|
|
6221
|
+
}
|
|
6222
|
+
else {
|
|
6223
|
+
await refreshTickets(dialog);
|
|
6224
|
+
}
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
}
|
|
6228
|
+
// ── Ticket detail ──────────────────────────────────────────────────────
|
|
6229
|
+
/** The detail pane (desktop two-column layout). */
|
|
6230
|
+
function getTicketDetail(dialog) {
|
|
6231
|
+
return dialog.getByTestId(SUPPORT_LABELS.testIds.ticketDetail);
|
|
6232
|
+
}
|
|
6233
|
+
/** The rendered ticket body (HTML/Markdown/plain, already formatted). */
|
|
6234
|
+
function getTicketDescription(dialog) {
|
|
6235
|
+
// On mobile the detail renders in a nested preview dialog instead of the
|
|
6236
|
+
// side pane; the testid is unique either way, so query from the page.
|
|
6237
|
+
return asPage(dialog).getByTestId(SUPPORT_LABELS.testIds.ticketDescription).first();
|
|
6238
|
+
}
|
|
6239
|
+
/**
|
|
6240
|
+
* Open a ticket from the list and wait for its detail to render. Returns
|
|
6241
|
+
* the detail pane locator for chained assertions.
|
|
6242
|
+
*/
|
|
6243
|
+
async function openTicket(dialog, subject) {
|
|
6244
|
+
await getTicketRow(dialog, subject).click();
|
|
6245
|
+
const detail = getTicketDetail(dialog);
|
|
6246
|
+
await test$1.expect(detail).toBeVisible({ timeout: 10000 });
|
|
6247
|
+
await test$1.expect(detail).toContainText(SUPPORT_LABELS.detail.requestSection, { timeout: 10000 });
|
|
6248
|
+
logger.info(`Opened ticket: ${subject}`);
|
|
6249
|
+
return detail;
|
|
6250
|
+
}
|
|
6251
|
+
/** Assert the opened ticket's rendered body contains the given text. */
|
|
6252
|
+
async function expectTicketDescriptionContains(dialog, text) {
|
|
6253
|
+
await test$1.expect(getTicketDescription(dialog)).toContainText(text, { timeout: 10000 });
|
|
6254
|
+
}
|
|
6255
|
+
/**
|
|
6256
|
+
* Change the opened ticket's status via the detail pane's Status select.
|
|
6257
|
+
* Selecting "Closed" routes through the dedicated close endpoint and
|
|
6258
|
+
* replaces the composer with the closed notice.
|
|
6259
|
+
*/
|
|
6260
|
+
async function setTicketStatus(dialog, status) {
|
|
6261
|
+
const detail = getTicketDetail(dialog);
|
|
6262
|
+
await detail.getByRole('combobox', { name: SUPPORT_LABELS.detail.statusLabel }).click();
|
|
6263
|
+
// Radix renders the option list in a portal outside the dialog subtree.
|
|
6264
|
+
await asPage(dialog)
|
|
6265
|
+
.getByRole('option', { name: SUPPORT_LABELS.status[status], exact: true })
|
|
6266
|
+
.click();
|
|
6267
|
+
logger.info(`Set ticket status: ${SUPPORT_LABELS.status[status]}`);
|
|
6268
|
+
}
|
|
6269
|
+
/** Assert the closed notice is shown (composer hidden). */
|
|
6270
|
+
async function expectTicketClosedNotice(dialog) {
|
|
6271
|
+
await test$1.expect(dialog.getByText(SUPPORT_LABELS.detail.closedNotice)).toBeVisible({
|
|
6272
|
+
timeout: 15000,
|
|
6273
|
+
});
|
|
6274
|
+
}
|
|
6275
|
+
// ── Conversation / replies ─────────────────────────────────────────────
|
|
6276
|
+
/** The reply composer textarea in the opened ticket. */
|
|
6277
|
+
function getReplyComposer(dialog) {
|
|
6278
|
+
return dialog.getByPlaceholder(SUPPORT_LABELS.detail.replyPlaceholder);
|
|
6279
|
+
}
|
|
6280
|
+
/**
|
|
6281
|
+
* Send a reply on the opened ticket and wait for the composer to clear
|
|
6282
|
+
* (the component empties it only after the API call succeeds).
|
|
6283
|
+
*/
|
|
6284
|
+
async function replyToTicket(dialog, message) {
|
|
6285
|
+
const composer = getReplyComposer(dialog);
|
|
6286
|
+
await test$1.expect(composer).toBeVisible({ timeout: 10000 });
|
|
6287
|
+
await composer.fill(message);
|
|
6288
|
+
const send = dialog.getByRole('button', { name: SUPPORT_LABELS.detail.sendReply });
|
|
6289
|
+
await test$1.expect(send).toBeEnabled({ timeout: 5000 });
|
|
6290
|
+
await send.click();
|
|
6291
|
+
await test$1.expect(getReplyComposer(dialog)).toHaveValue('', { timeout: 15000 });
|
|
6292
|
+
logger.info(`Replied to ticket: ${message.slice(0, 40)}`);
|
|
6293
|
+
}
|
|
6294
|
+
/** Assert a message (from either side) is visible in the conversation. */
|
|
6295
|
+
async function expectMessageInConversation(dialog, message) {
|
|
6296
|
+
await test$1.expect(getTicketDetail(dialog).getByText(message).first()).toBeVisible({
|
|
6297
|
+
timeout: 15000,
|
|
6298
|
+
});
|
|
6299
|
+
}
|
|
6300
|
+
/** Assert the opened ticket has no replies yet. */
|
|
6301
|
+
async function expectNoRepliesYet(dialog) {
|
|
6302
|
+
await test$1.expect(dialog.getByText(SUPPORT_LABELS.detail.noMessages)).toBeVisible({
|
|
6303
|
+
timeout: 10000,
|
|
6304
|
+
});
|
|
6305
|
+
}
|
|
6306
|
+
// ── Chat side (requesting a ticket from the agent) ─────────────────────
|
|
6307
|
+
/** The main chat textbox. */
|
|
6308
|
+
function getChatInput(page) {
|
|
6309
|
+
return page.getByRole('textbox', { name: SUPPORT_LABELS.chat.inputName, exact: true });
|
|
6310
|
+
}
|
|
6311
|
+
/**
|
|
6312
|
+
* Send a message to the agent from the main chat surface and wait for the
|
|
6313
|
+
* user bubble to render. Does NOT wait for the AI response — pair with
|
|
6314
|
+
* `waitForAgentChatResponse`.
|
|
6315
|
+
*/
|
|
6316
|
+
async function sendAgentChatMessage(page, message) {
|
|
6317
|
+
const input = getChatInput(page);
|
|
6318
|
+
await test$1.expect(input).toBeVisible({ timeout: 15000 });
|
|
6319
|
+
await input.fill(message);
|
|
6320
|
+
const send = page.getByRole('button', { name: SUPPORT_LABELS.chat.sendButton });
|
|
6321
|
+
await test$1.expect(send).toBeEnabled({ timeout: 10000 });
|
|
6322
|
+
await send.click();
|
|
6323
|
+
await test$1.expect(page.locator(SUPPORT_LABELS.chat.userQueryClass).filter({ hasText: message.slice(0, 60) })).toBeVisible({ timeout: 15000 });
|
|
6324
|
+
logger.info(`Sent chat message: ${message.slice(0, 60)}`);
|
|
6325
|
+
}
|
|
6326
|
+
/**
|
|
6327
|
+
* Wait for the agent's reply to finish. LLM latency plus tool execution
|
|
6328
|
+
* (the support-ticket tool call) makes this the slow step — default 90s.
|
|
6329
|
+
* Returns the reply text for content assertions.
|
|
6330
|
+
*/
|
|
6331
|
+
async function waitForAgentChatResponse(page, timeoutMs = 90000) {
|
|
6332
|
+
var _a;
|
|
6333
|
+
const reply = page.locator(SUPPORT_LABELS.chat.aiResponseClass).last();
|
|
6334
|
+
await test$1.expect(reply).toBeVisible({ timeout: timeoutMs });
|
|
6335
|
+
// Streaming done — the stop button unmounts when the response completes.
|
|
6336
|
+
await test$1.expect(page.locator(SUPPORT_LABELS.chat.stopStreamingClass)).toBeHidden({
|
|
6337
|
+
timeout: timeoutMs,
|
|
6338
|
+
});
|
|
6339
|
+
const text = (_a = (await reply.textContent())) !== null && _a !== void 0 ? _a : '';
|
|
6340
|
+
test$1.expect(text.length).toBeGreaterThan(0);
|
|
6341
|
+
logger.info(`Agent replied (${text.length} chars)`);
|
|
6342
|
+
return text;
|
|
6343
|
+
}
|
|
6344
|
+
/**
|
|
6345
|
+
* Ask the agent (via chat) to open a support ticket with a distinctive
|
|
6346
|
+
* subject, and wait for its reply. The explicit "subject" phrasing gives
|
|
6347
|
+
* the support tool an exact string to file, which the spec then looks
|
|
6348
|
+
* for in the ticket list.
|
|
6349
|
+
*/
|
|
6350
|
+
async function requestSupportTicketViaChat(page, opts) {
|
|
6351
|
+
var _a;
|
|
6352
|
+
const description = (_a = opts.description) !== null && _a !== void 0 ? _a : 'I need help from a human. Please escalate this conversation.';
|
|
6353
|
+
const prompt = `Please create a support ticket for me. ` +
|
|
6354
|
+
`Use exactly this subject: "${opts.subject}". ` +
|
|
6355
|
+
`Description: ${description}`;
|
|
6356
|
+
await sendAgentChatMessage(page, prompt);
|
|
6357
|
+
return waitForAgentChatResponse(page);
|
|
6358
|
+
}
|
|
6359
|
+
// ── End-to-end composition ─────────────────────────────────────────────
|
|
6360
|
+
/**
|
|
6361
|
+
* Full flow: with support enabled, ask the agent for a ticket in chat,
|
|
6362
|
+
* then verify it shows up in the Support tab.
|
|
6363
|
+
*
|
|
6364
|
+
* The Edit Agent modal is host-specific to open/close, so the caller
|
|
6365
|
+
* provides `openEditAgentModal` (and optionally `closeEditAgentModal`,
|
|
6366
|
+
* used to get the modal out of the chat's way before sending). Steps:
|
|
6367
|
+
*
|
|
6368
|
+
* 1. `openEditAgentModal()` → Support tab → ensure the toggle is ON.
|
|
6369
|
+
* 2. `closeEditAgentModal()` (when provided) → chat-request the ticket.
|
|
6370
|
+
* 3. `openEditAgentModal()` → Support tab → wait for the ticket row.
|
|
6371
|
+
*
|
|
6372
|
+
* Returns the dialog locator with the Support tab open and the new
|
|
6373
|
+
* ticket listed, so specs can keep asserting (open it, reply, close it).
|
|
6374
|
+
*/
|
|
6375
|
+
async function createSupportTicketViaChatAndVerify(page, opts) {
|
|
6376
|
+
// 1. Make sure the support tool is on.
|
|
6377
|
+
await opts.openEditAgentModal();
|
|
6378
|
+
let dialog = await switchToSupportTab(page);
|
|
6379
|
+
await enableSupport(dialog);
|
|
6380
|
+
// 2. Ask the agent for a ticket from the chat surface.
|
|
6381
|
+
if (opts.closeEditAgentModal) {
|
|
6382
|
+
await opts.closeEditAgentModal();
|
|
6383
|
+
await test$1.expect(getEditAgentDialog(page)).toBeHidden({ timeout: 10000 });
|
|
6384
|
+
}
|
|
6385
|
+
await requestSupportTicketViaChat(page, {
|
|
6386
|
+
subject: opts.subject,
|
|
6387
|
+
description: opts.description,
|
|
6388
|
+
});
|
|
6389
|
+
// 3. Back to the Support tab — the ticket must be listed.
|
|
6390
|
+
if (opts.closeEditAgentModal) {
|
|
6391
|
+
await opts.openEditAgentModal();
|
|
6392
|
+
}
|
|
6393
|
+
dialog = await switchToSupportTab(page);
|
|
6394
|
+
await waitForTicketInList(dialog, opts.subject, { timeoutMs: opts.listTimeoutMs });
|
|
6395
|
+
await expectTicketStatusInList(dialog, opts.subject, 'open');
|
|
6396
|
+
logger.info(`Support ticket created via chat and verified: ${opts.subject}`);
|
|
6397
|
+
return dialog;
|
|
6398
|
+
}
|
|
6399
|
+
|
|
5883
6400
|
/** Extract browser key from device name (e.g., 'Desktop Chrome' -> 'chrome') */
|
|
5884
6401
|
function getBrowserKey(deviceName) {
|
|
5885
6402
|
return deviceName.toLowerCase().replace(/^desktop\s+/, '');
|
|
@@ -6018,6 +6535,7 @@ exports.LTI_TEST_IDS = LTI_TEST_IDS;
|
|
|
6018
6535
|
exports.MailsacClient = MailsacClient;
|
|
6019
6536
|
exports.PRIVACY_LABELS = PRIVACY_LABELS;
|
|
6020
6537
|
exports.SCREENSHARE_LABELS = SCREENSHARE_LABELS;
|
|
6538
|
+
exports.SUPPORT_LABELS = SUPPORT_LABELS;
|
|
6021
6539
|
exports.TASKS_LABELS = TASKS_LABELS;
|
|
6022
6540
|
exports.VOICE_LABELS = VOICE_LABELS;
|
|
6023
6541
|
exports.addManualScore = addManualScore;
|
|
@@ -6043,6 +6561,7 @@ exports.checkAdminStatus = checkAdminStatus;
|
|
|
6043
6561
|
exports.checkRunStatus = checkRunStatus;
|
|
6044
6562
|
exports.clearDateRangeFilter = clearDateRangeFilter;
|
|
6045
6563
|
exports.clearInstanceSearch = clearInstanceSearch;
|
|
6564
|
+
exports.clearUserFilter = clearUserFilter;
|
|
6046
6565
|
exports.clickBackHome = clickBackHome;
|
|
6047
6566
|
exports.clickBillingAddCredits = clickBillingAddCredits;
|
|
6048
6567
|
exports.clickBillingManageBilling = clickBillingManageBilling;
|
|
@@ -6069,6 +6588,7 @@ exports.createKey = createKey;
|
|
|
6069
6588
|
exports.createLink = createLink;
|
|
6070
6589
|
exports.createPlaywrightConfig = createPlaywrightConfig;
|
|
6071
6590
|
exports.createSkill = createSkill;
|
|
6591
|
+
exports.createSupportTicketViaChatAndVerify = createSupportTicketViaChatAndVerify;
|
|
6072
6592
|
exports.createTool = createTool;
|
|
6073
6593
|
exports.creditBalancePanel = creditBalancePanel;
|
|
6074
6594
|
exports.creditBalancePlanBadge = creditBalancePlanBadge;
|
|
@@ -6082,6 +6602,7 @@ exports.deleteQaItem = deleteQaItem;
|
|
|
6082
6602
|
exports.deleteSkill = deleteSkill;
|
|
6083
6603
|
exports.deleteTask = deleteTask;
|
|
6084
6604
|
exports.disableSkill = disableSkill;
|
|
6605
|
+
exports.disableSupport = disableSupport;
|
|
6085
6606
|
exports.disconnectInstance = disconnectInstance;
|
|
6086
6607
|
exports.editAgentPrompt = editAgentPrompt;
|
|
6087
6608
|
exports.editInstance = editInstance;
|
|
@@ -6089,6 +6610,7 @@ exports.editLink = editLink;
|
|
|
6089
6610
|
exports.editSkill = editSkill;
|
|
6090
6611
|
exports.editTool = editTool;
|
|
6091
6612
|
exports.enableSkill = enableSkill;
|
|
6613
|
+
exports.enableSupport = enableSupport;
|
|
6092
6614
|
exports.expandReview = expandReview;
|
|
6093
6615
|
exports.expandTrace = expandTrace;
|
|
6094
6616
|
exports.expectAllEndpointsVisible = expectAllEndpointsVisible;
|
|
@@ -6129,10 +6651,13 @@ exports.expectLogDetailsStatus = expectLogDetailsStatus;
|
|
|
6129
6651
|
exports.expectLogsForTask = expectLogsForTask;
|
|
6130
6652
|
exports.expectLtiHeader = expectLtiHeader;
|
|
6131
6653
|
exports.expectMentorVoiceTriggerShows = expectMentorVoiceTriggerShows;
|
|
6654
|
+
exports.expectMessageInConversation = expectMessageInConversation;
|
|
6132
6655
|
exports.expectNoAccessibilityViolations = expectNoAccessibilityViolations;
|
|
6133
6656
|
exports.expectNoAccessibilityViolationsOnDialogs = expectNoAccessibilityViolationsOnDialogs;
|
|
6134
6657
|
exports.expectNoBenchmarksNotice = expectNoBenchmarksNotice;
|
|
6135
6658
|
exports.expectNoLogsForSelectedTask = expectNoLogsForSelectedTask;
|
|
6659
|
+
exports.expectNoRepliesYet = expectNoRepliesYet;
|
|
6660
|
+
exports.expectNoTickets = expectNoTickets;
|
|
6136
6661
|
exports.expectOutputFilterEnabled = expectOutputFilterEnabled;
|
|
6137
6662
|
exports.expectPrivacyFieldsHidden = expectPrivacyFieldsHidden;
|
|
6138
6663
|
exports.expectPrivacyFieldsVisible = expectPrivacyFieldsVisible;
|
|
@@ -6155,6 +6680,10 @@ exports.expectTaskStatus = expectTaskStatus;
|
|
|
6155
6680
|
exports.expectTasksEmpty = expectTasksEmpty;
|
|
6156
6681
|
exports.expectTenantChatPrivacyEnabled = expectTenantChatPrivacyEnabled;
|
|
6157
6682
|
exports.expectTenantChatPrivacyVisible = expectTenantChatPrivacyVisible;
|
|
6683
|
+
exports.expectTicketClosedNotice = expectTicketClosedNotice;
|
|
6684
|
+
exports.expectTicketDescriptionContains = expectTicketDescriptionContains;
|
|
6685
|
+
exports.expectTicketInList = expectTicketInList;
|
|
6686
|
+
exports.expectTicketStatusInList = expectTicketStatusInList;
|
|
6158
6687
|
exports.expectToolInList = expectToolInList;
|
|
6159
6688
|
exports.expectToolNotInList = expectToolNotInList;
|
|
6160
6689
|
exports.expectToolsEmpty = expectToolsEmpty;
|
|
@@ -6171,6 +6700,8 @@ exports.filterByActionAndVerify = filterByActionAndVerify;
|
|
|
6171
6700
|
exports.filterByActor = filterByActor;
|
|
6172
6701
|
exports.filterByActorAndVerify = filterByActorAndVerify;
|
|
6173
6702
|
exports.filterByDateRange = filterByDateRange;
|
|
6703
|
+
exports.filterTicketsByStatus = filterTicketsByStatus;
|
|
6704
|
+
exports.filterTicketsByUser = filterTicketsByUser;
|
|
6174
6705
|
exports.generateBrowserSetupProjects = generateBrowserSetupProjects;
|
|
6175
6706
|
exports.generateProjectConfig = generateProjectConfig;
|
|
6176
6707
|
exports.getAddItemsDialog = getAddItemsDialog;
|
|
@@ -6183,6 +6714,7 @@ exports.getBillingAutoRechargeStatus = getBillingAutoRechargeStatus;
|
|
|
6183
6714
|
exports.getBillingPlanLabel = getBillingPlanLabel;
|
|
6184
6715
|
exports.getBrowserKey = getBrowserKey;
|
|
6185
6716
|
exports.getCallConfigForm = getCallConfigForm;
|
|
6717
|
+
exports.getChatInput = getChatInput;
|
|
6186
6718
|
exports.getChatPrivacyConfirmDialog = getChatPrivacyConfirmDialog;
|
|
6187
6719
|
exports.getChatPrivacyToggle = getChatPrivacyToggle;
|
|
6188
6720
|
exports.getCreateBenchmarkDialog = getCreateBenchmarkDialog;
|
|
@@ -6195,6 +6727,7 @@ exports.getCurrentModel = getCurrentModel;
|
|
|
6195
6727
|
exports.getCurrentTenantShowPaywall = getCurrentTenantShowPaywall;
|
|
6196
6728
|
exports.getDeleteEvaluationDialog = getDeleteEvaluationDialog;
|
|
6197
6729
|
exports.getDeleteQaItemDialog = getDeleteQaItemDialog;
|
|
6730
|
+
exports.getEditAgentDialog = getEditAgentDialog;
|
|
6198
6731
|
exports.getEndpoint = getEndpoint;
|
|
6199
6732
|
exports.getEndpointCopyButton = getEndpointCopyButton;
|
|
6200
6733
|
exports.getEndpointUrl = getEndpointUrl;
|
|
@@ -6232,15 +6765,25 @@ exports.getNewEvaluationButton = getNewEvaluationButton;
|
|
|
6232
6765
|
exports.getOutputFilterSwitch = getOutputFilterSwitch;
|
|
6233
6766
|
exports.getPaginationInfo = getPaginationInfo;
|
|
6234
6767
|
exports.getPrivateModeCard = getPrivateModeCard;
|
|
6768
|
+
exports.getReplyComposer = getReplyComposer;
|
|
6235
6769
|
exports.getReviewRow = getReviewRow;
|
|
6236
6770
|
exports.getRunRow = getRunRow;
|
|
6237
6771
|
exports.getScheduleTaskButton = getScheduleTaskButton;
|
|
6238
6772
|
exports.getSearchInput = getSearchInput;
|
|
6239
6773
|
exports.getSkillRowCount = getSkillRowCount;
|
|
6240
6774
|
exports.getStartEvaluationDialog = getStartEvaluationDialog;
|
|
6775
|
+
exports.getStatusFilter = getStatusFilter;
|
|
6776
|
+
exports.getSupportInfoBox = getSupportInfoBox;
|
|
6777
|
+
exports.getSupportTabTrigger = getSupportTabTrigger;
|
|
6778
|
+
exports.getSupportToggle = getSupportToggle;
|
|
6241
6779
|
exports.getTaskRow = getTaskRow;
|
|
6242
6780
|
exports.getTenantChatPrivacyRow = getTenantChatPrivacyRow;
|
|
6243
6781
|
exports.getTenantChatPrivacySwitch = getTenantChatPrivacySwitch;
|
|
6782
|
+
exports.getTicketDescription = getTicketDescription;
|
|
6783
|
+
exports.getTicketDetail = getTicketDetail;
|
|
6784
|
+
exports.getTicketList = getTicketList;
|
|
6785
|
+
exports.getTicketRow = getTicketRow;
|
|
6786
|
+
exports.getTicketRowByIndex = getTicketRowByIndex;
|
|
6244
6787
|
exports.getToolEditButton = getToolEditButton;
|
|
6245
6788
|
exports.getToolKeySelect = getToolKeySelect;
|
|
6246
6789
|
exports.getToolModal = getToolModal;
|
|
@@ -6248,6 +6791,7 @@ exports.getToolRow = getToolRow;
|
|
|
6248
6791
|
exports.getToolsEmptyState = getToolsEmptyState;
|
|
6249
6792
|
exports.getToolsSection = getToolsSection;
|
|
6250
6793
|
exports.getTraceRow = getTraceRow;
|
|
6794
|
+
exports.getUserFilter = getUserFilter;
|
|
6251
6795
|
exports.getVoiceProviderCard = getVoiceProviderCard;
|
|
6252
6796
|
exports.getVoiceRow = getVoiceRow;
|
|
6253
6797
|
exports.goToFirstPage = goToFirstPage;
|
|
@@ -6268,6 +6812,8 @@ exports.isPrivateModeTabVisible = isPrivateModeTabVisible;
|
|
|
6268
6812
|
exports.isSandboxTabVisible = isSandboxTabVisible;
|
|
6269
6813
|
exports.isScreenShareTabVisible = isScreenShareTabVisible;
|
|
6270
6814
|
exports.isSkillEnabled = isSkillEnabled;
|
|
6815
|
+
exports.isSupportEnabled = isSupportEnabled;
|
|
6816
|
+
exports.isSupportTabVisible = isSupportTabVisible;
|
|
6271
6817
|
exports.isTasksTabVisible = isTasksTabVisible;
|
|
6272
6818
|
exports.isVoiceTabVisible = isVoiceTabVisible;
|
|
6273
6819
|
exports.logger = logger;
|
|
@@ -6309,6 +6855,7 @@ exports.openScheduleTaskDialog = openScheduleTaskDialog;
|
|
|
6309
6855
|
exports.openScreenSharePromptEditor = openScreenSharePromptEditor;
|
|
6310
6856
|
exports.openSkillActionsMenu = openSkillActionsMenu;
|
|
6311
6857
|
exports.openStartEvaluationDialog = openStartEvaluationDialog;
|
|
6858
|
+
exports.openTicket = openTicket;
|
|
6312
6859
|
exports.parseReportUrlParams = parseReportUrlParams;
|
|
6313
6860
|
exports.previewCallConfigVoiceInline = previewCallConfigVoiceInline;
|
|
6314
6861
|
exports.previewMentorVoiceInline = previewMentorVoiceInline;
|
|
@@ -6318,10 +6865,13 @@ exports.readEndpointUrl = readEndpointUrl;
|
|
|
6318
6865
|
exports.readKeyPublicJwk = readKeyPublicJwk;
|
|
6319
6866
|
exports.readKeyPublicKey = readKeyPublicKey;
|
|
6320
6867
|
exports.refreshEvaluationDetail = refreshEvaluationDetail;
|
|
6868
|
+
exports.refreshTickets = refreshTickets;
|
|
6321
6869
|
exports.reliableClick = reliableClick;
|
|
6322
6870
|
exports.reliableFill = reliableFill;
|
|
6323
6871
|
exports.removeTraceScore = removeTraceScore;
|
|
6324
6872
|
exports.renameKey = renameKey;
|
|
6873
|
+
exports.replyToTicket = replyToTicket;
|
|
6874
|
+
exports.requestSupportTicketViaChat = requestSupportTicketViaChat;
|
|
6325
6875
|
exports.resetCallConfig = resetCallConfig;
|
|
6326
6876
|
exports.retry = retry;
|
|
6327
6877
|
exports.runConnectedInstanceChecks = runConnectedInstanceChecks;
|
|
@@ -6350,13 +6900,16 @@ exports.selectToolSigningKey = selectToolSigningKey;
|
|
|
6350
6900
|
exports.selectTtsProvider = selectTtsProvider;
|
|
6351
6901
|
exports.selectVoice = selectVoice;
|
|
6352
6902
|
exports.selectVoiceProvider = selectVoiceProvider;
|
|
6903
|
+
exports.sendAgentChatMessage = sendAgentChatMessage;
|
|
6353
6904
|
exports.setBlockMessage = setBlockMessage;
|
|
6354
6905
|
exports.setCallLanguage = setCallLanguage;
|
|
6355
6906
|
exports.setEnableVideo = setEnableVideo;
|
|
6356
6907
|
exports.setEntitySelected = setEntitySelected;
|
|
6357
6908
|
exports.setOutputFilterEnabled = setOutputFilterEnabled;
|
|
6358
6909
|
exports.setScreenSharePrompt = setScreenSharePrompt;
|
|
6910
|
+
exports.setSupportEnabled = setSupportEnabled;
|
|
6359
6911
|
exports.setTenantChatPrivacyEnabled = setTenantChatPrivacyEnabled;
|
|
6912
|
+
exports.setTicketStatus = setTicketStatus;
|
|
6360
6913
|
exports.setUseFunctionCallingEnabled = setUseFunctionCallingEnabled;
|
|
6361
6914
|
exports.setupSandboxInstance = setupSandboxInstance;
|
|
6362
6915
|
exports.shouldAddNewRowWhenClickingAddRowButton = shouldAddNewRowWhenClickingAddRowButton;
|
|
@@ -6390,6 +6943,7 @@ exports.switchToPrivateModeTab = switchToPrivateModeTab;
|
|
|
6390
6943
|
exports.switchToSandboxTab = switchToSandboxTab;
|
|
6391
6944
|
exports.switchToScreenShareTab = switchToScreenShareTab;
|
|
6392
6945
|
exports.switchToSkillsTab = switchToSkillsTab;
|
|
6946
|
+
exports.switchToSupportTab = switchToSupportTab;
|
|
6393
6947
|
exports.switchToTasksTab = switchToTasksTab;
|
|
6394
6948
|
exports.switchToVoiceSubTab = switchToVoiceSubTab;
|
|
6395
6949
|
exports.switchToVoiceTab = switchToVoiceTab;
|
|
@@ -6423,6 +6977,7 @@ exports.verifyPreparingPhase = verifyPreparingPhase;
|
|
|
6423
6977
|
exports.verifySkillVisible = verifySkillVisible;
|
|
6424
6978
|
exports.verifySkillsEmptyState = verifySkillsEmptyState;
|
|
6425
6979
|
exports.verifySkillsTabVisible = verifySkillsTabVisible;
|
|
6980
|
+
exports.waitForAgentChatResponse = waitForAgentChatResponse;
|
|
6426
6981
|
exports.waitForAuditLogDataLoaded = waitForAuditLogDataLoaded;
|
|
6427
6982
|
exports.waitForBillingTabReady = waitForBillingTabReady;
|
|
6428
6983
|
exports.waitForCreditBalanceLoaded = waitForCreditBalanceLoaded;
|
|
@@ -6431,4 +6986,5 @@ exports.waitForElementStable = waitForElementStable;
|
|
|
6431
6986
|
exports.waitForPageLoad = waitForPageLoad;
|
|
6432
6987
|
exports.waitForPageReady = waitForPageReady;
|
|
6433
6988
|
exports.waitForReportDownload = waitForReportDownload;
|
|
6989
|
+
exports.waitForTicketInList = waitForTicketInList;
|
|
6434
6990
|
//# sourceMappingURL=index.cjs.map
|