package nwc_test import ( "context" "testing" "time" "next.orly.dev/pkg/protocol/nwc" "next.orly.dev/pkg/protocol/ws" ) func TestNWCClientCreation(t *testing.T) { uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" c, err := nwc.NewClient(uri) if err != nil { t.Fatal(err) } if c == nil { t.Fatal("client should not be nil") } } func TestNWCInvalidURI(t *testing.T) { invalidURIs := []string{ "invalid://test", "nostr+walletconnect://", "nostr+walletconnect://invalid", "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b", "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=invalid", } for _, uri := range invalidURIs { _, err := nwc.NewClient(uri) if err == nil { t.Fatalf("expected error for invalid URI: %s", uri) } } } func TestNWCRelayConnection(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second) defer cancel() rc, err := ws.RelayConnect(ctx, "wss://relay.getalby.com/v1") if err != nil { t.Fatalf("relay connection failed: %v", err) } defer rc.Close() t.Log("relay connection successful") } func TestNWCRequestTimeout(t *testing.T) { uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" c, err := nwc.NewClient(uri) if err != nil { t.Fatal(err) } ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second) defer cancel() var r map[string]any err = c.Request(ctx, "get_info", nil, &r) if err == nil { t.Log("wallet responded") return } expectedErrors := []string{ "no response from wallet", "subscription closed", "timeout waiting for response", "context deadline exceeded", } errorFound := false for _, expected := range expectedErrors { if contains(err.Error(), expected) { errorFound = true break } } if !errorFound { t.Fatalf("unexpected error: %v", err) } t.Logf("proper timeout handling: %v", err) } func contains(s, substr string) bool { return len(s) >= len(substr) && (s == substr || (len(s) > len(substr) && (s[:len(substr)] == substr || s[len(s)-len(substr):] == substr || findInString(s, substr)))) } func findInString(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } func TestNWCEncryption(t *testing.T) { uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" c, err := nwc.NewClient(uri) if err != nil { t.Fatal(err) } // We can't directly access private fields, but we can test the client creation // check conversation key generation if c == nil { t.Fatal("client creation should succeed with valid URI") } // Test passed } func TestNWCEventFormat(t *testing.T) { uri := "nostr+walletconnect://816fd7f1d000ae81a3da251c91866fc47f4bcd6ce36921e6d46773c32f1d548b?relay=wss://relay.getalby.com/v1&secret=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" c, err := nwc.NewClient(uri) if err != nil { t.Fatal(err) } // Test client creation // The Request method will create proper NWC events with: // - Kind 23194 for requests // - Proper encryption tag // - Signed with client key ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) defer cancel() var r map[string]any err = c.Request(ctx, "get_info", nil, &r) // We expect this to fail due to inactive connection, but it should fail // after creating and sending NWC event if err == nil { t.Log("wallet responded") return } // Verify it failed for the right reason (connection/response issue, not formatting) validFailures := []string{ "subscription closed", "no response from wallet", "context deadline exceeded", "timeout waiting for response", } validFailure := false for _, failure := range validFailures { if contains(err.Error(), failure) { validFailure = true break } } if !validFailure { t.Fatalf("unexpected error type (suggests formatting issue): %v", err) } // Test passed }