{log?.id &&
}
{log?.timestamp && (
-
+
)}
{log?.event_message && (
diff --git a/tests/local-studio-tests/playwright.config.ts b/tests/local-studio-tests/playwright.config.ts
index 2568a2cdcee..b3a260763ef 100644
--- a/tests/local-studio-tests/playwright.config.ts
+++ b/tests/local-studio-tests/playwright.config.ts
@@ -30,13 +30,18 @@ export default defineConfig({
trace: 'on-first-retry',
// record a video for failed tests, but only for local testing. We can't store videos on CI atm.
video: 'retain-on-failure',
+ launchOptions: {
+ env: {
+ NODE_ENV: 'test',
+ },
+ },
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
+ use: { ...devices['Desktop Chrome'], viewport: { width: 1366, height: 768 } },
},
// {
diff --git a/tests/local-studio-tests/tests/snapshot/spec/logs.spec.ts b/tests/local-studio-tests/tests/snapshot/spec/logs.spec.ts
new file mode 100644
index 00000000000..ab7c8f5b37b
--- /dev/null
+++ b/tests/local-studio-tests/tests/snapshot/spec/logs.spec.ts
@@ -0,0 +1,81 @@
+import { test, expect } from '@playwright/test'
+
+const LOGS_PAGES = [
+ 'API Gateway',
+ 'Postgres',
+ 'PostgREST',
+ // 'Auth', Wont have logs on first load
+ // 'Storage', Wont have logs on first load
+ //'Realtime' Wont have logs on first load
+]
+
+test.describe('Logs', async () => {
+ for (const logPage of LOGS_PAGES) {
+ test.describe(`${logPage} logs page`, () => {
+ test('can navigate to logs page', async ({ page }) => {
+ await page.goto('http://localhost:8082/project/default')
+ await page.locator('a', { hasText: 'Logs' }).click({ timeout: 4000 })
+ await expect(page.getByText('Logs & Analytics')).toBeVisible()
+
+ // Click anywhere on the screen to close the sidebar
+ await page.click('body')
+
+ await page
+ .getByRole('link', { name: logPage, exact: true })
+ .click()
+ .catch((e) => {
+ console.log('🔴 Error clicking', logPage, e)
+ throw e
+ })
+
+ // Wait for and verify the logs table is present
+ const logsTable = page.getByRole('table')
+ await expect(logsTable).toBeVisible()
+ })
+
+ test('shows logs data without errors', async ({ page }) => {
+ // Navigate to page first
+ await page.goto('http://localhost:8082/project/default')
+ await page.locator('a', { hasText: 'Logs' }).click({ timeout: 4000 })
+ await page.click('body')
+ await page.getByRole('link', { name: logPage, exact: true }).click()
+
+ // Wait a bit and check for errors with a longer timeout
+ const error = page.getByText('Error fetching logs')
+ await expect(error).not.toBeVisible({ timeout: 10000 })
+
+ // Check if the logs table has any rows
+ const gridcells = page.getByRole('gridcell')
+ await expect(gridcells.first()).toBeVisible()
+ })
+
+ test('can select and view log details', async ({ page }) => {
+ // Navigate to page first
+ await page.goto('http://localhost:8082/project/default')
+ await page.locator('a', { hasText: 'Logs' }).click({ timeout: 4000 })
+ await page.click('body')
+ await page.getByRole('link', { name: logPage, exact: true }).click()
+
+ const gridcells = page.getByRole('gridcell')
+
+ // Click first row and verify details
+ await gridcells.first().click()
+ const tabPanel = page.getByTestId('log-selection')
+ await expect(tabPanel).toBeVisible({ timeout: 2000 })
+
+ const selectionPanelTimestamp = tabPanel.getByTestId('log-selection-timestamp')
+ await expect(selectionPanelTimestamp).toBeVisible()
+
+ const rawTimestamp = await selectionPanelTimestamp.textContent()
+ const timestamp = rawTimestamp?.replace('timestamp', '')
+ const rowText = await gridcells.first().textContent()
+ expect(rowText).toContain(timestamp)
+
+ // Click second row and verify different content
+ await gridcells.nth(1).click()
+ const tabPanelText2 = await tabPanel.textContent()
+ expect(tabPanelText2).not.toBe(rowText)
+ })
+ })
+ }
+})
diff --git a/tests/local-studio-tests/tests/snapshot/spec/table-editor.spec.ts b/tests/local-studio-tests/tests/snapshot/spec/table-editor.spec.ts
index 6323716141f..a689cdcbf90 100644
--- a/tests/local-studio-tests/tests/snapshot/spec/table-editor.spec.ts
+++ b/tests/local-studio-tests/tests/snapshot/spec/table-editor.spec.ts
@@ -19,7 +19,7 @@ test.describe('Table Editor page', () => {
test('should create a new table, view its definition, add new rows, sort and filter', async ({
page,
}, testInfo) => {
- const tableName = `${kebabCase(testInfo.title).slice(0, 24)}-${testInfo.retry}-${Math.floor(Math.random() * 100)}`
+ const tableName = `${kebabCase(testInfo.title).slice(0, 24)}-${testInfo.retry}-${Math.floor(Math.random() * 10000)}`
// The page has been loaded with the table data, we can now interact with the page
await page.getByRole('button', { name: 'New table', exact: true }).click()
@@ -46,6 +46,14 @@ test.describe('Table Editor page', () => {
await page.getByRole('button', { name: 'Save' }).click()
await dismissToast(page)
+ // hide React Query DevTools if present
+ await page.evaluate(() => {
+ const devtools = document.querySelector('.ReactQueryDevtools')
+ if (devtools) {
+ devtools.remove()
+ }
+ })
+
// view its definition
await page.getByText('definition').click()
await expect(page.locator('div.view-lines')).toContainText(
@@ -69,9 +77,17 @@ test.describe('Table Editor page', () => {
await page.getByTestId('action-bar-save-row').click()
await dismissToast(page)
+ // Wait for both rows to be visible in the grid
+ await page.waitForResponse((response) =>
+ response.url().includes('/api/platform/pg-meta/default/query')
+ )
await expect(page.getByRole('grid')).toContainText('2')
await expect(page.getByRole('grid')).toContainText('100')
+ // Make sure we can see both rows in the grid before sorting
+ const rows = page.getByRole('row')
+ await expect(rows).toHaveCount(3) // header row + 2 data rows
+
// sort by the a column
await page.getByRole('button', { name: 'Sort' }).click()
await page.getByTestId('table-editor-pick-column-to-sort-button').click()
@@ -82,8 +98,8 @@ test.describe('Table Editor page', () => {
await page.locator('#spec-click-target').click()
// expect the row to be sorted by defaultValueColumn. They're inserted in the order 100, 2
- await expect(page.locator('div.rdg-row:nth-child(2)')).toContainText('2')
- await expect(page.locator('div.rdg-row:nth-child(3)')).toContainText('100')
+ await expect(rows.nth(1)).toContainText('2')
+ await expect(rows.nth(2)).toContainText('100')
// remove the sorting
await page.getByRole('button', { name: 'Sorted by 1 rule' }).click()
await page.getByRole('dialog').getByRole('button').nth(1).click()