@@ -20,7 +20,11 @@ import {
20
20
} from "../../core/relays.ts?nips=1" ;
21
21
import { SubscriptionClosed } from "../../nips/01/relays.ts" ;
22
22
23
- describe ( "NIP-01/Relay" , ( ) => {
23
+ function getRemoteSocket ( ) {
24
+ return MockWebSocket . instances [ 0 ] . remote ;
25
+ }
26
+
27
+ describe ( "Relay (NIP-01)" , ( ) => {
24
28
const url = "wss://localhost:8080" ;
25
29
let relay : Relay ;
26
30
let sub_0 : ReadableStream < NostrEvent < 0 > > ;
@@ -30,6 +34,7 @@ describe("NIP-01/Relay", () => {
30
34
globalThis . WebSocket = MockWebSocket ;
31
35
relay = new Relay ( url ) ;
32
36
} ) ;
37
+
33
38
afterAll ( ( ) => {
34
39
if ( relay . status === WebSocket . OPEN ) {
35
40
return relay . close ( ) ;
@@ -39,33 +44,33 @@ describe("NIP-01/Relay", () => {
39
44
it ( "should have loaded NIP-01 module" , ( ) => {
40
45
assertEquals ( relay . config . modules . length , 1 ) ;
41
46
} ) ;
47
+
42
48
it ( "should create a subscription" , ( ) => {
43
49
sub_1 = relay . subscribe ( { kinds : [ 1 ] } , { id : "test-1" } ) ;
44
50
assertInstanceOf ( sub_1 , ReadableStream ) ;
45
51
} ) ;
52
+
46
53
it ( "should receive text notes" , async ( ) => {
47
54
const reader = sub_1 . getReader ( ) ;
48
55
const read = reader . read ( ) ;
49
- MockWebSocket . instances [ 0 ] . remote . send (
50
- JSON . stringify ( [ "EVENT" , "test-1" , { kind : 1 } ] ) ,
51
- ) ;
56
+ getRemoteSocket ( ) . send ( JSON . stringify ( [ "EVENT" , "test-1" , { kind : 1 } ] ) ) ;
52
57
const { value, done } = await read ;
53
58
assert ( ! done ) ;
54
59
assertEquals ( value . kind , 1 ) ;
55
60
reader . releaseLock ( ) ;
56
61
} ) ;
62
+
57
63
it ( "should be able to open multiple subscriptions" , ( ) => {
58
- sub_0 = relay . subscribe ( { kinds : [ 0 ] , limit : 1 } , {
59
- id : "test-0" ,
60
- } ) ;
64
+ sub_0 = relay . subscribe ( { kinds : [ 0 ] } , { id : "test-0" } ) ;
61
65
assert ( sub_0 instanceof ReadableStream ) ;
62
66
} ) ;
67
+
63
68
it ( "should recieve metas and notes simultaneously" , async ( ) => {
64
69
const reader_0 = sub_0 . getReader ( ) ;
65
70
const reader_1 = sub_1 . getReader ( ) ;
66
- const ws = MockWebSocket . instances [ 0 ] ;
67
- ws . remote . send ( JSON . stringify ( [ "EVENT" , "test-0" , { kind : 0 } ] ) ) ;
68
- ws . remote . send ( JSON . stringify ( [ "EVENT" , "test-1" , { kind : 1 } ] ) ) ;
71
+ const remote = getRemoteSocket ( ) ;
72
+ remote . send ( JSON . stringify ( [ "EVENT" , "test-0" , { kind : 0 } ] ) ) ;
73
+ remote . send ( JSON . stringify ( [ "EVENT" , "test-1" , { kind : 1 } ] ) ) ;
69
74
const [ { value : value_0 } , { value : value_1 } ] = await Promise . all ( [
70
75
reader_0 . read ( ) ,
71
76
reader_1 . read ( ) ,
@@ -77,18 +82,54 @@ describe("NIP-01/Relay", () => {
77
82
reader_0 . releaseLock ( ) ;
78
83
reader_1 . releaseLock ( ) ;
79
84
} ) ;
85
+
86
+ it ( "should close a subscription with an error when receiving a CLOSED message" , async ( ) => {
87
+ getRemoteSocket ( ) . send ( JSON . stringify (
88
+ [
89
+ "CLOSED" ,
90
+ "test-1" as SubscriptionId ,
91
+ "error: test" ,
92
+ ] satisfies RelayToClientMessage < "CLOSED" > ,
93
+ ) ) ;
94
+ const reader = sub_1 . getReader ( ) ;
95
+ try {
96
+ await reader . read ( ) ;
97
+ } catch ( e ) {
98
+ assertInstanceOf ( e , SubscriptionClosed ) ;
99
+ assertEquals ( e . message , "error: test" ) ;
100
+ } finally {
101
+ reader . releaseLock ( ) ;
102
+ }
103
+ } ) ;
104
+
105
+ it ( "should reconnect if connection is closed while waiting for an event" , async ( ) => {
106
+ const reader = sub_0 . getReader ( ) ;
107
+ const read = reader . read ( ) ;
108
+ getRemoteSocket ( ) . close ( ) ;
109
+ const reconnected = new Promise < true > ( ( resolve ) => {
110
+ relay . ws . addEventListener ( "open" , ( ) => resolve ( true ) ) ;
111
+ } ) ;
112
+ assert ( await reconnected ) ;
113
+ // We must use a new instance of MockWebSocket.
114
+ getRemoteSocket ( ) . send ( JSON . stringify ( [ "EVENT" , "test-0" , { kind : 0 } ] ) ) ;
115
+ const { value, done } = await read ;
116
+ assert ( ! done ) ;
117
+ assertEquals ( value . kind , 0 ) ;
118
+ reader . releaseLock ( ) ;
119
+ } ) ;
120
+
80
121
it ( "should publish an event and recieve an accepting OK message" , async ( ) => {
81
122
const eid = "test-true" as EventId ;
82
- const ws = MockWebSocket . instances [ 0 ] ;
123
+ const remote = getRemoteSocket ( ) ;
83
124
const arrived = new Promise < true > ( ( resolve ) => {
84
- ws . remote . addEventListener (
125
+ remote . addEventListener (
85
126
"message" ,
86
127
( ev : MessageEvent < string > ) => {
87
128
// deno-fmt-ignore
88
129
const [ , event ] = JSON . parse ( ev . data ) as ClientToRelayMessage < "EVENT" > ;
89
130
if ( event . id === eid ) {
90
131
assertEquals ( event . kind , 1 ) ;
91
- ws . remote . send (
132
+ remote . send (
92
133
JSON . stringify (
93
134
[ "OK" , eid , true , "" ] satisfies RelayToClientMessage < "OK" > ,
94
135
) ,
@@ -102,21 +143,22 @@ describe("NIP-01/Relay", () => {
102
143
await relay . publish ( { id : eid , kind : 1 } as any ) ;
103
144
assert ( await arrived ) ;
104
145
} ) ;
146
+
105
147
it ( "should receieve a rejecting OK message and throw EventRejected" , async ( ) => {
106
148
const eid = "test-false" as EventId ;
107
149
// deno-fmt-ignore
108
150
const msg = [ "OK" , eid , false , "error: test" ] satisfies RelayToClientMessage < "OK" >
109
- const ws = MockWebSocket . instances [ 0 ] ;
151
+ const remote = getRemoteSocket ( ) ;
110
152
const arrived = new Promise < true > ( ( resolve ) => {
111
- ws . remote . addEventListener (
153
+ remote . addEventListener (
112
154
"message" ,
113
155
( ev : MessageEvent < string > ) => {
114
156
// deno-fmt-ignore
115
157
const [ , event ] = JSON . parse ( ev . data ) as ClientToRelayMessage < "EVENT" > ;
116
158
if ( event . id === eid ) {
117
159
assertEquals ( event . kind , 1 ) ;
118
160
resolve ( true ) ;
119
- ws . remote . send ( JSON . stringify ( msg ) ) ;
161
+ remote . send ( JSON . stringify ( msg ) ) ;
120
162
}
121
163
} ,
122
164
) ;
@@ -132,26 +174,16 @@ describe("NIP-01/Relay", () => {
132
174
}
133
175
await arrived ;
134
176
} ) ;
177
+
135
178
it ( "should throw ConnectionClosed when connection is closed before recieving an OK message" , async ( ) => {
136
179
const event = { id : "test-close" as EventId , kind : 1 } ;
137
180
// deno-lint-ignore no-explicit-any
138
181
const published = relay . publish ( event as any ) . catch ( ( e ) => e ) ;
139
- MockWebSocket . instances [ 0 ] . remote . close ( ) ;
140
- assertInstanceOf ( await published , ConnectionClosed ) ;
141
- } ) ;
142
- it ( "should close a subscription with an error when receiving a CLOSED message" , async ( ) => {
143
- MockWebSocket . instances [ 0 ] . remote . send ( JSON . stringify (
144
- [
145
- "CLOSED" ,
146
- "test-1" as SubscriptionId ,
147
- "error: test" ,
148
- ] satisfies RelayToClientMessage < "CLOSED" > ,
149
- ) ) ;
182
+ getRemoteSocket ( ) . close ( ) ;
150
183
try {
151
- await sub_1 . getReader ( ) . read ( ) ;
184
+ await published ;
152
185
} catch ( e ) {
153
- assertInstanceOf ( e , SubscriptionClosed ) ;
154
- assertEquals ( e . message , "error: test" ) ;
186
+ assertInstanceOf ( e , ConnectionClosed ) ;
155
187
}
156
188
} ) ;
157
189
} ) ;
0 commit comments