level 06 / nosql-testing

NoSQL Validation

Validate MongoDB, Redis, and other NoSQL databases in automated test suites.

NoSQL Landscape for Testers

DatabaseTypeNode driverTest use
MongoDBDocumentmongodbValidate document shape, queries
RedisKey-value / cacheioredisVerify cache entries, TTL, pub/sub
CassandraWide columncassandra-driverValidate partition queries
DynamoDBKey-value / document@aws-sdk/client-dynamodbValidate items, GSI queries

MongoDB Validation

// Install: npm install mongodb
import { MongoClient } from 'mongodb';
import { test, expect } from '@playwright/test';

let client: MongoClient;

test.beforeAll(async () => {
  client = new MongoClient(process.env.MONGO_URL!);
  await client.connect();
});

test.afterAll(async () => client.close());

test('user document has required fields', async ({ page }) => {
  await page.goto('/register');
  await page.fill('[name=email]', 'mongo@test.com');
  await page.fill('[name=password]', 'Pass123!');
  await page.click('[type=submit]');
  await expect(page.getByText('Welcome')).toBeVisible();

  const db = client.db('myapp');
  const user = await db.collection('users').findOne({ email: 'mongo@test.com' });
  expect(user).not.toBeNull();
  expect(user!.email).toBe('mongo@test.com');
  expect(user!.createdAt).toBeInstanceOf(Date);
  expect(user!.passwordHash).toBeDefined();
  expect(user!.password).toBeUndefined();  // raw password must NOT be stored
});

MongoDB Query Operators

// Find users created in last hour
const recent = await db.collection('users').find({
  createdAt: { $gte: new Date(Date.now() - 3600000) },
}).toArray();

// Count documents matching condition
const count = await db.collection('orders').countDocuments({
  status: { $in: ['pending', 'processing'] },
  total: { $gt: 100 },
});

// Assert nested field
const order = await db.collection('orders').findOne({ _id: orderId });
expect(order!.shipping.address.city).toBe('London');

Redis Validation

// Install: npm install ioredis
import Redis from 'ioredis';
import { test, expect } from '@playwright/test';

let redis: Redis;

test.beforeAll(async () => {
  redis = new Redis(process.env.REDIS_URL!);
});

test.afterAll(async () => redis.quit());

test('login sets session token in Redis', async ({ page }) => {
  await page.goto('/login');
  await page.fill('[name=username]', 'admin');
  await page.fill('[name=password]', 'admin123');
  await page.click('[type=submit]');

  const cookies = await page.context().cookies();
  const sessionId = cookies.find((c) => c.name === 'session')?.value;
  expect(sessionId).toBeDefined();

  const sessionData = await redis.get(`session:${sessionId}`);
  expect(sessionData).not.toBeNull();
  const session = JSON.parse(sessionData!);
  expect(session.userId).toBeDefined();
});

test('cache key has reasonable TTL', async () => {
  const ttl = await redis.ttl('product:catalog:featured');
  expect(ttl).toBeGreaterThan(0);     // key exists
  expect(ttl).toBeLessThan(3600);     // max 1 hour cache
});

Redis Data Structures in Tests

// List (e.g., job queue)
const queueLength = await redis.llen('email:queue');
expect(queueLength).toBeGreaterThan(0);

// Hash (e.g., user session)
const fields = await redis.hgetall(`user:${userId}:profile`);
expect(fields.email).toBeDefined();

// Set (e.g., unique visitors)
const isMember = await redis.sismember('active:users', String(userId));
expect(isMember).toBe(1);

// Sorted set (e.g., leaderboard)
const rank = await redis.zrank('leaderboard', String(userId));
expect(rank).not.toBeNull();

DynamoDB (AWS)

import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';

const dynamo = new DynamoDBClient({ region: 'us-east-1' });

test('item exists in DynamoDB after creation', async ({ request }) => {
  const res = await request.post('/items', { data: { id: 'test-123', name: 'Widget' } });
  expect(res.status()).toBe(201);

  const { Item } = await dynamo.send(new GetItemCommand({
    TableName: process.env.DYNAMO_TABLE!,
    Key: { id: { S: 'test-123' } },
  }));
  expect(Item).toBeDefined();
  expect(Item!.name.S).toBe('Widget');
});

NoSQL vs SQL Testing Patterns

AspectSQLNoSQL
Schema validationCHECK constraints, column typesManual field assertion in test
RelationshipsForeign key queriesEmbed or look up by ID
CleanupDELETE WHERE or ROLLBACKdeleteOne, del, remove
Partial update checkUPDATE ... SET col=val effectCompare before/after document