relay.spec.ts raw
1 import { Relay, InvalidRelayUrlError, toNip65RelayList } from './relay';
2 import { IdentityId } from '../value-objects';
3
4 describe('Relay Entity', () => {
5 const testIdentityId = IdentityId.from('identity-1');
6 const validUrl = 'wss://relay.example.com';
7
8 describe('create', () => {
9 it('should create relay with default read/write permissions', () => {
10 const relay = Relay.create(testIdentityId, validUrl);
11
12 expect(relay.url).toEqual(validUrl);
13 expect(relay.read).toBe(true);
14 expect(relay.write).toBe(true);
15 });
16
17 it('should create relay with specified permissions', () => {
18 const relay = Relay.create(testIdentityId, validUrl, true, false);
19
20 expect(relay.read).toBe(true);
21 expect(relay.write).toBe(false);
22 });
23
24 it('should create relay with read-only permissions', () => {
25 const relay = Relay.create(testIdentityId, validUrl, true, false);
26
27 expect(relay.read).toBe(true);
28 expect(relay.write).toBe(false);
29 });
30
31 it('should create relay with write-only permissions', () => {
32 const relay = Relay.create(testIdentityId, validUrl, false, true);
33
34 expect(relay.read).toBe(false);
35 expect(relay.write).toBe(true);
36 });
37
38 it('should throw InvalidRelayUrlError for invalid URL', () => {
39 expect(() => Relay.create(testIdentityId, 'not-a-url')).toThrowError(InvalidRelayUrlError);
40 });
41
42 it('should throw InvalidRelayUrlError for http URL', () => {
43 expect(() => Relay.create(testIdentityId, 'http://relay.example.com')).toThrowError(InvalidRelayUrlError);
44 });
45
46 it('should accept wss:// URL', () => {
47 expect(() => Relay.create(testIdentityId, 'wss://relay.example.com')).not.toThrow();
48 });
49
50 it('should accept ws:// URL (for local development)', () => {
51 expect(() => Relay.create(testIdentityId, 'ws://localhost:8080')).not.toThrow();
52 });
53 });
54
55 describe('updateUrl', () => {
56 it('should update URL to valid new URL', () => {
57 const relay = Relay.create(testIdentityId, validUrl);
58
59 relay.updateUrl('wss://new-relay.example.com');
60
61 expect(relay.url).toEqual('wss://new-relay.example.com');
62 });
63
64 it('should throw InvalidRelayUrlError for invalid new URL', () => {
65 const relay = Relay.create(testIdentityId, validUrl);
66
67 expect(() => relay.updateUrl('not-a-url')).toThrowError(InvalidRelayUrlError);
68 });
69 });
70
71 describe('read permission toggling', () => {
72 it('should enable read', () => {
73 const relay = Relay.create(testIdentityId, validUrl, false, false);
74
75 relay.enableRead();
76
77 expect(relay.read).toBe(true);
78 });
79
80 it('should disable read', () => {
81 const relay = Relay.create(testIdentityId, validUrl, true, true);
82
83 relay.disableRead();
84
85 expect(relay.read).toBe(false);
86 });
87 });
88
89 describe('write permission toggling', () => {
90 it('should enable write', () => {
91 const relay = Relay.create(testIdentityId, validUrl, false, false);
92
93 relay.enableWrite();
94
95 expect(relay.write).toBe(true);
96 });
97
98 it('should disable write', () => {
99 const relay = Relay.create(testIdentityId, validUrl, true, true);
100
101 relay.disableWrite();
102
103 expect(relay.write).toBe(false);
104 });
105 });
106
107 describe('fromSnapshot', () => {
108 it('should reconstruct relay from snapshot', () => {
109 const original = Relay.create(testIdentityId, validUrl, true, false);
110 const snapshot = original.toSnapshot();
111
112 const restored = Relay.fromSnapshot(snapshot);
113
114 expect(restored.url).toEqual(validUrl);
115 expect(restored.read).toBe(true);
116 expect(restored.write).toBe(false);
117 });
118 });
119
120 describe('toSnapshot', () => {
121 it('should create valid snapshot', () => {
122 const relay = Relay.create(testIdentityId, validUrl, true, false);
123 const snapshot = relay.toSnapshot();
124
125 expect(snapshot.identityId).toEqual(testIdentityId.toString());
126 expect(snapshot.url).toEqual(validUrl);
127 expect(snapshot.read).toBe(true);
128 expect(snapshot.write).toBe(false);
129 });
130 });
131 });
132
133 describe('toNip65RelayList', () => {
134 const identityId = IdentityId.from('identity-1');
135
136 it('should convert relays to NIP-65 format', () => {
137 const relays = [
138 Relay.create(identityId, 'wss://relay1.com', true, true),
139 Relay.create(identityId, 'wss://relay2.com', true, false),
140 Relay.create(identityId, 'wss://relay3.com', false, true),
141 ];
142
143 const nip65List = toNip65RelayList(relays);
144
145 expect(nip65List['wss://relay1.com']).toEqual({ read: true, write: true });
146 expect(nip65List['wss://relay2.com']).toEqual({ read: true, write: false });
147 expect(nip65List['wss://relay3.com']).toEqual({ read: false, write: true });
148 });
149
150 it('should return empty object for empty relay list', () => {
151 const nip65List = toNip65RelayList([]);
152
153 expect(nip65List).toEqual({});
154 });
155 });
156