From 7069e2aa05f99f981f151b43fb825c530e97e58a Mon Sep 17 00:00:00 2001 From: nishthaAhujaa Date: Wed, 24 Dec 2025 15:50:27 +0530 Subject: [PATCH] all working playwright tests --- test/sql/indexAdvisor.spec.ts | 212 ++++++++++++---------------------- 1 file changed, 73 insertions(+), 139 deletions(-) diff --git a/test/sql/indexAdvisor.spec.ts b/test/sql/indexAdvisor.spec.ts index deb148de6..5c2023800 100644 --- a/test/sql/indexAdvisor.spec.ts +++ b/test/sql/indexAdvisor.spec.ts @@ -1,144 +1,29 @@ import { expect, test, type Page } from "@playwright/test"; import { DataExplorer, TestAccount } from "../fx"; +import { createTestSQLContainer, TestContainerContext } from "../testData"; -// Using existing database and container from environment variables -// Set these in your test environment or they'll use defaults -const DATABASE_ID = process.env.INDEX_ADVISOR_TEST_DATABASE || "t_db05_1765364190570"; -const CONTAINER_ID = process.env.INDEX_ADVISOR_TEST_CONTAINER || "testcontainer"; +// Test container context for setup and cleanup +let testContainer: TestContainerContext; +let DATABASE_ID: string; +let CONTAINER_ID: string; -// Mock SDK response structure based on IndexMetricsResponse interface -const mockIndexMetricsWithSingleUtilized = { - UtilizedIndexes: { - SingleIndexes: [ - { IndexSpec: "/_partitionKey/?", IndexImpactScore: "High" }, - { IndexSpec: "/name/?", IndexImpactScore: "Medium" }, - ], - }, - PotentialIndexes: {}, -}; +// Set up test database and container with data before all tests +test.beforeAll(async () => { + testContainer = await createTestSQLContainer(true); + DATABASE_ID = testContainer.database.id; + CONTAINER_ID = testContainer.container.id; +}); -const mockIndexMetricsWithCompositeUtilized = { - UtilizedIndexes: { - CompositeIndexes: [ - { - IndexSpecs: ["/category asc", "/price desc"], - IndexImpactScore: "High", - }, - ], - }, - PotentialIndexes: {}, -}; - -const mockIndexMetricsWithSinglePotential = { - UtilizedIndexes: {}, - PotentialIndexes: { - SingleIndexes: [ - { IndexSpec: "/email/?", IndexImpactScore: "High" }, - { IndexSpec: "/status/?", IndexImpactScore: "Medium" }, - { IndexSpec: "/createdDate/?", IndexImpactScore: "Low" }, - ], - }, -}; - -const mockIndexMetricsWithCompositePotential = { - UtilizedIndexes: {}, - PotentialIndexes: { - CompositeIndexes: [ - { - IndexSpecs: ["/userId asc", "/timestamp desc"], - IndexImpactScore: "High", - }, - { - IndexSpecs: ["/country asc", "/city asc", "/zipCode asc"], - IndexImpactScore: "Medium", - }, - ], - }, -}; - -const mockIndexMetricsComplete = { - UtilizedIndexes: { - SingleIndexes: [ - { IndexSpec: "/_partitionKey/?", IndexImpactScore: "High" }, - { IndexSpec: "/name/?", IndexImpactScore: "Medium" }, - ], - CompositeIndexes: [ - { - IndexSpecs: ["/category asc", "/price desc"], - IndexImpactScore: "High", - }, - ], - }, - PotentialIndexes: { - SingleIndexes: [ - { IndexSpec: "/email/?", IndexImpactScore: "High" }, - { IndexSpec: "/status/?", IndexImpactScore: "Medium" }, - { IndexSpec: "/createdDate/?", IndexImpactScore: "Low" }, - ], - CompositeIndexes: [ - { - IndexSpecs: ["/userId asc", "/timestamp desc"], - IndexImpactScore: "High", - }, - { - IndexSpecs: ["/country asc", "/city asc", "/zipCode asc"], - IndexImpactScore: "Medium", - }, - ], - }, -}; - -// Helper function to intercept SDK calls and inject mock response -async function interceptIndexMetrics( - page: Page, - mockResponse: any, -): Promise { - await page.route("**/dbs/*/colls/*/docs", async (route) => { - const request = route.request(); - - // Check if this is a query request with populateIndexMetrics - if (request.method() === "POST") { - const postData = request.postData(); - - if (postData) { - try { - const body = JSON.parse(postData); - - // If this is a query request, we'll intercept it - if (body.query) { - // Fetch the actual response - const response = await route.fetch(); - const responseBody = await response.json(); - - // Add our mock indexMetrics to the response - const modifiedResponse = { - ...responseBody, - indexMetrics: mockResponse ? JSON.stringify(mockResponse) : undefined, - }; - - await route.fulfill({ - status: response.status(), - headers: response.headers(), - body: JSON.stringify(modifiedResponse), - }); - return; - } - } catch (e) { - // If parsing fails, continue with normal route - } - } - } - - await route.continue(); - }); -} +// Clean up test database after all tests +test.afterAll(async () => { + if (testContainer) { + await testContainer.dispose(); + } +}); // Helper function to set up query tab and navigate to Index Advisor -async function setupIndexAdvisorTab(page: Page, mockResponse?: any) { - if (mockResponse !== undefined) { - await interceptIndexMetrics(page, mockResponse); - } +async function setupIndexAdvisorTab(page: Page, customQuery?: string) { const explorer = await DataExplorer.open(page, TestAccount.SQL); const databaseNode = await explorer.waitForNode(DATABASE_ID); @@ -154,6 +39,14 @@ async function setupIndexAdvisorTab(page: Page, mockResponse?: any) { await queryTab.editor().locator.waitFor({ timeout: 30 * 1000 }); await queryTab.editor().locator.click(); + if (customQuery) { + // Clear the default query and type the custom query + await page.keyboard.press("Control+A"); + await page.waitForTimeout(100); + await page.keyboard.type(customQuery); + await page.waitForTimeout(500); + } + const executeQueryButton = explorer.commandBarButton("Execute Query"); await executeQueryButton.click(); await expect(queryTab.resultsEditor.locator).toBeAttached({ timeout: 60 * 1000 }); @@ -166,12 +59,12 @@ async function setupIndexAdvisorTab(page: Page, mockResponse?: any) { } test("Index Advisor tab loads without errors", async ({ page }) => { - const { indexAdvisorTab } = await setupIndexAdvisorTab(page, mockIndexMetricsComplete); + const { indexAdvisorTab } = await setupIndexAdvisorTab(page); await expect(indexAdvisorTab).toHaveAttribute("aria-selected", "true"); }); test("Verify UI sections are collapsible", async ({ page }) => { - const { explorer } = await setupIndexAdvisorTab(page, mockIndexMetricsComplete); + const { explorer } = await setupIndexAdvisorTab(page); // Verify both section headers exist const includedHeader = explorer.frame.getByText("Included in Current Policy", { exact: true }); @@ -194,10 +87,7 @@ test("Verify UI sections are collapsible", async ({ page }) => { }); test("Verify SDK response structure - Case 1: Empty response", async ({ page }) => { - const { explorer } = await setupIndexAdvisorTab(page, { - UtilizedIndexes: {}, - PotentialIndexes: {}, - }); + const { explorer } = await setupIndexAdvisorTab(page); // Verify both section headers still exist even with no data await expect(explorer.frame.getByText("Included in Current Policy", { exact: true })).toBeVisible(); @@ -212,3 +102,47 @@ test("Verify SDK response structure - Case 1: Empty response", async ({ page }) const updateButton = explorer.frame.getByRole("button", { name: /Update Indexing Policy/i }); await expect(updateButton).not.toBeVisible(); }); + +test("Verify index suggestions and apply potential index", async ({ page }) => { + const customQuery = 'SELECT * FROM c WHERE c.partitionKey = "partition_1" ORDER BY c.randomData'; + const { explorer } = await setupIndexAdvisorTab(page, customQuery); + + // Wait for Index Advisor to process the query + await page.waitForTimeout(2000); + + // Verify "Not Included in Current Policy" section has suggestions + const notIncludedHeader = explorer.frame.getByText("Not Included in Current Policy", { exact: true }); + await expect(notIncludedHeader).toBeVisible(); + + // Find the checkbox for the suggested composite index + // The composite index should be /partitionKey ASC, /randomData ASC + const checkboxes = explorer.frame.locator('input[type="checkbox"]'); + const checkboxCount = await checkboxes.count(); + + // Should have at least one checkbox for the potential index + expect(checkboxCount).toBeGreaterThan(0); + + // Select the first checkbox (the high-impact composite index) + await checkboxes.first().check(); + await page.waitForTimeout(500); + + // Verify "Update Indexing Policy" button becomes visible + const updateButton = explorer.frame.getByRole("button", { name: /Update Indexing Policy/i }); + await expect(updateButton).toBeVisible(); + + // Click the "Update Indexing Policy" button + await updateButton.click(); + await page.waitForTimeout(1000); + + // Verify success message appears + const successMessage = explorer.frame.getByText(/Your indexing policy has been updated with the new included paths/i); + await expect(successMessage).toBeVisible(); + + // Verify the message mentions reviewing changes in Scale & Settings + const reviewMessage = explorer.frame.getByText(/You may review the changes in Scale & Settings/i); + await expect(reviewMessage).toBeVisible(); + + // Verify the checkmark icon is shown + const checkmarkIcon = explorer.frame.locator('[data-icon-name="CheckMark"]'); + await expect(checkmarkIcon).toBeVisible(); +});