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