using System.Text.Json.Nodes; using w4c_workflows.Models.Credentials; using w4c_workflows.Services.Credentials; using Xunit; namespace w4c_workflows.Tests; /// /// The extraction strategy reads an OAuth-style token response, including /// non-standard token locations (e.g. Slack's authed_user.access_token). /// public class CredentialExtractorTests { private static readonly CredentialExtraction Extraction = new() { AccessTokenField = "authed_user.access_token", TokenTypeField = "token_type", ExpiresInField = "expires_in", RefreshTokenField = "refresh_token", ScopeField = "scope", DefaultTokenType = "Bearer", }; [Fact] public void Reads_a_nested_access_token_and_the_standard_fields() { var response = JsonNode.Parse(""" { "ok": true, "authed_user": { "access_token": "xoxp-123" }, "token_type": "bearer", "expires_in": 3600, "refresh_token": "refresh-1", "scope": "chat:write" } """)!.AsObject(); var tokens = CredentialExtractor.Extract(response, Extraction); Assert.NotNull(tokens); Assert.Equal("xoxp-123", tokens!.AccessToken); Assert.Equal("bearer", tokens.TokenType); Assert.Equal(3600, tokens.ExpiresInSeconds); Assert.Equal("refresh-1", tokens.RefreshToken); Assert.Equal("chat:write", tokens.Scope); } [Fact] public void Falls_back_to_the_default_token_type() { var response = new JsonObject { ["access_token"] = "tok" }; var extraction = new CredentialExtraction { AccessTokenField = "access_token", DefaultTokenType = "Bearer" }; var tokens = CredentialExtractor.Extract(response, extraction); Assert.Equal("Bearer", tokens!.TokenType); Assert.Null(tokens.ExpiresInSeconds); } [Fact] public void A_response_without_a_token_returns_null() { var response = new JsonObject { ["error"] = "invalid_grant" }; Assert.Null(CredentialExtractor.Extract(response, Extraction)); } }