midnight-dapp:testing-patterns

Use when writing unit tests for Midnight contract interaction code, integration testing without ZK proofs, E2E testing with Playwright or Cypress, or setting up CI/CD pipelines for Midnight DApps.

16 stars

Best use case

midnight-dapp:testing-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when writing unit tests for Midnight contract interaction code, integration testing without ZK proofs, E2E testing with Playwright or Cypress, or setting up CI/CD pipelines for Midnight DApps.

Teams using midnight-dapp:testing-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/midnight-dapp-testing-patterns/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/testing-security/midnight-dapp-testing-patterns/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/midnight-dapp-testing-patterns/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How midnight-dapp:testing-patterns Compares

Feature / Agentmidnight-dapp:testing-patternsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when writing unit tests for Midnight contract interaction code, integration testing without ZK proofs, E2E testing with Playwright or Cypress, or setting up CI/CD pipelines for Midnight DApps.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Testing Patterns

Test Midnight DApps efficiently using mocked providers, simulated wallets, and testnet integration strategies.

## When to Use

- Writing unit tests for contract interaction code
- Integration testing without real ZK proof generation
- E2E testing with Playwright or Cypress
- Setting up CI/CD pipelines for Midnight DApps
- Testing wallet connection flows without browser extension
- Validating transaction flows before testnet deployment

## Key Concepts

### The Testing Challenge

Midnight DApps face unique testing challenges:

| Challenge | Why It Matters | Solution |
|-----------|----------------|----------|
| **Proof generation takes seconds** | Tests would be too slow | Mock proof providers |
| **Wallet requires browser extension** | Can't run in CI/CD | Mock wallet provider |
| **Private state is local only** | Hard to verify in tests | Controlled test state |
| **Testnet requires real infrastructure** | Flaky in automation | Mock for unit tests, testnet for E2E |

### Testing Pyramid for Midnight DApps

```
           E2E (Testnet)
          /            \
         /  Real proofs  \
        /   Real wallet   \
       /    Slow (~min)    \
      /____________________\
             |
     Integration (Mocked)
    /                      \
   /   Mock proof provider   \
  /    Mock wallet provider   \
 /      Fast (~seconds)        \
/______________________________\
            |
       Unit Tests
      /          \
     /  Pure logic  \
    /   No providers  \
   /   Fast (~ms)      \
  /____________________\
```

### Mock vs Real: When to Use Each

| Test Type | Proof Provider | Wallet Provider | Use Case |
|-----------|---------------|-----------------|----------|
| **Unit** | N/A | N/A | Pure business logic |
| **Component** | Mock | Mock | UI components |
| **Integration** | Mock | Mock | Contract interactions |
| **E2E (local)** | Mock | Mock | Full user flows |
| **E2E (testnet)** | Real | Real (Lace) | Pre-deployment validation |

## References

| Document | Description |
|----------|-------------|
| [mocking-proofs.md](references/mocking-proofs.md) | Mock proof provider for fast tests |
| [mock-wallet-provider.md](references/mock-wallet-provider.md) | Simulating Lace wallet in tests |
| [testnet-workflows.md](references/testnet-workflows.md) | E2E testing against testnet |
| [web3-comparison.md](references/web3-comparison.md) | Hardhat/Foundry testing vs Midnight |

## Examples

| Example | Description |
|---------|-------------|
| [mock-proof-context/](examples/mock-proof-context/) | Mock proof provider and test utilities |
| [mock-wallet/](examples/mock-wallet/) | Fake wallet implementation for tests |
| [e2e-testnet/](examples/e2e-testnet/) | Playwright E2E test against testnet |

## Quick Start

### 1. Install Test Dependencies

```bash
pnpm add -D vitest @testing-library/react @playwright/test msw
```

### 2. Create Mock Proof Provider

```typescript
import { createMockProofProvider } from "./mockProofProvider";

// Returns dummy proofs instantly (no ZK computation)
const mockProofProvider = createMockProofProvider({
  latencyMs: 10, // Simulate realistic timing
});
```

### 3. Create Mock Wallet

```typescript
import { MockWallet } from "./MockWallet";

const mockWallet = new MockWallet({
  address: "addr_test1qz_mock_address_for_testing_purposes_xyz",
  balance: 1000000n,
  network: "testnet",
});

// Inject into window for components that check window.midnight
globalThis.window = {
  midnight: { mnLace: mockWallet.connector },
};
```

### 4. Write a Test

```typescript
import { describe, it, expect, beforeEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { MockWallet } from "./MockWallet";
import { createMockProofProvider } from "./mockProofProvider";
import { TransferButton } from "../TransferButton";

describe("TransferButton", () => {
  let mockWallet: MockWallet;
  let mockProofProvider: MockProofProvider;

  beforeEach(() => {
    mockWallet = new MockWallet({ balance: 1000n });
    mockProofProvider = createMockProofProvider();
  });

  it("should complete transfer with mocked providers", async () => {
    render(
      <TransferButton
        wallet={mockWallet.api}
        proofProvider={mockProofProvider}
        recipient="addr_test1..."
        amount={100n}
      />
    );

    fireEvent.click(screen.getByText("Transfer"));

    // No actual proof generation - instant!
    await screen.findByText("Transfer Complete");

    expect(mockWallet.getBalance()).toBe(900n);
  });
});
```

## Common Patterns

### Testing Contract State Reads

```typescript
import { describe, it, expect } from "vitest";
import { createMockContract } from "./testUtils";

describe("Contract State", () => {
  it("should read balance from contract state", async () => {
    const contract = createMockContract({
      state: {
        balances: new Map([["addr_test1...", 500n]]),
        totalSupply: 10000n,
      },
    });

    const balance = await contract.state.balances.get("addr_test1...");
    expect(balance).toBe(500n);
  });
});
```

### Testing Witness Execution

```typescript
import { describe, it, expect } from "vitest";
import { witnesses, createInitialPrivateState } from "../witnesses";

describe("Witnesses", () => {
  it("should return balance from private state", () => {
    const privateState = createInitialPrivateState(new Uint8Array(32));
    privateState.balance = 1000n;

    const context = { privateState, setPrivateState: () => {} };
    const balance = witnesses.get_balance(context);

    expect(balance).toBe(1000n);
  });

  it("should throw for expired credential", () => {
    const privateState = createInitialPrivateState(new Uint8Array(32));
    privateState.credentials.set("abc123", {
      expiry: BigInt(Date.now() / 1000 - 3600), // Expired 1 hour ago
      data: new Uint8Array(32),
    });

    const context = { privateState, setPrivateState: () => {} };

    expect(() =>
      witnesses.get_credential(context, hexToBytes("abc123"))
    ).toThrow("expired");
  });
});
```

### Testing Error Handling

```typescript
import { describe, it, expect, vi } from "vitest";
import { MockWallet } from "./MockWallet";

describe("Error Handling", () => {
  it("should handle user rejection", async () => {
    const wallet = new MockWallet();
    wallet.rejectNextTransaction("User rejected");

    await expect(
      wallet.api.submitTransaction(mockTx)
    ).rejects.toThrow("User rejected");
  });

  it("should handle proof server unavailable", async () => {
    const proofProvider = createMockProofProvider({
      shouldFail: true,
      errorMessage: "Proof server unavailable",
    });

    await expect(
      proofProvider.generateProof(mockCircuit, mockWitness)
    ).rejects.toThrow("Proof server unavailable");
  });
});
```

### Snapshot Testing for Disclosures

```typescript
import { describe, it, expect } from "vitest";
import { render } from "@testing-library/react";
import { DisclosureModal } from "../DisclosureModal";

describe("DisclosureModal", () => {
  it("should render disclosure summary correctly", () => {
    const disclosures = [
      { field: "age", label: "Your Age", value: "25" },
      { field: "country", label: "Country", value: "US" },
    ];

    const { container } = render(
      <DisclosureModal disclosures={disclosures} onConfirm={() => {}} />
    );

    expect(container).toMatchSnapshot();
  });
});
```

## CI/CD Integration

### GitHub Actions Example

```yaml
name: Test Midnight DApp

on: [push, pull_request]

jobs:
  unit-integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "pnpm"

      - run: pnpm install
      - run: pnpm test:unit
      - run: pnpm test:integration

  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v2
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "pnpm"

      - run: pnpm install
      - run: pnpm exec playwright install --with-deps

      # E2E with mocks - fast, reliable
      - run: pnpm test:e2e:mock

      # Optional: E2E with testnet (slower, requires secrets)
      # - run: pnpm test:e2e:testnet
      #   env:
      #     TESTNET_FAUCET_KEY: ${{ secrets.TESTNET_FAUCET_KEY }}
```

## Related Skills

- `proof-handling` - Understanding what to mock in proof generation
- `wallet-integration` - Understanding Lace wallet API to mock
- `error-handling` - Testing error scenarios
- `state-management` - Testing state synchronization

## Related Commands

- `/dapp-check` - Validates test configuration
- `/dapp-debug tests` - Diagnose test failures

Related Skills

qa-testing

16
from diegosouzapw/awesome-omni-skill

Ensure data integrity, stability, and basic security for a personal productivity app. Focus on preventing data loss, memory leaks, and sync failures during daily 8-hour usage sessions. Skip enterprise-grade testing. Use when testing, verifying, validating, checking features, running tests, or before claiming anything is "done" or "fixed".

qa-testing-strategy

16
from diegosouzapw/awesome-omni-skill

Risk-based quality engineering test strategy across unit, integration, contract, E2E, performance, and security testing with shift-left gates, flake control, CI economics, and observability-first debugging.

qa-testing-playwright

16
from diegosouzapw/awesome-omni-skill

End-to-end web application testing with Playwright: scope control, stable selectors, parallelization/sharding, flake control, network mocking vs real services, visual testing tradeoffs, and CI/CD integration.

qa-testing-ios

16
from diegosouzapw/awesome-omni-skill

iOS testing with XCTest/XCUITest on simulators and devices: layered strategy, determinism/flake control, device matrix selection, CI ergonomics, and repeatable simulator automation.

Property Testing

16
from diegosouzapw/awesome-omni-skill

Property-based testing with fast-check for business logic validation

Playwright E2E Testing

16
from diegosouzapw/awesome-omni-skill

Comprehensive Playwright end-to-end testing patterns with Page Object Model, fixtures, and best practices

OWASP Security Testing

16
from diegosouzapw/awesome-omni-skill

OWASP Top 10 security testing patterns and vulnerability scanning

mobile-testing

16
from diegosouzapw/awesome-omni-skill

Executes automated tests on mobile apps via MCP. Use when testing iOS/Android apps, verifying UI states, automating interactions, or performing end-to-end validation. Not for web testing, API validation, or desktop applications.

moai-workflow-testing

16
from diegosouzapw/awesome-omni-skill

AI-powered enterprise web application testing orchestrator with Context7 integration, intelligent test generation, visual regression testing, cross-browser coordination, and automated QA workflows for modern web applications

implementing-e2e-testing

16
from diegosouzapw/awesome-omni-skill

Master end-to-end testing with Playwright and Cypress to build reliable test suites that catch bugs, improve confidence, and enable fast deployment. Use when implementing E2E tests, debugging flaky tests, or establishing testing standards.

idor-testing

16
from diegosouzapw/awesome-omni-skill

This skill should be used when the user asks to "test for insecure direct object references," "find IDOR vulnerabilities," "exploit broken access control," "enumerate user IDs or obje...

File Path Traversal Testing

16
from diegosouzapw/awesome-omni-skill

This skill should be used when the user asks to "test for directory traversal", "exploit path traversal vulnerabilities", "read arbitrary files through web applications", "find LFI vulnerabilities", or "access files outside web root". It provides comprehensive file path traversal attack and testing methodologies.