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 🙏

© 2024 – Pkg Stats / Ryan Hefner

vitest-nostr

v0.4.1

Published

vitest utilities for Nostr client

Downloads

36

Readme

vitest-nostr

vitest utilities for Nostr client, including faker, extended matcher, and relay mock.

Installation

npm install -D vitest vitest-websocket-mock vitest-nostr

Examples

Faker

import { faker } from "vitest-nostr";

// Get dummy event object.
faker.event();

// You can specify some values.
faker.event({ kind: 1 });

See faker.ts for a complete list of objects supported.

Extended Matcher

vitest-nostr provides extended matchers for common data types exchanged over the Nostr protocol.

import "vitest-nostr"; // needed to extend matcher.
import { expect, test } from "vitest";

test("It is REQ message", () => {
  // Tests if it is an REQ message.
  // We are not interested in the specifics of the message now.
  expect(["REQ", "sub1", { kinds: [1] }]).beToRelayREQ();
});

test("It is REQ message with specified subId", () => {
  // We are now only interested in subId matching.
  expect(["REQ", "sub1", { kinds: [1] }]).beToRelayREQ("sub1");
});

test("It is specified REQ message", () => {
  // We are interested in the complete REQ message.
  expect(["REQ", "sub1", { kinds: [1] }]).beToRelayREQ([
    "sub1",
    { kinds: [1] },
  ]);

  // or just you can use toEqual() matcher.
});

See matcher.ts for a complete list of extended matchers.

Relay Mock

createMockRelay() provides an imitation of a relay. You can test what messages your real WebSocket on the client side sends to the (mock) relay, and whether the client behaves ideally when the (mock) relay sends a particular message to the client.

import { expect, test, beforeEach, afterEach } from "vitest";
import { createMockRelay, faker, type MockRelay } from "vitest-nostr";

let relay: MockRelay;
let client: WebSocket;

beforeEach(async () => {
  relay = createMockRelay("ws://localhost:1234");
  client = new WebSocket("ws://localhost:1234");

  await relay.connected;
});

afterEach(() => {
  relay.close();
  client.close();
});

test("Client can send REQ", async () => {
  client.send(JSON.stringify(["REQ", "sub1", { kinds: [1] }]));
  await expect(relay).toReceiveREQ();
});

test("Client can send REQ with specified subId", async () => {
  client.send(JSON.stringify(["REQ", "sub1", { kinds: [1] }]));
  await expect(relay).toReceiveREQ("sub1");
});

test("Client can send specified REQ", async () => {
  const REQ = ["REQ", "sub1", { kinds: [1] }];

  client.send(JSON.stringify(REQ));

  const received = await relay.next();
  await expect(received).beToRelayREQ(["sub1", { kinds: [1] }]);

  // or you can just use toReceiveMessage() provided by vitest-websocket-mock
});

test("Client can receive message", async () => {
  let resolver = () => {
    /* */
  };
  const promise = new Promise<void>((resolve) => {
    resolver = resolve;
  });

  client.onmessage = ({ data }) => {
    expect(JSON.parse(data)).beToClientEVENT();
    client.onmessage = null;
    resolver();
  };

  // Wait until the relay establishes the first connection,
  // then get the socket on the relay side.
  const socket = await relay.getSocket(0);
  // When you have multiple connections,
  // you will get a list of the order in which they are connected.

  // Send message to client.
  socket.send(faker.toClientMessage.EVENT("sub1"));

  // Wait for onmessage callback.
  return promise;
});

test("Client can REQ and CLOSE", async () => {
  client.send(JSON.stringify(faker.REQ("sub1")));
  await expect(relay).toReceiveREQ();

  // If the mock relay has already received the REQ,
  // the relay will automatically determine where to deliver the EVENT, based on given subId.
  relay.emitEVENT("sub1");

  // ditto
  relay.emitEOSE("sub1");

  // It is expected that client receive EVENT and EOSE!
});

Client Spy

createClientSpy() allows you to test whether your client, or more precisely, your any callback function that may receive Nostr.ToClientMessage.Any, is actually receiving the desired message.

import { afterEach, beforeEach, expect, test } from "vitest";

import {
  type ClientSpy,
  createClientSpy,
  createMockRelay,
  type MockRelay,
} from "vitest-nostr";

let relay: MockRelay;
let client: WebSocket;
let spy: ClientSpy;

beforeEach(async () => {
  relay = createMockRelay("ws://localhost:1234");
  client = new WebSocket("ws://localhost:1234");

  spy = createClientSpy((listener) => {
    client.addEventListener("message", ({ data }) =>
      listener(JSON.parse(data))
    );
  });

  await relay.connected;
});

afterEach(() => {
  relay.close();
  client.close();
  spy.dispose();
});

test("Client can send REQ", async () => {
  relay.emit(["NOTICE", "Hello, client!"]);
  await expect(spy).toSeeNOTICE("Hello, client!");
});