npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nosana/scenario

v2.2.5

Published

Nosana scenario test helpers: network-aware client setup for localnet, devnet, and mainnet

Readme

@nosana/scenario

Network-aware scenario test helpers for Nosana. Run the same tests against localnet, devnet, or mainnet — controlled entirely via environment variables.

Uses @nosana/localnet for Docker infrastructure and @nosana/kit for the Nosana SDK.

Quick Start

npm install --save-dev @nosana/scenario

Write Tests

import { describe, it, expect } from 'vitest';
import { getScenarioClient, createMarket, listJob } from '@nosana/scenario';

describe('scenario: basic', () => {
  it('works with the Nosana SDK', async () => {
    const client = await getScenarioClient();
    const balance = await client.solana.getBalance();
    expect(balance).toBeGreaterThan(0);
  });

  it('creates a market and lists a job', async () => {
    const marketAddress = await createMarket();
    const jobAddress = await listJob({ market: marketAddress });
    expect(jobAddress).toBeDefined();
  });
});

Multiple Clients

Use the key option to create independently funded clients — useful for multi-party scenarios:

const deployer = await getScenarioClient();                          // cached as 'default'
const node     = await getScenarioClient({ key: 'node' });           // separate wallet
const node2    = await getScenarioClient({ key: 'node2' });          // another separate wallet

Each unique key gets its own keypair, SOL airdrop, and NOS mint on localnet.

Run Against Different Networks

No code changes needed — just set environment variables:

# Localnet (default) — starts a local Solana validator via Docker
npm run test:scenario:localnet

# Devnet — requires a funded wallet
NOSANA_NETWORK=devnet NOSANA_WALLET=~/.config/solana/id.json npm run test:scenario

# Mainnet
NOSANA_NETWORK=mainnet NOSANA_WALLET=/path/to/keypair.json npm run test:scenario

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | NOSANA_NETWORK | localnet | Target network: localnet, devnet, or mainnet | | NOSANA_WALLET | — | Path to a Solana keypair JSON file (required for devnet/mainnet) |

Vitest Integration

// vitest.scenario.config.ts
import { defineScenarioVitestConfig } from '@nosana/scenario';

export default defineScenarioVitestConfig({
  test: {
    include: ['tests/scenarios/**/*.test.ts'],
  },
});

npm Scripts

These scripts are already included in @nosana/scenario's package.json:

| Script | Description | |--------|-------------| | test:scenario | Run scenario tests with vitest | | test:scenario:localnet | Start localnet + run scenario tests | | localnet:up | Start the Docker-based Solana validator | | localnet:down | Stop the validator and clean up |

From the workspace root:

# Run everything
pnpm --filter @nosana/scenario run test:scenario:localnet

# Or step by step
pnpm run localnet:up
pnpm --filter @nosana/scenario run test:scenario
pnpm run localnet:down

API Reference

getScenarioClient(options?): Promise<NosanaClient>

Returns a cached NosanaClient for the target network. Each unique key gets its own independently funded client instance.

| Option | Type | Default | Description | |--------|------|---------|-------------| | key | string | 'default' | Cache key — each unique key creates a separate client with its own wallet | | network | 'localnet' \| 'devnet' \| 'mainnet' | NOSANA_NETWORK env or 'localnet' | Target network | | wallet | Wallet | NOSANA_WALLET env or auto-generated (localnet) | Wallet signer | | airdropAmount | bigint | 2_000_000_000n | SOL airdrop amount (localnet only) | | mintAmount | bigint | 1_000_000_000n | NOS mint amount (localnet only) | | config | Partial<NosanaClientConfig> | — | Override client config |

Localnet (default): generates a random keypair, airdrops SOL, and mints NOS tokens.

Devnet / Mainnet: connects with the provided wallet (via option or NOSANA_WALLET env var). No airdrop or minting is performed.

getLocalnetClient(options?): Promise<NosanaClient>

Returns a cached NosanaClient connected to localnet. Equivalent to getScenarioClient({ network: 'localnet' }).


Helper Functions

All helper functions include built-in vitest expect assertions and accept an optional clientOverride parameter. When omitted, they use the default scenario client (getScenarioClient()).

Jobs

createMarket(params?, clientOverride?): Promise<Address>

Create a market on-chain and return its address.

const marketAddress = await createMarket();
const marketAddress = await createMarket({ jobPrice: 1000n });
closeMarket(marketAddress, clientOverride?): Promise<void>

Close an existing market.

await closeMarket(marketAddress.toString());
listJob(params, clientOverride?): Promise<Address>

List (submit) a job to a market and return the job address. timeout defaults to 3600 and ipfsHash defaults to a test hash — only market is required.

const jobAddress = await listJob({ market: marketAddress });
const jobAddress = await listJob({ market: marketAddress, timeout: 7200 });
joinMarketQueue(marketAddress, options?, clientOverride?): Promise<void>

Join a market's node queue. Verifies the node is queued by default.

const nodeClient = await getScenarioClient({ key: 'node' });
await joinMarketQueue(marketAddress.toString(), {}, nodeClient);

// Disable queue verification
await joinMarketQueue(marketAddress.toString(), { verifyQueued: false }, nodeClient);
waitForJobState(jobAddress, expectedState, clientOverride?): Promise<void>

Poll until a job reaches the expected state using vitest's expect.poll.

import { JobState } from '@nosana/scenario';

await waitForJobState(jobAddress.toString(), JobState.RUNNING);

Nodes

finishJob(jobAddress, clientOverride?): Promise<void>

Finish (complete) a job as a node, submitting a default IPFS results hash.

const nodeClient = await getScenarioClient({ key: 'node' });
await finishJob(jobAddress.toString(), nodeClient);
verifyJobAssignedToNode(jobAddress, options?, clientOverride?): Promise<void>

Assert that a job is assigned to the client's wallet. Optionally verify the job state.

const nodeClient = await getScenarioClient({ key: 'node' });
await verifyJobAssignedToNode(jobAddress.toString(), { expectedState: 1 }, nodeClient);

Utilities

mintNosTo(client, recipient, amount): Promise<void>

Mint NOS tokens to any address on the localnet.

ensureLocalnetMint(client): Promise<{ mintAuthority, mintAddress }>

Ensures the NOS mint exists on localnet. Creates it if it doesn't exist.

executeInstructionPlan(client, plan): Promise<void>

Execute a Solana instruction plan using the client's wallet as fee payer.

defineScenarioVitestConfig(overrides?): object

Returns a Vitest config object with the scenario setup file pre-configured.

Re-exports from @nosana/localnet

  • startLocalnet, stopLocalnet
  • LOCALNET_RPC_ENDPOINT, LOCALNET_WS_ENDPOINT

Re-exports from @nosana/kit

  • NosanaNetwork, JobState, type NosanaClient, type Wallet, type Address