-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
403 additions
and
0 deletions.
There are no files selected for viewing
132 changes: 132 additions & 0 deletions
132
web-local/tests/UI/check-inspector-source-model.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { test, expect } from '@playwright/test'; | ||
import { test as RillTest } from '../utils/test'; | ||
import { cloud, waitForTable } from '../utils/sourceHelpers'; | ||
import { checkInspectorSource, checkInspectorModel } from '../utils/inspectorHelpers'; | ||
import { createModel } from '../utils/modelHelpers'; | ||
|
||
// Testing the contents of the Inspector Panel | ||
// Does the correct rows and columns appear, and does each column have a visible graph? | ||
test.describe('Checking the Inspector Panel for Source and Model. Check if values are correct as well as if the UI populates graph.', () => { | ||
RillTest('Reading Source into Rill from GCS', async ({ page }) => { | ||
console.log('Testing cloud sales data ingestion...'); | ||
await Promise.all([ | ||
waitForTable(page, '/sources/sales.yaml', [ | ||
'sale_date', | ||
'sale_id', | ||
'duration_ms', | ||
'customer_id', | ||
'sales_amount_usd', | ||
'products', | ||
'discounts', | ||
'region', | ||
'is_online', | ||
]), | ||
cloud(page, 'sales.csv', 'gcs'), | ||
]); | ||
console.log('Sales table validated.'); | ||
|
||
await checkInspectorSource(page, '100,000', '9', | ||
[ | ||
'sale_date', | ||
'sale_id', | ||
'duration_ms', | ||
'customer_id', | ||
'sales_amount_usd', | ||
'products', | ||
'discounts', | ||
'region', | ||
'is_online' | ||
] | ||
) | ||
console.log('Testing cloud customer data ingestion...'); | ||
await Promise.all([ | ||
waitForTable(page, '/sources/customer_data.yaml', [ | ||
'customer_id', | ||
'name', | ||
'email', | ||
'signup_date', | ||
'preferences', | ||
'total_spent_usd', | ||
'loyalty_tier', | ||
'is_active', | ||
]), | ||
cloud(page, 'customer_data.csv', 'gcs'), | ||
]); | ||
console.log('Customer data table validated.'); | ||
await checkInspectorSource(page, '10,000', '8', | ||
[ | ||
'signup_date', | ||
'customer_id', | ||
'name', | ||
'email', | ||
'preferences', | ||
'total_spent_usd', | ||
'loyalty_tier', | ||
'is_active', | ||
] | ||
), | ||
console.log("Creating model to join sources.") | ||
await createModel(page, 'joined_model.sql'); | ||
// wait for textbox to appear for model | ||
await page.waitForSelector('div[role="textbox"]'); | ||
|
||
await page.evaluate(() => { | ||
// Ensure the parent textbox is focused for typing | ||
const parentTextbox = document.querySelector('div[role="textbox"]'); | ||
if (parentTextbox) { | ||
parentTextbox.focus(); | ||
} else { | ||
console.error("Parent textbox not found!"); | ||
} | ||
}); | ||
|
||
// Mimic typing in the child contenteditable div | ||
const childTextbox = await page.locator('div[role="textbox"] div.cm-content'); | ||
await childTextbox.click(); // Ensure it's focused for typing | ||
|
||
// Clear existing contents | ||
await childTextbox.press('Meta+A'); // need to check this | ||
await childTextbox.press('Backspace'); // Delete selected text | ||
|
||
const lines = [ | ||
"-- Model SQL", | ||
"-- Reference documentation: https://docs.rilldata.com/reference/project-files/models", | ||
"SELECT a.*,", | ||
" b.* exclude customer_id", | ||
"FROM sales AS a", | ||
"LEFT JOIN customer_data AS b", | ||
"ON a.customer_id = b.customer_id", | ||
"", "" | ||
]; | ||
|
||
// Type each line with a newline after | ||
for (const line of lines) { | ||
await childTextbox.type(line); // Type the line | ||
await childTextbox.press('Enter'); // Press Enter for a new line | ||
} | ||
|
||
console.log("Content typed successfully."); | ||
await checkInspectorModel(page, '100,000', '16', | ||
[ | ||
'sale_date', | ||
'sale_id', | ||
'duration_ms', | ||
'customer_id', | ||
'sales_amount_usd', | ||
'products', | ||
'discounts', | ||
'region', | ||
'is_online', | ||
'signup_date', | ||
'customer_id', | ||
'name', | ||
'email', | ||
'preferences', | ||
'total_spent_usd', | ||
'loyalty_tier', | ||
'is_active', | ||
] | ||
); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { test, expect } from '@playwright/test'; | ||
import { test as RillTest } from '../utils/test'; | ||
import { cloud, waitForTable } from '../utils/sourceHelpers'; | ||
import { waitForFileNavEntry } from "../utils/waitHelpers"; | ||
import { actionUsingMenu, checkExistInConnector, renameFileUsingMenu } from "../utils/commonHelpers"; | ||
|
||
// GCS source ingestion test | ||
// based on public bucket gs://playwright-gcs-qa/* | ||
// Can add more files as required, currently parquet.gz files are erroring so removed. | ||
|
||
|
||
test.describe('Check Source UI buttons.', () => { | ||
RillTest('Reading Source into Rill from GCS', async ({ page }) => { | ||
console.log('Testing cloud sales data ingestion...'); | ||
await Promise.all([ | ||
waitForTable(page, '/sources/sales.yaml', [ | ||
'sale_date', | ||
'sale_id', | ||
'duration_ms', | ||
'customer_id', | ||
'sales_amount_usd', | ||
'products', | ||
'discounts', | ||
'region', | ||
'is_online', | ||
]), | ||
cloud(page, 'sales.csv', 'gcs'), | ||
]); | ||
console.log('Sales table validated...'); | ||
|
||
// Create Model! | ||
console.log("Creating Create Model Button...") | ||
await Promise.all([ | ||
waitForFileNavEntry(page, "/models/sales_model.sql", false), //set true? | ||
page.getByRole('button', { name: 'Create model' }).click() | ||
]); | ||
|
||
// CHECK CONNECTORS for MODEL (table name dynamic so wildcard) | ||
await checkExistInConnector(page, 'duckdb', 'main_db', 'sales_model') | ||
|
||
|
||
// CHECKING BUTTONS | ||
//Close File Explore Sidebar | ||
await page.locator('span[aria-label="Close sidebar"]').click(); | ||
// Assert that the class changes | ||
const sidebarClose = page.locator('.sidebar.svelte-5nrsv4'); | ||
await expect(sidebarClose).toHaveClass('sidebar svelte-5nrsv4 hide'); | ||
|
||
|
||
await page.locator('span[aria-label="Show sidebar"]').click(); | ||
// Assert that the class changes | ||
const sidebarOpen = page.locator('.sidebar.svelte-5nrsv4'); | ||
await expect(sidebarOpen).toHaveClass('sidebar svelte-5nrsv4'); | ||
|
||
|
||
// checking the refresh button | ||
await page.locator('button[aria-label="Refresh Model"]').click(); //#6316, need to find where this gets added | ||
await expect(page.getByText('Building model sales_model').first().isVisible()).toBeTruthy(); // Test will fail if the text is not visible | ||
|
||
// checking the panels , | ||
await page.getByRole('button', { name: 'Toggle table visibility' }).click(); // #6308 | ||
const resultsPreviewTable = await page.locator('[aria-label="Results Preview Table"]'); // #6316 | ||
await expect(resultsPreviewTable).toBeHidden(); | ||
await expect(resultsPreviewTable.locator(`text="sale_id"`)).toHaveCount(0); | ||
|
||
await page.getByRole('button', { name: 'Toggle inspector visibility' }).click(); // #6308 | ||
const inspectorPanel = await page.locator('[aria-label="Inspector Panel"]'); // #6316 | ||
await expect(inspectorPanel).toBeHidden(); | ||
await expect(inspectorPanel.locator(`text="rows"`)).toHaveCount(0); | ||
|
||
|
||
|
||
// Wait for the download and confirm success (CSV, XLSX, Parquet) | ||
const [downloadCSV] = await Promise.all([ | ||
page.waitForEvent('download'), // Wait for the download event | ||
page.getByLabel('Export Model Data').click(), // Dropdown | ||
page.getByRole('menuitem', { name: 'Export as CSV' }).click()// Export | ||
]); | ||
|
||
const filePathCSV = await downloadCSV.path(); | ||
if (filePathCSV) { | ||
console.log(`File successfully downloaded to: ${filePathCSV}`); | ||
} else { | ||
console.error('Download failed.'); | ||
} | ||
|
||
const [downloadParquet] = await Promise.all([ | ||
page.waitForEvent('download'), // Wait for the download event | ||
page.getByLabel('Export Model Data').click(), // Dropdown | ||
page.locator('div[role="menuitem"]:has-text("Export as Parquet")').click()// Export | ||
]); | ||
|
||
const filePathParquet = await downloadParquet.path(); | ||
if (filePathParquet) { | ||
console.log(`File successfully downloaded to: ${filePathParquet}`); | ||
} else { | ||
console.error('Download failed.'); | ||
} | ||
|
||
const [downloadXSLX] = await Promise.all([ | ||
page.waitForEvent('download'), // Wait for the download event | ||
page.getByLabel('Export Model Data').click(), // Dropdown | ||
page.locator('div[role="menuitem"]:has-text("Export as XLSX")').click()// Export | ||
]); | ||
|
||
const filePathXLSX = await downloadXSLX.path(); | ||
if (filePathXLSX) { | ||
console.log(`File successfully downloaded to: ${filePathXLSX}`); | ||
} else { | ||
console.error('Download failed.'); | ||
} | ||
|
||
// Select "Generate Metrics with AI", | ||
await Promise.all([ | ||
waitForFileNavEntry(page, "/metrics/sales_model_metrics.yaml", false), //set true? | ||
page.getByRole('button', { name: 'Generate metrics view' }).click(), | ||
]); | ||
|
||
// Return to source and check Go to for both models. | ||
await page.locator('span:has-text("sales_model.sql")').click(); | ||
|
||
await page.getByRole('button', { name: 'Go to metrics view' }).click(); | ||
|
||
await Promise.all([ | ||
waitForFileNavEntry(page, "/metrics/sales_model_metrics_1.yaml", false), //set true? | ||
page.getByText('Create metrics view').click(), | ||
]); | ||
|
||
await expect(page.getByRole('link', { name: 'sales_model_metrics.yaml' })).toBeVisible(); | ||
await expect(page.getByRole('link', { name: 'sales_model_metrics_1.yaml' })).toBeVisible(); | ||
|
||
// Delete a metrics vie and rename another | ||
await page.locator('span:has-text("sales_model_metrics.yaml")').hover(); | ||
await actionUsingMenu(page, "/sales_model_metrics.yaml", "Delete") | ||
|
||
await renameFileUsingMenu(page, '/metrics/sales_model_metrics_1.yaml', 'random_metrics.yaml') | ||
|
||
// Check the model and metrics are still linked | ||
await page.locator('span:has-text("sales_model.sql")').click(); | ||
await page.getByRole('button', { name: 'Go to metrics view' }).click(); | ||
await page.locator('div[role="menuitem"]:has-text("Create metrics view")').waitFor(); | ||
await expect(page.getByRole('menuitem', { name: 'random_metrics', exact: true })).toBeVisible(); | ||
await page.getByRole('menuitem', { name: 'random_metrics', exact: true }).click(); | ||
|
||
// Can add further testing like renaming files and creating metrics from button to see if number is correct. | ||
|
||
await page.locator('span:has-text("random_metrics.yaml")').hover(); | ||
await actionUsingMenu(page, "/random_metrics.yaml", "Delete") | ||
|
||
// Check the UI has returned to Generate metrics view with AI | ||
await page.locator('span:has-text("sales_model.sql")').click(); | ||
await expect(page.getByRole('button', { name: 'Generate metrics view' })).toBeVisible(); | ||
|
||
}); | ||
}); |
Oops, something went wrong.