Skip to main content
The @privora/test-utils-ts package provides shared utilities for testing Privora applications in TypeScript.

Installation

npm install --save-dev @privora/test-utils-ts

Quick Start

import {
  createFundedAccount,
  requireSequencer,
  getRpcUrl,
} from '@privora/test-utils-ts';

beforeAll(async () => {
  // Ensure sequencer is running (fails fast if not)
  await requireSequencer();

  // Create a funded test account
  const { keypair, balance } = await createFundedAccount();
  console.log(`Account ${keypair.publicKey.toBase58()} funded with ${balance} lamports`);
});

Constants

import {
  DEFAULT_RPC_URL,           // 'http://localhost:18899'
  DEFAULT_AIRDROP_LAMPORTS,  // 2_000_000_000 (2 SOL)
  DEFAULT_AIRDROP_WAIT_MS,   // 1000
  DEFAULT_TEST_TIMEOUT_MS,   // 30_000
  FHE_TEST_TIMEOUT_MS,       // 60_000
  TEST_SEED,                 // Uint8Array(32) for deterministic keypairs
  getRpcUrl,                 // Returns RPC_URL env var or DEFAULT_RPC_URL
  getAirdropAmount,          // Returns AIRDROP_AMOUNT env var or default
} from '@privora/test-utils-ts';

getRpcUrl

function getRpcUrl(): string
Returns the RPC URL from the RPC_URL environment variable, or falls back to DEFAULT_RPC_URL.

getAirdropAmount

function getAirdropAmount(): number
Returns the airdrop amount from the AIRDROP_AMOUNT environment variable, or falls back to DEFAULT_AIRDROP_LAMPORTS.

Sequencer Utilities

requireSequencer

async function requireSequencer(rpcUrl?: string): Promise<void>
Check that the sequencer is running and exit the process if not. Useful for test setup that should fail fast.
beforeAll(async () => {
  await requireSequencer();
});

waitForSequencer

async function waitForSequencer(
  rpcUrl?: string,
  maxWaitMs?: number,    // default: 30000
  intervalMs?: number    // default: 1000
): Promise<void>
Wait for the sequencer to become healthy. Throws an error if not ready within the timeout.
// Wait up to 60 seconds for sequencer
await waitForSequencer(undefined, 60000);

checkSequencerHealth

async function checkSequencerHealth(rpcUrl?: string): Promise<SequencerStatus>

interface SequencerStatus {
  healthy: boolean;
  url: string;
  error?: string;
}
Check if the sequencer is running and healthy.
const status = await checkSequencerHealth();
if (!status.healthy) {
  console.error('Sequencer error:', status.error);
}

rpcCall

async function rpcCall<T>(
  method: string,
  params?: unknown[],
  rpcUrl?: string
): Promise<T>
Make a raw JSON-RPC call to the sequencer.
const result = await rpcCall<string>('getVersion', []);

Funded Account Utilities

createFundedAccount

async function createFundedAccount(options?: {
  keypair?: Keypair;
  lamports?: number;
  rpcUrl?: string;
  waitMs?: number;
}): Promise<FundedAccount>

interface FundedAccount {
  keypair: Keypair;
  publicKey: PublicKey;
  balance: number;
}
Create a new keypair, request an airdrop, and verify the balance.
// Create with defaults
const account = await createFundedAccount();

// With custom options
const account = await createFundedAccount({
  lamports: 5_000_000_000, // 5 SOL
  waitMs: 2000,            // Wait 2s for confirmation
});

requestAirdrop

async function requestAirdrop(
  publicKey: PublicKey | string,
  lamports?: number,
  rpcUrl?: string
): Promise<string>
Request an airdrop to the given public key. Returns the transaction signature.

getBalance

async function getBalance(
  publicKey: PublicKey | string,
  rpcUrl?: string
): Promise<number>
Get the balance of an account in lamports.

getTestKeypair

function getTestKeypair(): Keypair
Create a deterministic test keypair from the standard test seed. Useful for reproducible tests.

getTestKeypairWithSeed

function getTestKeypairWithSeed(seedModifier: number): Keypair
Create a deterministic test keypair from a custom seed modifier.
const alice = getTestKeypairWithSeed(1);
const bob = getTestKeypairWithSeed(2);

Program Deployment

deployProgram

async function deployProgram(
  programId: string,
  programPath: string,
  rpcUrl?: string
): Promise<DeployResult>

interface DeployResult {
  success: boolean;
  programId: string;
  message?: string;
  alreadyDeployed?: boolean;
}
Deploy a program to the sequencer from a .so file.

buildProgram

function buildProgram(programDir: string): boolean
Build a program using cargo build-sbf. Returns true if successful.

buildAndDeploy

async function buildAndDeploy(options: {
  programId: string;
  programDir: string;
  programSoPath: string;
  rpcUrl?: string;
  buildIfMissing?: boolean;  // default: true
}): Promise<DeployResult>
Build (if needed) and deploy a program.
const result = await buildAndDeploy({
  programId: 'MyProgram11111111111111111111111111111111',
  programDir: './programs/my-program',
  programSoPath: './target/deploy/my_program.so',
});

if (result.success) {
  console.log('Program deployed:', result.programId);
}

findExamplesRoot

function findExamplesRoot(startPath: string): string | null
Find the examples directory root from a given path.

Vitest Configuration

The package provides a base Vitest configuration optimized for FHE tests:
// vitest.config.ts
import { defineConfig, mergeConfig } from 'vitest/config';
import baseConfig from '@privora/test-utils-ts/vitest';

export default mergeConfig(baseConfig, defineConfig({
  // Your overrides here
}));
The base config includes:
  • 60-second test timeout for FHE operations
  • 30-second hook timeout
  • Sequential test execution (no shuffling)
  • Single fork mode for WASM stability
  • Verbose reporter

Example Test Setup

import { describe, it, expect, beforeAll } from 'vitest';
import {
  requireSequencer,
  createFundedAccount,
  buildAndDeploy,
  getRpcUrl,
  FHE_TEST_TIMEOUT_MS,
} from '@privora/test-utils-ts';
import { Privora } from '@privora/sdk';

describe('My FHE Tests', () => {
  let privora: Privora;
  let payer: Keypair;

  beforeAll(async () => {
    // Ensure sequencer is running
    await requireSequencer();

    // Deploy program if needed
    await buildAndDeploy({
      programId: 'MyProgram11111111111111111111111111111111',
      programDir: './programs/my-program',
      programSoPath: './target/deploy/my_program.so',
    });

    // Create funded account
    const account = await createFundedAccount();
    payer = account.keypair;

    // Connect to Privora
    privora = await Privora.connect(getRpcUrl());
  }, FHE_TEST_TIMEOUT_MS);

  it('encrypts and submits data', async () => {
    const encrypted = privora.encrypt(100, 'u8');
    const hash = await privora.submit(encrypted);
    expect(hash).toBeDefined();
  });
});