Skip to content

Commit 0b27b6d

Browse files
committed
test(rpc): add cross-domain field mapping validation tests
1 parent 1a9c243 commit 0b27b6d

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# SPDX-FileCopyrightText: 2025 ash_typescript contributors <https://github.com/ash-project/ash_typescript/graphs.contributors>
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
defmodule AshTypescript.Rpc.TypedQueryFieldMappingCrossDomainTest do
6+
@moduledoc """
7+
Tests that field name mappings work correctly in typed queries when the same
8+
resource is exposed through multiple domains.
9+
10+
This verifies that the TypeScript code generation properly applies field name
11+
mappings from the resource definition, regardless of which domain exposes it.
12+
"""
13+
use ExUnit.Case, async: false
14+
15+
alias AshTypescript.Test.User
16+
17+
setup_all do
18+
# Ensure TypeScript is generated before tests run
19+
Mix.Task.run("test.codegen")
20+
:ok
21+
end
22+
23+
describe "typed query field name mapping across domains" do
24+
test "field mappings are applied in typed queries from first domain" do
25+
# The User resource has field_names mapping: address_line_1: :address_line1
26+
# The first domain (AshTypescript.Test.Domain) has a typed query for User
27+
# in test/support/domain.ex that includes various fields
28+
29+
# Generate TypeScript code
30+
{:ok, typescript} = AshTypescript.Rpc.Codegen.generate_typescript_types(:ash_typescript)
31+
32+
# Check that the typed query from the first domain uses mapped field names
33+
# The typed query "list_users_with_invalid_arg" should have addressLine1, not address_line_1
34+
assert typescript =~ ~r/ListUsersWithInvalidArg/
35+
36+
# Find the fields const for this typed query
37+
assert typescript =~ ~r/export const ListUsersWithInvalidArg.*=.*\[/s
38+
39+
# The generated TypeScript should NOT contain the unmapped name in the fields const
40+
refute typescript =~ ~r/ListUsersWithInvalidArg.*address_line_1/s
41+
end
42+
43+
test "field mappings are applied in typed queries from second domain" do
44+
# The User resource has field_names mappings:
45+
# - address_line_1: :address_line1
46+
# - is_active?: :is_active (calculation with question mark)
47+
# The second domain (AshTypescript.Test.SecondDomain) also has a typed query for User
48+
# This tests that the mapping is correctly applied even in the second domain
49+
50+
# Read the generated TypeScript file that was created during compilation
51+
typescript = File.read!("test/ts/generated.ts")
52+
53+
# Check that the typed query from the second domain exists
54+
assert typescript =~ "listUsersSecondDomain"
55+
assert typescript =~ "ListUsersSecondDomainResult"
56+
57+
# Extract the line with the fields const
58+
[fields_line] = Regex.run(~r/export const listUsersSecondDomain = \[.*\];/, typescript)
59+
60+
# It should contain "addressLine1" (mapped) not "address_line_1" (unmapped)
61+
assert fields_line =~ "addressLine1"
62+
63+
# Verify the unmapped name is NOT present in the fields const
64+
refute fields_line =~ "address_line_1"
65+
66+
# It should contain "isActive" (mapped, question mark removed) not "isActive?" (unmapped with question mark)
67+
assert fields_line =~ ~s["isActive"]
68+
refute fields_line =~ ~s["isActive?"]
69+
refute fields_line =~ "is_active?"
70+
end
71+
72+
test "typed query result types use mapped field names" do
73+
# Generate TypeScript code
74+
{:ok, typescript} = AshTypescript.Rpc.Codegen.generate_typescript_types(:ash_typescript)
75+
76+
# The UserResourceSchema should have addressLine1 (mapped), not address_line_1
77+
assert typescript =~ ~r/export type UserResourceSchema = \{/
78+
assert typescript =~ ~r/addressLine1\?:\s*string/
79+
refute typescript =~ ~r/address_line_1\?:\s*string/
80+
end
81+
82+
test "resource schema is generated only once even with multiple domains" do
83+
# Generate TypeScript code
84+
{:ok, typescript} = AshTypescript.Rpc.Codegen.generate_typescript_types(:ash_typescript)
85+
86+
# Count how many times UserResourceSchema is defined
87+
matches = Regex.scan(~r/export type UserResourceSchema = \{/, typescript)
88+
assert length(matches) == 1, "UserResourceSchema should be defined exactly once"
89+
end
90+
end
91+
92+
describe "runtime field mapping with typed queries" do
93+
setup do
94+
# Create a test user with address_line_1
95+
{:ok, user} =
96+
User
97+
|> Ash.Changeset.for_create(:create, %{
98+
name: "Test User",
99+
100+
address_line_1: "123 Test Street"
101+
})
102+
|> Ash.create()
103+
104+
{:ok, user: user}
105+
end
106+
107+
test "reading with typed query fields uses correct field mapping", %{user: user} do
108+
conn = %Plug.Conn{
109+
assigns: %{
110+
ash_actor: nil,
111+
ash_tenant: "test_tenant"
112+
}
113+
}
114+
115+
# Simulate what the TypeScript client would send for the typed query
116+
# The fields should use the mapped names (addressLine1)
117+
result =
118+
AshTypescript.Rpc.run_action(:ash_typescript, conn, %{
119+
"action" => "list_users",
120+
"resource" => "User",
121+
"input" => %{},
122+
"fields" => ["id", "name", "email", "addressLine1"]
123+
})
124+
125+
assert %{"success" => true, "data" => users} = result
126+
assert is_list(users)
127+
128+
found_user = Enum.find(users, fn u -> u["id"] == user.id end)
129+
assert found_user != nil
130+
assert found_user["name"] == "Test User"
131+
assert found_user["email"] == "[email protected]"
132+
# The output should use the mapped name
133+
assert found_user["addressLine1"] == "123 Test Street"
134+
# The unmapped name should not be present
135+
refute Map.has_key?(found_user, "address_line_1")
136+
end
137+
end
138+
end

0 commit comments

Comments
 (0)