From db-cosmosdb
Use when writing tests for Azure Cosmos DB code — Cosmos DB Emulator for integration tests, xUnit/.NET patterns, Jest/Node.js patterns, mock strategies, and RU budget validation
How this skill is triggered — by the user, by Claude, or both
Slash command
/db-cosmosdb:cosmosdb-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
```csharp
public class OrderRepositoryTests : IAsyncLifetime
{
private CosmosClient _client;
private Container _container;
public async Task InitializeAsync()
{
// Cosmos DB Emulator runs at https://localhost:8081
_client = new CosmosClient(
"AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==");
var database = await _client.CreateDatabaseIfNotExistsAsync("testdb");
_container = await database.Database.CreateContainerIfNotExistsAsync("orders", "/customerId");
}
public async Task DisposeAsync()
{
await _client.GetDatabase("testdb").DeleteAsync();
_client.Dispose();
}
[Fact]
public async Task CreateOrder_SetsId()
{
// Arrange
var order = new Order
{
Id = Guid.NewGuid().ToString(),
CustomerId = "customer-1",
Total = 100m,
Status = "pending"
};
// Act
var response = await _container.CreateItemAsync(order, new PartitionKey(order.CustomerId));
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.Resource.Id.Should().NotBeNullOrEmpty();
response.RequestCharge.Should().BeLessThan(10); // RU budget check
}
[Fact]
public async Task PointRead_CostsApproximately1RU()
{
var order = new Order { Id = "test-1", CustomerId = "c1", Total = 50m, Status = "pending" };
await _container.CreateItemAsync(order, new PartitionKey("c1"));
var response = await _container.ReadItemAsync<Order>("test-1", new PartitionKey("c1"));
response.RequestCharge.Should().BeLessThan(2); // Point reads ~1 RU
}
}
const { CosmosClient } = require("@azure/cosmos");
const client = new CosmosClient({
endpoint: "https://localhost:8081",
key: "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
});
let container;
beforeAll(async () => {
const { database } = await client.databases.createIfNotExists({ id: "testdb" });
const { container: c } = await database.containers.createIfNotExists({
id: "orders",
partitionKey: { paths: ["/customerId"] },
});
container = c;
});
afterAll(async () => {
await client.database("testdb").delete();
});
afterEach(async () => {
// Clean up test data
const { resources } = await container.items.readAll().fetchAll();
for (const item of resources) {
await container.item(item.id, item.customerId).delete();
}
});
test("create order returns 201", async () => {
const order = {
id: "test-order-1",
customerId: "c1",
total: 100,
status: "pending",
};
const { resource, statusCode } = await container.items.create(order);
expect(statusCode).toBe(201);
expect(resource.id).toBe("test-order-1");
});
var mockContainer = new Mock<Container>();
mockContainer
.Setup(c => c.ReadItemAsync<Order>(It.IsAny<string>(), It.IsAny<PartitionKey>(), null, default))
.ReturnsAsync(MockResponse(new Order { Id = "1", CustomerId = "c1", Total = 100m }));
RequestCharge is within expected bounds[Fact]
public async Task CreateOrder_WithValidData_PersistsToCosmosDb()
{
var order = new Order { Id = Guid.NewGuid().ToString(), CustomerId = "c1", Status = "pending" };
var response = await _container.CreateItemAsync(order, new PartitionKey(order.CustomerId));
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.RequestCharge.Should().BeLessThan(10);
}
[Fact]
public async Task CreateOrder_WithDuplicateId_ReturnsConflict()
{
var order = new Order { Id = "dup-1", CustomerId = "c1", Status = "pending" };
await _container.CreateItemAsync(order, new PartitionKey("c1"));
var act = () => _container.CreateItemAsync(order, new PartitionKey("c1"));
var ex = await act.Should().ThrowAsync<CosmosException>();
ex.Which.StatusCode.Should().Be(HttpStatusCode.Conflict);
}
[Fact]
public async Task GetOrder_WithWrongPartitionKey_ReturnsNotFound()
{
var order = new Order { Id = "o1", CustomerId = "c1" };
await _container.CreateItemAsync(order, new PartitionKey("c1"));
var act = () => _container.ReadItemAsync<Order>("o1", new PartitionKey("wrong-pk"));
var ex = await act.Should().ThrowAsync<CosmosException>();
ex.Which.StatusCode.Should().Be(HttpStatusCode.NotFound);
}
[Fact]
public async Task QueryOrders_EmptyContainer_ReturnsEmptyList()
{
var query = _container.GetItemQueryIterator<Order>("SELECT * FROM c WHERE c.customerId = 'nonexistent'");
var results = new List<Order>();
while (query.HasMoreResults)
{
var response = await query.ReadNextAsync();
results.AddRange(response);
}
results.Should().BeEmpty();
}
[Fact]
public async Task CreateOrder_WithMaxPartitionKeyLength_Succeeds()
{
var longPk = new string('c', 2048);
var order = new Order { Id = Guid.NewGuid().ToString(), CustomerId = longPk };
var response = await _container.CreateItemAsync(order, new PartitionKey(longPk));
response.StatusCode.Should().Be(HttpStatusCode.Created);
}
[Fact]
public async Task QueryOrders_WithInjectionPayload_TreatsAsLiteral()
{
var malicious = "' OR '1'='1";
var query = new QueryDefinition("SELECT * FROM c WHERE c.customerId = @id")
.WithParameter("@id", malicious);
var iterator = _container.GetItemQueryIterator<Order>(query);
var results = new List<Order>();
while (iterator.HasMoreResults)
{
var response = await iterator.ReadNextAsync();
results.AddRange(response);
}
results.Should().BeEmpty();
}
[Fact]
public async Task CosmosException_DoesNotExposeConnectionKey()
{
var badContainer = _database.GetContainer("nonexistent");
var act = () => badContainer.ReadItemAsync<Order>("id", new PartitionKey("pk"));
var ex = await act.Should().ThrowAsync<CosmosException>();
ex.Which.Message.Should().NotContain("AccountKey=");
ex.Which.Message.Should().NotContain("AccountEndpoint=");
}
Jest (Node.js):
describe("OrderRepository — security", () => {
it("security: parameterized query prevents injection", async () => {
const malicious = "' OR '1'='1";
const { resources } = await container.items
.query({ query: "SELECT * FROM c WHERE c.customerId = @id", parameters: [{ name: "@id", value: malicious }] })
.fetchAll();
expect(resources).toEqual([]);
});
});
npx claudepluginhub gagandeepp/software-agent-teams --plugin db-cosmosdbGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.