@iblai/iblai-js 1.4.2 → 1.4.4
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/audit-log-helpers.d.ts +119 -0
- package/dist/data-layer/playwright/index.d.ts +1 -0
- package/dist/data-layer/playwright/shared-test-helpers.d.ts +12 -0
- package/dist/playwright/index.cjs +535 -109
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.ts +120 -1
- package/dist/playwright/index.esm.js +510 -110
- package/dist/playwright/index.esm.js.map +1 -1
- package/dist/playwright/playwright/audit-log-helpers.d.ts +119 -0
- package/dist/playwright/playwright/index.d.ts +1 -0
- package/dist/playwright/playwright/shared-test-helpers.d.ts +12 -0
- package/dist/web-containers/playwright/audit-log-helpers.d.ts +119 -0
- package/dist/web-containers/playwright/index.d.ts +1 -0
- package/dist/web-containers/playwright/shared-test-helpers.d.ts +12 -0
- package/dist/web-containers/source/index.esm.js +1458 -655
- package/dist/web-containers/source/next/index.esm.js +950 -406
- package/dist/web-utils/playwright/audit-log-helpers.d.ts +119 -0
- package/dist/web-utils/playwright/index.d.ts +1 -0
- package/dist/web-utils/playwright/shared-test-helpers.d.ts +12 -0
- package/package.json +5 -5
|
@@ -825,6 +825,7 @@ async function expectNoAccessibilityViolationsOnDialogs(page, rules, exclude = [
|
|
|
825
825
|
test$1.expect(results.violations).toEqual([]);
|
|
826
826
|
}
|
|
827
827
|
|
|
828
|
+
const deferredNotificationText = 'You will be notified once the report is available.';
|
|
828
829
|
async function inviteUserTest(page, inviteModal) {
|
|
829
830
|
const emailInput = inviteModal.locator('#email-invite');
|
|
830
831
|
await test$1.expect(emailInput).toBeVisible({ timeout: 10000 });
|
|
@@ -848,6 +849,28 @@ async function navigateToAccountComponent(page, profileBtn) {
|
|
|
848
849
|
await test$1.expect(tenantDialog).toBeVisible();
|
|
849
850
|
return tenantDialog;
|
|
850
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* Click a report card's primary action and confirm the date-range picker, so callers
|
|
854
|
+
* always end up in the post-generation state.
|
|
855
|
+
*
|
|
856
|
+
* Prefers the "Regenerate report" button when present (completed reports) because the plain
|
|
857
|
+
* "Download report" button on a completed card re-downloads the existing URL and skips the
|
|
858
|
+
* picker. When no Regenerate button exists, clicks "Download report" — which on a
|
|
859
|
+
* non-completed card also opens the picker.
|
|
860
|
+
*
|
|
861
|
+
* Either way we wait for the picker and click Generate/Regenerate to start the report.
|
|
862
|
+
*/
|
|
863
|
+
async function triggerReportFromCard(page, card) {
|
|
864
|
+
const regenerateButton = card.getByRole('button', { name: 'Regenerate report' });
|
|
865
|
+
const downloadButton = card.getByRole('button', { name: 'Download report' });
|
|
866
|
+
const hasRegenerate = await regenerateButton.isVisible().catch(() => false);
|
|
867
|
+
const trigger = hasRegenerate ? regenerateButton : downloadButton;
|
|
868
|
+
await trigger.click();
|
|
869
|
+
const dateRangePopover = page.getByTestId('report-date-range-popover');
|
|
870
|
+
await test$1.expect(dateRangePopover).toBeVisible({ timeout: 10000 });
|
|
871
|
+
await dateRangePopover.getByRole('button', { name: /^(Generate|Regenerate)$/ }).click();
|
|
872
|
+
await test$1.expect(dateRangePopover).not.toBeVisible({ timeout: 10000 });
|
|
873
|
+
}
|
|
851
874
|
async function navigateToDataReports(page) {
|
|
852
875
|
const dataReportsTab = page.getByRole('tab', { name: 'Data Reports' });
|
|
853
876
|
await test$1.expect(dataReportsTab).toBeVisible({ timeout: 120000 });
|
|
@@ -899,14 +922,40 @@ async function shouldOpenCSVEditorDialog(page) {
|
|
|
899
922
|
test$1.skip();
|
|
900
923
|
return;
|
|
901
924
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
925
|
+
await triggerReportFromCard(page, userReportCard);
|
|
926
|
+
//expect Report generation processing...
|
|
927
|
+
await test$1.expect(page.getByText('Report generation processing...')).toBeVisible({ timeout: 5000 });
|
|
928
|
+
// After the processing toast appears, the backend either finishes in time (CSV editor opens)
|
|
929
|
+
// or polling times out (deferred-notification toast appears). Treat both as valid outcomes.
|
|
930
|
+
await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
931
|
+
}
|
|
932
|
+
async function waitForReportOutcomeOrCSVDialogOpen(page) {
|
|
933
|
+
const csvEditorDialog = page.getByRole('dialog', { name: 'Edit CSV Data' });
|
|
934
|
+
const deferredNotification = page.getByText(deferredNotificationText);
|
|
935
|
+
const downloadPromise = page.waitForEvent('download', { timeout: 60000 });
|
|
936
|
+
const outcome = await Promise.race([
|
|
937
|
+
csvEditorDialog
|
|
938
|
+
.waitFor({ state: 'visible', timeout: 60000 })
|
|
939
|
+
.then(() => 'csv-editor'),
|
|
940
|
+
deferredNotification
|
|
941
|
+
.waitFor({ state: 'visible', timeout: 60000 })
|
|
942
|
+
.then(() => 'deferred'),
|
|
943
|
+
downloadPromise.then(() => 'download'),
|
|
944
|
+
]).catch(() => null);
|
|
945
|
+
if (outcome === 'deferred') {
|
|
946
|
+
logger.info('Report generation deferred — user will be notified when available');
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
if (outcome === 'download') {
|
|
950
|
+
const download = await downloadPromise;
|
|
951
|
+
const filename = download.suggestedFilename();
|
|
952
|
+
test$1.expect(filename).toBe('report.csv');
|
|
953
|
+
logger.info(`CSV file "${filename}" downloaded successfully`);
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
if (outcome !== 'csv-editor') {
|
|
957
|
+
throw new Error('Report generation did not complete: neither CSV editor nor deferred-notification toast appeared within 60s');
|
|
958
|
+
}
|
|
910
959
|
const dialogTitle = csvEditorDialog.getByRole('heading', {
|
|
911
960
|
name: 'Edit CSV Data',
|
|
912
961
|
level: 2,
|
|
@@ -920,6 +969,7 @@ async function shouldOpenCSVEditorDialog(page) {
|
|
|
920
969
|
await test$1.expect(csvEditorDialog.getByRole('button', { name: 'Save' })).toBeVisible();
|
|
921
970
|
await test$1.expect(csvEditorDialog.getByRole('button', { name: 'Close' }).first()).toBeVisible();
|
|
922
971
|
logger.info('CSV Editor dialog opened successfully');
|
|
972
|
+
return csvEditorDialog;
|
|
923
973
|
}
|
|
924
974
|
async function shouldDisplayCSVInEditableTableFormat(page) {
|
|
925
975
|
const dataReportsTab = page.getByRole('tab', { name: 'Data Reports' });
|
|
@@ -932,14 +982,12 @@ async function shouldDisplayCSVInEditableTableFormat(page) {
|
|
|
932
982
|
test$1.skip();
|
|
933
983
|
return;
|
|
934
984
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
});
|
|
942
|
-
await test$1.expect(csvEditorDialog).toBeVisible({ timeout: 60000 });
|
|
985
|
+
await triggerReportFromCard(page, userReportCard);
|
|
986
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
987
|
+
if (!csvEditorDialog) {
|
|
988
|
+
test$1.skip();
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
943
991
|
const table = csvEditorDialog.getByRole('table', {
|
|
944
992
|
name: 'CSV data table',
|
|
945
993
|
});
|
|
@@ -963,14 +1011,12 @@ async function shouldAllowEditingCellValuesInCSVEditor(page) {
|
|
|
963
1011
|
test$1.skip();
|
|
964
1012
|
return;
|
|
965
1013
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
});
|
|
973
|
-
await test$1.expect(csvEditorDialog).toBeVisible({ timeout: 60000 });
|
|
1014
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1015
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1016
|
+
if (!csvEditorDialog) {
|
|
1017
|
+
test$1.skip();
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
974
1020
|
const table = csvEditorDialog.getByRole('table', {
|
|
975
1021
|
name: 'CSV data table',
|
|
976
1022
|
});
|
|
@@ -1003,14 +1049,12 @@ async function shouldAddNewRowWhenClickingAddRowButton(page) {
|
|
|
1003
1049
|
test$1.skip();
|
|
1004
1050
|
return;
|
|
1005
1051
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
});
|
|
1013
|
-
await test$1.expect(csvEditorDialog).toBeVisible({ timeout: 60000 });
|
|
1052
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1053
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1054
|
+
if (!csvEditorDialog) {
|
|
1055
|
+
test$1.skip();
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1014
1058
|
const table = csvEditorDialog.locator('table');
|
|
1015
1059
|
const initialRowCount = await table.locator('tbody tr').count();
|
|
1016
1060
|
const addRowButton = csvEditorDialog.getByRole('button', {
|
|
@@ -1033,16 +1077,14 @@ async function shouldSaveEditedCSVAndTriggerDownload(page) {
|
|
|
1033
1077
|
test$1.skip();
|
|
1034
1078
|
return;
|
|
1035
1079
|
}
|
|
1036
|
-
|
|
1037
|
-
name: 'Download report',
|
|
1038
|
-
});
|
|
1039
|
-
await downloadButton.click();
|
|
1080
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1040
1081
|
await page.waitForLoadState('networkidle');
|
|
1041
|
-
const csvEditorDialog = page
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1082
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1083
|
+
if (!csvEditorDialog) {
|
|
1084
|
+
test$1.skip();
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const downloadPromise = page.waitForEvent('download', { timeout: 40000 });
|
|
1046
1088
|
const saveButton = csvEditorDialog.getByRole('button', { name: 'Save' });
|
|
1047
1089
|
await saveButton.click();
|
|
1048
1090
|
const download = await downloadPromise;
|
|
@@ -1062,15 +1104,13 @@ async function shouldCloseCSVEditorWithoutSavingWhenClickingCancel(page) {
|
|
|
1062
1104
|
test$1.skip();
|
|
1063
1105
|
return;
|
|
1064
1106
|
}
|
|
1065
|
-
|
|
1066
|
-
name: 'Download report',
|
|
1067
|
-
});
|
|
1068
|
-
await downloadButton.click();
|
|
1107
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1069
1108
|
await page.waitForLoadState('networkidle');
|
|
1070
|
-
const csvEditorDialog = page
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1109
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1110
|
+
if (!csvEditorDialog) {
|
|
1111
|
+
test$1.skip();
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1074
1114
|
const cancelButton = csvEditorDialog.getByRole('button', {
|
|
1075
1115
|
name: 'Cancel',
|
|
1076
1116
|
});
|
|
@@ -1090,15 +1130,13 @@ async function shouldCloseCSVEditorWhenClickingCloseButton(page) {
|
|
|
1090
1130
|
test$1.skip();
|
|
1091
1131
|
return;
|
|
1092
1132
|
}
|
|
1093
|
-
|
|
1094
|
-
name: 'Download report',
|
|
1095
|
-
});
|
|
1096
|
-
await downloadButton.click();
|
|
1133
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1097
1134
|
await page.waitForLoadState('networkidle');
|
|
1098
|
-
const csvEditorDialog = page
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1135
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1136
|
+
if (!csvEditorDialog) {
|
|
1137
|
+
test$1.skip();
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1102
1140
|
const closeButton = csvEditorDialog
|
|
1103
1141
|
.getByRole('button', {
|
|
1104
1142
|
name: 'Close',
|
|
@@ -1119,15 +1157,13 @@ async function shouldVerifyCSVEditorDialogAccessibility(page) {
|
|
|
1119
1157
|
test$1.skip();
|
|
1120
1158
|
return;
|
|
1121
1159
|
}
|
|
1122
|
-
|
|
1123
|
-
name: 'Download report',
|
|
1124
|
-
});
|
|
1125
|
-
await downloadButton.click();
|
|
1160
|
+
await triggerReportFromCard(page, userReportCard);
|
|
1126
1161
|
await page.waitForLoadState('networkidle');
|
|
1127
|
-
const csvEditorDialog = page
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1162
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1163
|
+
if (!csvEditorDialog) {
|
|
1164
|
+
test$1.skip();
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1131
1167
|
await test$1.expect(csvEditorDialog).toHaveAttribute('role', 'dialog');
|
|
1132
1168
|
const csvTable = csvEditorDialog.getByRole('table', {
|
|
1133
1169
|
name: 'CSV data table',
|
|
@@ -1162,15 +1198,12 @@ async function shouldOpenCSVEditorForUserMetadataReport(page) {
|
|
|
1162
1198
|
test$1.skip();
|
|
1163
1199
|
return;
|
|
1164
1200
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
name: 'Edit CSV Data',
|
|
1172
|
-
});
|
|
1173
|
-
await test$1.expect(csvEditorDialog).toBeVisible({ timeout: 60000 });
|
|
1201
|
+
await triggerReportFromCard(page, userMetadataReportCard);
|
|
1202
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1203
|
+
if (!csvEditorDialog) {
|
|
1204
|
+
test$1.skip();
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1174
1207
|
const table = csvEditorDialog.locator('table');
|
|
1175
1208
|
const companyHeader = table.locator('thead th input[value="company"]');
|
|
1176
1209
|
const hasCompanyColumn = await companyHeader.isVisible().catch(() => false);
|
|
@@ -1190,21 +1223,32 @@ async function shouldDirectlyDownloadChatHistoryReportWithoutCSVEditor(page) {
|
|
|
1190
1223
|
test$1.skip();
|
|
1191
1224
|
return;
|
|
1192
1225
|
}
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const downloadPromise = page.waitForEvent('download', { timeout:
|
|
1197
|
-
await
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1226
|
+
// Prefer the Regenerate button (guaranteed to open the picker); fall back to Download.
|
|
1227
|
+
// Start listening for the download event before clicking since the auto-download fires
|
|
1228
|
+
// as soon as the picker is confirmed.
|
|
1229
|
+
const downloadPromise = page.waitForEvent('download', { timeout: 40000 });
|
|
1230
|
+
await triggerReportFromCard(page, chatHistoryCard);
|
|
1231
|
+
// Either the browser fires a download within 40s, or the backend defers and shows the
|
|
1232
|
+
// "You will be notified once the report is available." toast. Both are valid outcomes.
|
|
1233
|
+
const deferredNotification = page.getByText(deferredNotificationText);
|
|
1234
|
+
const outcome = await Promise.race([
|
|
1235
|
+
downloadPromise.then((download) => ({ kind: 'download', download })),
|
|
1236
|
+
deferredNotification
|
|
1237
|
+
.waitFor({ state: 'visible', timeout: 40000 })
|
|
1238
|
+
.then(() => ({ kind: 'deferred' })),
|
|
1239
|
+
]).catch(() => null);
|
|
1240
|
+
if (!outcome) {
|
|
1241
|
+
throw new Error('Chat History generation did not complete: neither a download nor the deferred-notification toast appeared within 40s');
|
|
1242
|
+
}
|
|
1243
|
+
if (outcome.kind === 'download') {
|
|
1244
|
+
const filename = outcome.download.suggestedFilename();
|
|
1202
1245
|
test$1.expect(filename.endsWith('.csv')).toBeTruthy();
|
|
1203
1246
|
logger.info(`Chat History report downloaded: ${filename}`);
|
|
1204
1247
|
}
|
|
1205
|
-
|
|
1206
|
-
logger.info('Chat History
|
|
1248
|
+
else {
|
|
1249
|
+
logger.info('Chat History generation deferred — user will be notified when available');
|
|
1207
1250
|
}
|
|
1251
|
+
// Regardless of outcome, the CSV editor dialog should never have opened for chat history.
|
|
1208
1252
|
const csvEditorDialog = page.getByRole('dialog', {
|
|
1209
1253
|
name: 'Edit CSV Data',
|
|
1210
1254
|
});
|
|
@@ -1225,23 +1269,23 @@ async function shouldDisableOtherDownloadButtonsWhileGeneratingReport(page) {
|
|
|
1225
1269
|
test$1.skip();
|
|
1226
1270
|
return;
|
|
1227
1271
|
}
|
|
1228
|
-
|
|
1272
|
+
// Trigger generation on the first report card (preferring Regenerate when present so the
|
|
1273
|
+
// date-range picker always shows, then confirming it).
|
|
1274
|
+
const firstCard = page.getByLabel(/ report card$/).first();
|
|
1275
|
+
await triggerReportFromCard(page, firstCard);
|
|
1276
|
+
//slight timeout to wait for other download buttons to be disabled
|
|
1229
1277
|
await page.waitForTimeout(500);
|
|
1230
1278
|
const secondButton = downloadButtons.nth(1);
|
|
1231
1279
|
const isSecondDisabled = await secondButton.isDisabled();
|
|
1232
1280
|
if (isSecondDisabled) {
|
|
1233
1281
|
logger.info('Other download buttons correctly disabled during report generation');
|
|
1234
1282
|
}
|
|
1235
|
-
const csvEditorDialog = page
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
.waitFor({ state: 'visible', timeout: 30000 })
|
|
1240
|
-
.then(() => true)
|
|
1241
|
-
.catch(() => false);
|
|
1242
|
-
if (dialogVisible) {
|
|
1243
|
-
await csvEditorDialog.getByRole('button', { name: 'Close' }).first().click();
|
|
1283
|
+
const csvEditorDialog = await waitForReportOutcomeOrCSVDialogOpen(page);
|
|
1284
|
+
if (!csvEditorDialog) {
|
|
1285
|
+
test$1.skip();
|
|
1286
|
+
return;
|
|
1244
1287
|
}
|
|
1288
|
+
await csvEditorDialog.getByRole('button', { name: 'Close' }).first().click();
|
|
1245
1289
|
}
|
|
1246
1290
|
// ============================================
|
|
1247
1291
|
// Combined Recommendation Reports Test Helpers
|
|
@@ -1261,12 +1305,9 @@ async function shouldShowCombiningReportsDialog(page) {
|
|
|
1261
1305
|
test$1.skip();
|
|
1262
1306
|
return;
|
|
1263
1307
|
}
|
|
1264
|
-
|
|
1265
|
-
.first()
|
|
1266
|
-
.getByRole('button', { name: 'Download report' });
|
|
1267
|
-
await downloadButton.click();
|
|
1308
|
+
await triggerReportFromCard(page, combinedReportCard.first());
|
|
1268
1309
|
const combiningDialog = page.locator('[data-testid="combining-reports-dialog"]');
|
|
1269
|
-
await test$1.expect(combiningDialog).toBeVisible({ timeout:
|
|
1310
|
+
await test$1.expect(combiningDialog).toBeVisible({ timeout: 40000 });
|
|
1270
1311
|
await test$1.expect(combiningDialog.getByText('Combining Reports')).toBeVisible();
|
|
1271
1312
|
await test$1.expect(combiningDialog.getByText('Loading & combining recommendations data')).toBeVisible();
|
|
1272
1313
|
logger.info('Combining reports dialog displayed successfully');
|
|
@@ -1286,12 +1327,9 @@ async function shouldCancelCombiningReports(page) {
|
|
|
1286
1327
|
test$1.skip();
|
|
1287
1328
|
return;
|
|
1288
1329
|
}
|
|
1289
|
-
|
|
1290
|
-
.first()
|
|
1291
|
-
.getByRole('button', { name: 'Download report' });
|
|
1292
|
-
await downloadButton.click();
|
|
1330
|
+
await triggerReportFromCard(page, combinedReportCard.first());
|
|
1293
1331
|
const combiningDialog = page.locator('[data-testid="combining-reports-dialog"]');
|
|
1294
|
-
await test$1.expect(combiningDialog).toBeVisible({ timeout:
|
|
1332
|
+
await test$1.expect(combiningDialog).toBeVisible({ timeout: 40000 });
|
|
1295
1333
|
const cancelButton = page.locator('[data-testid="cancel-combining-button"]');
|
|
1296
1334
|
await test$1.expect(cancelButton).toBeVisible();
|
|
1297
1335
|
await cancelButton.click();
|
|
@@ -1332,10 +1370,7 @@ async function shouldCombineRecommendationReports(page) {
|
|
|
1332
1370
|
test$1.skip();
|
|
1333
1371
|
return;
|
|
1334
1372
|
}
|
|
1335
|
-
|
|
1336
|
-
.first()
|
|
1337
|
-
.getByRole('button', { name: 'Download report' });
|
|
1338
|
-
await downloadButton.click();
|
|
1373
|
+
await triggerReportFromCard(page, combinedReportCard.first());
|
|
1339
1374
|
const combiningDialog = page.locator('[data-testid="combining-reports-dialog"]');
|
|
1340
1375
|
const dialogOrEditor = await Promise.race([
|
|
1341
1376
|
combiningDialog.waitFor({ state: 'visible', timeout: 10000 }).then(() => 'dialog'),
|
|
@@ -1675,6 +1710,371 @@ async function verifyMemoryNotExists(page, content) {
|
|
|
1675
1710
|
logger.info(`Verified memory removed: "${content}"`);
|
|
1676
1711
|
}
|
|
1677
1712
|
|
|
1713
|
+
// ============================
|
|
1714
|
+
// Navigation Helpers
|
|
1715
|
+
// ============================
|
|
1716
|
+
/**
|
|
1717
|
+
* Navigate to the Audit tab within the Analytics section.
|
|
1718
|
+
* Assumes the user is already on the analytics page (any tab).
|
|
1719
|
+
*/
|
|
1720
|
+
async function navigateToAuditLog(page) {
|
|
1721
|
+
const auditLogTab = page.getByRole('tab', { name: 'Audit' });
|
|
1722
|
+
await test$1.expect(auditLogTab).toBeVisible({ timeout: 60000 });
|
|
1723
|
+
await auditLogTab.click();
|
|
1724
|
+
await waitForPageReady(page);
|
|
1725
|
+
await safeWaitForURL(page, /\/analytics\/audit-log$/);
|
|
1726
|
+
logger.info('Successfully navigated to Audit page');
|
|
1727
|
+
}
|
|
1728
|
+
// ============================
|
|
1729
|
+
// Table Verification Helpers
|
|
1730
|
+
// ============================
|
|
1731
|
+
/**
|
|
1732
|
+
* Verify the audit log table is visible with correct headers.
|
|
1733
|
+
*/
|
|
1734
|
+
async function verifyAuditLogTableVisible(page) {
|
|
1735
|
+
const table = page.locator('table');
|
|
1736
|
+
await test$1.expect(table).toBeVisible({ timeout: 30000 });
|
|
1737
|
+
await test$1.expect(table.locator('th').filter({ hasText: 'Person' })).toBeVisible();
|
|
1738
|
+
await test$1.expect(table.locator('th').filter({ hasText: 'Action' })).toBeVisible();
|
|
1739
|
+
await test$1.expect(table.locator('th').filter({ hasText: 'Timestamp' })).toBeVisible();
|
|
1740
|
+
logger.info('Audit log table is visible with correct headers');
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1743
|
+
* Get the number of rows currently displayed in the audit log table.
|
|
1744
|
+
* Returns 0 if no table body rows are found.
|
|
1745
|
+
*/
|
|
1746
|
+
async function getAuditLogRowCount(page) {
|
|
1747
|
+
const rows = page.locator('table tbody tr');
|
|
1748
|
+
const count = await rows.count();
|
|
1749
|
+
logger.info(`Audit log table has ${count} rows`);
|
|
1750
|
+
return count;
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Verify that audit log entries contain expected data structure
|
|
1754
|
+
* (person name in first cell, action description in second, timestamp in third).
|
|
1755
|
+
*/
|
|
1756
|
+
async function verifyAuditLogEntryStructure(page) {
|
|
1757
|
+
const firstRow = page.locator('table tbody tr').first();
|
|
1758
|
+
await test$1.expect(firstRow).toBeVisible({ timeout: 30000 });
|
|
1759
|
+
const cells = firstRow.locator('td');
|
|
1760
|
+
const cellCount = await cells.count();
|
|
1761
|
+
test$1.expect(cellCount).toBe(3);
|
|
1762
|
+
// Person cell should have text content
|
|
1763
|
+
const personText = await cells.nth(0).textContent();
|
|
1764
|
+
test$1.expect(personText === null || personText === void 0 ? void 0 : personText.trim().length).toBeGreaterThan(0);
|
|
1765
|
+
// Action cell should have text content
|
|
1766
|
+
const actionText = await cells.nth(1).textContent();
|
|
1767
|
+
test$1.expect(actionText === null || actionText === void 0 ? void 0 : actionText.trim().length).toBeGreaterThan(0);
|
|
1768
|
+
// Timestamp cell should have text content
|
|
1769
|
+
const timestampText = await cells.nth(2).textContent();
|
|
1770
|
+
test$1.expect(timestampText === null || timestampText === void 0 ? void 0 : timestampText.trim().length).toBeGreaterThan(0);
|
|
1771
|
+
logger.info(`Audit log entry: Person="${personText === null || personText === void 0 ? void 0 : personText.trim()}", Action="${actionText === null || actionText === void 0 ? void 0 : actionText.trim()}", Timestamp="${timestampText === null || timestampText === void 0 ? void 0 : timestampText.trim()}"`);
|
|
1772
|
+
}
|
|
1773
|
+
// ============================
|
|
1774
|
+
// Empty & Error State Helpers
|
|
1775
|
+
// ============================
|
|
1776
|
+
/**
|
|
1777
|
+
* Verify the empty state is displayed when there are no audit log entries.
|
|
1778
|
+
*/
|
|
1779
|
+
async function verifyAuditLogEmptyState(page) {
|
|
1780
|
+
const emptyMessage = page.getByText('No audit log entries found for this tenant.');
|
|
1781
|
+
await test$1.expect(emptyMessage).toBeVisible({ timeout: 30000 });
|
|
1782
|
+
logger.info('Audit log empty state is displayed');
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Verify the 403 permission error state is displayed.
|
|
1786
|
+
*/
|
|
1787
|
+
async function verifyAuditLogPermissionError(page) {
|
|
1788
|
+
const errorMessage = page.getByText('You do not have permission to view audit logs.');
|
|
1789
|
+
await test$1.expect(errorMessage).toBeVisible({ timeout: 30000 });
|
|
1790
|
+
logger.info('Audit log permission error is displayed');
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Verify the generic error state is displayed.
|
|
1794
|
+
*/
|
|
1795
|
+
async function verifyAuditLogGenericError(page) {
|
|
1796
|
+
const errorMessage = page.getByText('An error occurred while loading audit logs.');
|
|
1797
|
+
await test$1.expect(errorMessage).toBeVisible({ timeout: 30000 });
|
|
1798
|
+
logger.info('Audit log generic error is displayed');
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Verify the loading spinner is displayed while audit logs are being fetched.
|
|
1802
|
+
*/
|
|
1803
|
+
async function verifyAuditLogLoading(page) {
|
|
1804
|
+
const spinner = page.locator('.animate-spin');
|
|
1805
|
+
await test$1.expect(spinner).toBeVisible({ timeout: 10000 });
|
|
1806
|
+
logger.info('Audit log loading spinner is displayed');
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Wait for the audit log data to finish loading.
|
|
1810
|
+
* Waits for either table data, empty state, or error state to appear.
|
|
1811
|
+
*/
|
|
1812
|
+
async function waitForAuditLogDataLoaded(page, timeout = 60000) {
|
|
1813
|
+
await page
|
|
1814
|
+
.locator('table tbody tr, [class*="empty"], [class*="error"]')
|
|
1815
|
+
.first()
|
|
1816
|
+
.waitFor({ state: 'visible', timeout })
|
|
1817
|
+
.catch(() => {
|
|
1818
|
+
// Also check for known text states
|
|
1819
|
+
});
|
|
1820
|
+
// Wait for spinner to disappear
|
|
1821
|
+
const spinner = page.locator('.animate-spin');
|
|
1822
|
+
const isSpinnerVisible = await spinner.isVisible().catch(() => false);
|
|
1823
|
+
if (isSpinnerVisible) {
|
|
1824
|
+
await test$1.expect(spinner).not.toBeVisible({ timeout });
|
|
1825
|
+
}
|
|
1826
|
+
logger.info('Audit log data has finished loading');
|
|
1827
|
+
}
|
|
1828
|
+
// ============================
|
|
1829
|
+
// Filter Interaction Helpers
|
|
1830
|
+
// ============================
|
|
1831
|
+
/**
|
|
1832
|
+
* Filter audit log entries by action type.
|
|
1833
|
+
* @param action - One of 'All Actions', 'Create', 'Update', or 'Delete'
|
|
1834
|
+
*/
|
|
1835
|
+
async function filterByAction(page, action) {
|
|
1836
|
+
const selectTrigger = page.locator('[role="combobox"][dir="ltr"]');
|
|
1837
|
+
await test$1.expect(selectTrigger).toBeVisible({ timeout: 10000 });
|
|
1838
|
+
await selectTrigger.click();
|
|
1839
|
+
const option = page.getByRole('option', { name: action });
|
|
1840
|
+
await test$1.expect(option).toBeVisible({ timeout: 5000 });
|
|
1841
|
+
await option.click();
|
|
1842
|
+
await waitForAuditLogDataLoaded(page);
|
|
1843
|
+
logger.info(`Filtered audit log by action: ${action}`);
|
|
1844
|
+
}
|
|
1845
|
+
/**
|
|
1846
|
+
* Filter audit log entries by actor/person using the search combobox.
|
|
1847
|
+
* @param actorName - The username to filter by, or empty string to clear the filter
|
|
1848
|
+
*/
|
|
1849
|
+
async function filterByActor(page, actorName) {
|
|
1850
|
+
const actorButton = page.getByLabel('Search for User');
|
|
1851
|
+
await test$1.expect(actorButton).toBeVisible({ timeout: 10000 });
|
|
1852
|
+
await actorButton.click();
|
|
1853
|
+
// Wait for the command popover to open
|
|
1854
|
+
const searchInput = page.getByPlaceholder('Search user...');
|
|
1855
|
+
await test$1.expect(searchInput).toBeVisible({ timeout: 5000 });
|
|
1856
|
+
if (actorName) {
|
|
1857
|
+
await searchInput.fill(actorName);
|
|
1858
|
+
// Select the matching actor from the dropdown
|
|
1859
|
+
const actorItem = page.locator('[cmdk-item]').filter({ hasText: actorName });
|
|
1860
|
+
await test$1.expect(actorItem).toBeVisible({ timeout: 5000 });
|
|
1861
|
+
await actorItem.click();
|
|
1862
|
+
}
|
|
1863
|
+
else {
|
|
1864
|
+
// Select "All Users" to clear the filter
|
|
1865
|
+
const allPeopleItem = page.locator('[cmdk-item]').filter({ hasText: 'All Users' });
|
|
1866
|
+
await test$1.expect(allPeopleItem).toBeVisible({ timeout: 5000 });
|
|
1867
|
+
await allPeopleItem.click();
|
|
1868
|
+
}
|
|
1869
|
+
await waitForAuditLogDataLoaded(page);
|
|
1870
|
+
logger.info(`Filtered audit log by actor: ${actorName || 'All Users'}`);
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Get the list of actors available in the actor filter dropdown.
|
|
1874
|
+
* Opens the dropdown, reads the options, then closes it.
|
|
1875
|
+
*/
|
|
1876
|
+
async function getAvailableActors(page) {
|
|
1877
|
+
const actorButton = page.getByLabel('Search for User');
|
|
1878
|
+
await test$1.expect(actorButton).toBeVisible({ timeout: 10000 });
|
|
1879
|
+
await actorButton.click();
|
|
1880
|
+
// Wait for the command popover
|
|
1881
|
+
await test$1.expect(page.getByPlaceholder('Search user...')).toBeVisible({ timeout: 5000 });
|
|
1882
|
+
const actorItems = page.locator('[cmdk-item] .font-medium.text-gray-700');
|
|
1883
|
+
const count = await actorItems.count();
|
|
1884
|
+
const actors = [];
|
|
1885
|
+
for (let i = 0; i < count; i++) {
|
|
1886
|
+
const text = await actorItems.nth(i).textContent();
|
|
1887
|
+
if (text)
|
|
1888
|
+
actors.push(text.trim());
|
|
1889
|
+
}
|
|
1890
|
+
// Close the dropdown by pressing Escape
|
|
1891
|
+
await page.keyboard.press('Escape');
|
|
1892
|
+
logger.info(`Available actors: ${actors.join(', ')}`);
|
|
1893
|
+
return actors;
|
|
1894
|
+
}
|
|
1895
|
+
/**
|
|
1896
|
+
* Open the date range picker and select a date range.
|
|
1897
|
+
* @param fromDate - Start date to select
|
|
1898
|
+
* @param toDate - End date to select
|
|
1899
|
+
*/
|
|
1900
|
+
async function filterByDateRange(page, fromDate, toDate) {
|
|
1901
|
+
const dateButton = page.getByRole('button', {
|
|
1902
|
+
name: /Pick a Date Range|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/,
|
|
1903
|
+
});
|
|
1904
|
+
await test$1.expect(dateButton).toBeVisible({ timeout: 10000 });
|
|
1905
|
+
await dateButton.click();
|
|
1906
|
+
// Wait for calendar to appear
|
|
1907
|
+
const calendar = page.locator('[role="grid"]').first();
|
|
1908
|
+
await test$1.expect(calendar).toBeVisible({ timeout: 5000 });
|
|
1909
|
+
// Select the from date
|
|
1910
|
+
const fromDay = String(fromDate.getDate());
|
|
1911
|
+
const fromButton = calendar.getByRole('gridcell', { name: fromDay, exact: true }).first();
|
|
1912
|
+
await fromButton.click();
|
|
1913
|
+
// Select the to date
|
|
1914
|
+
const toDay = String(toDate.getDate());
|
|
1915
|
+
const toButton = calendar.getByRole('gridcell', { name: toDay, exact: true }).first();
|
|
1916
|
+
await toButton.click();
|
|
1917
|
+
// Close by clicking outside
|
|
1918
|
+
await page.locator('body').click({ position: { x: 0, y: 0 } });
|
|
1919
|
+
await waitForAuditLogDataLoaded(page);
|
|
1920
|
+
logger.info(`Filtered audit log by date range: ${fromDate.toISOString().split('T')[0]} to ${toDate.toISOString().split('T')[0]}`);
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Clear the date range filter by clicking the date picker and resetting.
|
|
1924
|
+
*/
|
|
1925
|
+
async function clearDateRangeFilter(page) {
|
|
1926
|
+
const dateButton = page.getByRole('button', { name: /Pick a Date Range/ });
|
|
1927
|
+
// If button shows "Pick a Date Range", filter is already cleared
|
|
1928
|
+
const isCleared = await dateButton.isVisible().catch(() => false);
|
|
1929
|
+
if (isCleared) {
|
|
1930
|
+
logger.info('Date range filter is already cleared');
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
logger.info('Date range filter cleared');
|
|
1934
|
+
}
|
|
1935
|
+
// ============================
|
|
1936
|
+
// Pagination Helpers
|
|
1937
|
+
// ============================
|
|
1938
|
+
/**
|
|
1939
|
+
* Get the current pagination info text (e.g., "Showing 1 to 20 of 45 results").
|
|
1940
|
+
* Returns null if pagination is not visible.
|
|
1941
|
+
*/
|
|
1942
|
+
async function getPaginationInfo(page) {
|
|
1943
|
+
var _a;
|
|
1944
|
+
const paginationText = page.locator('.text-sm.text-gray-700');
|
|
1945
|
+
const isVisible = await paginationText.isVisible().catch(() => false);
|
|
1946
|
+
if (!isVisible) {
|
|
1947
|
+
logger.info('Pagination info is not visible (likely single page)');
|
|
1948
|
+
return null;
|
|
1949
|
+
}
|
|
1950
|
+
const text = await paginationText.textContent();
|
|
1951
|
+
logger.info(`Pagination info: ${text === null || text === void 0 ? void 0 : text.trim()}`);
|
|
1952
|
+
return (_a = text === null || text === void 0 ? void 0 : text.trim()) !== null && _a !== void 0 ? _a : null;
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Navigate to the next page of audit log results.
|
|
1956
|
+
*/
|
|
1957
|
+
async function goToNextPage(page) {
|
|
1958
|
+
const nextLink = page.getByRole('link', { name: 'Go to next page' });
|
|
1959
|
+
await test$1.expect(nextLink).toBeVisible({ timeout: 5000 });
|
|
1960
|
+
await nextLink.click();
|
|
1961
|
+
await waitForAuditLogDataLoaded(page);
|
|
1962
|
+
logger.info('Navigated to next page');
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Navigate to the previous page of audit log results.
|
|
1966
|
+
*/
|
|
1967
|
+
async function goToPreviousPage(page) {
|
|
1968
|
+
const prevLink = page.getByRole('link', { name: 'Go to previous page' });
|
|
1969
|
+
await test$1.expect(prevLink).toBeVisible({ timeout: 5000 });
|
|
1970
|
+
await prevLink.click();
|
|
1971
|
+
await waitForAuditLogDataLoaded(page);
|
|
1972
|
+
logger.info('Navigated to previous page');
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Navigate to the first page of audit log results.
|
|
1976
|
+
*/
|
|
1977
|
+
async function goToFirstPage(page) {
|
|
1978
|
+
await goToPage(page, 1);
|
|
1979
|
+
logger.info('Navigated to first page');
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Navigate to the last page of audit log results.
|
|
1983
|
+
* Finds the highest numbered page link in the pagination.
|
|
1984
|
+
*/
|
|
1985
|
+
async function goToLastPage(page) {
|
|
1986
|
+
const paginationNav = page.getByRole('navigation', { name: 'pagination' });
|
|
1987
|
+
await test$1.expect(paginationNav).toBeVisible({ timeout: 5000 });
|
|
1988
|
+
const pageLinks = paginationNav.getByRole('link');
|
|
1989
|
+
const count = await pageLinks.count();
|
|
1990
|
+
// The last numeric link before "Next" is the last page
|
|
1991
|
+
let lastPageNum = 1;
|
|
1992
|
+
for (let i = 0; i < count; i++) {
|
|
1993
|
+
const text = await pageLinks.nth(i).textContent();
|
|
1994
|
+
const num = Number(text === null || text === void 0 ? void 0 : text.trim());
|
|
1995
|
+
if (!isNaN(num) && num > lastPageNum) {
|
|
1996
|
+
lastPageNum = num;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
await goToPage(page, lastPageNum);
|
|
2000
|
+
logger.info(`Navigated to last page (${lastPageNum})`);
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Navigate to a specific page number by clicking its page button.
|
|
2004
|
+
*/
|
|
2005
|
+
async function goToPage(page, pageNumber) {
|
|
2006
|
+
const pageLink = page
|
|
2007
|
+
.getByRole('navigation', { name: 'pagination' })
|
|
2008
|
+
.getByRole('link', { name: String(pageNumber), exact: true });
|
|
2009
|
+
await test$1.expect(pageLink).toBeVisible({ timeout: 5000 });
|
|
2010
|
+
await pageLink.click();
|
|
2011
|
+
await waitForAuditLogDataLoaded(page);
|
|
2012
|
+
logger.info(`Navigated to page ${pageNumber}`);
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Verify the current page is highlighted/active in pagination.
|
|
2016
|
+
*/
|
|
2017
|
+
async function verifyCurrentPage(page, expectedPage) {
|
|
2018
|
+
const pageLink = page
|
|
2019
|
+
.getByRole('navigation', { name: 'pagination' })
|
|
2020
|
+
.getByRole('link', { name: String(expectedPage), exact: true });
|
|
2021
|
+
await test$1.expect(pageLink).toBeVisible({ timeout: 5000 });
|
|
2022
|
+
await test$1.expect(pageLink).toHaveClass(/bg-blue-500/);
|
|
2023
|
+
logger.info(`Verified current page is ${expectedPage}`);
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
2026
|
+
* Check if the next page button is disabled (i.e., we're on the last page).
|
|
2027
|
+
*/
|
|
2028
|
+
async function isOnLastPage(page) {
|
|
2029
|
+
const nextLink = page.getByRole('link', { name: 'Go to next page' });
|
|
2030
|
+
const hasDisabledClass = await nextLink
|
|
2031
|
+
.evaluate((el) => el.classList.contains('pointer-events-none'))
|
|
2032
|
+
.catch(() => true);
|
|
2033
|
+
return hasDisabledClass;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Check if the previous page button is disabled (i.e., we're on the first page).
|
|
2037
|
+
*/
|
|
2038
|
+
async function isOnFirstPage(page) {
|
|
2039
|
+
const prevLink = page.getByRole('link', { name: 'Go to previous page' });
|
|
2040
|
+
const hasDisabledClass = await prevLink
|
|
2041
|
+
.evaluate((el) => el.classList.contains('pointer-events-none'))
|
|
2042
|
+
.catch(() => true);
|
|
2043
|
+
return hasDisabledClass;
|
|
2044
|
+
}
|
|
2045
|
+
// ============================
|
|
2046
|
+
// Combined Workflow Helpers
|
|
2047
|
+
// ============================
|
|
2048
|
+
/**
|
|
2049
|
+
* Full workflow: Navigate to audit log tab, wait for data to load,
|
|
2050
|
+
* and verify the table is visible. Use this as a test setup helper.
|
|
2051
|
+
*/
|
|
2052
|
+
async function navigateToAuditLogAndWaitForData(page) {
|
|
2053
|
+
await navigateToAuditLog(page);
|
|
2054
|
+
await waitForAuditLogDataLoaded(page);
|
|
2055
|
+
logger.info('Audit log page ready with data loaded');
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Verify audit log entries are displayed after applying action filter.
|
|
2059
|
+
* Returns the row count after filtering.
|
|
2060
|
+
*/
|
|
2061
|
+
async function filterByActionAndVerify(page, action) {
|
|
2062
|
+
await filterByAction(page, action);
|
|
2063
|
+
const count = await getAuditLogRowCount(page);
|
|
2064
|
+
logger.info(`After filtering by "${action}": ${count} entries found`);
|
|
2065
|
+
return count;
|
|
2066
|
+
}
|
|
2067
|
+
/**
|
|
2068
|
+
* Verify audit log entries are displayed after applying actor filter.
|
|
2069
|
+
* Returns the row count after filtering.
|
|
2070
|
+
*/
|
|
2071
|
+
async function filterByActorAndVerify(page, actorName) {
|
|
2072
|
+
await filterByActor(page, actorName);
|
|
2073
|
+
const count = await getAuditLogRowCount(page);
|
|
2074
|
+
logger.info(`After filtering by actor "${actorName}": ${count} entries found`);
|
|
2075
|
+
return count;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
1678
2078
|
/** Extract browser key from device name (e.g., 'Desktop Chrome' -> 'chrome') */
|
|
1679
2079
|
function getBrowserKey(deviceName) {
|
|
1680
2080
|
return deviceName.toLowerCase().replace(/^desktop\s+/, '');
|
|
@@ -1813,6 +2213,7 @@ exports.archiveMemoryByContent = archiveMemoryByContent;
|
|
|
1813
2213
|
exports.buildReportUrl = buildReportUrl;
|
|
1814
2214
|
exports.canChatWithEmbedMentor = canChatWithEmbedMentor;
|
|
1815
2215
|
exports.checkAdminStatus = checkAdminStatus;
|
|
2216
|
+
exports.clearDateRangeFilter = clearDateRangeFilter;
|
|
1816
2217
|
exports.clickBackHome = clickBackHome;
|
|
1817
2218
|
exports.clickDownloadAgain = clickDownloadAgain;
|
|
1818
2219
|
exports.clickManualDownloadLink = clickManualDownloadLink;
|
|
@@ -1824,19 +2225,36 @@ exports.deleteFirstMemory = deleteFirstMemory;
|
|
|
1824
2225
|
exports.deleteMemoryByContent = deleteMemoryByContent;
|
|
1825
2226
|
exports.expectNoAccessibilityViolations = expectNoAccessibilityViolations;
|
|
1826
2227
|
exports.expectNoAccessibilityViolationsOnDialogs = expectNoAccessibilityViolationsOnDialogs;
|
|
2228
|
+
exports.filterByAction = filterByAction;
|
|
2229
|
+
exports.filterByActionAndVerify = filterByActionAndVerify;
|
|
2230
|
+
exports.filterByActor = filterByActor;
|
|
2231
|
+
exports.filterByActorAndVerify = filterByActorAndVerify;
|
|
2232
|
+
exports.filterByDateRange = filterByDateRange;
|
|
1827
2233
|
exports.generateBrowserSetupProjects = generateBrowserSetupProjects;
|
|
1828
2234
|
exports.generateProjectConfig = generateProjectConfig;
|
|
2235
|
+
exports.getAuditLogRowCount = getAuditLogRowCount;
|
|
2236
|
+
exports.getAvailableActors = getAvailableActors;
|
|
1829
2237
|
exports.getBrowserKey = getBrowserKey;
|
|
1830
2238
|
exports.getMemoryCount = getMemoryCount;
|
|
1831
2239
|
exports.getMentorIdFromUrl = getMentorIdFromUrl;
|
|
2240
|
+
exports.getPaginationInfo = getPaginationInfo;
|
|
2241
|
+
exports.goToFirstPage = goToFirstPage;
|
|
2242
|
+
exports.goToLastPage = goToLastPage;
|
|
2243
|
+
exports.goToNextPage = goToNextPage;
|
|
2244
|
+
exports.goToPage = goToPage;
|
|
2245
|
+
exports.goToPreviousPage = goToPreviousPage;
|
|
1832
2246
|
exports.inviteUserTest = inviteUserTest;
|
|
1833
2247
|
exports.isFirefox = isFirefox;
|
|
1834
2248
|
exports.isJSON = isJSON;
|
|
1835
2249
|
exports.isMemoryTabVisible = isMemoryTabVisible;
|
|
2250
|
+
exports.isOnFirstPage = isOnFirstPage;
|
|
2251
|
+
exports.isOnLastPage = isOnLastPage;
|
|
1836
2252
|
exports.logger = logger;
|
|
1837
2253
|
exports.loginWithEmailAndPassword = loginWithEmailAndPassword;
|
|
1838
2254
|
exports.loginWithMicrosoftIdp = loginWithMicrosoftIdp;
|
|
1839
2255
|
exports.navigateToAccountComponent = navigateToAccountComponent;
|
|
2256
|
+
exports.navigateToAuditLog = navigateToAuditLog;
|
|
2257
|
+
exports.navigateToAuditLogAndWaitForData = navigateToAuditLogAndWaitForData;
|
|
1840
2258
|
exports.navigateToDataReports = navigateToDataReports;
|
|
1841
2259
|
exports.navigateToReportDownload = navigateToReportDownload;
|
|
1842
2260
|
exports.openAddMemoryDialog = openAddMemoryDialog;
|
|
@@ -1866,6 +2284,13 @@ exports.signUpWithEmailAndPassword = signUpWithEmailAndPassword;
|
|
|
1866
2284
|
exports.switchToMemoryTab = switchToMemoryTab;
|
|
1867
2285
|
exports.test = test;
|
|
1868
2286
|
exports.toggleMemorySwitch = toggleMemorySwitch;
|
|
2287
|
+
exports.verifyAuditLogEmptyState = verifyAuditLogEmptyState;
|
|
2288
|
+
exports.verifyAuditLogEntryStructure = verifyAuditLogEntryStructure;
|
|
2289
|
+
exports.verifyAuditLogGenericError = verifyAuditLogGenericError;
|
|
2290
|
+
exports.verifyAuditLogLoading = verifyAuditLogLoading;
|
|
2291
|
+
exports.verifyAuditLogPermissionError = verifyAuditLogPermissionError;
|
|
2292
|
+
exports.verifyAuditLogTableVisible = verifyAuditLogTableVisible;
|
|
2293
|
+
exports.verifyCurrentPage = verifyCurrentPage;
|
|
1869
2294
|
exports.verifyDonePhase = verifyDonePhase;
|
|
1870
2295
|
exports.verifyDownloadingPhase = verifyDownloadingPhase;
|
|
1871
2296
|
exports.verifyErrorPhase = verifyErrorPhase;
|
|
@@ -1874,6 +2299,7 @@ exports.verifyMemoryNotExists = verifyMemoryNotExists;
|
|
|
1874
2299
|
exports.verifyMemoryTabMemoriesList = verifyMemoryTabMemoriesList;
|
|
1875
2300
|
exports.verifyMemoryTabSettings = verifyMemoryTabSettings;
|
|
1876
2301
|
exports.verifyPreparingPhase = verifyPreparingPhase;
|
|
2302
|
+
exports.waitForAuditLogDataLoaded = waitForAuditLogDataLoaded;
|
|
1877
2303
|
exports.waitForDialogReady = waitForDialogReady;
|
|
1878
2304
|
exports.waitForElementStable = waitForElementStable;
|
|
1879
2305
|
exports.waitForPageLoad = waitForPageLoad;
|