@iblai/iblai-js 1.4.3 → 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.
@@ -1709,6 +1709,371 @@ async function verifyMemoryNotExists(page, content) {
1709
1709
  logger.info(`Verified memory removed: "${content}"`);
1710
1710
  }
1711
1711
 
1712
+ // ============================
1713
+ // Navigation Helpers
1714
+ // ============================
1715
+ /**
1716
+ * Navigate to the Audit tab within the Analytics section.
1717
+ * Assumes the user is already on the analytics page (any tab).
1718
+ */
1719
+ async function navigateToAuditLog(page) {
1720
+ const auditLogTab = page.getByRole('tab', { name: 'Audit' });
1721
+ await expect(auditLogTab).toBeVisible({ timeout: 60000 });
1722
+ await auditLogTab.click();
1723
+ await waitForPageReady(page);
1724
+ await safeWaitForURL(page, /\/analytics\/audit-log$/);
1725
+ logger.info('Successfully navigated to Audit page');
1726
+ }
1727
+ // ============================
1728
+ // Table Verification Helpers
1729
+ // ============================
1730
+ /**
1731
+ * Verify the audit log table is visible with correct headers.
1732
+ */
1733
+ async function verifyAuditLogTableVisible(page) {
1734
+ const table = page.locator('table');
1735
+ await expect(table).toBeVisible({ timeout: 30000 });
1736
+ await expect(table.locator('th').filter({ hasText: 'Person' })).toBeVisible();
1737
+ await expect(table.locator('th').filter({ hasText: 'Action' })).toBeVisible();
1738
+ await expect(table.locator('th').filter({ hasText: 'Timestamp' })).toBeVisible();
1739
+ logger.info('Audit log table is visible with correct headers');
1740
+ }
1741
+ /**
1742
+ * Get the number of rows currently displayed in the audit log table.
1743
+ * Returns 0 if no table body rows are found.
1744
+ */
1745
+ async function getAuditLogRowCount(page) {
1746
+ const rows = page.locator('table tbody tr');
1747
+ const count = await rows.count();
1748
+ logger.info(`Audit log table has ${count} rows`);
1749
+ return count;
1750
+ }
1751
+ /**
1752
+ * Verify that audit log entries contain expected data structure
1753
+ * (person name in first cell, action description in second, timestamp in third).
1754
+ */
1755
+ async function verifyAuditLogEntryStructure(page) {
1756
+ const firstRow = page.locator('table tbody tr').first();
1757
+ await expect(firstRow).toBeVisible({ timeout: 30000 });
1758
+ const cells = firstRow.locator('td');
1759
+ const cellCount = await cells.count();
1760
+ expect(cellCount).toBe(3);
1761
+ // Person cell should have text content
1762
+ const personText = await cells.nth(0).textContent();
1763
+ expect(personText === null || personText === void 0 ? void 0 : personText.trim().length).toBeGreaterThan(0);
1764
+ // Action cell should have text content
1765
+ const actionText = await cells.nth(1).textContent();
1766
+ expect(actionText === null || actionText === void 0 ? void 0 : actionText.trim().length).toBeGreaterThan(0);
1767
+ // Timestamp cell should have text content
1768
+ const timestampText = await cells.nth(2).textContent();
1769
+ expect(timestampText === null || timestampText === void 0 ? void 0 : timestampText.trim().length).toBeGreaterThan(0);
1770
+ 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()}"`);
1771
+ }
1772
+ // ============================
1773
+ // Empty & Error State Helpers
1774
+ // ============================
1775
+ /**
1776
+ * Verify the empty state is displayed when there are no audit log entries.
1777
+ */
1778
+ async function verifyAuditLogEmptyState(page) {
1779
+ const emptyMessage = page.getByText('No audit log entries found for this tenant.');
1780
+ await expect(emptyMessage).toBeVisible({ timeout: 30000 });
1781
+ logger.info('Audit log empty state is displayed');
1782
+ }
1783
+ /**
1784
+ * Verify the 403 permission error state is displayed.
1785
+ */
1786
+ async function verifyAuditLogPermissionError(page) {
1787
+ const errorMessage = page.getByText('You do not have permission to view audit logs.');
1788
+ await expect(errorMessage).toBeVisible({ timeout: 30000 });
1789
+ logger.info('Audit log permission error is displayed');
1790
+ }
1791
+ /**
1792
+ * Verify the generic error state is displayed.
1793
+ */
1794
+ async function verifyAuditLogGenericError(page) {
1795
+ const errorMessage = page.getByText('An error occurred while loading audit logs.');
1796
+ await expect(errorMessage).toBeVisible({ timeout: 30000 });
1797
+ logger.info('Audit log generic error is displayed');
1798
+ }
1799
+ /**
1800
+ * Verify the loading spinner is displayed while audit logs are being fetched.
1801
+ */
1802
+ async function verifyAuditLogLoading(page) {
1803
+ const spinner = page.locator('.animate-spin');
1804
+ await expect(spinner).toBeVisible({ timeout: 10000 });
1805
+ logger.info('Audit log loading spinner is displayed');
1806
+ }
1807
+ /**
1808
+ * Wait for the audit log data to finish loading.
1809
+ * Waits for either table data, empty state, or error state to appear.
1810
+ */
1811
+ async function waitForAuditLogDataLoaded(page, timeout = 60000) {
1812
+ await page
1813
+ .locator('table tbody tr, [class*="empty"], [class*="error"]')
1814
+ .first()
1815
+ .waitFor({ state: 'visible', timeout })
1816
+ .catch(() => {
1817
+ // Also check for known text states
1818
+ });
1819
+ // Wait for spinner to disappear
1820
+ const spinner = page.locator('.animate-spin');
1821
+ const isSpinnerVisible = await spinner.isVisible().catch(() => false);
1822
+ if (isSpinnerVisible) {
1823
+ await expect(spinner).not.toBeVisible({ timeout });
1824
+ }
1825
+ logger.info('Audit log data has finished loading');
1826
+ }
1827
+ // ============================
1828
+ // Filter Interaction Helpers
1829
+ // ============================
1830
+ /**
1831
+ * Filter audit log entries by action type.
1832
+ * @param action - One of 'All Actions', 'Create', 'Update', or 'Delete'
1833
+ */
1834
+ async function filterByAction(page, action) {
1835
+ const selectTrigger = page.locator('[role="combobox"][dir="ltr"]');
1836
+ await expect(selectTrigger).toBeVisible({ timeout: 10000 });
1837
+ await selectTrigger.click();
1838
+ const option = page.getByRole('option', { name: action });
1839
+ await expect(option).toBeVisible({ timeout: 5000 });
1840
+ await option.click();
1841
+ await waitForAuditLogDataLoaded(page);
1842
+ logger.info(`Filtered audit log by action: ${action}`);
1843
+ }
1844
+ /**
1845
+ * Filter audit log entries by actor/person using the search combobox.
1846
+ * @param actorName - The username to filter by, or empty string to clear the filter
1847
+ */
1848
+ async function filterByActor(page, actorName) {
1849
+ const actorButton = page.getByLabel('Search for User');
1850
+ await expect(actorButton).toBeVisible({ timeout: 10000 });
1851
+ await actorButton.click();
1852
+ // Wait for the command popover to open
1853
+ const searchInput = page.getByPlaceholder('Search user...');
1854
+ await expect(searchInput).toBeVisible({ timeout: 5000 });
1855
+ if (actorName) {
1856
+ await searchInput.fill(actorName);
1857
+ // Select the matching actor from the dropdown
1858
+ const actorItem = page.locator('[cmdk-item]').filter({ hasText: actorName });
1859
+ await expect(actorItem).toBeVisible({ timeout: 5000 });
1860
+ await actorItem.click();
1861
+ }
1862
+ else {
1863
+ // Select "All Users" to clear the filter
1864
+ const allPeopleItem = page.locator('[cmdk-item]').filter({ hasText: 'All Users' });
1865
+ await expect(allPeopleItem).toBeVisible({ timeout: 5000 });
1866
+ await allPeopleItem.click();
1867
+ }
1868
+ await waitForAuditLogDataLoaded(page);
1869
+ logger.info(`Filtered audit log by actor: ${actorName || 'All Users'}`);
1870
+ }
1871
+ /**
1872
+ * Get the list of actors available in the actor filter dropdown.
1873
+ * Opens the dropdown, reads the options, then closes it.
1874
+ */
1875
+ async function getAvailableActors(page) {
1876
+ const actorButton = page.getByLabel('Search for User');
1877
+ await expect(actorButton).toBeVisible({ timeout: 10000 });
1878
+ await actorButton.click();
1879
+ // Wait for the command popover
1880
+ await expect(page.getByPlaceholder('Search user...')).toBeVisible({ timeout: 5000 });
1881
+ const actorItems = page.locator('[cmdk-item] .font-medium.text-gray-700');
1882
+ const count = await actorItems.count();
1883
+ const actors = [];
1884
+ for (let i = 0; i < count; i++) {
1885
+ const text = await actorItems.nth(i).textContent();
1886
+ if (text)
1887
+ actors.push(text.trim());
1888
+ }
1889
+ // Close the dropdown by pressing Escape
1890
+ await page.keyboard.press('Escape');
1891
+ logger.info(`Available actors: ${actors.join(', ')}`);
1892
+ return actors;
1893
+ }
1894
+ /**
1895
+ * Open the date range picker and select a date range.
1896
+ * @param fromDate - Start date to select
1897
+ * @param toDate - End date to select
1898
+ */
1899
+ async function filterByDateRange(page, fromDate, toDate) {
1900
+ const dateButton = page.getByRole('button', {
1901
+ name: /Pick a Date Range|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/,
1902
+ });
1903
+ await expect(dateButton).toBeVisible({ timeout: 10000 });
1904
+ await dateButton.click();
1905
+ // Wait for calendar to appear
1906
+ const calendar = page.locator('[role="grid"]').first();
1907
+ await expect(calendar).toBeVisible({ timeout: 5000 });
1908
+ // Select the from date
1909
+ const fromDay = String(fromDate.getDate());
1910
+ const fromButton = calendar.getByRole('gridcell', { name: fromDay, exact: true }).first();
1911
+ await fromButton.click();
1912
+ // Select the to date
1913
+ const toDay = String(toDate.getDate());
1914
+ const toButton = calendar.getByRole('gridcell', { name: toDay, exact: true }).first();
1915
+ await toButton.click();
1916
+ // Close by clicking outside
1917
+ await page.locator('body').click({ position: { x: 0, y: 0 } });
1918
+ await waitForAuditLogDataLoaded(page);
1919
+ logger.info(`Filtered audit log by date range: ${fromDate.toISOString().split('T')[0]} to ${toDate.toISOString().split('T')[0]}`);
1920
+ }
1921
+ /**
1922
+ * Clear the date range filter by clicking the date picker and resetting.
1923
+ */
1924
+ async function clearDateRangeFilter(page) {
1925
+ const dateButton = page.getByRole('button', { name: /Pick a Date Range/ });
1926
+ // If button shows "Pick a Date Range", filter is already cleared
1927
+ const isCleared = await dateButton.isVisible().catch(() => false);
1928
+ if (isCleared) {
1929
+ logger.info('Date range filter is already cleared');
1930
+ return;
1931
+ }
1932
+ logger.info('Date range filter cleared');
1933
+ }
1934
+ // ============================
1935
+ // Pagination Helpers
1936
+ // ============================
1937
+ /**
1938
+ * Get the current pagination info text (e.g., "Showing 1 to 20 of 45 results").
1939
+ * Returns null if pagination is not visible.
1940
+ */
1941
+ async function getPaginationInfo(page) {
1942
+ var _a;
1943
+ const paginationText = page.locator('.text-sm.text-gray-700');
1944
+ const isVisible = await paginationText.isVisible().catch(() => false);
1945
+ if (!isVisible) {
1946
+ logger.info('Pagination info is not visible (likely single page)');
1947
+ return null;
1948
+ }
1949
+ const text = await paginationText.textContent();
1950
+ logger.info(`Pagination info: ${text === null || text === void 0 ? void 0 : text.trim()}`);
1951
+ return (_a = text === null || text === void 0 ? void 0 : text.trim()) !== null && _a !== void 0 ? _a : null;
1952
+ }
1953
+ /**
1954
+ * Navigate to the next page of audit log results.
1955
+ */
1956
+ async function goToNextPage(page) {
1957
+ const nextLink = page.getByRole('link', { name: 'Go to next page' });
1958
+ await expect(nextLink).toBeVisible({ timeout: 5000 });
1959
+ await nextLink.click();
1960
+ await waitForAuditLogDataLoaded(page);
1961
+ logger.info('Navigated to next page');
1962
+ }
1963
+ /**
1964
+ * Navigate to the previous page of audit log results.
1965
+ */
1966
+ async function goToPreviousPage(page) {
1967
+ const prevLink = page.getByRole('link', { name: 'Go to previous page' });
1968
+ await expect(prevLink).toBeVisible({ timeout: 5000 });
1969
+ await prevLink.click();
1970
+ await waitForAuditLogDataLoaded(page);
1971
+ logger.info('Navigated to previous page');
1972
+ }
1973
+ /**
1974
+ * Navigate to the first page of audit log results.
1975
+ */
1976
+ async function goToFirstPage(page) {
1977
+ await goToPage(page, 1);
1978
+ logger.info('Navigated to first page');
1979
+ }
1980
+ /**
1981
+ * Navigate to the last page of audit log results.
1982
+ * Finds the highest numbered page link in the pagination.
1983
+ */
1984
+ async function goToLastPage(page) {
1985
+ const paginationNav = page.getByRole('navigation', { name: 'pagination' });
1986
+ await expect(paginationNav).toBeVisible({ timeout: 5000 });
1987
+ const pageLinks = paginationNav.getByRole('link');
1988
+ const count = await pageLinks.count();
1989
+ // The last numeric link before "Next" is the last page
1990
+ let lastPageNum = 1;
1991
+ for (let i = 0; i < count; i++) {
1992
+ const text = await pageLinks.nth(i).textContent();
1993
+ const num = Number(text === null || text === void 0 ? void 0 : text.trim());
1994
+ if (!isNaN(num) && num > lastPageNum) {
1995
+ lastPageNum = num;
1996
+ }
1997
+ }
1998
+ await goToPage(page, lastPageNum);
1999
+ logger.info(`Navigated to last page (${lastPageNum})`);
2000
+ }
2001
+ /**
2002
+ * Navigate to a specific page number by clicking its page button.
2003
+ */
2004
+ async function goToPage(page, pageNumber) {
2005
+ const pageLink = page
2006
+ .getByRole('navigation', { name: 'pagination' })
2007
+ .getByRole('link', { name: String(pageNumber), exact: true });
2008
+ await expect(pageLink).toBeVisible({ timeout: 5000 });
2009
+ await pageLink.click();
2010
+ await waitForAuditLogDataLoaded(page);
2011
+ logger.info(`Navigated to page ${pageNumber}`);
2012
+ }
2013
+ /**
2014
+ * Verify the current page is highlighted/active in pagination.
2015
+ */
2016
+ async function verifyCurrentPage(page, expectedPage) {
2017
+ const pageLink = page
2018
+ .getByRole('navigation', { name: 'pagination' })
2019
+ .getByRole('link', { name: String(expectedPage), exact: true });
2020
+ await expect(pageLink).toBeVisible({ timeout: 5000 });
2021
+ await expect(pageLink).toHaveClass(/bg-blue-500/);
2022
+ logger.info(`Verified current page is ${expectedPage}`);
2023
+ }
2024
+ /**
2025
+ * Check if the next page button is disabled (i.e., we're on the last page).
2026
+ */
2027
+ async function isOnLastPage(page) {
2028
+ const nextLink = page.getByRole('link', { name: 'Go to next page' });
2029
+ const hasDisabledClass = await nextLink
2030
+ .evaluate((el) => el.classList.contains('pointer-events-none'))
2031
+ .catch(() => true);
2032
+ return hasDisabledClass;
2033
+ }
2034
+ /**
2035
+ * Check if the previous page button is disabled (i.e., we're on the first page).
2036
+ */
2037
+ async function isOnFirstPage(page) {
2038
+ const prevLink = page.getByRole('link', { name: 'Go to previous page' });
2039
+ const hasDisabledClass = await prevLink
2040
+ .evaluate((el) => el.classList.contains('pointer-events-none'))
2041
+ .catch(() => true);
2042
+ return hasDisabledClass;
2043
+ }
2044
+ // ============================
2045
+ // Combined Workflow Helpers
2046
+ // ============================
2047
+ /**
2048
+ * Full workflow: Navigate to audit log tab, wait for data to load,
2049
+ * and verify the table is visible. Use this as a test setup helper.
2050
+ */
2051
+ async function navigateToAuditLogAndWaitForData(page) {
2052
+ await navigateToAuditLog(page);
2053
+ await waitForAuditLogDataLoaded(page);
2054
+ logger.info('Audit log page ready with data loaded');
2055
+ }
2056
+ /**
2057
+ * Verify audit log entries are displayed after applying action filter.
2058
+ * Returns the row count after filtering.
2059
+ */
2060
+ async function filterByActionAndVerify(page, action) {
2061
+ await filterByAction(page, action);
2062
+ const count = await getAuditLogRowCount(page);
2063
+ logger.info(`After filtering by "${action}": ${count} entries found`);
2064
+ return count;
2065
+ }
2066
+ /**
2067
+ * Verify audit log entries are displayed after applying actor filter.
2068
+ * Returns the row count after filtering.
2069
+ */
2070
+ async function filterByActorAndVerify(page, actorName) {
2071
+ await filterByActor(page, actorName);
2072
+ const count = await getAuditLogRowCount(page);
2073
+ logger.info(`After filtering by actor "${actorName}": ${count} entries found`);
2074
+ return count;
2075
+ }
2076
+
1712
2077
  /** Extract browser key from device name (e.g., 'Desktop Chrome' -> 'chrome') */
1713
2078
  function getBrowserKey(deviceName) {
1714
2079
  return deviceName.toLowerCase().replace(/^desktop\s+/, '');
@@ -1834,5 +2199,5 @@ function createPlaywrightConfig(options) {
1834
2199
  });
1835
2200
  }
1836
2201
 
1837
- export { AuthFlowBuilder, CustomReporter, MailsacClient, addMemory, archiveFirstMemory, archiveMemoryByContent, buildReportUrl, canChatWithEmbedMentor, checkAdminStatus, clickBackHome, clickDownloadAgain, clickManualDownloadLink, closeWithEsc, createAuthSetup, createEnvConfig, createPlaywrightConfig, deleteFirstMemory, deleteMemoryByContent, expectNoAccessibilityViolations, expectNoAccessibilityViolationsOnDialogs, generateBrowserSetupProjects, generateProjectConfig, getBrowserKey, getMemoryCount, getMentorIdFromUrl, inviteUserTest, isFirefox, isJSON, isMemoryTabVisible, logger, loginWithEmailAndPassword, loginWithMicrosoftIdp, navigateToAccountComponent, navigateToDataReports, navigateToReportDownload, openAddMemoryDialog, parseReportUrlParams, reliableClick, reliableFill, retry, safeWaitForURL, selectDateFromCalendar, shouldAddNewRowWhenClickingAddRowButton, shouldAllowEditingCellValuesInCSVEditor, shouldCancelCombiningReports, shouldCloseCSVEditorWhenClickingCloseButton, shouldCloseCSVEditorWithoutSavingWhenClickingCancel, shouldCombineRecommendationReports, shouldDirectlyDownloadChatHistoryReportWithoutCSVEditor, shouldDisableOtherDownloadButtonsWhileGeneratingReport, shouldDisplayCSVInEditableTableFormat, shouldDisplayReportCards, shouldHaveCombinedReportDataTestIds, shouldOpenCSVEditorDialog, shouldOpenCSVEditorForUserMetadataReport, shouldSaveEditedCSVAndTriggerDownload, shouldShowCombiningReportsDialog, shouldVerifyCSVEditorDialogAccessibility, signUpWithEmailAndPassword, switchToMemoryTab, test, toggleMemorySwitch, verifyDonePhase, verifyDownloadingPhase, verifyErrorPhase, verifyMemoryExists, verifyMemoryNotExists, verifyMemoryTabMemoriesList, verifyMemoryTabSettings, verifyPreparingPhase, waitForDialogReady, waitForElementStable, waitForPageLoad, waitForPageReady, waitForReportDownload };
2202
+ export { AuthFlowBuilder, CustomReporter, MailsacClient, addMemory, archiveFirstMemory, archiveMemoryByContent, buildReportUrl, canChatWithEmbedMentor, checkAdminStatus, clearDateRangeFilter, clickBackHome, clickDownloadAgain, clickManualDownloadLink, closeWithEsc, createAuthSetup, createEnvConfig, createPlaywrightConfig, deleteFirstMemory, deleteMemoryByContent, expectNoAccessibilityViolations, expectNoAccessibilityViolationsOnDialogs, filterByAction, filterByActionAndVerify, filterByActor, filterByActorAndVerify, filterByDateRange, generateBrowserSetupProjects, generateProjectConfig, getAuditLogRowCount, getAvailableActors, getBrowserKey, getMemoryCount, getMentorIdFromUrl, getPaginationInfo, goToFirstPage, goToLastPage, goToNextPage, goToPage, goToPreviousPage, inviteUserTest, isFirefox, isJSON, isMemoryTabVisible, isOnFirstPage, isOnLastPage, logger, loginWithEmailAndPassword, loginWithMicrosoftIdp, navigateToAccountComponent, navigateToAuditLog, navigateToAuditLogAndWaitForData, navigateToDataReports, navigateToReportDownload, openAddMemoryDialog, parseReportUrlParams, reliableClick, reliableFill, retry, safeWaitForURL, selectDateFromCalendar, shouldAddNewRowWhenClickingAddRowButton, shouldAllowEditingCellValuesInCSVEditor, shouldCancelCombiningReports, shouldCloseCSVEditorWhenClickingCloseButton, shouldCloseCSVEditorWithoutSavingWhenClickingCancel, shouldCombineRecommendationReports, shouldDirectlyDownloadChatHistoryReportWithoutCSVEditor, shouldDisableOtherDownloadButtonsWhileGeneratingReport, shouldDisplayCSVInEditableTableFormat, shouldDisplayReportCards, shouldHaveCombinedReportDataTestIds, shouldOpenCSVEditorDialog, shouldOpenCSVEditorForUserMetadataReport, shouldSaveEditedCSVAndTriggerDownload, shouldShowCombiningReportsDialog, shouldVerifyCSVEditorDialogAccessibility, signUpWithEmailAndPassword, switchToMemoryTab, test, toggleMemorySwitch, verifyAuditLogEmptyState, verifyAuditLogEntryStructure, verifyAuditLogGenericError, verifyAuditLogLoading, verifyAuditLogPermissionError, verifyAuditLogTableVisible, verifyCurrentPage, verifyDonePhase, verifyDownloadingPhase, verifyErrorPhase, verifyMemoryExists, verifyMemoryNotExists, verifyMemoryTabMemoriesList, verifyMemoryTabSettings, verifyPreparingPhase, waitForAuditLogDataLoaded, waitForDialogReady, waitForElementStable, waitForPageLoad, waitForPageReady, waitForReportDownload };
1838
2203
  //# sourceMappingURL=index.esm.js.map