/
ecto_strategy_test.exs
206 lines (153 loc) · 6.24 KB
/
ecto_strategy_test.exs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
defmodule ExMachina.EctoStrategyTest do
use ExMachina.EctoCase
alias ExMachina.TestFactory
alias ExMachina.User
defmodule FactoryWithNoRepo do
use ExMachina.EctoStrategy
def whatever_factory do
%{}
end
end
test "raises helpful error message if no repo is provided" do
assert_raise RuntimeError, ~r/expected :repo to be given/, fn ->
FactoryWithNoRepo.insert(:whatever)
end
end
test "insert/1 inserts the record into the repo" do
model = TestFactory.insert(%User{name: "John"})
new_user = ExMachina.TestRepo.one!(User)
assert model.id
assert model.name == new_user.name
end
test "insert/1 raises if a map is passed" do
message = "%{foo: \"bar\"} is not an Ecto model. Use `build` instead"
assert_raise ArgumentError, message, fn ->
TestFactory.insert(%{foo: "bar"})
end
end
test "insert/1 raises if a non-Ecto struct is passed" do
message = "%{__struct__: Foo.Bar} is not an Ecto model. Use `build` instead"
assert_raise ArgumentError, message, fn ->
TestFactory.insert(%{__struct__: Foo.Bar})
end
end
test "insert/1 casts all values" do
model = TestFactory.insert(:user, net_worth: 300)
assert model.net_worth == Decimal.new(300)
end
test "insert/1 casts belongs_to associations" do
built_author = TestFactory.build(:user, net_worth: 300)
model = TestFactory.insert(:article, author: built_author)
assert model.author.net_worth == Decimal.new(300)
end
test "insert/1 casts has_many associations" do
built_article = TestFactory.build(:article, visits: 10, author: nil)
model = TestFactory.insert(:user, articles: [built_article])
assert List.first(model.articles).visits == Decimal.new(10)
end
test "insert/1 casts embedded associations" do
author = %ExMachina.Author{name: "Paul", salary: 10.3}
link = %ExMachina.Link{url: "wow", rating: 4.5}
comment =
TestFactory.insert(:comment_with_embedded_assocs,
author: author,
links: [link]
)
assert comment.author.name == author.name
assert comment.author.salary == Decimal.from_float(author.salary)
assert List.first(comment.links).url == link.url
assert List.first(comment.links).rating == Decimal.from_float(link.rating)
end
test "insert/1 ignores virtual fields" do
user = TestFactory.insert(:user, password: "foo")
assert user.id != nil
end
test "insert/1 sets nil values" do
model = TestFactory.insert(:article, author: nil)
assert model.author == nil
end
test "insert/1 casts bare maps" do
model = TestFactory.insert(:article, author: %{net_worth: 300})
assert model.author.net_worth == Decimal.new(300)
end
test "insert/1 casts lists of bare maps" do
model = TestFactory.insert(:article, comments: [%{author: %{name: "John Doe", salary: 300}}])
assert hd(model.comments).author.salary == Decimal.new(300)
end
test "insert/1 casts bare maps for embeds" do
model = TestFactory.insert(:comment_with_embedded_assocs, author: %{salary: 300})
assert model.author.salary == Decimal.new(300)
end
test "insert/1 casts lists of bare maps for embeds" do
model =
TestFactory.insert(:comment_with_embedded_assocs,
links: [%{url: "http://thoughtbot.com", rating: 5}]
)
assert hd(model.links).rating == Decimal.new(5)
end
test "insert/1 casts associations recursively" do
editor = TestFactory.build(:user, net_worth: 300)
article = TestFactory.build(:article, editor: editor, author: nil)
author = TestFactory.insert(:user, articles: [article])
assert List.first(author.articles).editor.net_worth == Decimal.new(300)
end
test "insert/1 assigns params that aren't in the schema" do
publisher_assoc = ExMachina.Article.__schema__(:association, :publisher)
publisher_struct = publisher_assoc.related
publisher_fields = publisher_struct.__schema__(:fields)
refute Enum.member?(publisher_fields, :name)
publisher = Map.merge(TestFactory.build(:publisher), %{name: "name"})
model = TestFactory.insert(:article, publisher: publisher)
assert model.publisher.name == "name"
end
test "passed in attrs can override associations" do
my_user = TestFactory.insert(:user, name: "Jane")
article = TestFactory.insert(:article, author: my_user)
assert article.author == my_user
end
test "insert/3 allows options to be passed to the repo" do
with_args = TestFactory.insert(:user, [name: "Jane"], returning: true)
assert with_args.id
assert with_args.name == "Jane"
assert with_args.db_value
without_args = TestFactory.insert(:user, [], returning: true)
assert without_args.id
assert without_args.db_value
with_struct = TestFactory.build(:user) |> TestFactory.insert(returning: true)
assert with_struct.id
assert with_struct.db_value
without_opts = TestFactory.build(:user) |> TestFactory.insert()
assert without_opts.id
refute without_opts.db_value
end
test "insert_pair/3 allows options to be passed to the repo" do
[with_args | _] = TestFactory.insert_pair(:user, [name: "Jane"], returning: true)
assert with_args.id
assert with_args.name == "Jane"
assert with_args.db_value
[without_args | _] = TestFactory.insert_pair(:user, [], returning: true)
assert without_args.id
assert without_args.db_value
end
test "insert_list/4 allows options to be passed to the repo" do
[with_args | _] = TestFactory.insert_list(2, :user, [name: "Jane"], returning: true)
assert with_args.id
assert with_args.name == "Jane"
assert with_args.db_value
[without_args | _] = TestFactory.insert_list(2, :user, [], returning: true)
assert without_args.id
assert without_args.db_value
end
test "insert/1 raises a friendly error when casting invalid types" do
message = ~r/Failed to cast `:invalid` of type ExMachina.InvalidType/
assert_raise RuntimeError, message, fn ->
TestFactory.insert(:invalid_cast, invalid: :invalid)
end
end
test "insert/1 raises if attempting to insert already inserted record" do
message = ~r/You called `insert` on a record that has already been inserted./
assert_raise RuntimeError, message, fn ->
TestFactory.insert(:user, name: "Maximus") |> TestFactory.insert()
end
end
end