Skip to content

test(publish): unit tests for NIP-71 publish, kind 16 repost, and useNostrPublish #339

@DSanich

Description

@DSanich

Summary

Add focused unit and hook tests for the video publish pipeline: construction of kind 34236 (NIP-71) events, kind 16 repost tags, and the shared useNostrPublish mutation (sign + relay publish). This complements #295 / upload hook coverage — upload prepares blobs; these paths decide what gets signed and sent.

Problem

  • src/hooks/usePublishVideo.ts contains non-exported helpers (generateVineId, buildImetaTag) and tag assembly that encodes NIP-71 rules (required tags, imeta, hashtags, alt, MIME guessing). Regressions only surface after publish or when relays/indexers reject events.
  • useRepostVideo (same file) builds kind 16 tags (a, p, k, client) with no direct tests.
  • useNostrPublish (src/hooks/useNostrPublish.ts) is the single mutation used across publish/like/delete/report flows: behaviour when logged out, signEvent, nostr.event timeout, and optional client tag injection must stay stable.

Today these hooks are only mocked from page/component tests (VideoPage, etc.), so hook behaviour is not regression-protected.

Expected outcome

  1. Pure logic is unit-tested — preferably by extracting buildImetaTag, vine-id generation, and “build tags for publish/repost” into a small src/lib/ module if extraction keeps the PR reviewable; acceptable alternative: test via mutationFn invocation with heavily mocked dependencies if extraction is deferred.
  2. useNostrPublish covered with renderHook + mocks: logged-in success path, missing user/signer throws "User is not logged in", nostr.event failure surfaces correctly.

What needs to be tested

A. Pure helpers (preferred extracted module)

  • buildImetaTag: correct ordering/subset of url, m, dim, blurhash, image, duration, size, x; empty/minimal metadata still yields valid ['imeta', ...] shape per implementation.
  • generateVineId (if kept): deterministic enough for tests (prefix / uniqueness pattern — assert shape, not wall-clock randomness).

B. usePublishVideo mutation (mock useNostrPublish)

  • Default duration (6), dimensions (480x480), title fallback 'Untitled'.
  • published_at tag present (numeric string).
  • Hashtags: #Foo stripped and lowercased for t tags.
  • GIF vs MP4 MIME inference from videoUrl suffix.
  • publishEvent called with kind: SHORT_VIDEO_KIND, expected tags including d, title, imeta, optional alt, client.

C. useRepostVideo

  • publishEvent called with kind: 16, empty content, tags a, p, k, client matching ${SHORT_VIDEO_KIND}:${pubkey}:${vineId} pattern.

D. useNostrPublish

  • When no user/signer: mutation rejects with the existing error message.
  • When signed in: signer.signEvent receives merged tags; on HTTPS, client tag may be added with hostname (match current location.protocol behaviour — mock location in vi.stubGlobal if needed).
  • nostr.event called with timeout signal behaviour as implemented (AbortSignal.timeout(5000)).

Mocking strategy

  • vi.mock('@/hooks/useCurrentUser'), vi.mock('@nostrify/react') returning { nostr: { event: vi.fn() } }.
  • Mock signer.signEvent to return a deterministic signed event shape (id/pubkey/sig can be fixed hex-like strings).
  • Follow patterns from src/hooks/useProfileStats.test.ts / useVideoUpload.test.ts.

Acceptance criteria

  • New test file(s): e.g. src/lib/…PublishTags.test.ts (if extracted) and/or src/hooks/usePublishVideo.test.ts, src/hooks/useNostrPublish.test.ts.
  • No real network / no live relays.
  • npm run test and npx tsc --noEmit pass locally.
  • Replace or gate console.log on success in useNostrPublish if tests make noise — preferably align with debugLog in a minimal follow-up if out of scope.

Related files

File Role
src/hooks/usePublishVideo.ts Publish + repost mutations, buildImetaTag
src/hooks/useNostrPublish.ts Shared publish mutation
src/types/video.ts SHORT_VIDEO_KIND, VideoMetadata

Notes

  • Scope is publish/repost + nostr publish only — not useVideoUpload (covered by #295).
  • Avoid tightening NIP-71 semantics beyond what tests document today; refactors should preserve observable tag output.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions