Gli agenti autenticati con token Bearer possono leggere today/pipeline e annotare attività, con host MCP allineati a quelli di produzione. Co-authored-by: Cursor <cursoragent@cursor.com>
131 lines
4.2 KiB
Ruby
131 lines
4.2 KiB
Ruby
require "test_helper"
|
|
|
|
class Api::V1::ApiTest < ActionDispatch::IntegrationTest
|
|
setup do
|
|
@admin_token = ApiToken.issue!(user: users(:admin), name: "test-admin")
|
|
@marco_token = ApiToken.issue!(user: users(:marco), name: "test-marco")
|
|
@org = organizations(:acme)
|
|
@task = tasks(:follow_up)
|
|
@opportunity = opportunities(:deal)
|
|
end
|
|
|
|
test "rejects missing token" do
|
|
get "/api/v1/projects", as: :json
|
|
assert_response :unauthorized
|
|
assert_equal "Non autenticato", json_body["error"]
|
|
end
|
|
|
|
test "rejects invalid token" do
|
|
get "/api/v1/projects", headers: bearer("crm_invalid"), as: :json
|
|
assert_response :unauthorized
|
|
end
|
|
|
|
test "lists accessible projects" do
|
|
get "/api/v1/projects", headers: bearer(@marco_token.plaintext), as: :json
|
|
assert_response :success
|
|
codes = json_body["projects"].map { |p| p["code"] }
|
|
assert_includes codes, "matchlivetv"
|
|
assert_not_includes codes, "riskmeter"
|
|
end
|
|
|
|
test "forbids project the user cannot access" do
|
|
get "/api/v1/p/riskmeter/today", headers: bearer(@marco_token.plaintext), as: :json
|
|
assert_response :forbidden
|
|
end
|
|
|
|
test "returns 404 for unknown project" do
|
|
get "/api/v1/p/sconosciuto/today", headers: bearer(@admin_token.plaintext), as: :json
|
|
assert_response :not_found
|
|
end
|
|
|
|
test "today includes due tasks" do
|
|
get "/api/v1/p/matchlivetv/today", headers: bearer(@admin_token.plaintext), as: :json
|
|
assert_response :success
|
|
ids = json_body["today_tasks"].map { |t| t["id"] }
|
|
assert_includes ids, @task.id
|
|
assert_equal "matchlivetv", json_body["project"]["code"]
|
|
end
|
|
|
|
test "search finds organization" do
|
|
get "/api/v1/p/matchlivetv/search", params: { q: "ASD Test" }, headers: bearer(@admin_token.plaintext), as: :json
|
|
assert_response :success
|
|
org_ids = json_body["organizations"].map { |o| o["id"] }
|
|
assert_includes org_ids, @org.id
|
|
end
|
|
|
|
test "shows organization card" do
|
|
get "/api/v1/p/matchlivetv/organizations/#{@org.id}", headers: bearer(@admin_token.plaintext), as: :json
|
|
assert_response :success
|
|
assert_equal @org.name, json_body["organization"]["name"]
|
|
assert json_body["contacts"].any?
|
|
assert json_body["open_opportunities"].any?
|
|
assert json_body["pending_tasks"].any?
|
|
end
|
|
|
|
test "creates activity" do
|
|
assert_difference -> { Activity.count }, 1 do
|
|
post "/api/v1/p/matchlivetv/activities",
|
|
params: {
|
|
organization_id: @org.id,
|
|
activity_type: "note",
|
|
subject: "Nota agente",
|
|
description: "Creato via API"
|
|
},
|
|
headers: bearer(@admin_token.plaintext),
|
|
as: :json
|
|
end
|
|
assert_response :created
|
|
assert_equal "Nota agente", json_body["activity"]["subject"]
|
|
end
|
|
|
|
test "creates and completes task" do
|
|
post "/api/v1/p/matchlivetv/tasks",
|
|
params: {
|
|
organization_id: @org.id,
|
|
title: "Richiamare dopo demo",
|
|
due_at: 1.day.from_now.iso8601,
|
|
task_type: "call",
|
|
priority: "high"
|
|
},
|
|
headers: bearer(@admin_token.plaintext),
|
|
as: :json
|
|
assert_response :created
|
|
task_id = json_body["task"]["id"]
|
|
|
|
post "/api/v1/p/matchlivetv/tasks/#{task_id}/complete",
|
|
headers: bearer(@admin_token.plaintext),
|
|
as: :json
|
|
assert_response :success
|
|
assert_equal "completed", json_body["task"]["status"]
|
|
end
|
|
|
|
test "updates opportunity stage" do
|
|
patch "/api/v1/p/matchlivetv/opportunities/#{@opportunity.id}/stage",
|
|
params: { pipeline_stage: "demo_trial", notes: "Demo fissata dall'agente" },
|
|
headers: bearer(@admin_token.plaintext),
|
|
as: :json
|
|
assert_response :success
|
|
assert_equal "demo_trial", json_body["opportunity"]["pipeline_stage"]
|
|
@opportunity.reload
|
|
assert_equal "demo_trial", @opportunity.pipeline_stage
|
|
end
|
|
|
|
test "rejects lost stage without reason" do
|
|
patch "/api/v1/p/matchlivetv/opportunities/#{@opportunity.id}/stage",
|
|
params: { pipeline_stage: "lost" },
|
|
headers: bearer(@admin_token.plaintext),
|
|
as: :json
|
|
assert_response :unprocessable_entity
|
|
end
|
|
|
|
private
|
|
|
|
def bearer(plaintext)
|
|
{ "Authorization" => "Bearer #{plaintext}" }
|
|
end
|
|
|
|
def json_body
|
|
JSON.parse(response.body)
|
|
end
|
|
end
|