import { expect, test } from "@playwright/test"; import { CosmosDBManagementClient } from "@azure/arm-cosmosdb"; import { Container, CosmosClient } from "@azure/cosmos"; import { DataExplorer, ONE_MINUTE_MS, TestAccount, TestAuthType, generateUniqueName, getAccountName, getAzureCLICredentials, resourceGroupName, subscriptionId, } from "../fx"; // Table API accounts store tables in a fixed "TablesDB" database, with each table as a container. const databaseId = "TablesDB"; const tableId = generateUniqueName("table"); const partitionKey = "testpartition"; const rowKey = "testrow"; test.describe("Tables account using connection string login", () => { let container: Container = null!; test.beforeAll("Seed Test Table", async () => { const credentials = getAzureCLICredentials(); const armClient = new CosmosDBManagementClient(credentials, subscriptionId); const accountName = getAccountName(TestAccount.Tables, TestAuthType.ConnectionString); const account = await armClient.databaseAccounts.get(resourceGroupName, accountName); const keys = await armClient.databaseAccounts.listKeys(resourceGroupName, accountName); const client = new CosmosClient({ endpoint: account.documentEndpoint!, key: keys.primaryMasterKey }); const { database } = await client.databases.createIfNotExists({ id: databaseId }); container = ( await database.containers.createIfNotExists({ id: tableId, partitionKey: { paths: ["/'$pk'"] }, }) ).container; await container.items.upsert({ $pk: partitionKey, id: rowKey, $id: rowKey }); }); test.afterAll("Delete Test Table", async () => { // Only remove the table we created; the fixed "TablesDB" database is shared by every table in the // account, so deleting it would destroy unrelated tables. await container?.delete(); }); test("reads an entity after connection string login", async ({ page }) => { const credentials = getAzureCLICredentials(); const armClient = new CosmosDBManagementClient(credentials, subscriptionId); const accountName = getAccountName(TestAccount.Tables, TestAuthType.ConnectionString); const { connectionStrings = [] } = await armClient.databaseAccounts.listConnectionStrings( resourceGroupName, accountName, ); // Table accounts sign data-plane requests client-side with the account key, so no encrypted token is issued. const connectionString = connectionStrings.find((cs) => cs.type === "Table")?.connectionString; await page.goto("https://localhost:1234/hostedExplorer.html"); const switchConnectionLink = page.getByTestId("Link:SwitchConnectionType"); await switchConnectionLink.waitFor(); await switchConnectionLink.click(); await page.getByPlaceholder("Please enter a connection string").fill(connectionString!); await page.getByRole("button", { name: "Connect" }).click(); const explorer = await DataExplorer.waitForExplorer(page); const tableNode = await explorer.waitForContainerNode(databaseId, tableId); await tableNode.expand(); // Open the Entities node to load the table entities grid and read the seeded entity through the data plane. const entitiesNode = await explorer.waitForNode(`${databaseId}/${tableId}/Entities`); await entitiesNode.element.click(); const entitiesGrid = explorer.frame.locator("#storageTable"); await expect(entitiesGrid).toBeVisible({ timeout: ONE_MINUTE_MS }); await expect(entitiesGrid.getByText(rowKey, { exact: true }).first()).toBeVisible({ timeout: ONE_MINUTE_MS }); await expect(entitiesGrid.getByText(partitionKey, { exact: true }).first()).toBeVisible(); }); });