mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-02 15:51:16 +00:00
Compare commits
2 Commits
users/saks
...
users/aisa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21123b61dc | ||
|
|
b718f0c136 |
1
Untitled-1.txt
Normal file
1
Untitled-1.txt
Normal file
@@ -0,0 +1 @@
|
||||
.t
|
||||
@@ -17,38 +17,6 @@
|
||||
position: fixed;
|
||||
top: -200px;
|
||||
}
|
||||
body.isDarkMode .ms-Layer {
|
||||
.ms-Callout-main {
|
||||
background-color: @BaseHigh !important;
|
||||
}
|
||||
|
||||
.ms-Callout-beak {
|
||||
background-color: @BaseHigh !important;
|
||||
}
|
||||
|
||||
.ms-ContextualMenu {
|
||||
background-color: @BaseHigh !important;
|
||||
}
|
||||
|
||||
.ms-Dropdown-items {
|
||||
background-color: @BaseHigh !important;
|
||||
}
|
||||
|
||||
.ms-Dropdown-item {
|
||||
background-color: @BaseHigh !important;
|
||||
color: @BaseLight !important;
|
||||
|
||||
&:hover {
|
||||
background-color: @BaseMediumHigh !important;
|
||||
color: @BaseLight !important;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background-color: @BaseMediumHigh !important;
|
||||
color: @BaseLight !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||
@@ -161,65 +129,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
&.isDarkMode .accountSwitchContextualMenu {
|
||||
background-color: @BaseHigh;
|
||||
|
||||
.ms-Callout-main {
|
||||
background-color: @BaseHigh;
|
||||
}
|
||||
|
||||
.ms-ContextualMenu-item {
|
||||
background-color: @BaseHigh;
|
||||
}
|
||||
|
||||
.ms-Dropdown {
|
||||
.ms-Dropdown-title {
|
||||
background-color: @BaseDark;
|
||||
color: @BaseLight;
|
||||
border-color: @BaseMediumHigh;
|
||||
}
|
||||
|
||||
.ms-Dropdown-caretDownWrapper {
|
||||
color: @BaseLight;
|
||||
}
|
||||
|
||||
&:hover .ms-Dropdown-title {
|
||||
background-color: @BaseHigh;
|
||||
color: @BaseLight;
|
||||
border-color: @BaseMedium;
|
||||
}
|
||||
}
|
||||
|
||||
.ms-Label {
|
||||
color: @BaseLight;
|
||||
}
|
||||
}
|
||||
|
||||
&.isDarkMode .ms-Dropdown-callout {
|
||||
.ms-Callout-main {
|
||||
background-color: @BaseHigh;
|
||||
}
|
||||
|
||||
.ms-Dropdown-items {
|
||||
background-color: @BaseHigh;
|
||||
}
|
||||
|
||||
.ms-Dropdown-item {
|
||||
background-color: @BaseHigh;
|
||||
color: @BaseLight;
|
||||
|
||||
&:hover {
|
||||
background-color: @BaseMediumHigh;
|
||||
color: @BaseLight;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background-color: @BaseMediumHigh;
|
||||
color: @BaseLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fixedleftpane {
|
||||
background: @BaseLow;
|
||||
height: 100vh;
|
||||
|
||||
@@ -187,7 +187,7 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
<Text styles={textSubHeadingStyle}>Current {partitionKeyName.toLowerCase()}</Text>
|
||||
<Text styles={textSubHeadingStyle}>Partitioning</Text>
|
||||
</Stack>
|
||||
<Stack tokens={{ childrenGap: 5 }} data-test="partition-key-values">
|
||||
<Stack tokens={{ childrenGap: 5 }}>
|
||||
<Text styles={textSubHeadingStyle1}>{partitionKeyValue}</Text>
|
||||
<Text styles={textSubHeadingStyle1}>
|
||||
{isHierarchicalPartitionedContainer() ? "Hierarchical" : "Non-hierarchical"}
|
||||
@@ -199,7 +199,6 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
{!isReadOnly && (
|
||||
<>
|
||||
<MessageBar
|
||||
data-test="partition-key-warning"
|
||||
messageBarType={MessageBarType.warning}
|
||||
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
|
||||
styles={darkThemeMessageBarStyles}
|
||||
@@ -221,7 +220,6 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
|
||||
</Text>
|
||||
{configContext.platform !== Platform.Emulator && (
|
||||
<PrimaryButton
|
||||
data-test="change-partition-key-button"
|
||||
styles={{ root: { width: "fit-content" } }}
|
||||
text="Change"
|
||||
onClick={startPartitionkeyChangeWorkflow}
|
||||
|
||||
@@ -78,7 +78,6 @@ exports[`PartitionKeyComponent renders default component and matches snapshot 1`
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack
|
||||
data-test="partition-key-values"
|
||||
tokens={
|
||||
{
|
||||
"childrenGap": 5,
|
||||
@@ -109,7 +108,6 @@ exports[`PartitionKeyComponent renders default component and matches snapshot 1`
|
||||
</Stack>
|
||||
</Stack>
|
||||
<StyledMessageBar
|
||||
data-test="partition-key-warning"
|
||||
messageBarIconProps={
|
||||
{
|
||||
"className": "messageBarWarningIcon",
|
||||
@@ -162,7 +160,6 @@ exports[`PartitionKeyComponent renders default component and matches snapshot 1`
|
||||
To change the partition key, a new destination container must be created or an existing destination container selected. Data will then be copied to the destination container.
|
||||
</Text>
|
||||
<CustomizedPrimaryButton
|
||||
data-test="change-partition-key-button"
|
||||
onClick={[Function]}
|
||||
styles={
|
||||
{
|
||||
@@ -240,7 +237,6 @@ exports[`PartitionKeyComponent renders read-only component and matches snapshot
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack
|
||||
data-test="partition-key-values"
|
||||
tokens={
|
||||
{
|
||||
"childrenGap": 5,
|
||||
|
||||
@@ -208,7 +208,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
</div>
|
||||
</Stack>
|
||||
{createNewContainer ? (
|
||||
<Stack data-test="create-new-container-form">
|
||||
<Stack>
|
||||
<MessageBar>All configurations except for unique keys will be copied from the source container</MessageBar>
|
||||
<Stack className="panelGroupSpacing">
|
||||
<Stack horizontal>
|
||||
@@ -230,7 +230,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
</TooltipHost>
|
||||
</Stack>
|
||||
<input
|
||||
data-test="new-container-id-input"
|
||||
name="collectionId"
|
||||
id="collectionId"
|
||||
type="text"
|
||||
@@ -272,7 +271,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
|
||||
<input
|
||||
type="text"
|
||||
data-test="new-container-partition-key-input"
|
||||
id="addCollection-partitionKeyValue"
|
||||
aria-required
|
||||
required
|
||||
@@ -306,7 +304,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
type="text"
|
||||
id="addCollection-partitionKeyValue"
|
||||
key={`addCollection-partitionKeyValue_${index}`}
|
||||
data-test={`new-container-sub-partition-key-input-${index}`}
|
||||
aria-required
|
||||
required
|
||||
size={40}
|
||||
@@ -330,8 +327,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
data-test={`remove-sub-partition-key-button-${index}`}
|
||||
ariaLabel="Remove hierarchical partition key"
|
||||
iconProps={{ iconName: "Delete" }}
|
||||
style={{ height: 27 }}
|
||||
onClick={() => {
|
||||
@@ -344,7 +339,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
})}
|
||||
<Stack className="panelGroupSpacing">
|
||||
<DefaultButton
|
||||
data-test="add-sub-partition-key-button"
|
||||
styles={{ root: { padding: 0, width: 200, height: 30 }, label: { fontSize: 12 } }}
|
||||
disabled={subPartitionKeys.length >= Constants.BackendDefaults.maxNumMultiHashPartition}
|
||||
onClick={() => setSubPartitionKeys([...subPartitionKeys, ""])}
|
||||
@@ -352,11 +346,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
Add hierarchical partition key
|
||||
</DefaultButton>
|
||||
{subPartitionKeys.length > 0 && (
|
||||
<Text
|
||||
data-test="hierarchical-partitioning-info-text"
|
||||
variant="small"
|
||||
style={{ color: "var(--colorNeutralForeground1)" }}
|
||||
>
|
||||
<Text variant="small" style={{ color: "var(--colorNeutralForeground1)" }}>
|
||||
<Icon iconName="InfoSolid" className="removeIcon" tabIndex={0} /> This feature allows you to
|
||||
partition your data with up to three levels of keys for better data distribution. Requires .NET V3,
|
||||
Java V4 SDK, or preview JavaScript V3 SDK.{" "}
|
||||
@@ -369,7 +359,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
</Stack>
|
||||
</Stack>
|
||||
) : (
|
||||
<Stack data-test="use-existing-container-form">
|
||||
<Stack>
|
||||
<Stack horizontal>
|
||||
<span className="mandatoryStar">* </span>
|
||||
<Text className="panelTextBold" variant="small">
|
||||
@@ -400,7 +390,6 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
|
||||
}}
|
||||
defaultSelectedKey={targetCollectionId}
|
||||
responsiveMode={999}
|
||||
ariaLabel="Existing Containers"
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { initializeIcons } from "@fluentui/react";
|
||||
import { useBoolean } from "@fluentui/react-hooks";
|
||||
import { MessageTypes } from "Contracts/MessageTypes";
|
||||
import { AadAuthorizationFailure } from "Platform/Hosted/Components/AadAuthorizationFailure";
|
||||
import * as React from "react";
|
||||
import { render } from "react-dom";
|
||||
@@ -22,33 +21,9 @@ import "./Shared/appInsights";
|
||||
import { useAADAuth } from "./hooks/useAADAuth";
|
||||
import { useConfig } from "./hooks/useConfig";
|
||||
import { useTokenMetadata } from "./hooks/usePortalAccessToken";
|
||||
import { THEME_MODE_DARK, useThemeStore } from "./hooks/useTheme";
|
||||
|
||||
initializeIcons();
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("message", (event) => {
|
||||
const messageData = event.data?.data || event.data;
|
||||
const messageType = messageData?.type;
|
||||
|
||||
if (messageType === MessageTypes.UpdateTheme) {
|
||||
const themeData = messageData?.params?.theme || messageData?.theme;
|
||||
if (themeData && themeData.mode !== undefined) {
|
||||
const isDark = themeData.mode === THEME_MODE_DARK;
|
||||
useThemeStore.setState({
|
||||
isDarkMode: isDark,
|
||||
themeMode: themeData.mode,
|
||||
});
|
||||
if (isDark) {
|
||||
document.body.classList.add("isDarkMode");
|
||||
} else {
|
||||
document.body.classList.remove("isDarkMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const App: React.FunctionComponent = () => {
|
||||
// For handling encrypted portal tokens sent via query paramter
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
@@ -125,10 +125,7 @@ const App = (): JSX.Element => {
|
||||
<KeyboardShortcutRoot>
|
||||
<div className="flexContainer" aria-hidden="false">
|
||||
{userContext.features.enableContainerCopy && userContext.apiType === "SQL" ? (
|
||||
<>
|
||||
<ContainerCopyPanel explorer={explorer} />
|
||||
<SidePanel />
|
||||
</>
|
||||
<ContainerCopyPanel explorer={explorer} />
|
||||
) : (
|
||||
<DivExplorer explorer={explorer} />
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// TODO: Renable this rule for the file or turn it off everywhere
|
||||
/* eslint-disable react/display-name */
|
||||
|
||||
import { DefaultButton, IButtonStyles, IContextualMenuItem, IContextualMenuProps } from "@fluentui/react";
|
||||
import { DefaultButton, IButtonStyles, IContextualMenuItem } from "@fluentui/react";
|
||||
import * as React from "react";
|
||||
import { FunctionComponent, useEffect, useState } from "react";
|
||||
import { StyleConstants } from "../../../Common/StyleConstants";
|
||||
@@ -92,16 +92,14 @@ export const AccountSwitcher: FunctionComponent<Props> = ({ armToken, setDatabas
|
||||
},
|
||||
];
|
||||
|
||||
const menuProps: IContextualMenuProps = {
|
||||
directionalHintFixed: true,
|
||||
className: "accountSwitchContextualMenu",
|
||||
items,
|
||||
};
|
||||
|
||||
return (
|
||||
<DefaultButton
|
||||
text={buttonText}
|
||||
menuProps={menuProps}
|
||||
menuProps={{
|
||||
directionalHintFixed: true,
|
||||
className: "accountSwitchContextualMenu",
|
||||
items,
|
||||
}}
|
||||
styles={buttonStyles}
|
||||
className="accountSwitchButton"
|
||||
id="accountSwitchButton"
|
||||
|
||||
@@ -31,6 +31,9 @@ export const SwitchAccount: FunctionComponent<Props> = ({
|
||||
}}
|
||||
defaultSelectedKey={selectedAccount?.name}
|
||||
placeholder={accounts && accounts.length === 0 ? "No Accounts Found" : "Select an Account"}
|
||||
styles={{
|
||||
callout: "accountSwitchAccountDropdownMenu",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -30,6 +30,9 @@ export const SwitchSubscription: FunctionComponent<Props> = ({
|
||||
}}
|
||||
defaultSelectedKey={selectedSubscription?.subscriptionId}
|
||||
placeholder={subscriptions && subscriptions.length === 0 ? "No Subscriptions Found" : "Select a Subscription"}
|
||||
styles={{
|
||||
callout: "accountSwitchSubscriptionDropdownMenu",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -470,15 +470,6 @@ export class DataExplorer {
|
||||
return this.frame.getByTestId("notification-console/header-status");
|
||||
}
|
||||
|
||||
async getDropdownItemByName(name: string, ariaLabel?: string): Promise<Locator> {
|
||||
const dropdownItemsWrapper = this.frame.locator("div.ms-Dropdown-items");
|
||||
if (ariaLabel) {
|
||||
expect(await dropdownItemsWrapper.getAttribute("aria-label")).toEqual(ariaLabel);
|
||||
}
|
||||
const containerDropdownItems = dropdownItemsWrapper.locator("button.ms-Dropdown-item[role='option']");
|
||||
return containerDropdownItems.filter({ hasText: name });
|
||||
}
|
||||
|
||||
/** Waits for the Data Explorer app to load */
|
||||
static async waitForExplorer(page: Page) {
|
||||
const iframeElement = await page.getByTestId("DataExplorerFrame").elementHandle();
|
||||
|
||||
@@ -9,7 +9,7 @@ let explorer: DataExplorer = null!;
|
||||
let documentsTab: DocumentsTab = null!;
|
||||
|
||||
for (const { name, databaseId, containerId, documents } of documentTestCases) {
|
||||
test.describe(`Test MongoRU Documents with ${name}`, () => {
|
||||
test.describe.serial(`Test MongoRU Documents with ${name}`, () => {
|
||||
// test.skip(true, "Temporarily disabling all tests in this spec file");
|
||||
test.beforeEach("Open documents tab", async ({ page }) => {
|
||||
await setupCORSBypass(page);
|
||||
@@ -33,7 +33,7 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
|
||||
|
||||
for (const document of documents) {
|
||||
const { documentId: docId, partitionKeys } = document;
|
||||
test.describe(`Document ID: ${docId}`, () => {
|
||||
test.describe.serial(`Document ID: ${docId}`, () => {
|
||||
test(`should load and view document ${docId}`, async () => {
|
||||
const span = documentsTab.documentsListPane.getByText(docId, { exact: true }).nth(0);
|
||||
await span.waitFor();
|
||||
|
||||
@@ -8,7 +8,7 @@ let explorer: DataExplorer = null!;
|
||||
let documentsTab: DocumentsTab = null!;
|
||||
|
||||
for (const { name, databaseId, containerId, documents } of documentTestCases) {
|
||||
test.describe(`Test SQL Documents with ${name}`, () => {
|
||||
test.describe.serial(`Test SQL Documents with ${name}`, () => {
|
||||
// test.skip(true, "Temporarily disabling all tests in this spec file");
|
||||
test.beforeEach("Open documents tab", async ({ page }) => {
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQLReadOnly);
|
||||
@@ -28,7 +28,7 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
|
||||
|
||||
for (const document of documents) {
|
||||
const { documentId: docId, partitionKeys, skipCreateDelete } = document;
|
||||
test.describe(`Document ID: ${docId}`, () => {
|
||||
test.describe.serial(`Document ID: ${docId}`, () => {
|
||||
test(`should load and view document ${docId}`, async () => {
|
||||
const span = documentsTab.documentsListPane.getByText(docId, { exact: true }).nth(0);
|
||||
await span.waitFor();
|
||||
|
||||
@@ -9,7 +9,7 @@ let queryTab: QueryTab = null!;
|
||||
let queryEditor: Editor = null!;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer({ includeTestData: true });
|
||||
context = await createTestSQLContainer(true);
|
||||
});
|
||||
|
||||
test.beforeEach("Open new query tab", async ({ page }) => {
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
import { expect, Page, test } from "@playwright/test";
|
||||
import { DataExplorer, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Change Partition Key", () => {
|
||||
let pageInstance: Page;
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
const newPartitionKeyPath = "/newPartitionKey";
|
||||
const newContainerId = "testcontainer_1";
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer();
|
||||
});
|
||||
|
||||
test.beforeEach("Open container settings", async ({ page }) => {
|
||||
pageInstance = page;
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
|
||||
// Click Scale & Settings and open Partition Key tab
|
||||
await explorer.openScaleAndSettings(context);
|
||||
const PartitionKeyTab = explorer.frame.getByTestId("settings-tab-header/PartitionKeyTab");
|
||||
await PartitionKeyTab.click();
|
||||
});
|
||||
|
||||
test.afterAll("Delete Test Database", async () => {
|
||||
await context?.dispose();
|
||||
});
|
||||
|
||||
test("Change partition key path", async () => {
|
||||
await expect(explorer.frame.getByText("/partitionKey")).toBeVisible();
|
||||
await expect(explorer.frame.getByText("Change partition key")).toBeVisible();
|
||||
await expect(explorer.frame.getByText(/To safeguard the integrity of/)).toBeVisible();
|
||||
await expect(explorer.frame.getByText(/To change the partition key/)).toBeVisible();
|
||||
|
||||
const changePartitionKeyButton = explorer.frame.getByTestId("change-partition-key-button");
|
||||
expect(changePartitionKeyButton).toBeVisible();
|
||||
await changePartitionKeyButton.click();
|
||||
|
||||
// Fill out new partition key form in the panel
|
||||
const changePkPanel = explorer.frame.getByTestId(`Panel:Change partition key`);
|
||||
await expect(changePkPanel.getByText(context.database.id)).toBeVisible();
|
||||
await expect(explorer.frame.getByRole("heading", { name: "Change partition key" })).toBeVisible();
|
||||
await expect(explorer.frame.getByText(/When changing a container/)).toBeVisible();
|
||||
|
||||
// Try to switch to new container
|
||||
await expect(changePkPanel.getByText("New container")).toBeVisible();
|
||||
await expect(changePkPanel.getByText("Existing container")).toBeVisible();
|
||||
await expect(changePkPanel.getByTestId("new-container-id-input")).toBeVisible();
|
||||
|
||||
changePkPanel.getByTestId("new-container-id-input").fill(newContainerId);
|
||||
await expect(changePkPanel.getByTestId("new-container-partition-key-input")).toBeVisible();
|
||||
changePkPanel.getByTestId("new-container-partition-key-input").fill(newPartitionKeyPath);
|
||||
|
||||
await expect(changePkPanel.getByTestId("add-sub-partition-key-button")).toBeVisible();
|
||||
changePkPanel.getByTestId("add-sub-partition-key-button").click();
|
||||
await expect(changePkPanel.getByTestId("new-container-sub-partition-key-input-0")).toBeVisible();
|
||||
await expect(changePkPanel.getByTestId("remove-sub-partition-key-button-0")).toBeVisible();
|
||||
await expect(changePkPanel.getByTestId("hierarchical-partitioning-info-text")).toBeVisible();
|
||||
changePkPanel.getByTestId("new-container-sub-partition-key-input-0").fill("/customerId");
|
||||
|
||||
await changePkPanel.getByTestId("Panel/OkButton").click();
|
||||
|
||||
await pageInstance.waitForLoadState("networkidle");
|
||||
await expect(changePkPanel).not.toBeVisible({ timeout: 60 * 1000 });
|
||||
|
||||
// Verify partition key change job
|
||||
const jobText = explorer.frame.getByText(/Partition key change job/);
|
||||
await expect(jobText).toBeVisible();
|
||||
await expect(explorer.frame.locator(".ms-ProgressIndicator-itemName")).toContainText("Portal_testcontainer_1");
|
||||
|
||||
const jobRow = explorer.frame.locator(".ms-ProgressIndicator-itemDescription");
|
||||
await expect(jobRow.getByText("Completed")).toBeVisible({ timeout: 30 * 1000 });
|
||||
|
||||
const newContainerNode = await explorer.waitForContainerNode(context.database.id, newContainerId);
|
||||
expect(newContainerNode).not.toBeNull();
|
||||
|
||||
// Now try to switch to existing container
|
||||
await changePartitionKeyButton.click();
|
||||
await changePkPanel.getByText("Existing container").click();
|
||||
await changePkPanel.getByLabel("Use existing container").check();
|
||||
await changePkPanel.getByText("Choose an existing container").click();
|
||||
|
||||
const containerDropdownItem = await explorer.getDropdownItemByName(newContainerId, "Existing Containers");
|
||||
await containerDropdownItem.click();
|
||||
|
||||
await changePkPanel.getByTestId("Panel/OkButton").click();
|
||||
await explorer.frame.getByRole("button", { name: "Cancel" }).click();
|
||||
|
||||
// Dismiss overlay if it appears
|
||||
const overlayFrame = explorer.frame.locator("#webpack-dev-server-client-overlay").first();
|
||||
if (await overlayFrame.count()) {
|
||||
await overlayFrame.contentFrame().getByLabel("Dismiss").click();
|
||||
}
|
||||
const cancelledJobRow = explorer.frame.getByTestId("Tab:tab0");
|
||||
await expect(cancelledJobRow.getByText("Cancelled")).toBeVisible({ timeout: 30 * 1000 });
|
||||
});
|
||||
});
|
||||
@@ -9,12 +9,12 @@ import {
|
||||
} from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Autoscale and Manual throughput", () => {
|
||||
test.describe.serial("Autoscale and Manual throughput", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer({ includeTestData: true });
|
||||
context = await createTestSQLContainer(true);
|
||||
});
|
||||
|
||||
test.beforeEach("Open container settings", async ({ page }) => {
|
||||
|
||||
@@ -2,12 +2,12 @@ import { expect, test } from "@playwright/test";
|
||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Settings under Scale & Settings", () => {
|
||||
test.describe.serial("Settings under Scale & Settings", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer({ includeTestData: true });
|
||||
context = await createTestSQLContainer(true);
|
||||
});
|
||||
|
||||
test.beforeEach("Open Settings tab under Scale & Settings", async ({ page }) => {
|
||||
|
||||
@@ -74,18 +74,8 @@ export class TestContainerContext {
|
||||
}
|
||||
}
|
||||
|
||||
type createTestSqlContainerConfig = {
|
||||
includeTestData?: boolean;
|
||||
partitionKey?: string;
|
||||
databaseName?: string;
|
||||
};
|
||||
|
||||
export async function createTestSQLContainer({
|
||||
includeTestData = false,
|
||||
partitionKey = "/partitionKey",
|
||||
databaseName = "",
|
||||
}: createTestSqlContainerConfig = {}) {
|
||||
const databaseId = databaseName ? databaseName : generateUniqueName("db");
|
||||
export async function createTestSQLContainer(includeTestData?: boolean) {
|
||||
const databaseId = generateUniqueName("db");
|
||||
const containerId = "testcontainer"; // A unique container name isn't needed because the database is unique
|
||||
const credentials = getAzureCLICredentials();
|
||||
const adaptedCredentials = new AzureIdentityCredentialAdapter(credentials);
|
||||
@@ -114,7 +104,7 @@ export async function createTestSQLContainer({
|
||||
try {
|
||||
const { container } = await database.containers.createIfNotExists({
|
||||
id: containerId,
|
||||
partitionKey,
|
||||
partitionKey: "/partitionKey",
|
||||
});
|
||||
if (includeTestData) {
|
||||
const batchCount = TestData.length / 100;
|
||||
|
||||
Reference in New Issue
Block a user