Skip to content

Commit 25f9637

Browse files
vikashsiwachcameri
andauthored
test(integration): add integration tests for NIP-02 contact lists (#552)
Co-authored-by: Ricardo Cabral <me@ricardocabral.io>
1 parent 7fc0552 commit 25f9637

3 files changed

Lines changed: 186 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"nostream": patch
3+
---
4+
5+
Add integration tests for NIP-02 contact lists (Kind 3)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Feature: NIP-02 Contact Lists
2+
Scenario: Alice publishes a contact list
3+
Given someone called Alice
4+
When Alice sends a contact_list event with tags
5+
And Alice subscribes to author Alice
6+
Then Alice receives a contact_list event from Alice
7+
8+
Scenario: Alice publishes an updated contact list
9+
Given someone called Alice
10+
When Alice sends a contact_list event with tags
11+
And Alice sends a second contact_list event with different tags
12+
And Alice subscribes to author Alice
13+
Then Alice receives 1 contact_list event from Alice with the latest tags and EOSE
14+
15+
Scenario: Tie-breaker on Identical Timestamps for contact list
16+
Given someone called Alice
17+
When Alice sends two identically-timestamped contact_list events where the second has a lower ID
18+
And Alice subscribes to author Alice
19+
Then Alice receives 1 contact_list event from Alice matching the lower ID event and EOSE
20+
21+
Scenario: Bob subscribes to Alice's contact list
22+
Given someone called Alice
23+
And someone called Bob
24+
When Alice sends a contact_list event with tags
25+
And Bob subscribes to author Alice
26+
Then Bob receives a contact_list event from Alice
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { Then, When } from '@cucumber/cucumber'
2+
import { expect } from 'chai'
3+
import WebSocket from 'ws'
4+
5+
import { createEvent, sendEvent, waitForEventCount, waitForNextEvent } from '../helpers'
6+
import { Event } from '../../../../src/@types/event'
7+
import { EventKinds, EventTags } from '../../../../src/constants/base'
8+
9+
When(
10+
/^(\w+) sends a contact_list event with tags$/,
11+
async function (name: string) {
12+
const ws = this.parameters.clients[name] as WebSocket
13+
const { pubkey, privkey } = this.parameters.identities[name]
14+
15+
// Create a simple contact list with a few pubkeys
16+
const contactPubkey1 = 'a'.repeat(64)
17+
const contactPubkey2 = 'b'.repeat(64)
18+
19+
const event: Event = await createEvent(
20+
{
21+
pubkey,
22+
kind: EventKinds.CONTACT_LIST,
23+
tags: [
24+
[EventTags.Pubkey, contactPubkey1],
25+
[EventTags.Pubkey, contactPubkey2],
26+
],
27+
content: '',
28+
},
29+
privkey,
30+
)
31+
32+
await sendEvent(ws, event)
33+
this.parameters.events[name].push(event)
34+
this.parameters.contactListEvent = event
35+
},
36+
)
37+
38+
When(
39+
/^(\w+) sends a second contact_list event with different tags$/,
40+
async function (name: string) {
41+
const ws = this.parameters.clients[name] as WebSocket
42+
const { pubkey, privkey } = this.parameters.identities[name]
43+
44+
// Create an updated contact list with different pubkeys
45+
const contactPubkey3 = 'c'.repeat(64)
46+
const contactPubkey4 = 'd'.repeat(64)
47+
48+
const event: Event = await createEvent(
49+
{
50+
pubkey,
51+
kind: EventKinds.CONTACT_LIST,
52+
tags: [
53+
[EventTags.Pubkey, contactPubkey3],
54+
[EventTags.Pubkey, contactPubkey4],
55+
],
56+
content: '',
57+
},
58+
privkey,
59+
)
60+
61+
await sendEvent(ws, event)
62+
this.parameters.events[name].push(event)
63+
this.parameters.updatedContactListEvent = event
64+
},
65+
)
66+
67+
Then(
68+
/^(\w+) receives a contact_list event from (\w+)$/,
69+
async function (name: string, author: string) {
70+
const ws = this.parameters.clients[name] as WebSocket
71+
const subscription = this.parameters.subscriptions[name][this.parameters.subscriptions[name].length - 1]
72+
const receivedEvent = await waitForNextEvent(ws, subscription.name)
73+
74+
expect(receivedEvent.kind).to.equal(EventKinds.CONTACT_LIST)
75+
expect(receivedEvent.pubkey).to.equal(this.parameters.identities[author].pubkey)
76+
},
77+
)
78+
79+
Then(
80+
/^(\w+) receives 1 contact_list event from (\w+) with the latest tags and EOSE$/,
81+
async function (name: string, author: string) {
82+
const ws = this.parameters.clients[name] as WebSocket
83+
const subscription = this.parameters.subscriptions[name][this.parameters.subscriptions[name].length - 1]
84+
const events = await waitForEventCount(ws, subscription.name, 1, true)
85+
86+
expect(events.length).to.equal(1)
87+
expect(events[0].kind).to.equal(EventKinds.CONTACT_LIST)
88+
expect(events[0].pubkey).to.equal(this.parameters.identities[author].pubkey)
89+
90+
// Verify it's the updated event (has the different contact pubkeys)
91+
expect(events[0].tags).to.deep.equal(this.parameters.updatedContactListEvent.tags)
92+
},
93+
)
94+
95+
When(
96+
/^(\w+) sends two identically-timestamped contact_list events where the second has a lower ID$/,
97+
async function (name: string) {
98+
const ws = this.parameters.clients[name] as WebSocket
99+
const { pubkey, privkey } = this.parameters.identities[name]
100+
101+
const commonTimestamp = Math.floor(Date.now() / 1000)
102+
103+
const contactPubkey1 = 'e'.repeat(64)
104+
const event1 = await createEvent(
105+
{
106+
pubkey,
107+
kind: EventKinds.CONTACT_LIST,
108+
tags: [[EventTags.Pubkey, contactPubkey1]],
109+
content: 'first contact list',
110+
created_at: commonTimestamp,
111+
},
112+
privkey,
113+
)
114+
115+
let nonce = 0
116+
let event2: Event
117+
const contactPubkey2 = 'f'.repeat(64)
118+
for (;;) {
119+
event2 = await createEvent(
120+
{
121+
pubkey,
122+
kind: EventKinds.CONTACT_LIST,
123+
tags: [[EventTags.Pubkey, contactPubkey2]],
124+
content: `second contact list ${nonce++}`,
125+
created_at: commonTimestamp,
126+
},
127+
privkey,
128+
)
129+
130+
if (event2.id < event1.id) {
131+
break
132+
}
133+
}
134+
135+
await sendEvent(ws, event1)
136+
await sendEvent(ws, event2)
137+
138+
this.parameters.events[name].push(event1, event2)
139+
this.parameters.lowerIdContactListContent = event2.tags
140+
},
141+
)
142+
143+
Then(
144+
/^(\w+) receives 1 contact_list event from (\w+) matching the lower ID event and EOSE$/,
145+
async function (name: string, author: string) {
146+
const ws = this.parameters.clients[name] as WebSocket
147+
const subscription = this.parameters.subscriptions[name][this.parameters.subscriptions[name].length - 1]
148+
const events = await waitForEventCount(ws, subscription.name, 1, true)
149+
150+
expect(events.length).to.equal(1)
151+
expect(events[0].kind).to.equal(EventKinds.CONTACT_LIST)
152+
expect(events[0].pubkey).to.equal(this.parameters.identities[author].pubkey)
153+
expect(events[0].tags).to.deep.equal(this.parameters.lowerIdContactListContent)
154+
},
155+
)

0 commit comments

Comments
 (0)