OverviewFilesCommitsIssuesDocsReleasesPeers

pearbrowser-desktop / test / catalog-bee.test.js

116 lines · javascript ref:
// Proves the Hyperbee catalog publisher (scripts/lib/catalog-bee.js) writes
// exactly what backend/catalog-manager.js loadCatalogBee() reads. Builds a
// real on-disk Hyperbee and reads it back through the loader's query path.
import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import Corestore from 'corestore'
import Hyperbee from 'hyperbee'
import { normalizeManifest, catalogEntries, readCatalogBee } from '../scripts/lib/catalog-bee.js'

const SAMPLE = {
  name: '  Pear Picks  ',
  version: 1,
  apps: [
    { id: 'keet', name: 'Keet', type: 'standalone', description: 'P2P chat', link: 'hyper://' + 'b'.repeat(64) + '/', categories: ['chat'], author: 'Holepunch', homepage: 'https://keet.io', source: 'https://github.com/holepunchto/keet', license: 'Apache-2.0' },
    { id: 'pearpass', name: 'PearPass', driveKey: 'a'.repeat(64), version: '2.0' },
    {
      id: 'native-tool',
      name: 'Native Tool',
      type: 'standalone',
      version: '3.2.1',
      nativeDelivery: {
        status: 'available',
        kind: 'pear-v3',
        installLink: 'pear://' + 'a'.repeat(52),
        productName: 'Native Tool',
        targets: ['darwin-arm64', 'linux-x64']
      }
    }
  ]
}

test('normalizeManifest cleans input and applies defaults', () => {
  const n = normalizeManifest(SAMPLE, 1700000000000)
  assert.equal(n.name, 'Pear Picks') // trimmed
  assert.equal(n.version, 1)
  assert.equal(n.apps.length, 3)
  assert.equal(n.apps[0].publishedAt, 1700000000000) // injected default now
  assert.deepEqual(n.apps[0].categories, ['chat'])
  assert.equal(n.apps[0].sourceUrl, 'https://github.com/holepunchto/keet')
  assert.equal(n.apps[0].homepage, 'https://keet.io')
  assert.equal(n.apps[0].license, 'Apache-2.0')
  assert.equal(n.apps[1].name, 'PearPass')
  assert.equal(n.apps[1].categories.length, 0) // default empty
})

test('normalizeManifest rejects bad input', () => {
  assert.throws(() => normalizeManifest(null), /JSON object/)
  assert.throws(() => normalizeManifest({}), /apps must be an array/)
  assert.throws(() => normalizeManifest({ apps: 'nope' }), /apps must be an array/)
  assert.throws(() => normalizeManifest({ apps: [{}] }), /needs an id/)
  assert.throws(() => normalizeManifest({ apps: [{ id: 'x', link: 'hyper://' + 'c'.repeat(64) + '/' }, { id: 'x', link: 'hyper://' + 'd'.repeat(64) + '/' }] }), /duplicate app id/)
})

test('normalizeManifest allows an explicitly empty community catalog', () => {
  const n = normalizeManifest({ name: 'Community', apps: [] })
  assert.equal(n.name, 'Community')
  assert.equal(n.apps.length, 0)
})

test('derives an id from driveKey/link when id is absent', () => {
  const link = 'hyper://' + 'e'.repeat(64) + '/'
  const n = normalizeManifest({ apps: [{ link }] })
  assert.equal(n.apps[0].id, 'e'.repeat(64))
})

test('round-trips through a real Hyperbee using the loader query', async () => {
  const dir = await mkdtemp(join(tmpdir(), 'catalog-bee-test-'))
  try {
    const store = new Corestore(dir)
    await store.ready()
    const core = store.get({ name: 'catalog' })
    await core.ready()
    const bee = new Hyperbee(core, { keyEncoding: 'utf-8', valueEncoding: 'json' })
    await bee.ready()

    const normalized = normalizeManifest(SAMPLE, 1700000000000)
    for (const [key, value] of catalogEntries(normalized)) await bee.put(key, value)

    const keyHex = Buffer.from(core.key).toString('hex')
    const data = await readCatalogBee(bee, keyHex)

    // This is the exact `data` shape ExploreScreen consumes.
    assert.equal(data.source, 'hyperbee')
    assert.equal(data.name, 'Pear Picks')
    assert.equal(data.version, 1)
    assert.equal(data.sourceKey, keyHex)
    assert.equal(data.count.total, 3)
    assert.equal(data.apps.length, 3)

    const byId = Object.fromEntries(data.apps.map((a) => [a.id, a]))
    assert.equal(byId.keet.name, 'Keet')
    assert.equal(byId.keet.type, 'standalone')
    assert.equal(byId.keet.link, 'hyper://' + 'b'.repeat(64) + '/')
    assert.equal(byId.keet.source, 'hyperbee')
    assert.equal(byId.keet.sourceUrl, 'https://github.com/holepunchto/keet')
    assert.equal(byId.keet.homepage, 'https://keet.io')
    assert.equal(byId.keet.license, 'Apache-2.0')
    assert.equal(byId.pearpass.driveKey, 'a'.repeat(64))
    assert.deepEqual(byId['native-tool'].nativeDelivery, {
      status: 'available',
      kind: 'pear-v3',
      installLink: 'pear://' + 'a'.repeat(52),
      productName: 'Native Tool',
      targets: ['darwin-arm64', 'linux-x64']
    })
    assert.equal(byId['native-tool'].link, undefined)

    await store.close()
  } finally {
    await rm(dir, { recursive: true, force: true })
  }
})