mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-06-08 13:37:29 +01:00
Added quantizer type playwright test
This commit is contained in:
@@ -13,6 +13,7 @@ export interface CollapsibleSectionProps {
|
|||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
disableDelete?: boolean;
|
disableDelete?: boolean;
|
||||||
|
testId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollapsibleSectionState {
|
export interface CollapsibleSectionState {
|
||||||
@@ -57,6 +58,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="button"
|
role="button"
|
||||||
aria-expanded={this.state.isExpanded}
|
aria-expanded={this.state.isExpanded}
|
||||||
|
data-test={this.props.testId}
|
||||||
>
|
>
|
||||||
<Icon iconName={this.state.isExpanded ? "ChevronDown" : "ChevronRight"} />
|
<Icon iconName={this.state.isExpanded ? "ChevronDown" : "ChevronRight"} />
|
||||||
<Label styles={{ root: { color: "var(--colorNeutralForeground1)" } }}>{this.props.title}</Label>
|
<Label styles={{ root: { color: "var(--colorNeutralForeground1)" } }}>{this.props.title}</Label>
|
||||||
|
|||||||
@@ -426,6 +426,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent<IVectorEmbeddin
|
|||||||
</Label>
|
</Label>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
disabled={isExistingPolicy(vectorEmbeddingPolicy)}
|
disabled={isExistingPolicy(vectorEmbeddingPolicy)}
|
||||||
|
id={`vector-policy-indexType-${index + 1}`}
|
||||||
required={true}
|
required={true}
|
||||||
styles={dropdownStyles}
|
styles={dropdownStyles}
|
||||||
options={getIndexTypeOptions()}
|
options={getIndexTypeOptions()}
|
||||||
|
|||||||
@@ -838,6 +838,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
scrollToSection("collapsibleVectorPolicySectionContent");
|
scrollToSection("collapsibleVectorPolicySectionContent");
|
||||||
}}
|
}}
|
||||||
tooltipContent={ContainerVectorPolicyTooltipContent()}
|
tooltipContent={ContainerVectorPolicyTooltipContent()}
|
||||||
|
testId="container-vector-policy-section"
|
||||||
>
|
>
|
||||||
<Stack id="collapsibleVectorPolicySectionContent" styles={{ root: { position: "relative" } }}>
|
<Stack id="collapsibleVectorPolicySectionContent" styles={{ root: { position: "relative" } }}>
|
||||||
<Stack styles={{ root: { paddingLeft: 40 } }}>
|
<Stack styles={{ root: { paddingLeft: 40 } }}>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// Temporary init script for Playwright MCP to override browser locale
|
||||||
|
// This runs before any page scripts, so i18next will detect 'ja' from navigator
|
||||||
|
Object.defineProperty(navigator, "language", { get: () => "ja" });
|
||||||
|
Object.defineProperty(navigator, "languages", { get: () => ["ja", "ja-JP"] });
|
||||||
+173
-1
@@ -1,6 +1,13 @@
|
|||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
|
|
||||||
import { DataExplorer, TEST_AUTOSCALE_THROUGHPUT_RU, TestAccount, generateUniqueName } from "../fx";
|
import {
|
||||||
|
DataExplorer,
|
||||||
|
ONE_MINUTE_MS,
|
||||||
|
TEST_AUTOSCALE_THROUGHPUT_RU,
|
||||||
|
TestAccount,
|
||||||
|
generateUniqueName,
|
||||||
|
getDropdownItemByNameOrPosition,
|
||||||
|
} from "../fx";
|
||||||
|
|
||||||
test("SQL database and container CRUD", async ({ page }) => {
|
test("SQL database and container CRUD", async ({ page }) => {
|
||||||
const databaseId = generateUniqueName("db");
|
const databaseId = generateUniqueName("db");
|
||||||
@@ -50,3 +57,168 @@ test("SQL database and container CRUD", async ({ page }) => {
|
|||||||
|
|
||||||
await expect(databaseNode.element).not.toBeAttached();
|
await expect(databaseNode.element).not.toBeAttached();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.describe("Vector embedding quantizer type in New Container panel", () => {
|
||||||
|
/**
|
||||||
|
* Opens the New Container panel and expands the Container Vector Policy section.
|
||||||
|
* Returns the panel locator and the scoped vector policy content locator.
|
||||||
|
*/
|
||||||
|
const openPanelWithVectorPolicy = async (explorer: DataExplorer) => {
|
||||||
|
const newContainerButton = await explorer.globalCommandButton("New Container");
|
||||||
|
await newContainerButton.click();
|
||||||
|
|
||||||
|
const panel = explorer.panel("New Container");
|
||||||
|
await panel.waitFor();
|
||||||
|
|
||||||
|
// Expand section via its stable data-test id (avoids matching localized title text)
|
||||||
|
await explorer.frame.getByTestId("container-vector-policy-section").click();
|
||||||
|
|
||||||
|
const vectorSection = explorer.frame.locator("#collapsibleVectorPolicySectionContent");
|
||||||
|
await vectorSection.locator("#add-vector-policy").waitFor();
|
||||||
|
|
||||||
|
return { panel, vectorSection };
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Closes the New Container panel without submitting via the Fluent UI Panel close button. */
|
||||||
|
const closePanel = async (explorer: DataExplorer) => {
|
||||||
|
await explorer.frame.locator("button.ms-Panel-closeButton").click();
|
||||||
|
await explorer.panel("New Container").waitFor({ state: "detached" });
|
||||||
|
};
|
||||||
|
|
||||||
|
test("Quantizer type dropdown is disabled by default when index type is none", async ({ page }) => {
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
const { vectorSection } = await openPanelWithVectorPolicy(explorer);
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
|
||||||
|
// Index type defaults to "none" — quantizer type must be disabled
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await expect(quantizerDropdownBtn).toBeDisabled();
|
||||||
|
|
||||||
|
await closePanel(explorer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown is disabled for flat index type", async ({ page }) => {
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
const { vectorSection } = await openPanelWithVectorPolicy(explorer);
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
|
||||||
|
// Select "flat" index type (does not support quantization).
|
||||||
|
// Use exact match because "flat" is also a substring of "quantizedFlat".
|
||||||
|
await vectorSection.locator("#vector-policy-indexType-1").click();
|
||||||
|
await explorer.frame.getByRole("option", { name: "flat", exact: true }).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await expect(quantizerDropdownBtn).toBeDisabled();
|
||||||
|
|
||||||
|
await closePanel(explorer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown becomes enabled with diskANN index type and defaults to Product", async ({ page }) => {
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
const { vectorSection } = await openPanelWithVectorPolicy(explorer);
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
|
||||||
|
await vectorSection.locator("#vector-policy-indexType-1").click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await expect(quantizerDropdownBtn).toBeEnabled();
|
||||||
|
await expect(quantizerDropdownBtn).toContainText("Product");
|
||||||
|
|
||||||
|
await closePanel(explorer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown becomes enabled with quantizedFlat index type and defaults to Product", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
const { vectorSection } = await openPanelWithVectorPolicy(explorer);
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
|
||||||
|
// Select "quantizedFlat" index type — supports quantization
|
||||||
|
await vectorSection.locator("#vector-policy-indexType-1").click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "quantizedFlat" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await expect(quantizerDropdownBtn).toBeEnabled();
|
||||||
|
await expect(quantizerDropdownBtn).toContainText("Product");
|
||||||
|
|
||||||
|
await closePanel(explorer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type can be changed to Spherical (Preview)", async ({ page }) => {
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
const { vectorSection } = await openPanelWithVectorPolicy(explorer);
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
|
||||||
|
await vectorSection.locator("#vector-policy-indexType-1").click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await quantizerDropdownBtn.click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { position: 1 })).click();
|
||||||
|
|
||||||
|
await expect(quantizerDropdownBtn).not.toContainText("Product");
|
||||||
|
|
||||||
|
await closePanel(explorer);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Creating a container with diskANN index type and Spherical quantizer type succeeds", async ({ page }) => {
|
||||||
|
const databaseId = generateUniqueName("db");
|
||||||
|
const containerId = "testvecquantizer";
|
||||||
|
const explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||||
|
|
||||||
|
await (await explorer.globalCommandButton("New Container")).click();
|
||||||
|
|
||||||
|
await explorer.whilePanelOpen(
|
||||||
|
"New Container",
|
||||||
|
async (panel, okButton) => {
|
||||||
|
await panel.getByPlaceholder("Type a new database id").fill(databaseId);
|
||||||
|
await panel.getByRole("textbox", { name: "Container id, Example Container1" }).fill(containerId);
|
||||||
|
await panel.getByRole("textbox", { name: "Partition key" }).fill("/pk");
|
||||||
|
await panel.getByTestId("autoscaleRUInput").fill(TEST_AUTOSCALE_THROUGHPUT_RU.toString());
|
||||||
|
|
||||||
|
await explorer.frame.getByTestId("container-vector-policy-section").click();
|
||||||
|
const vectorSection = explorer.frame.locator("#collapsibleVectorPolicySectionContent");
|
||||||
|
await vectorSection.locator("#add-vector-policy").waitFor();
|
||||||
|
|
||||||
|
await vectorSection.locator("#add-vector-policy").click();
|
||||||
|
await vectorSection.locator("#vector-policy-path-1").fill("/embedding");
|
||||||
|
await vectorSection.locator("#vector-policy-dimension-1").fill("1536");
|
||||||
|
|
||||||
|
await vectorSection.locator("#vector-policy-indexType-1").click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = vectorSection.locator("#vector-policy-quantizerType-1");
|
||||||
|
await expect(quantizerDropdownBtn).toBeEnabled();
|
||||||
|
await quantizerDropdownBtn.click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { position: 1 })).click();
|
||||||
|
|
||||||
|
await okButton.click();
|
||||||
|
},
|
||||||
|
{ closeTimeout: 5 * 60 * 1000 },
|
||||||
|
);
|
||||||
|
|
||||||
|
const containerNode = await explorer.waitForContainerNode(databaseId, containerId);
|
||||||
|
await expect(containerNode.element).toBeVisible();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
const databaseNode = await explorer.waitForNode(databaseId);
|
||||||
|
await databaseNode.openContextMenu();
|
||||||
|
await databaseNode.contextMenuItem("Delete Database").click();
|
||||||
|
await explorer.whilePanelOpen(
|
||||||
|
"Delete Database",
|
||||||
|
async (panel, okButton) => {
|
||||||
|
await panel.getByRole("textbox", { name: "Confirm by typing the database id" }).fill(databaseId);
|
||||||
|
await okButton.click();
|
||||||
|
},
|
||||||
|
{ closeTimeout: 5 * 60 * 1000 },
|
||||||
|
);
|
||||||
|
await expect(databaseNode.element).not.toBeAttached({ timeout: ONE_MINUTE_MS });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../../fx";
|
import {
|
||||||
|
CommandBarButton,
|
||||||
|
DataExplorer,
|
||||||
|
getDropdownItemByNameOrPosition,
|
||||||
|
ONE_MINUTE_MS,
|
||||||
|
TestAccount,
|
||||||
|
} from "../../../fx";
|
||||||
import { createTestSQLContainer, TestContainerContext } from "../../../testData";
|
import { createTestSQLContainer, TestContainerContext } from "../../../testData";
|
||||||
|
|
||||||
test.describe("Vector Policy under Scale & Settings", () => {
|
test.describe("Vector Policy under Scale & Settings", () => {
|
||||||
@@ -190,4 +196,119 @@ test.describe("Vector Policy under Scale & Settings", () => {
|
|||||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||||
await expect(saveButton).toBeDisabled();
|
await expect(saveButton).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown is disabled when index type is none", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await expect(quantizerDropdownBtn).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown is disabled for flat index type", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-indexType-${newIndex}`).click();
|
||||||
|
// Use exact match because "flat" is also a substring of "quantizedFlat".
|
||||||
|
await explorer.frame.getByRole("option", { name: "flat", exact: true }).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await expect(quantizerDropdownBtn).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown becomes enabled and defaults to Product for diskANN index type", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-indexType-${newIndex}`).click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await expect(quantizerDropdownBtn).toBeEnabled();
|
||||||
|
await expect(quantizerDropdownBtn).toContainText("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type dropdown becomes enabled and defaults to Product for quantizedFlat index type", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-indexType-${newIndex}`).click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "quantizedFlat" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await expect(quantizerDropdownBtn).toBeEnabled();
|
||||||
|
await expect(quantizerDropdownBtn).toContainText("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Quantizer type can be changed to Spherical (Preview)", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-path-${newIndex}`).fill("/embedding");
|
||||||
|
await explorer.frame.locator(`#vector-policy-dimension-${newIndex}`).fill("1536");
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-indexType-${newIndex}`).click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await quantizerDropdownBtn.click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { position: 1 })).click();
|
||||||
|
|
||||||
|
await expect(quantizerDropdownBtn).not.toContainText("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Saving a vector policy with diskANN and Spherical quantizer type persists", async () => {
|
||||||
|
const existingCount = await getPolicyCount();
|
||||||
|
|
||||||
|
const addButton = explorer.frame.locator("#add-vector-policy");
|
||||||
|
await addButton.click();
|
||||||
|
|
||||||
|
const newIndex = existingCount + 1;
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-path-${newIndex}`).fill("/vecQuantizer");
|
||||||
|
await explorer.frame.locator(`#vector-policy-dimension-${newIndex}`).fill("1536");
|
||||||
|
|
||||||
|
await explorer.frame.locator(`#vector-policy-indexType-${newIndex}`).click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { name: "diskANN" })).click();
|
||||||
|
|
||||||
|
const quantizerDropdownBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await quantizerDropdownBtn.click();
|
||||||
|
await (await getDropdownItemByNameOrPosition(explorer.frame, { position: 1 })).click();
|
||||||
|
|
||||||
|
// Save
|
||||||
|
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||||
|
await expect(saveButton).toBeEnabled();
|
||||||
|
await saveButton.click();
|
||||||
|
await expect(explorer.getConsoleHeaderStatus()).toContainText(`${context.container.id}`, {
|
||||||
|
timeout: 2 * ONE_MINUTE_MS,
|
||||||
|
});
|
||||||
|
|
||||||
|
await explorer.openScaleAndSettings(context);
|
||||||
|
await explorer.frame.getByTestId("settings-tab-header/ContainerVectorPolicyTab").click();
|
||||||
|
await explorer.frame.getByRole("tab", { name: "Vector Policy" }).click();
|
||||||
|
|
||||||
|
const savedQuantizerBtn = explorer.frame.locator(`#vector-policy-quantizerType-${newIndex}`);
|
||||||
|
await expect(savedQuantizerBtn).toContainText("Spherical");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user