Thank you a lot for answer. 
Ok, so now I have this code:
def validate_url(changeset, field, opts \\ []) do
validate_change changeset, field, fn _, value ->
case check_url(value) do
:ok -> []
{:error, error} -> [{field, Keyword.get(opts, :message, error)}]
end
end
end
def check_url(value) do
case URI.parse(value) do
%URI{scheme: nil} -> "is missing a scheme (e.g. https)"
%URI{host: nil} -> "is missing a host"
%URI{host: host} -> validate_host(host)
end
end
end
def validate_host(host) do
case :inet.gethostbyname(Kernel.to_charlist(host)) do
{:ok, _} -> nil
{:error, _} -> "invalid host"
end
end
end
That’s what I call in this changesets:
def changeset(site, attrs) do
site
|> cast(attrs, [:name, :url, :page_counts, :user_id, :site_config_id])
|> validate_required([:name, :url, :page_counts, :user_id])
|> MyApp.EctoHelpers.validate_url(:url)
end
#and this
def changeset(site_config, attrs) do
site_config
|> cast(attrs, [:lang, :privacy_policy_url, :logo, :color, :user_id])
|> validate_required([:lang, :privacy_policy_url, :logo, :color, :user_id])
|> MyApp.EctoHelpers.validate_url(:privacy_policy_url)
end
Interestingly, if I only comment out the changeset with the privacy policy(validate_url(:privacy_policy_url)
), my tests pass. And validate_utl(url)
can be left as is.
So I thought there was already a test somewhere for the url, but I just couldn’t find it. (As a newbie I still don’t understand every part of the code in detail)
So I wanted to write my own test for validation in addition to the automatically generated tests.
Unfortunately, I’ve only modified the generated tests so far, so I’m having trouble understanding the principle of how to put this test together correctly.
I originally thought that as the automated test verifies the creation of the page with valid data, I would similarly create something to validate the URL.
test "create_site/1 with valid data creates a site" do
user = user_fixture()
valid_attrs = %{
name: "some name",
page_counts: 42,
url: "https://some_url.com",
user_id: user.id
}
assert {:ok, %Site{} = site} = Sites.create_site(valid_attrs)
assert site.name == "some name"
assert site.page_counts == 42
assert site.url == "https://some_url.com"
assert site.user_id == user.id
end
Then I came across the method of validation viz. first comment and thought I might write something like this:
test "validate_url" do
assert MyApp.EctoHelpers.validate_url("https://example.com/bar/123") == :ok
assert MyApp.EctoHelpers.validate_url("https://example.com/bar/123/../456") == {:error, ???}
assert MyApp.EctoHelpers.validate_url("1.2.3.4") == {:error, ???}
assert MyApp.EctoHelpers.validate_url("https://1.2.3.4") == {:error, ???}
assert MyApp.EctoHelpers.validate_url("http://1.2.3.4") == {:error, ???}
assert MyApp.EctoHelpers.validate_url("http://example.com/bar/123") == {:error, ???}
assert MyApp.EctoHelpers.validate_url(123) == {:error, ???}
end
test "valid_url?" do
assert MyApp.EctoHelpers.validate_url?("https://example.com/bar/123")
refute MyApp.EctoHelpers.validate_url?("https://example.com/bar/123/../456")
end
So what should I write instead ??? or how should i write functional test?
Thank you very much for your help and patience. And I apologize for any stupidity in the question. 