Convert all tests to TypeScript

This commit is contained in:
Alex Gleason 2023-05-10 16:10:19 -05:00 committed by fiatjaf_
parent 64caef9cda
commit 18e8227123
32 changed files with 439 additions and 405 deletions

View File

@ -2,7 +2,7 @@
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"plugins": ["@typescript-eslint", "babel"],
"parserOptions": {
"ecmaVersion": 9,
@ -18,8 +18,6 @@
"node": true
},
"plugins": ["babel"],
"globals": {
"document": false,
"navigator": false,
@ -152,5 +150,13 @@
"wrap-iife": [2, "any"],
"yield-star-spacing": [2, "both"],
"yoda": [0]
}
},
"overrides": [
{
"files": ["**/*.test.ts"],
"env": { "jest/globals": true },
"plugins": ["jest"],
"extends": ["plugin:jest/recommended"]
}
]
}

View File

@ -1,4 +1,4 @@
const {
import {
getBlankEvent,
finishEvent,
serializeEvent,
@ -8,7 +8,7 @@ const {
getSignature,
getPublicKey,
Kind
} = require('./lib/nostr.cjs')
} from '.'
describe('Event', () => {
describe('getBlankEvent', () => {
@ -97,6 +97,7 @@ describe('Event', () => {
}
expect(() => {
// @ts-expect-error
serializeEvent(invalidEvent)
}).toThrow("can't serialize event with wrong or missing properties")
})
@ -307,6 +308,7 @@ describe('Event', () => {
const sig = getSignature(unsignedEvent, privateKey)
// verify the signature
// @ts-expect-error
const isValid = verifySignature({
...unsignedEvent,
sig
@ -336,6 +338,7 @@ describe('Event', () => {
const sig = getSignature(unsignedEvent, wrongPrivateKey)
// verify the signature
// @ts-expect-error
const isValid = verifySignature({
...unsignedEvent,
sig

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {fj} = require('./lib/nostr.cjs')
import {fj} from '.'
test('match id', () => {
expect(

View File

@ -1,6 +1,5 @@
/* eslint-env jest */
const {matchFilter, matchFilters} = require('./lib/nostr.cjs.js')
import {matchFilter, matchFilters} from '.'
import {buildEvent} from './test-helpers'
describe('Filter', () => {
describe('matchFilter', () => {
@ -14,13 +13,13 @@ describe('Filter', () => {
'#tag': ['value']
}
const event = {
const event = buildEvent({
id: '123',
kind: 1,
pubkey: 'abc',
created_at: 150,
tags: [['tag', 'value']]
}
tags: [['tag', 'value']],
})
const result = matchFilter(filter, event)
@ -30,7 +29,7 @@ describe('Filter', () => {
it('should return false when the event id is not in the filter', () => {
const filter = {ids: ['123', '456']}
const event = {id: '789'}
const event = buildEvent({id: '789'})
const result = matchFilter(filter, event)
@ -40,7 +39,7 @@ describe('Filter', () => {
it('should return true when the event id starts with a prefix', () => {
const filter = {ids: ['22', '00']}
const event = {id: '001'}
const event = buildEvent({id: '001'})
const result = matchFilter(filter, event)
@ -50,7 +49,7 @@ describe('Filter', () => {
it('should return false when the event kind is not in the filter', () => {
const filter = {kinds: [1, 2, 3]}
const event = {kind: 4}
const event = buildEvent({kind: 4})
const result = matchFilter(filter, event)
@ -60,7 +59,7 @@ describe('Filter', () => {
it('should return false when the event author is not in the filter', () => {
const filter = {authors: ['abc', 'def']}
const event = {pubkey: 'ghi'}
const event = buildEvent({pubkey: 'ghi'})
const result = matchFilter(filter, event)
@ -70,7 +69,7 @@ describe('Filter', () => {
it('should return false when a tag is not present in the event', () => {
const filter = {'#tag': ['value1', 'value2']}
const event = {tags: [['not_tag', 'value1']]}
const event = buildEvent({tags: [['not_tag', 'value1']]})
const result = matchFilter(filter, event)
@ -80,7 +79,7 @@ describe('Filter', () => {
it('should return false when a tag value is not present in the event', () => {
const filter = {'#tag': ['value1', 'value2']}
const event = {tags: [['tag', 'value3']]}
const event = buildEvent({tags: [['tag', 'value3']]})
const result = matchFilter(filter, event)
@ -90,7 +89,7 @@ describe('Filter', () => {
it('should return true when filter has tags that is present in the event', () => {
const filter = {'#tag1': ['foo']}
const event = {
const event = buildEvent({
id: '123',
kind: 1,
pubkey: 'abc',
@ -99,7 +98,7 @@ describe('Filter', () => {
['tag1', 'foo'],
['tag2', 'bar']
]
}
})
const result = matchFilter(filter, event)
@ -109,7 +108,7 @@ describe('Filter', () => {
it('should return false when the event is before the filter since value', () => {
const filter = {since: 100}
const event = {created_at: 50}
const event = buildEvent({created_at: 50})
const result = matchFilter(filter, event)
@ -119,7 +118,7 @@ describe('Filter', () => {
it('should return false when the event is after the filter until value', () => {
const filter = {until: 100}
const event = {created_at: 150}
const event = buildEvent({created_at: 150})
const result = matchFilter(filter, event)
@ -135,7 +134,7 @@ describe('Filter', () => {
{ids: ['789'], kinds: [3], authors: ['ghi']}
]
const event = {id: '789', kind: 3, pubkey: 'ghi'}
const event = buildEvent({id: '789', kind: 3, pubkey: 'ghi'})
const result = matchFilters(filters, event)
@ -149,7 +148,7 @@ describe('Filter', () => {
{ids: ['9'], kinds: [3], authors: ['g']}
]
const event = {id: '987', kind: 3, pubkey: 'ghi'}
const event = buildEvent({id: '987', kind: 3, pubkey: 'ghi'})
const result = matchFilters(filters, event)
@ -163,7 +162,7 @@ describe('Filter', () => {
{authors: ['abc'], limit: 3}
]
const event = {id: '123', kind: 1, pubkey: 'abc', created_at: 150}
const event = buildEvent({id: '123', kind: 1, pubkey: 'abc', created_at: 150})
const result = matchFilters(filters, event)
@ -177,7 +176,7 @@ describe('Filter', () => {
{ids: ['789'], kinds: [3], authors: ['ghi']}
]
const event = {id: '100', kind: 4, pubkey: 'jkl'}
const event = buildEvent({id: '100', kind: 4, pubkey: 'jkl'})
const result = matchFilters(filters, event)
@ -190,7 +189,7 @@ describe('Filter', () => {
{kinds: [1], limit: 2},
{authors: ['abc'], limit: 3}
]
const event = {id: '456', kind: 2, pubkey: 'def', created_at: 200}
const event = buildEvent({id: '456', kind: 2, pubkey: 'def', created_at: 200})
const result = matchFilters(filters, event)

View File

@ -1,16 +1,14 @@
/* eslint-env jest */
import {generatePrivateKey, getPublicKey} from '.'
const {generatePrivateKey, getPublicKey} = require('./lib/nostr.cjs')
test('test private key generation', () => {
test('private key generation', () => {
expect(generatePrivateKey()).toMatch(/[a-f0-9]{64}/)
})
test('test public key generation', () => {
test('public key generation', () => {
expect(getPublicKey(generatePrivateKey())).toMatch(/[a-f0-9]{64}/)
})
test('test public key from private key deterministic', () => {
test('public key from private key deterministic', () => {
let sk = generatePrivateKey()
let pk = getPublicKey(sk)

View File

@ -1,7 +1,9 @@
/* eslint-env jest */
import {nip04, getPublicKey, generatePrivateKey} from '.'
import crypto from 'crypto'
globalThis.crypto = require('crypto')
const {nip04, getPublicKey, generatePrivateKey} = require('./lib/nostr.cjs')
// @ts-ignore
// eslint-disable-next-line no-undef
globalThis.crypto = crypto
test('encrypt and decrypt message', async () => {
let sk1 = generatePrivateKey()

View File

@ -1,39 +0,0 @@
/* eslint-env jest */
const fetch = require('node-fetch')
const {nip05} = require('./lib/nostr.cjs')
test('fetch nip05 profiles', async () => {
nip05.useFetchImplementation(fetch)
let p1 = await nip05.queryProfile('jb55.com')
expect(p1.pubkey).toEqual(
'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'
)
expect(p1.relays).toEqual(['wss://relay.damus.io'])
let p2 = await nip05.queryProfile('jb55@jb55.com')
expect(p2.pubkey).toEqual(
'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'
)
expect(p2.relays).toEqual(['wss://relay.damus.io'])
let p3 = await nip05.queryProfile('channel.ninja@channel.ninja')
expect(p3.pubkey).toEqual(
'36e65b503eba8a6b698e724a59137603101166a1cddb45ddc704247fc8aa0fce'
)
expect(p3.relays).toEqual(undefined)
let p4 = await nip05.queryProfile('_@fiatjaf.com')
expect(p4.pubkey).toEqual(
'3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
)
expect(p4.relays).toEqual([
'wss://relay.nostr.bg',
'wss://nos.lol',
'wss://nostr-verified.wellorder.net',
'wss://nostr.zebedee.cloud',
'wss://eden.nostr.land',
'wss://nostr.milou.lol',
])
})

View File

@ -1,5 +1,3 @@
/* eslint-env jest */
import fetch from 'node-fetch'
import {nip05} from '.'

View File

@ -1,5 +1,4 @@
/* eslint-env jest */
const {nip06} = require('./lib/nostr.cjs')
import {nip06} from '.'
test('generate private key from a mnemonic', async () => {
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {nip10} = require('./lib/nostr.cjs')
import {nip10} from '.'
describe('parse NIP10-referenced events', () => {
test('legacy + a lot of events', () => {

View File

@ -1,5 +1,4 @@
/* eslint-env jest */
const {nip13} = require('./lib/nostr.cjs')
import {nip13} from '.'
test('identifies proof-of-work difficulty', async () => {
const id = '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358'

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {nip18, finishEvent, getPublicKey, Kind} = require('./lib/nostr.cjs')
import {nip18, finishEvent, getPublicKey, Kind} from '.'
const relayUrl = 'https://relay.example.com'
@ -48,9 +46,9 @@ describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () =>
const repostedEventPointer = nip18.getRepostedEventPointer(event)
expect(repostedEventPointer.id).toEqual(repostedEvent.id)
expect(repostedEventPointer.author).toEqual(repostedEvent.pubkey)
expect(repostedEventPointer.relays).toEqual([relayUrl])
expect(repostedEventPointer!.id).toEqual(repostedEvent.id)
expect(repostedEventPointer!.author).toEqual(repostedEvent.pubkey)
expect(repostedEventPointer!.relays).toEqual([relayUrl])
const repostedEventFromContent = nip18.getRepostedEvent(event)
@ -60,7 +58,7 @@ describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () =>
it('should create a signed event from a filled template', () => {
const template = {
tags: [['nonstandard', 'tag']],
content: '',
content: '' as const,
created_at: 1617932115
}
@ -85,9 +83,9 @@ describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () =>
const repostedEventPointer = nip18.getRepostedEventPointer(event)
expect(repostedEventPointer.id).toEqual(repostedEvent.id)
expect(repostedEventPointer.author).toEqual(repostedEvent.pubkey)
expect(repostedEventPointer.relays).toEqual([relayUrl])
expect(repostedEventPointer!.id).toEqual(repostedEvent.id)
expect(repostedEventPointer!.author).toEqual(repostedEvent.pubkey)
expect(repostedEventPointer!.relays).toEqual([relayUrl])
const repostedEventFromContent = nip18.getRepostedEvent(event)
@ -99,13 +97,18 @@ describe('getRepostedEventPointer', () => {
it('should parse an event with only an `e` tag', () => {
const event = {
kind: Kind.Repost,
tags: [['e', 'reposted event id', relayUrl]]
tags: [['e', 'reposted event id', relayUrl]],
content: '',
created_at: 0,
pubkey: '',
id: '',
sig: '',
}
const repostedEventPointer = nip18.getRepostedEventPointer(event)
expect(repostedEventPointer.id).toEqual('reposted event id')
expect(repostedEventPointer.author).toEqual(undefined)
expect(repostedEventPointer.relays).toEqual([relayUrl])
expect(repostedEventPointer!.id).toEqual('reposted event id')
expect(repostedEventPointer!.author).toEqual(undefined)
expect(repostedEventPointer!.relays).toEqual([relayUrl])
})
})

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {nip19, generatePrivateKey, getPublicKey} = require('./lib/nostr.cjs')
import {nip19, generatePrivateKey, getPublicKey} from '.'
test('encode and decode nsec', () => {
let sk = generatePrivateKey()
@ -30,9 +28,10 @@ test('encode and decode nprofile', () => {
expect(nprofile).toMatch(/nprofile1\w+/)
let {type, data} = nip19.decode(nprofile)
expect(type).toEqual('nprofile')
expect(data.pubkey).toEqual(pk)
expect(data.relays).toContain(relays[0])
expect(data.relays).toContain(relays[1])
const pointer = data as nip19.ProfilePointer
expect(pointer.pubkey).toEqual(pk)
expect(pointer.relays).toContain(relays[0])
expect(pointer.relays).toContain(relays[1])
})
test('decode nprofile without relays', () => {
@ -65,11 +64,12 @@ test('encode and decode naddr', () => {
expect(naddr).toMatch(/naddr1\w+/)
let {type, data} = nip19.decode(naddr)
expect(type).toEqual('naddr')
expect(data.pubkey).toEqual(pk)
expect(data.relays).toContain(relays[0])
expect(data.relays).toContain(relays[1])
expect(data.kind).toEqual(30023)
expect(data.identifier).toEqual('banana')
const pointer = data as nip19.AddressPointer
expect(pointer.pubkey).toEqual(pk)
expect(pointer.relays).toContain(relays[0])
expect(pointer.relays).toContain(relays[1])
expect(pointer.kind).toEqual(30023)
expect(pointer.identifier).toEqual('banana')
})
test('decode naddr from habla.news', () => {
@ -77,11 +77,12 @@ test('decode naddr from habla.news', () => {
'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5'
)
expect(type).toEqual('naddr')
expect(data.pubkey).toEqual(
const pointer = data as nip19.AddressPointer
expect(pointer.pubkey).toEqual(
'7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194'
)
expect(data.kind).toEqual(30023)
expect(data.identifier).toEqual('references')
expect(pointer.kind).toEqual(30023)
expect(pointer.identifier).toEqual('references')
})
test('decode naddr from go-nostr with different TLV ordering', () => {
@ -90,15 +91,16 @@ test('decode naddr from go-nostr with different TLV ordering', () => {
)
expect(type).toEqual('naddr')
expect(data.pubkey).toEqual(
const pointer = data as nip19.AddressPointer
expect(pointer.pubkey).toEqual(
'3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
)
expect(data.relays).toContain(
expect(pointer.relays).toContain(
'wss://relay.nostr.example.mydomain.example.com'
)
expect(data.relays).toContain('wss://nostr.banana.com')
expect(data.kind).toEqual(30023)
expect(data.identifier).toEqual('banana')
expect(pointer.relays).toContain('wss://nostr.banana.com')
expect(pointer.kind).toEqual(30023)
expect(pointer.identifier).toEqual('banana')
})
test('encode and decode nrelay', () => {

View File

@ -1,7 +1,6 @@
/* eslint-env jest */
const {nip21} = require('./lib/nostr.cjs')
import {nip21} from '.'
test('test', () => {
test('test()', () => {
expect(
nip21.test(
'nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6'

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {nip25, finishEvent, getPublicKey, Kind} = require('./lib/nostr.cjs')
import {nip25, finishEvent, getPublicKey, Kind} from '.'
describe('finishReactionEvent + getReactedEventPointer', () => {
const privateKey =
@ -43,8 +41,8 @@ describe('finishReactionEvent + getReactedEventPointer', () => {
const reactedEventPointer = nip25.getReactedEventPointer(event)
expect(reactedEventPointer.id).toEqual(reactedEvent.id)
expect(reactedEventPointer.author).toEqual(reactedEvent.pubkey)
expect(reactedEventPointer!.id).toEqual(reactedEvent.id)
expect(reactedEventPointer!.author).toEqual(reactedEvent.pubkey)
})
it('should create a signed event from a filled template', () => {
@ -72,7 +70,7 @@ describe('finishReactionEvent + getReactedEventPointer', () => {
const reactedEventPointer = nip25.getReactedEventPointer(event)
expect(reactedEventPointer.id).toEqual(reactedEvent.id)
expect(reactedEventPointer.author).toEqual(reactedEvent.pubkey)
expect(reactedEventPointer!.id).toEqual(reactedEvent.id)
expect(reactedEventPointer!.author).toEqual(reactedEvent.pubkey)
})
})

View File

@ -1,6 +1,4 @@
/* eslint-env jest */
const {nip26, getPublicKey, generatePrivateKey} = require('./lib/nostr.cjs')
import {nip26, getPublicKey, generatePrivateKey} from '.'
test('parse good delegation from NIP', async () => {
expect(
@ -99,7 +97,11 @@ test('create and verify delegation', async () => {
let event = {
kind: 1,
tags: [['delegation', delegation.from, delegation.cond, delegation.sig]],
pubkey: pk2
pubkey: pk2,
content: '',
created_at: 0,
id: '',
sig: '',
}
expect(nip26.getDelegator(event)).toEqual(pk1)
})

View File

@ -8,9 +8,9 @@ import {getPublicKey} from './keys'
export type Parameters = {
pubkey: string // the key to whom the delegation will be given
kind: number | undefined
until: number | undefined // delegation will only be valid until this date
since: number | undefined // delegation will be valid from this date on
kind?: number
until?: number // delegation will only be valid until this date
since?: number // delegation will be valid from this date on
}
export type Delegation = {

View File

@ -1,5 +1,4 @@
/* eslint-env jest */
const {nip27} = require('./lib/nostr.cjs')
import {nip27} from '.'
test('matchAll', () => {
const result = nip27.matchAll(

View File

@ -1,7 +1,5 @@
/* eslint-env jest */
const fetch = require('node-fetch')
const {nip39} = require('./lib/nostr.cjs.js')
import fetch from 'node-fetch'
import {nip39} from '.'
test('validate github claim', async () => {
nip39.useFetchImplementation(fetch)

View File

@ -1,27 +0,0 @@
/* eslint-env jest */
require('websocket-polyfill')
const {
relayInit,
generatePrivateKey,
finishEvent,
nip42
} = require('./lib/nostr.cjs')
test('auth flow', done => {
const relay = relayInit('wss://nostr.kollider.xyz')
relay.connect()
const sk = generatePrivateKey()
relay.on('auth', async challenge => {
await expect(
nip42.authenticate({
challenge,
relay,
sign: e => finishEvent(e, sk)
})
).rejects.toBeTruthy()
relay.close()
done()
})
})

27
nip42.test.ts Normal file
View File

@ -0,0 +1,27 @@
import 'websocket-polyfill'
import {
relayInit,
generatePrivateKey,
finishEvent,
nip42
} from '.'
test('auth flow', () => {
const relay = relayInit('wss://nostr.kollider.xyz')
relay.connect()
const sk = generatePrivateKey()
return new Promise<void>((resolve) => {
relay.on('auth', async challenge => {
await expect(
nip42.authenticate({
challenge,
relay,
sign: (e) => finishEvent(e, sk)
})
).rejects.toBeTruthy()
relay.close()
resolve()
})
})
})

View File

@ -17,7 +17,7 @@ export const authenticate = async ({
}: {
challenge: string
relay: Relay
sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>>
sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>> | Event<K>
}): Promise<void> => {
const e: EventTemplate = {
kind: Kind.ClientAuth,

View File

@ -1,14 +1,14 @@
const {bech32} = require('@scure/base')
const {
import {
nip57,
generatePrivateKey,
getPublicKey,
finishEvent
} = require('./lib/nostr.cjs')
} from '.'
import { buildEvent } from './test-helpers'
describe('getZapEndpoint', () => {
test('returns null if neither lud06 nor lud16 is present', async () => {
const metadata = {content: '{}'}
const metadata = buildEvent({kind: 0, content: '{}'})
const result = await nip57.getZapEndpoint(metadata)
expect(result).toBeNull()
@ -18,7 +18,7 @@ describe('getZapEndpoint', () => {
const fetchImplementation = jest.fn(() => Promise.reject(new Error()))
nip57.useFetchImplementation(fetchImplementation)
const metadata = {content: '{"lud16": "name@domain"}'}
const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'})
const result = await nip57.getZapEndpoint(metadata)
expect(result).toBeNull()
@ -33,7 +33,7 @@ describe('getZapEndpoint', () => {
)
nip57.useFetchImplementation(fetchImplementation)
const metadata = {content: '{"lud16": "name@domain"}'}
const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'})
const result = await nip57.getZapEndpoint(metadata)
expect(result).toBeNull()
@ -54,7 +54,7 @@ describe('getZapEndpoint', () => {
)
nip57.useFetchImplementation(fetchImplementation)
const metadata = {content: '{"lud16": "name@domain"}'}
const metadata = buildEvent({kind: 0, content: '{"lud16": "name@domain"}'})
const result = await nip57.getZapEndpoint(metadata)
expect(result).toBe('callback')
@ -67,6 +67,7 @@ describe('getZapEndpoint', () => {
describe('makeZapRequest', () => {
test('throws an error if amount is not given', () => {
expect(() =>
// @ts-expect-error
nip57.makeZapRequest({
profile: 'profile',
event: null,
@ -78,6 +79,7 @@ describe('makeZapRequest', () => {
test('throws an error if profile is not given', () => {
expect(() =>
// @ts-expect-error
nip57.makeZapRequest({
event: null,
amount: 100,

View File

@ -119,7 +119,7 @@ export function makeZapReceipt({
paidAt
}: {
zapRequest: string
preimage: string | null
preimage?: string
bolt11: string
paidAt: Date
}): EventTemplate<Kind.Zap> {

View File

@ -44,8 +44,9 @@
"@typescript-eslint/parser": "^5.51.0",
"esbuild": "0.16.9",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "^8.33.0",
"eslint": "^8.40.0",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-jest": "^27.2.1",
"esm-loader-typescript": "^1.0.3",
"events": "^3.3.0",
"jest": "^29.5.0",

View File

@ -1,13 +1,11 @@
/* eslint-env jest */
require('websocket-polyfill')
const {
import 'websocket-polyfill'
import {
SimplePool,
generatePrivateKey,
getPublicKey,
getEventHash,
getSignature
} = require('./lib/nostr.cjs')
finishEvent,
type Event,
} from '.'
let pool = new SimplePool()
@ -33,7 +31,7 @@ test('removing duplicates when querying', async () => {
let pub = getPublicKey(priv)
let sub = pool.sub(relays, [{authors: [pub]}])
let received = []
let received: Event[] = []
sub.on('event', event => {
// this should be called only once even though we're listening
@ -42,15 +40,12 @@ test('removing duplicates when querying', async () => {
received.push(event)
})
let event = {
pubkey: pub,
let event = finishEvent({
created_at: Math.round(Date.now() / 1000),
content: 'test',
kind: 22345,
tags: []
}
event.id = getEventHash(event)
event.sig = getSignature(event, priv)
}, priv)
pool.publish(relays, event)
@ -66,7 +61,7 @@ test('same with double querying', async () => {
let sub1 = pool.sub(relays, [{authors: [pub]}])
let sub2 = pool.sub(relays, [{authors: [pub]}])
let received = []
let received: Event[] = []
sub1.on('event', event => {
received.push(event)
@ -76,15 +71,12 @@ test('same with double querying', async () => {
received.push(event)
})
let event = {
pubkey: pub,
let event = finishEvent({
created_at: Math.round(Date.now() / 1000),
content: 'test2',
kind: 22346,
tags: []
}
event.id = getEventHash(event)
event.sig = getSignature(event, priv)
}, priv)
pool.publish(relays, event)
@ -122,6 +114,7 @@ test('list()', async () => {
expect(events.length).toEqual(
events
.map(evt => evt.id)
// @ts-ignore ???
.reduce((acc, n) => (acc.indexOf(n) !== -1 ? acc : [...acc, n]), [])
.length
)

View File

@ -1,9 +1,10 @@
/* eslint-env jest */
const {parseReferences} = require('./lib/nostr.cjs')
import {parseReferences} from '.'
test('parse mentions', () => {
let evt = {
kind: 1,
id: '',
pubkey: '',
tags: [
[
'p',
@ -23,7 +24,9 @@ test('parse mentions', () => {
]
],
content:
'hello #[0], have you seen #[2]? it was made by nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg on nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4! broken #[3]'
'hello #[0], have you seen #[2]? it was made by nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg on nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4! broken #[3]',
created_at: 0,
sig: '',
}
expect(parseReferences(evt)).toEqual([

View File

@ -1,13 +1,10 @@
/* eslint-env jest */
require('websocket-polyfill')
const {
import 'websocket-polyfill'
import {
relayInit,
generatePrivateKey,
getPublicKey,
getEventHash,
getSignature
} = require('./lib/nostr.cjs')
finishEvent,
} from '.'
let relay = relayInit('wss://relay.damus.io/')
@ -33,8 +30,8 @@ test('connectivity', () => {
})
test('querying', async () => {
var resolve1
var resolve2
var resolve1: (value: boolean) => void
var resolve2: (value: boolean) => void
let sub = relay.sub([
{
@ -53,10 +50,10 @@ test('querying', async () => {
})
let [t1, t2] = await Promise.all([
new Promise(resolve => {
new Promise<boolean>(resolve => {
resolve1 = resolve
}),
new Promise(resolve => {
new Promise<boolean>(resolve => {
resolve2 = resolve
})
])
@ -93,8 +90,8 @@ test('list()', async () => {
test('listening (twice) and publishing', async () => {
let sk = generatePrivateKey()
let pk = getPublicKey(sk)
var resolve1
var resolve2
var resolve1: (value: boolean) => void
var resolve2: (value: boolean) => void
let sub = relay.sub([
{
@ -116,15 +113,12 @@ test('listening (twice) and publishing', async () => {
resolve2(true)
})
let event = {
let event = finishEvent({
kind: 27572,
pubkey: pk,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'nostr-tools test suite'
}
event.id = getEventHash(event)
event.sig = getSignature(event, sk)
}, sk)
relay.publish(event)
return expect(

17
test-helpers.ts Normal file
View File

@ -0,0 +1,17 @@
import {type Event} from '.'
type EventParams<K extends number> = Partial<Event<K>>
/** Build an event for testing purposes. */
export function buildEvent<K extends number = 1>(params: EventParams<K>): Event<K> {
return {
id: '',
kind: 1 as K,
pubkey: '',
created_at: 0,
content: '',
tags: [],
sig: '',
...params
}
}

View File

@ -1,183 +0,0 @@
/* eslint-env jest */
const {utils} = require('./lib/nostr.cjs')
const {insertEventIntoAscendingList, insertEventIntoDescendingList} = utils
describe('inserting into a desc sorted list of events', () => {
test('insert into an empty list', async () => {
const list0 = []
expect(
insertEventIntoDescendingList(list0, {id: 'abc', created_at: 10})
).toHaveLength(1)
})
test('insert in the beginning of a list', async () => {
const list0 = [{created_at: 20}, {created_at: 10}]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 30
})
expect(list1).toHaveLength(3)
expect(list1[0].id).toBe('abc')
})
test('insert in the beginning of a list with same created_at', async () => {
const list0 = [{created_at: 30}, {created_at: 20}, {created_at: 10}]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 30
})
expect(list1).toHaveLength(4)
expect(list1[0].id).toBe('abc')
})
test('insert in the middle of a list', async () => {
const list0 = [
{created_at: 30},
{created_at: 20},
{created_at: 10},
{created_at: 1}
]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 15
})
expect(list1).toHaveLength(5)
expect(list1[2].id).toBe('abc')
})
test('insert in the end of a list', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 10}
]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 5
})
expect(list1).toHaveLength(6)
expect(list1.slice(-1)[0].id).toBe('abc')
})
test('insert in the last-to-end of a list with same created_at', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 10}
]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 10
})
expect(list1).toHaveLength(6)
expect(list1.slice(-2)[0].id).toBe('abc')
})
test('do not insert duplicates', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 10, id: 'abc'}
]
const list1 = insertEventIntoDescendingList(list0, {
id: 'abc',
created_at: 10
})
expect(list1).toHaveLength(3)
})
})
describe('inserting into a asc sorted list of events', () => {
test('insert into an empty list', async () => {
const list0 = []
expect(
insertEventIntoAscendingList(list0, {id: 'abc', created_at: 10})
).toHaveLength(1)
})
test('insert in the beginning of a list', async () => {
const list0 = [{created_at: 10}, {created_at: 20}]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 1
})
expect(list1).toHaveLength(3)
expect(list1[0].id).toBe('abc')
})
test('insert in the beginning of a list with same created_at', async () => {
const list0 = [{created_at: 10}, {created_at: 20}, {created_at: 30}]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 10
})
expect(list1).toHaveLength(4)
expect(list1[0].id).toBe('abc')
})
test('insert in the middle of a list', async () => {
const list0 = [
{created_at: 10},
{created_at: 20},
{created_at: 30},
{created_at: 40}
]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 25
})
expect(list1).toHaveLength(5)
expect(list1[2].id).toBe('abc')
})
test('insert in the end of a list', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 40}
]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 50
})
expect(list1).toHaveLength(6)
expect(list1.slice(-1)[0].id).toBe('abc')
})
test('insert in the last-to-end of a list with same created_at', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 20},
{created_at: 30}
]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 30
})
expect(list1).toHaveLength(6)
expect(list1.slice(-2)[0].id).toBe('abc')
})
test('do not insert duplicates', async () => {
const list0 = [
{created_at: 20},
{created_at: 20},
{created_at: 30, id: 'abc'}
]
const list1 = insertEventIntoAscendingList(list0, {
id: 'abc',
created_at: 30
})
expect(list1).toHaveLength(3)
})
})

190
utils.test.ts Normal file
View File

@ -0,0 +1,190 @@
import {utils, type Event} from '.'
import {buildEvent} from './test-helpers'
const {insertEventIntoAscendingList, insertEventIntoDescendingList} = utils
describe('inserting into a desc sorted list of events', () => {
test('insert into an empty list', async () => {
const list0: Event[] = []
expect(
insertEventIntoDescendingList(list0, buildEvent({id: 'abc', created_at: 10}))
).toHaveLength(1)
})
test('insert in the beginning of a list', async () => {
const list0 = [buildEvent({created_at: 20}), buildEvent({created_at: 10})]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 30
}))
expect(list1).toHaveLength(3)
expect(list1[0].id).toBe('abc')
})
test('insert in the beginning of a list with same created_at', async () => {
const list0 = [
buildEvent({created_at: 30}),
buildEvent({created_at: 20}),
buildEvent({created_at: 10}),
]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 30
}))
expect(list1).toHaveLength(4)
expect(list1[0].id).toBe('abc')
})
test('insert in the middle of a list', async () => {
const list0 = [
buildEvent({created_at: 30}),
buildEvent({created_at: 20}),
buildEvent({created_at: 10}),
buildEvent({created_at: 1}),
]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 15
}))
expect(list1).toHaveLength(5)
expect(list1[2].id).toBe('abc')
})
test('insert in the end of a list', async () => {
const list0 = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 10}),
]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 5
}))
expect(list1).toHaveLength(6)
expect(list1.slice(-1)[0].id).toBe('abc')
})
test('insert in the last-to-end of a list with same created_at', async () => {
const list0: Event[] = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 10}),
]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 10
}))
expect(list1).toHaveLength(6)
expect(list1.slice(-2)[0].id).toBe('abc')
})
test('do not insert duplicates', async () => {
const list0 = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 10, id: 'abc'}),
]
const list1 = insertEventIntoDescendingList(list0, buildEvent({
id: 'abc',
created_at: 10
}))
expect(list1).toHaveLength(3)
})
})
describe('inserting into a asc sorted list of events', () => {
test('insert into an empty list', async () => {
const list0: Event[] = []
expect(
insertEventIntoAscendingList(list0, buildEvent({id: 'abc', created_at: 10}))
).toHaveLength(1)
})
test('insert in the beginning of a list', async () => {
const list0 = [buildEvent({created_at: 10}), buildEvent({created_at: 20})]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 1
}))
expect(list1).toHaveLength(3)
expect(list1[0].id).toBe('abc')
})
test('insert in the beginning of a list with same created_at', async () => {
const list0 = [
buildEvent({created_at: 10}),
buildEvent({created_at: 20}),
buildEvent({created_at: 30}),
]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 10
}))
expect(list1).toHaveLength(4)
expect(list1[0].id).toBe('abc')
})
test('insert in the middle of a list', async () => {
const list0 = [
buildEvent({created_at: 10}),
buildEvent({created_at: 20}),
buildEvent({created_at: 30}),
buildEvent({created_at: 40}),
]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 25
}))
expect(list1).toHaveLength(5)
expect(list1[2].id).toBe('abc')
})
test('insert in the end of a list', async () => {
const list0 = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 40}),
]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 50
}))
expect(list1).toHaveLength(6)
expect(list1.slice(-1)[0].id).toBe('abc')
})
test('insert in the last-to-end of a list with same created_at', async () => {
const list0 = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 30}),
]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 30
}))
expect(list1).toHaveLength(6)
expect(list1.slice(-2)[0].id).toBe('abc')
})
test('do not insert duplicates', async () => {
const list0 = [
buildEvent({created_at: 20}),
buildEvent({created_at: 20}),
buildEvent({created_at: 30, id: 'abc'}),
]
const list1 = insertEventIntoAscendingList(list0, buildEvent({
id: 'abc',
created_at: 30
}))
expect(list1).toHaveLength(3)
})
})

View File

@ -958,6 +958,14 @@
"@typescript-eslint/types" "5.59.2"
"@typescript-eslint/visitor-keys" "5.59.2"
"@typescript-eslint/scope-manager@5.59.5":
version "5.59.5"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d"
integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==
dependencies:
"@typescript-eslint/types" "5.59.5"
"@typescript-eslint/visitor-keys" "5.59.5"
"@typescript-eslint/type-utils@5.59.2":
version "5.59.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf"
@ -973,6 +981,11 @@
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655"
integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==
"@typescript-eslint/types@5.59.5":
version "5.59.5"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7"
integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==
"@typescript-eslint/typescript-estree@5.59.2":
version "5.59.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936"
@ -986,6 +999,19 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.59.5":
version "5.59.5"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42"
integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==
dependencies:
"@typescript-eslint/types" "5.59.5"
"@typescript-eslint/visitor-keys" "5.59.5"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.59.2":
version "5.59.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4"
@ -1000,6 +1026,20 @@
eslint-scope "^5.1.1"
semver "^7.3.7"
"@typescript-eslint/utils@^5.10.0":
version "5.59.5"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae"
integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.59.5"
"@typescript-eslint/types" "5.59.5"
"@typescript-eslint/typescript-estree" "5.59.5"
eslint-scope "^5.1.1"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.59.2":
version "5.59.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750"
@ -1008,6 +1048,14 @@
"@typescript-eslint/types" "5.59.2"
eslint-visitor-keys "^3.3.0"
"@typescript-eslint/visitor-keys@5.59.5":
version "5.59.5"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b"
integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==
dependencies:
"@typescript-eslint/types" "5.59.5"
eslint-visitor-keys "^3.3.0"
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@ -1651,6 +1699,13 @@ eslint-plugin-babel@^5.3.1:
dependencies:
eslint-rule-composer "^0.3.0"
eslint-plugin-jest@^27.2.1:
version "27.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz#b85b4adf41c682ea29f1f01c8b11ccc39b5c672c"
integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==
dependencies:
"@typescript-eslint/utils" "^5.10.0"
eslint-rule-composer@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
@ -1682,7 +1737,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994"
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
eslint@^8.33.0:
eslint@^8.40.0:
version "8.40.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.40.0.tgz#a564cd0099f38542c4e9a2f630fa45bf33bc42a4"
integrity sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==