mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-21 10:44:14 +00:00
More playwright tests (#2310)
* Add playwright tests for Autoscale/Manual Throughpout and TTL * fix unit tests and lint * fix unit tests * fix tests * fix autoscale selector * changed throughput above limit * Add more playwright tests * fix tests * nit * cleanup * format * stored procedure playwright test * add user defined function playwright test * Add user defined functions and trigger test * fix upload items * fix tests * fix lint errors * fix lint * run cleanup every 3 hours * keep cleanup at 2 hours --------- Co-authored-by: Asier Isayas <aisayas@microsoft.com>
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
import { DataExplorer, DocumentsTab, TestAccount } from "../fx";
|
||||
import { retry, setPartitionKeys } from "../testData";
|
||||
import { existsSync, mkdtempSync, rmdirSync, unlinkSync, writeFileSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import path from "path";
|
||||
import { CommandBarButton, DataExplorer, DocumentsTab, ONE_MINUTE_MS, TestAccount } from "../fx";
|
||||
import {
|
||||
createTestSQLContainer,
|
||||
itemsPerPartition,
|
||||
partitionCount,
|
||||
retry,
|
||||
setPartitionKeys,
|
||||
TestContainerContext,
|
||||
TestData,
|
||||
} from "../testData";
|
||||
import { documentTestCases } from "./testCases";
|
||||
|
||||
let explorer: DataExplorer = null!;
|
||||
@@ -95,3 +106,105 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test.describe.serial("Upload Item", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let uploadDocumentDirPath: string = null!;
|
||||
let uploadDocumentFilePath: string = null!;
|
||||
|
||||
test.beforeAll("Create Test database and open documents tab", async ({ browser }) => {
|
||||
uploadDocumentDirPath = mkdtempSync(path.join(tmpdir(), "upload-document-"));
|
||||
uploadDocumentFilePath = path.join(uploadDocumentDirPath, "uploadDocument.json");
|
||||
|
||||
const page = await browser.newPage();
|
||||
context = await createTestSQLContainer();
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
|
||||
const containerNode = await explorer.waitForContainerNode(context.database.id, context.container.id);
|
||||
await containerNode.expand();
|
||||
|
||||
const containerMenuNode = await explorer.waitForContainerItemsNode(context.database.id, context.container.id);
|
||||
await containerMenuNode.element.click();
|
||||
// We need to click twice in order to remove a tooltip
|
||||
await containerMenuNode.element.click();
|
||||
});
|
||||
|
||||
test.afterAll("Delete Test Database and uploadDocument temp folder", async () => {
|
||||
if (existsSync(uploadDocumentFilePath)) {
|
||||
unlinkSync(uploadDocumentFilePath);
|
||||
}
|
||||
if (existsSync(uploadDocumentDirPath)) {
|
||||
rmdirSync(uploadDocumentDirPath);
|
||||
}
|
||||
if (!process.env.CI) {
|
||||
await context?.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
test.afterEach("Close Upload Items panel if still open", async () => {
|
||||
const closeUploadItemsPanelButton = explorer.frame.getByLabel("Close Upload Items");
|
||||
if (await closeUploadItemsPanelButton.isVisible()) {
|
||||
await closeUploadItemsPanelButton.click();
|
||||
}
|
||||
});
|
||||
|
||||
test("upload document", async () => {
|
||||
// Create file to upload
|
||||
const TestDataJsonString: string = JSON.stringify(TestData, null, 2);
|
||||
writeFileSync(uploadDocumentFilePath, TestDataJsonString);
|
||||
|
||||
const uploadItemCommandBar = explorer.commandBarButton(CommandBarButton.UploadItem);
|
||||
await uploadItemCommandBar.click();
|
||||
|
||||
// Select file to upload
|
||||
await explorer.frame.setInputFiles("#importFileInput", uploadDocumentFilePath);
|
||||
|
||||
const uploadButton = explorer.frame.getByTestId("Panel/OkButton");
|
||||
await uploadButton.click();
|
||||
|
||||
// Verify upload success message
|
||||
const fileUploadStatusExpected: string = `${partitionCount * itemsPerPartition} created, 0 throttled, 0 errors`;
|
||||
const fileUploadStatus = explorer.frame.getByTestId("file-upload-status");
|
||||
await expect(fileUploadStatus).toContainText(fileUploadStatusExpected, {
|
||||
timeout: ONE_MINUTE_MS,
|
||||
});
|
||||
|
||||
// Select file to upload again
|
||||
await explorer.frame.setInputFiles("#importFileInput", uploadDocumentFilePath);
|
||||
await uploadButton.click();
|
||||
|
||||
// Verify upload failure message
|
||||
const errorIcon = explorer.frame.getByRole("img", { name: "error" });
|
||||
await expect(errorIcon).toBeVisible({ timeout: ONE_MINUTE_MS });
|
||||
await expect(fileUploadStatus).toContainText(
|
||||
`0 created, 0 throttled, ${partitionCount * itemsPerPartition} errors`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("upload invalid json", async () => {
|
||||
// Create file to upload
|
||||
let TestDataJsonString: string = JSON.stringify(TestData, null, 2);
|
||||
// Remove the first '[' so that it becomes invalid json
|
||||
TestDataJsonString = TestDataJsonString.substring(1);
|
||||
writeFileSync(uploadDocumentFilePath, TestDataJsonString);
|
||||
|
||||
const uploadItemCommandBar = explorer.commandBarButton(CommandBarButton.UploadItem);
|
||||
await uploadItemCommandBar.click();
|
||||
|
||||
// Select file to upload
|
||||
await explorer.frame.setInputFiles("#importFileInput", uploadDocumentFilePath);
|
||||
|
||||
const uploadButton = explorer.frame.getByTestId("Panel/OkButton");
|
||||
await uploadButton.click();
|
||||
|
||||
// Verify upload failure message
|
||||
const fileUploadErrorList = explorer.frame.getByLabel("error list");
|
||||
// The parsing error will show up differently in different browsers so just check for the word "JSON"
|
||||
await expect(fileUploadErrorList).toContainText("JSON", {
|
||||
timeout: ONE_MINUTE_MS,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
108
test/sql/scaleAndSettings/computedProperties.spec.ts
Normal file
108
test/sql/scaleAndSettings/computedProperties.spec.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { expect, Page, test } from "@playwright/test";
|
||||
import * as DataModels from "../../../src/Contracts/DataModels";
|
||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Computed Properties", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer();
|
||||
});
|
||||
|
||||
test.beforeEach("Open Settings tab under Scale & Settings", async ({ page }) => {
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
const containerNode = await explorer.waitForContainerNode(context.database.id, context.container.id);
|
||||
await containerNode.expand();
|
||||
|
||||
// Click Scale & Settings and open Settings tab
|
||||
await explorer.openScaleAndSettings(context);
|
||||
const computedPropertiesTab = explorer.frame.getByTestId("settings-tab-header/ComputedPropertiesTab");
|
||||
await computedPropertiesTab.click();
|
||||
});
|
||||
|
||||
test.afterAll("Delete Test Database", async () => {
|
||||
await context?.dispose();
|
||||
});
|
||||
|
||||
test("Add valid computed property", async ({ page }) => {
|
||||
await clearComputedPropertiesTextBoxContent({ page });
|
||||
|
||||
// Create computed property
|
||||
const computedProperties: DataModels.ComputedProperties = [
|
||||
{
|
||||
name: "cp_lowerName",
|
||||
query: "SELECT VALUE LOWER(c.name) FROM c",
|
||||
},
|
||||
];
|
||||
const computedPropertiesString: string = JSON.stringify(computedProperties);
|
||||
await page.keyboard.type(computedPropertiesString);
|
||||
|
||||
// Save changes
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await expect(saveButton).toBeEnabled();
|
||||
await saveButton.click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully updated container ${context.container.id}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("Add computed property with invalid query", async ({ page }) => {
|
||||
await clearComputedPropertiesTextBoxContent({ page });
|
||||
|
||||
// Create computed property with no VALUE keyword in query
|
||||
const computedProperties: DataModels.ComputedProperties = [
|
||||
{
|
||||
name: "cp_lowerName",
|
||||
query: "SELECT LOWER(c.name) FROM c",
|
||||
},
|
||||
];
|
||||
const computedPropertiesString: string = JSON.stringify(computedProperties);
|
||||
await page.keyboard.type(computedPropertiesString);
|
||||
|
||||
// Save changes
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await expect(saveButton).toBeEnabled();
|
||||
await saveButton.click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Failed to update container ${context.container.id}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("Add computed property with invalid json", async ({ page }) => {
|
||||
await clearComputedPropertiesTextBoxContent({ page });
|
||||
|
||||
// Create computed property with no VALUE keyword in query
|
||||
const computedProperties: DataModels.ComputedProperties = [
|
||||
{
|
||||
name: "cp_lowerName",
|
||||
query: "SELECT LOWER(c.name) FROM c",
|
||||
},
|
||||
];
|
||||
const computedPropertiesString: string = JSON.stringify(computedProperties);
|
||||
await page.keyboard.type(computedPropertiesString + "]");
|
||||
|
||||
// Save button should remain disabled due to invalid json
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await expect(saveButton).toBeDisabled();
|
||||
});
|
||||
|
||||
const clearComputedPropertiesTextBoxContent = async ({ page }: { page: Page }): Promise<void> => {
|
||||
// Get computed properties text box
|
||||
await explorer.frame.waitForSelector(".monaco-scrollable-element", { state: "visible" });
|
||||
const computedPropertiesEditor = explorer.frame.getByTestId("computed-properties-editor");
|
||||
await computedPropertiesEditor.click();
|
||||
|
||||
// Clear existing content (Ctrl+A + Backspace does not work with webkit)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
await page.keyboard.press("Backspace");
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -11,7 +11,7 @@ test.describe("Settings under Scale & Settings", () => {
|
||||
const page = await browser.newPage();
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
|
||||
// Click Scale & Settings and open Scale tab
|
||||
// Click Scale & Settings and open Settings tab
|
||||
await explorer.openScaleAndSettings(context);
|
||||
const settingsTab = explorer.frame.getByTestId("settings-tab-header/SubSettingsTab");
|
||||
await settingsTab.click();
|
||||
@@ -53,4 +53,28 @@ test.describe("Settings under Scale & Settings", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("Set Geospatial Config to Geometry then Geography", async () => {
|
||||
const geometryRadioButton = explorer.frame.getByRole("radio", { name: "geometry-option" });
|
||||
await geometryRadioButton.click();
|
||||
|
||||
await explorer.commandBarButton(CommandBarButton.Save).click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully updated container ${context.container.id}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
|
||||
const geographyRadioButton = explorer.frame.getByRole("radio", { name: "geography-option" });
|
||||
await geographyRadioButton.click();
|
||||
|
||||
await explorer.commandBarButton(CommandBarButton.Save).click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully updated container ${context.container.id}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
78
test/sql/scripts/storedProcedure.spec.ts
Normal file
78
test/sql/scripts/storedProcedure.spec.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Stored Procedures", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer();
|
||||
});
|
||||
|
||||
test.beforeEach("Open container", async ({ page }) => {
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
});
|
||||
|
||||
test.afterAll("Delete Test Database", async () => {
|
||||
await context?.dispose();
|
||||
});
|
||||
|
||||
test("Add, execute, and delete stored procedure", async ({ page }, testInfo) => {
|
||||
void page;
|
||||
// Open container context menu and click New Stored Procedure
|
||||
const containerNode = await explorer.waitForContainerNode(context.database.id, context.container.id);
|
||||
await containerNode.openContextMenu();
|
||||
await containerNode.contextMenuItem("New Stored Procedure").click();
|
||||
|
||||
// Type stored procedure id and use stock procedure
|
||||
const storedProcedureIdTextBox = explorer.frame.getByLabel("Stored procedure id");
|
||||
await storedProcedureIdTextBox.isVisible();
|
||||
const storedProcedureName = `stored-procedure-${testInfo.testId}`;
|
||||
await storedProcedureIdTextBox.fill(storedProcedureName);
|
||||
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await expect(saveButton).toBeEnabled();
|
||||
await saveButton.click();
|
||||
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully created stored procedure ${storedProcedureName}`,
|
||||
{
|
||||
timeout: 2 * ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
|
||||
// Execute stored procedure
|
||||
const executeButton = explorer.commandBarButton(CommandBarButton.Execute);
|
||||
await executeButton.click();
|
||||
const executeSidePanelButton = explorer.frame.getByTestId("Panel/OkButton");
|
||||
await executeSidePanelButton.click();
|
||||
|
||||
const executeStoredProcedureResult = explorer.frame.getByLabel("Execute stored procedure result");
|
||||
await expect(executeStoredProcedureResult).toBeAttached({
|
||||
timeout: ONE_MINUTE_MS,
|
||||
});
|
||||
|
||||
// Delete stored procedure
|
||||
await containerNode.expand();
|
||||
const storedProceduresNode = await explorer.waitForNode(
|
||||
`${context.database.id}/${context.container.id}/Stored Procedures`,
|
||||
);
|
||||
await storedProceduresNode.expand();
|
||||
const storedProcedureNode = await explorer.waitForNode(
|
||||
`${context.database.id}/${context.container.id}/Stored Procedures/${storedProcedureName}`,
|
||||
);
|
||||
|
||||
await storedProcedureNode.openContextMenu();
|
||||
await storedProcedureNode.contextMenuItem("Delete Stored Procedure").click();
|
||||
const deleteStoredProcedureButton = explorer.frame.getByTestId("DialogButton:Delete");
|
||||
await deleteStoredProcedureButton.click();
|
||||
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully deleted stored procedure ${storedProcedureName}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
80
test/sql/scripts/trigger.spec.ts
Normal file
80
test/sql/scripts/trigger.spec.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("Triggers", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
const triggerBody = `function validateToDoItemTimestamp() {
|
||||
var context = getContext();
|
||||
var request = context.getRequest();
|
||||
|
||||
var itemToCreate = request.getBody();
|
||||
|
||||
if (!("timestamp" in itemToCreate)) {
|
||||
var ts = new Date();
|
||||
itemToCreate["timestamp"] = ts.getTime();
|
||||
}
|
||||
|
||||
request.setBody(itemToCreate);
|
||||
}`;
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer();
|
||||
});
|
||||
|
||||
test.beforeEach("Open container", async ({ page }) => {
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
});
|
||||
|
||||
if (!process.env.CI) {
|
||||
test.afterAll("Delete Test Database", async () => {
|
||||
await context?.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
test("Add and delete trigger", async ({ page }, testInfo) => {
|
||||
// Open container context menu and click New Trigger
|
||||
const containerNode = await explorer.waitForContainerNode(context.database.id, context.container.id);
|
||||
await containerNode.openContextMenu();
|
||||
await containerNode.contextMenuItem("New Trigger").click();
|
||||
|
||||
// Assign Trigger id
|
||||
const triggerIdTextBox = explorer.frame.getByLabel("Trigger Id");
|
||||
const triggerId: string = `validateItemTimestamp-${testInfo.testId}`;
|
||||
await triggerIdTextBox.fill(triggerId);
|
||||
|
||||
// Create Trigger body that validates item timestamp
|
||||
const triggerBodyTextArea = explorer.frame.getByTestId("EditorReact/Host/Loaded");
|
||||
await triggerBodyTextArea.click();
|
||||
|
||||
// Clear existing content
|
||||
const isMac: boolean = process.platform === "darwin";
|
||||
await page.keyboard.press(isMac ? "Meta+A" : "Control+A");
|
||||
await page.keyboard.press("Backspace");
|
||||
|
||||
await page.keyboard.type(triggerBody);
|
||||
|
||||
// Save changes
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await saveButton.click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(`Successfully created trigger ${triggerId}`, {
|
||||
timeout: 2 * ONE_MINUTE_MS,
|
||||
});
|
||||
|
||||
// Delete Trigger
|
||||
await containerNode.expand();
|
||||
const triggersNode = await explorer.waitForNode(`${context.database.id}/${context.container.id}/Triggers`);
|
||||
await triggersNode.expand();
|
||||
const triggerNode = await explorer.waitForNode(
|
||||
`${context.database.id}/${context.container.id}/Triggers/${triggerId}`,
|
||||
);
|
||||
|
||||
await triggerNode.openContextMenu();
|
||||
await triggerNode.contextMenuItem("Delete Trigger").click();
|
||||
const deleteTriggerButton = explorer.frame.getByTestId("DialogButton:Delete");
|
||||
await deleteTriggerButton.click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(`Successfully deleted trigger ${triggerId}`, {
|
||||
timeout: ONE_MINUTE_MS,
|
||||
});
|
||||
});
|
||||
});
|
||||
82
test/sql/scripts/userDefinedFunction.spec.ts
Normal file
82
test/sql/scripts/userDefinedFunction.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { CommandBarButton, DataExplorer, ONE_MINUTE_MS, TestAccount } from "../../fx";
|
||||
import { createTestSQLContainer, TestContainerContext } from "../../testData";
|
||||
|
||||
test.describe("User Defined Functions", () => {
|
||||
let context: TestContainerContext = null!;
|
||||
let explorer: DataExplorer = null!;
|
||||
const udfBody: string = `function extractDocumentId(doc) {
|
||||
return {
|
||||
id: doc.id
|
||||
};
|
||||
}`;
|
||||
|
||||
test.beforeAll("Create Test Database", async () => {
|
||||
context = await createTestSQLContainer();
|
||||
});
|
||||
|
||||
test.beforeEach("Open container", async ({ page }) => {
|
||||
explorer = await DataExplorer.open(page, TestAccount.SQL);
|
||||
});
|
||||
|
||||
if (!process.env.CI) {
|
||||
test.afterAll("Delete Test Database", async () => {
|
||||
await context?.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
test("Add, execute, and delete user defined function", async ({ page }, testInfo) => {
|
||||
// Open container context menu and click New UDF
|
||||
const containerNode = await explorer.waitForContainerNode(context.database.id, context.container.id);
|
||||
await containerNode.openContextMenu();
|
||||
await containerNode.contextMenuItem("New UDF").click();
|
||||
|
||||
// Assign UDF id
|
||||
const udfIdTextBox = explorer.frame.getByLabel("User Defined Function Id");
|
||||
const udfId: string = `extractDocumentId-${testInfo.testId}`;
|
||||
await udfIdTextBox.fill(udfId);
|
||||
|
||||
// Create UDF body that extracts the document id from a document
|
||||
const udfBodyTextArea = explorer.frame.getByTestId("EditorReact/Host/Loaded");
|
||||
await udfBodyTextArea.click();
|
||||
|
||||
// Clear existing content
|
||||
const isMac: boolean = process.platform === "darwin";
|
||||
await page.keyboard.press(isMac ? "Meta+A" : "Control+A");
|
||||
await page.keyboard.press("Backspace");
|
||||
|
||||
await page.keyboard.type(udfBody);
|
||||
|
||||
// Save changes
|
||||
const saveButton = explorer.commandBarButton(CommandBarButton.Save);
|
||||
await expect(saveButton).toBeEnabled();
|
||||
await saveButton.click();
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully created user defined function ${udfId}`,
|
||||
{
|
||||
timeout: 2 * ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
|
||||
// Delete UDF
|
||||
await containerNode.expand();
|
||||
const udfsNode = await explorer.waitForNode(
|
||||
`${context.database.id}/${context.container.id}/User Defined Functions`,
|
||||
);
|
||||
await udfsNode.expand();
|
||||
const udfNode = await explorer.waitForNode(
|
||||
`${context.database.id}/${context.container.id}/User Defined Functions/${udfId}`,
|
||||
);
|
||||
await udfNode.openContextMenu();
|
||||
await udfNode.contextMenuItem("Delete User Defined Function").click();
|
||||
const deleteUserDefinedFunctionButton = explorer.frame.getByTestId("DialogButton:Delete");
|
||||
await deleteUserDefinedFunctionButton.click();
|
||||
|
||||
await expect(explorer.getConsoleHeaderStatus()).toContainText(
|
||||
`Successfully deleted user defined function ${udfId}`,
|
||||
{
|
||||
timeout: ONE_MINUTE_MS,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user