import { expect, test } from "@playwright/test"; import { CosmosDBManagementClient } from "@azure/arm-cosmosdb"; import { CosmosClient, Database } from "@azure/cosmos"; import { DataExplorer, Editor, ONE_MINUTE_MS, TestAccount, TestAuthType, generateUniqueName, getAccountName, getAzureCLICredentials, resourceGroupName, subscriptionId, } from "../fx"; const databaseId = generateUniqueName("db"); const graphId = "testgraph"; const vertexId = "testvertex"; test.describe("Gremlin account using connection string login", () => { let database: Database = null!; test.beforeAll("Seed Test Database", async () => { const credentials = getAzureCLICredentials(); const armClient = new CosmosDBManagementClient(credentials, subscriptionId); const accountName = getAccountName(TestAccount.Gremlin, TestAuthType.ConnectionString); const account = await armClient.databaseAccounts.get(resourceGroupName, accountName); const keys = await armClient.databaseAccounts.listKeys(resourceGroupName, accountName); // Gremlin graphs are stored as documents, so seed a vertex via the SQL client using Cosmos' internal graph format. const client = new CosmosClient({ endpoint: account.documentEndpoint!, key: keys.primaryMasterKey }); database = (await client.databases.createIfNotExists({ id: databaseId })).database; const { container } = await database.containers.createIfNotExists({ id: graphId, partitionKey: { paths: ["/pk"] }, }); await container.items.upsert({ id: vertexId, label: "person", pk: "pk1" }); }); test.afterAll("Delete Test Database", async () => { await database?.delete(); }); test("reads a vertex after connection string login", async ({ page }) => { const credentials = getAzureCLICredentials(); const armClient = new CosmosDBManagementClient(credentials, subscriptionId); const accountName = getAccountName(TestAccount.Gremlin, TestAuthType.ConnectionString); const account = await armClient.databaseAccounts.get(resourceGroupName, accountName); const keys = await armClient.databaseAccounts.listKeys(resourceGroupName, accountName); // Gremlin signs data-plane requests client-side with the account key, so no encrypted token is issued. const connectionString = `AccountEndpoint=${account.documentEndpoint};AccountKey=${keys.primaryMasterKey};ApiKind=Gremlin;`; 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 graphNode = await explorer.waitForContainerNode(databaseId, graphId); await graphNode.expand(); // Open the Graph node to load the graph explorer, then run the default query to read the seeded vertex. const graphDataNode = await explorer.waitForNode(`${databaseId}/${graphId}/Graph`); await graphDataNode.element.click(); await explorer.frame.getByRole("button", { name: "Execute Gremlin Query" }).click(); // Results open in the Graph view; switch to the JSON view to read the vertex document. const jsonResultsTab = explorer.frame.getByRole("tab", { name: "JSON" }); await jsonResultsTab.waitFor({ timeout: ONE_MINUTE_MS }); await jsonResultsTab.click(); const graphJsonEditor = new Editor( explorer.frame, explorer.frame.locator(".graphJsonEditor").getByTestId("EditorReact/Host/Loaded"), ); await expect.poll(async () => await graphJsonEditor.text(), { timeout: ONE_MINUTE_MS }).toContain(vertexId); }); });