|
1 | 1 | describe "attribute aliases" do |
2 | | - before do |
3 | | - define_model("User", name: :string, age: :integer) |
| 2 | + around do |example| |
| 3 | + original_aliases = FactoryBot.aliases.dup |
| 4 | + example.run |
| 5 | + ensure |
| 6 | + FactoryBot.aliases.clear |
| 7 | + FactoryBot.aliases.concat(original_aliases) |
| 8 | + end |
| 9 | + |
| 10 | + describe "basic alias functionality" do |
| 11 | + it "allows using different parameter names that map to model attributes" do |
| 12 | + FactoryBot.aliases << [/author_name/, "name"] |
| 13 | + define_model("User", name: :string, author_name: :string) |
| 14 | + |
| 15 | + FactoryBot.define do |
| 16 | + factory :user do |
| 17 | + name { "Default Name" } |
| 18 | + end |
| 19 | + end |
| 20 | + |
| 21 | + user = FactoryBot.create(:user, author_name: "Custom Name") |
4 | 22 |
|
5 | | - define_model("Post", user_id: :integer) do |
6 | | - belongs_to :user |
| 23 | + expect(user.author_name).to eq "Custom Name" |
| 24 | + expect(user.name).to be_nil |
7 | 25 | end |
8 | 26 |
|
9 | | - FactoryBot.define do |
10 | | - factory :user do |
11 | | - factory :user_with_name do |
12 | | - name { "John Doe" } |
| 27 | + it "ignores factory defaults when alias is used" do |
| 28 | + FactoryBot.aliases << [/display_name/, "name"] |
| 29 | + define_model("User", name: :string, display_name: :string) |
| 30 | + |
| 31 | + FactoryBot.define do |
| 32 | + factory :user do |
| 33 | + name { "Factory Name" } |
13 | 34 | end |
14 | 35 | end |
15 | 36 |
|
16 | | - factory :post do |
17 | | - user |
| 37 | + user = FactoryBot.create(:user, display_name: "Override Name") |
| 38 | + |
| 39 | + expect(user.display_name).to eq "Override Name" |
| 40 | + expect(user.name).to be_nil |
| 41 | + end |
| 42 | + end |
| 43 | + |
| 44 | + describe "built-in _id aliases" do |
| 45 | + it "automatically alias between associations and foreign keys" do |
| 46 | + define_model("User", name: :string) |
| 47 | + define_model("Post", user_id: :integer) do |
| 48 | + belongs_to :user, optional: true |
18 | 49 | end |
19 | 50 |
|
20 | | - factory :post_with_named_user, class: Post do |
21 | | - user factory: :user_with_name, age: 20 |
| 51 | + FactoryBot.define do |
| 52 | + factory :user do |
| 53 | + name { "Test User" } |
| 54 | + end |
| 55 | + |
| 56 | + factory :post |
22 | 57 | end |
| 58 | + |
| 59 | + user = FactoryBot.create(:user) |
| 60 | + |
| 61 | + post_with_direct_id = FactoryBot.create(:post, user_id: user.id) |
| 62 | + expect(post_with_direct_id.user_id).to eq user.id |
| 63 | + |
| 64 | + post_with_association = FactoryBot.create(:post, user: user) |
| 65 | + expect(post_with_association.user_id).to eq user.id |
| 66 | + end |
| 67 | + |
| 68 | + it "prevents conflicts between associations and foreign keys" do |
| 69 | + define_model("User", name: :string, age: :integer) |
| 70 | + define_model("Post", user_id: :integer) do |
| 71 | + belongs_to :user |
| 72 | + end |
| 73 | + |
| 74 | + FactoryBot.define do |
| 75 | + factory :user do |
| 76 | + factory :user_with_name do |
| 77 | + name { "John Doe" } |
| 78 | + end |
| 79 | + end |
| 80 | + |
| 81 | + factory :post do |
| 82 | + user |
| 83 | + end |
| 84 | + end |
| 85 | + |
| 86 | + post_with_foreign_key = FactoryBot.build(:post, user_id: 1) |
| 87 | + |
| 88 | + expect(post_with_foreign_key.user_id).to eq 1 |
| 89 | + end |
| 90 | + |
| 91 | + it "allows passing attributes to associated factories" do |
| 92 | + define_model("User", name: :string, age: :integer) |
| 93 | + define_model("Post", user_id: :integer) do |
| 94 | + belongs_to :user |
| 95 | + end |
| 96 | + |
| 97 | + FactoryBot.define do |
| 98 | + factory :user do |
| 99 | + factory :user_with_name do |
| 100 | + name { "John Doe" } |
| 101 | + end |
| 102 | + end |
| 103 | + |
| 104 | + factory :post do |
| 105 | + user |
| 106 | + end |
| 107 | + |
| 108 | + factory :post_with_named_user, class: Post do |
| 109 | + user factory: :user_with_name, age: 20 |
| 110 | + end |
| 111 | + end |
| 112 | + |
| 113 | + created_user = FactoryBot.create(:post_with_named_user).user |
| 114 | + |
| 115 | + expect(created_user.name).to eq "John Doe" |
| 116 | + expect(created_user.age).to eq 20 |
23 | 117 | end |
24 | 118 | end |
25 | 119 |
|
26 | | - context "assigning an association by foreign key" do |
27 | | - subject { FactoryBot.build(:post, user_id: 1) } |
| 120 | + describe "custom alias patterns" do |
| 121 | + it "supports regex patterns with capture groups" do |
| 122 | + FactoryBot.aliases << [/(.+)_alias/, '\1'] |
| 123 | + define_model("User", name: :string, name_alias: :string, email: :string, email_alias: :string) |
| 124 | + |
| 125 | + FactoryBot.define do |
| 126 | + factory :user do |
| 127 | + name { "Default Name" } |
| 128 | + |
| 129 | + end |
| 130 | + end |
| 131 | + |
| 132 | + user = FactoryBot.create(:user, name_alias: "Aliased Name", email_alias: "[email protected]") |
28 | 133 |
|
29 | | - it "doesn't assign both an association and its foreign key" do |
30 | | - expect(subject.user_id).to eq 1 |
| 134 | + expect(user.name).to be_nil |
| 135 | + expect(user.email).to be_nil |
| 136 | + expect(user.name_alias).to eq "Aliased Name" |
| 137 | + expect(user.email_alias).to eq "[email protected]" |
| 138 | + end |
| 139 | + |
| 140 | + it "supports multiple alias patterns working together" do |
| 141 | + FactoryBot.aliases << [/primary_(.+)/, '\1'] |
| 142 | + FactoryBot.aliases << [/alt_name/, "name"] |
| 143 | + define_model("User", name: :string, email: :string, primary_email: :string, alt_name: :string) |
| 144 | + |
| 145 | + FactoryBot.define do |
| 146 | + factory :user do |
| 147 | + name { "Default Name" } |
| 148 | + |
| 149 | + end |
| 150 | + end |
| 151 | + |
| 152 | + user = FactoryBot.create(:user, primary_email: "[email protected]", alt_name: "Alternative Name") |
| 153 | + |
| 154 | + expect(user.name).to be_nil |
| 155 | + expect(user.email).to be_nil |
| 156 | + expect(user.primary_email).to eq "[email protected]" |
| 157 | + expect(user.alt_name).to eq "Alternative Name" |
| 158 | + end |
| 159 | + |
| 160 | + it "works with custom foreign key names" do |
| 161 | + FactoryBot.aliases << [/owner_id/, "user_id"] |
| 162 | + define_model("User", name: :string) |
| 163 | + define_model("Document", user_id: :integer, owner_id: :integer, title: :string) do |
| 164 | + belongs_to :user, optional: true |
| 165 | + end |
| 166 | + |
| 167 | + FactoryBot.define do |
| 168 | + factory :user do |
| 169 | + name { "Test User" } |
| 170 | + end |
| 171 | + |
| 172 | + factory :document do |
| 173 | + title { "Test Document" } |
| 174 | + end |
| 175 | + end |
| 176 | + |
| 177 | + document_owner = FactoryBot.create(:user) |
| 178 | + document = FactoryBot.create(:document, owner_id: document_owner.id) |
| 179 | + |
| 180 | + expect(document.user_id).to be_nil |
| 181 | + expect(document.owner_id).to eq document_owner.id |
| 182 | + expect(document.title).to eq "Test Document" |
| 183 | + end |
| 184 | + end |
| 185 | + |
| 186 | + describe "edge cases" do |
| 187 | + it "allows setting nil values through aliases" do |
| 188 | + FactoryBot.aliases << [/clear_name/, "name"] |
| 189 | + define_model("User", name: :string, clear_name: :string) |
| 190 | + |
| 191 | + FactoryBot.define do |
| 192 | + factory :user do |
| 193 | + name { "Default Name" } |
| 194 | + end |
| 195 | + end |
| 196 | + |
| 197 | + user = FactoryBot.create(:user, clear_name: nil) |
| 198 | + |
| 199 | + expect(user.name).to be_nil |
| 200 | + expect(user.clear_name).to be_nil |
| 201 | + end |
| 202 | + |
| 203 | + context "when both alias and target attributes exist on model" do |
| 204 | + it "ignores factory defaults for target when alias is used" do |
| 205 | + FactoryBot.aliases << [/one/, "two"] |
| 206 | + define_model("User", two: :string, one: :string) |
| 207 | + |
| 208 | + FactoryBot.define do |
| 209 | + factory :user do |
| 210 | + two { "set value" } |
| 211 | + end |
| 212 | + end |
| 213 | + |
| 214 | + user = FactoryBot.create(:user, one: "override") |
| 215 | + |
| 216 | + expect(user.one).to eq "override" |
| 217 | + expect(user.two).to be_nil |
| 218 | + end |
| 219 | + end |
| 220 | + end |
| 221 | + |
| 222 | + describe "with attributes_for strategy" do |
| 223 | + it "includes alias names in hash and ignores aliased factory defaults" do |
| 224 | + FactoryBot.aliases << [/author_name/, "name"] |
| 225 | + define_model("User", name: :string, author_name: :string) |
| 226 | + |
| 227 | + FactoryBot.define do |
| 228 | + factory :user do |
| 229 | + name { "Default Name" } |
| 230 | + end |
| 231 | + end |
| 232 | + |
| 233 | + attributes = FactoryBot.attributes_for(:user, author_name: "Custom Name") |
| 234 | + |
| 235 | + expect(attributes[:author_name]).to eq "Custom Name" |
| 236 | + expect(attributes[:name]).to be_nil |
31 | 237 | end |
32 | 238 | end |
33 | 239 |
|
34 | | - context "assigning an association by passing factory" do |
35 | | - subject { FactoryBot.create(:post_with_named_user).user } |
| 240 | + describe "attribute conflicts with _id patterns" do |
| 241 | + it "doesn't set factory defaults when alias is used instead of target attribute" do |
| 242 | + define_model("User", name: :string, response_id: :integer) |
| 243 | + |
| 244 | + FactoryBot.define do |
| 245 | + factory :user do |
| 246 | + name { "orig name" } |
| 247 | + response_id { 42 } |
| 248 | + end |
| 249 | + end |
| 250 | + |
| 251 | + attributes = FactoryBot.attributes_for(:user, name: "new name", response: 13.75) |
| 252 | + |
| 253 | + expect(attributes[:name]).to eq "new name" |
| 254 | + expect(attributes[:response]).to eq 13.75 |
| 255 | + expect(attributes[:response_id]).to be_nil |
| 256 | + end |
| 257 | + |
| 258 | + it "allows setting both attribute and attribute_id without conflicts" do |
| 259 | + define_model("User", name: :string, response: :string, response_id: :float) |
| 260 | + |
| 261 | + FactoryBot.define do |
| 262 | + factory :user do |
| 263 | + name { "orig name" } |
| 264 | + response { "orig response" } |
| 265 | + response_id { 42 } |
| 266 | + end |
| 267 | + end |
| 268 | + |
| 269 | + user = FactoryBot.build(:user, name: "new name", response: "new response", response_id: 13.75) |
36 | 270 |
|
37 | | - it "assigns attributes correctly" do |
38 | | - expect(subject.name).to eq "John Doe" |
39 | | - expect(subject.age).to eq 20 |
| 271 | + expect(user.name).to eq "new name" |
| 272 | + expect(user.response).to eq "new response" |
| 273 | + expect(user.response_id).to eq 13.75 |
40 | 274 | end |
41 | 275 | end |
42 | 276 | end |
0 commit comments