Skip to content

Commit

Permalink
UI (Inspector + Buttons)
Browse files Browse the repository at this point in the history
requires #6316 and #6308
  • Loading branch information
royendo committed Dec 21, 2024
1 parent fe2a204 commit 074cc7c
Show file tree
Hide file tree
Showing 3 changed files with 403 additions and 0 deletions.
132 changes: 132 additions & 0 deletions web-local/tests/UI/check-inspector-source-model.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { test, expect } from '@playwright/test';

Check failure on line 1 in web-local/tests/UI/check-inspector-source-model.spec.ts

View workflow job for this annotation

GitHub Actions / build

'expect' is defined but never used
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',
]
);
});

});
155 changes: 155 additions & 0 deletions web-local/tests/UI/check-model-ui-buttons.spec.ts
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();

});
});
Loading

0 comments on commit 074cc7c

Please sign in to comment.