diff --git a/features/config.exs b/features/config.exs
index f9fc77577c6c07344671ab4cd110a713dac3906b..904424dd3c62fe5f1098933109e3abf2ca474f1a 100644
--- a/features/config.exs
+++ b/features/config.exs
@@ -21,6 +21,10 @@ defmodule WhiteBreadConfig do
         context:       UserProfileContext,
         feature_paths: ["features/user_profile.feature"]
 
+  suite name:          "FR-09 Property Update Features",
+        context:        PropertyUpdateContext,
+        feature_paths: ["features/property_update.feature"]
+
   suite name:          "FR-08 Property Advertisement Creation Features",
         context:       AdvertisementCreationContext,
         feature_paths: ["features/advertisement_creation.feature"]
diff --git a/features/contexts/property_update_context.exs b/features/contexts/property_update_context.exs
new file mode 100644
index 0000000000000000000000000000000000000000..5e916f85b363bf214728b7dd015b78087586f0c4
--- /dev/null
+++ b/features/contexts/property_update_context.exs
@@ -0,0 +1,159 @@
+defmodule PropertyUpdateContext do
+  use WhiteBread.Context
+  use Hound.Helpers
+  alias PropTrackr.Repo
+  alias PropTrackr.Accounts.User
+  alias PropTrackr.Properties.Property
+
+  scenario_starting_state fn _state ->
+    Ecto.Adapters.SQL.Sandbox.checkout(PropTrackr.Repo)
+    Ecto.Adapters.SQL.Sandbox.mode(PropTrackr.Repo, {:shared, self()})
+    Hound.start_session()
+    %{}
+  end
+
+  scenario_finalize fn _status, _state ->
+    Ecto.Adapters.SQL.Sandbox.checkin(PropTrackr.Repo)
+    Hound.end_session()
+  end
+
+  given_ ~r/^there exists following accounts$/, fn state, %{table_data: table} ->
+    table
+    |> Enum.map(fn user_details -> User.changeset(%User{}, user_details) end)
+    |> Enum.each(fn changeset -> Repo.insert!(changeset) end)
+
+    existing_user = List.first(table)
+    random_user = List.last(table)
+
+    {
+      :ok,
+      state
+      |> Map.put(:email, existing_user[:email])
+      |> Map.put(:password, existing_user[:password])
+      |> Map.put(:random_email, random_user[:email])
+      |> Map.put(:random_password, random_user[:password])
+    }
+  end
+
+  and_ ~r/^the following properties exist$/, fn state, %{ table_data: table } ->
+    logged_in_user = Repo.get_by(User, email: state[:email])
+
+    advertisements =
+      table                                                                                
+      |> Enum.map(fn details -> details |> Map.put(:reference, Ecto.UUID.generate()) end)
+      |> Enum.map(fn details -> {Ecto.build_assoc(logged_in_user, :properties, details), details} end)
+      |> Enum.map(fn {assoc, details} -> Property.changeset(assoc, details) end)                            
+      |> Enum.map(fn changeset -> Repo.insert!(changeset) end)
+
+    {
+      :ok,
+      state
+      |> Map.put(:advertisements, advertisements)
+    }
+  end
+
+  and_ ~r/^I am logged in$/, fn state ->
+    setup_session(state[:email], state[:password])
+    {:ok, state}
+  end
+
+  and_ ~r/^I navigate to my property's details page$/, fn state ->
+    advertisement = List.first(state[:advertisements])
+    click({:id, "edit-#{advertisement.reference}"})
+    {:ok, state}
+  end
+
+  when_ ~r/^I click the edit button$/, fn state ->
+    click({:id, "edit-property"})
+    {:ok, state}
+  end
+
+  and_ ~r/^I update the following fields$/, fn state, %{ table_data: table } ->
+    data = List.first(table)
+    fill_field({:id, "title"}, data[:title])
+    fill_field({:id, "description"}, data[:description])
+    select_dropdown("type", data[:type])
+    select_dropdown("property_type", data[:property_type])
+    select_dropdown("state", data[:state])
+    fill_field({:id, "location"}, data[:location])
+    fill_field({:id, "room_count"}, data[:room_count])
+    fill_field({:id, "area"}, data[:area])
+    fill_field({:id, "floor"}, data[:floor])
+    fill_field({:id, "price"}, data[:price])
+    {
+      :ok,
+      state
+      |> Map.put(:updated_data, data)
+    }
+  end
+
+  and_ ~r/^I click save changes$/, fn state ->
+    click({:id, "save-changes"})
+    {:ok, state}
+  end
+
+  then_ ~r/^I should see a success message$/, fn state ->
+    assert visible_in_page? ~r/Property updated successfully./
+    {:ok, state}
+  end
+
+  and_ ~r/^I should be redirected back to the property page$/, fn state ->
+    advertisement = List.first(state[:advertisements])
+    assert current_path() == "/properties/#{advertisement.reference}"
+    {:ok, state}
+  end
+
+  and_ ~r/^I should see the updated property details$/, fn state ->
+    advertisement = state[:updated_data]
+    assert visible_in_page? ~r/#{advertisement.title}/
+    assert visible_in_page? ~r/#{advertisement.description}/
+    assert visible_in_page? ~r/#{advertisement.type}/i
+    assert visible_in_page? ~r/#{advertisement.property_type}/i
+    assert visible_in_page? ~r/#{advertisement.location}/
+    assert visible_in_page? ~r/#{advertisement.price}/
+    assert visible_in_page? ~r/#{advertisement.room_count}/
+    assert visible_in_page? ~r/#{advertisement.area}/
+    assert visible_in_page? ~r/#{advertisement.floor}/
+    assert visible_in_page? ~r/#{advertisement.state}/i
+    
+    {:ok, state}
+  end
+
+  then_ ~r/^I should see error message$/, fn state ->
+    assert visible_in_page? ~r/Oops, something went wrong! Please check the errors below./
+    {:ok, state}
+  end
+
+  and_ ~r/^I should see the edit page again$/, fn state ->
+    assert visible_in_page? ~r/Edit Property/
+    {:ok, state}
+  end
+
+  and_ ~r/^I am logged in as a random user who does not own the advertisement$/, fn state ->
+    setup_session(state[:random_email], state[:random_password])
+    {:ok, state}
+  end
+
+  and_ ~r/^I navigate to the property's details page$/, fn state ->
+    advertisement = List.first(state[:advertisements])
+    click({:id, "edit-#{advertisement.reference}"})
+    {:ok, state}
+  end
+
+  then_ ~r/^I should not see an edit button$/, fn state ->
+    assert not visible_in_page? ~r/Edit Property/
+    {:ok, state}
+  end
+
+  defp setup_session(email, password) do
+    navigate_to("/login")
+    fill_field({:id, "email"}, email)
+    fill_field({:id, "password"}, password)
+    click({:id, "login_button"})
+  end
+
+  # https://stackoverflow.com/a/49861811
+  defp select_dropdown(drop_down_id, option) do
+    find_element(:css, "##{drop_down_id} option[value='#{option}']") |> click()
+  end
+end
diff --git a/features/property_update.feature b/features/property_update.feature
new file mode 100644
index 0000000000000000000000000000000000000000..abbcfc6af5e89b3969b4101aa9dc5c4d550ff8a0
--- /dev/null
+++ b/features/property_update.feature
@@ -0,0 +1,48 @@
+Feature: Property Update
+
+    Scenario: Owner can update their property
+        Given there exists following accounts
+            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+        And the following properties exist
+            | title                | description                       | type  | property_type | state      | location | room_count | area  | floor | floor_count | price
+            | Really cool property | Selling this really really house  | sell  | house         | available  | London   | 3          | 100.0 | 2     | 5           | 500000
+        And I am logged in
+        And I navigate to my property's details page
+        When I click the edit button
+        And I update the following fields
+            | title                   | description                            | type | property_type | state    | location | room_count | area  | floor | price  |
+            | Really AMAZING property | Pls rent this really amazing apartment | rent | apartment     | reserved | Paris    | 4          | 120.0 | 3     | 600    |
+        And I click save changes
+        Then I should see a success message
+        And I should be redirected back to the property page
+        And I should see the updated property details
+
+    Scenario: Owner cannot update their property when entering invalid details
+        Given there exists following accounts
+            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+        And the following properties exist
+            | title                | description                       | type  | property_type | location | room_count | area  | floor | floor_count | price
+            | Really cool property | Selling this really really house  | sell  | house         | London   | 3          | 100.0 | 2     | 5           | 500000
+        And I am logged in
+        And I navigate to my property's details page
+        When I click the edit button
+        And I update the following fields
+            | title     | description | type | property_type | state     | location | room_count | area   | floor | price  |
+            | Too short | Too short   | rent | house         | available | Paris    | 4          | -120.0 | 3     | -600   |
+        And I click save changes
+        Then I should see error message
+        And I should see the edit page again
+
+    Scenario: A random user cannot update a property
+        Given there exists following accounts
+            | name     | surname | birth_date | phone_number | email                      | password | confirm_password |
+            | Existing | Account | 2000-01-01 | 000          | existing.account@gmail.com | password | password         |
+            | Random   | Account | 2000-01-01 | 000          | random.account@gmail.com   | password | password         |
+        And the following properties exist
+            | title                | description                       | type  | property_type | state      | location | room_count | area  | floor | floor_count | price
+            | Really cool property | Selling this really really house  | sell  | house         | available  | London   | 3          | 100.0 | 2     | 5           | 500000
+        And I am logged in as a random user who does not own the advertisement
+        And I navigate to the property's details page
+        Then I should not see an edit button
diff --git a/lib/proptrackr_web/controllers/properties_controller.ex b/lib/proptrackr_web/controllers/properties_controller.ex
index 8d85a9537b3d2b7b5848cd7ec1ebe349439f9ec3..92a9e415fe76e1feea06203059579f969f1d8ce9 100644
--- a/lib/proptrackr_web/controllers/properties_controller.ex
+++ b/lib/proptrackr_web/controllers/properties_controller.ex
@@ -14,6 +14,28 @@ defmodule PropTrackrWeb.PropertiesController do
     render conn, "index.html", properties: properties
   end
 
+  def show(conn, %{"reference" => reference}) do
+    property = Repo.one(
+      from p in Property,
+      where: p.reference == ^reference,
+      preload: [:user],
+      select: p
+    )
+
+    current_user = conn.assigns.current_user
+    can_edit = current_user && current_user.id == property.user_id
+
+    case property do
+      nil ->
+        conn
+        |> put_flash(:error, "Property not found.")
+        |> redirect(to: ~p"/")
+      property ->
+        render(conn, "show.html", property: property, can_edit: can_edit)
+    end
+  end
+
+
   def new(conn, _params) do
     changeset = Property.changeset(%Property{}, %{})
     render conn, "new.html", changeset: changeset
@@ -46,8 +68,52 @@ defmodule PropTrackrWeb.PropertiesController do
     end
   end
 
-  def show(conn, %{"id" => id}) do
-    # TODO: Fill this in with the appropriate code (FR-12)
-    render conn, "index.html", properties: []
+  def edit(conn, %{"reference" => reference}) do
+    property = Repo.get_by(Property, reference: reference)
+
+    case property do
+      nil ->
+        conn
+        |> put_flash(:error, "Property not found.")
+        |> redirect(to: ~p"/")
+      property ->
+        if conn.assigns.current_user && conn.assigns.current_user.id == property.user_id do
+          changeset = Property.changeset(property)
+          render(conn, "edit.html", property: property, changeset: changeset)
+        else
+          conn
+          |> put_flash(:error, "You don't have permission to edit this property.")
+          |> redirect(to: ~p"/properties/#{property.reference}")
+        end
+    end
   end
+
+  def update(conn, %{"reference" => reference, "property" => property_params}) do
+    property = Repo.get_by(Property, reference: reference)
+
+    case property do
+      nil ->
+        conn
+        |> put_flash(:error, "Property not found.")
+        |> redirect(to: ~p"/")
+
+      property ->
+        if conn.assigns.current_user && conn.assigns.current_user.id == property.user_id do
+          case Repo.update(Property.changeset(property, property_params)) do
+            {:ok, updated_property} ->
+              conn
+              |> put_flash(:info, "Property updated successfully.")
+              |> redirect(to: ~p"/properties/#{updated_property.reference}")
+
+            {:error, changeset} ->
+              render(conn, "edit.html", property: property, changeset: changeset)
+          end
+        else
+          conn
+          |> put_flash(:error, "You don't have permission to update this property.")
+          |> redirect(to: ~p"/properties/#{property.reference}")
+        end
+    end
+   end
+
 end
diff --git a/lib/proptrackr_web/controllers/properties_html/edit.html.heex b/lib/proptrackr_web/controllers/properties_html/edit.html.heex
new file mode 100644
index 0000000000000000000000000000000000000000..1970b8902b89347890617124082387669bc5ba68
--- /dev/null
+++ b/lib/proptrackr_web/controllers/properties_html/edit.html.heex
@@ -0,0 +1,80 @@
+<.header>
+  Edit Property
+  <:subtitle>Update property details</:subtitle>
+</.header>
+
+<.error :if={@changeset.action}>
+  Oops, something went wrong! Please check the errors below.
+</.error>
+
+<.simple_form
+  :let={f}
+  for={@changeset}
+  method="put"
+  action={~p"/properties/#{@property.reference}"}
+>
+  <.input field={f[:title]} id="title" type="text" label="Title" required />
+  <.input
+    field={f[:description]}
+    id="description"
+    type="textarea"
+    label="Description"
+    required
+  />
+  <.input
+    field={f[:type]}
+    id="type"
+    type="select"
+    label="Type"
+    options={[:rent, :sell]}
+    required
+  />
+  <.input
+    field={f[:property_type]}
+    id="property_type"
+    type="select"
+    label="Property Type"
+    options={[:apartment, :house, :other]}
+    required
+  />
+  <.input
+    field={f[:state]}
+    id="state"
+    type="select"
+    label="State"
+    options={[:available, :reserved, :unavailable]}
+    required
+  />
+  <.input field={f[:location]} id="location" type="text" label="Location" required />
+  <.input
+    field={f[:room_count]}
+    id="room_count"
+    type="number"
+    label="Room Count"
+    required
+  />
+  <.input
+    field={f[:area]}
+    id="area"
+    type="number"
+    step="0.01"
+    label="Area (mآ²)"
+    required
+  />
+  <.input field={f[:floor]} id="floor" type="number" label="Floor" required />
+  <.input
+    field={f[:floor_count]}
+    id="floor_count"
+    type="number"
+    label="Total Floors"
+    required
+  />
+  <.input field={f[:price]} id="price" type="number" step="0.01" label="Price" required />
+
+  <:actions>
+    <.button id="save-changes">Save Changes</.button>
+    <.link href={~p"/properties/#{@property.reference}"} class="ml-4">
+      Cancel
+    </.link>
+  </:actions>
+</.simple_form>
diff --git a/lib/proptrackr_web/controllers/properties_html/index.html.heex b/lib/proptrackr_web/controllers/properties_html/index.html.heex
index 87e1b99ffb84bed24c1491db9c09ae16a004bede..4b7bdb72c0d21a9de917b2c5c626e00681e8b075 100644
--- a/lib/proptrackr_web/controllers/properties_html/index.html.heex
+++ b/lib/proptrackr_web/controllers/properties_html/index.html.heex
@@ -29,9 +29,8 @@
       </div>
 
       <div class="flex flex-row justify-end">
-        <!-- TODO: Implement linking -->
         <.link href={~p"/properties/#{property.reference}"}>
-          <.button type="button" class="text-white rounded px-4 py-2">View more</.button>
+          <.button type="button" class="text-white rounded px-4 py-2" id={ "edit-#{property.reference}" }>View more</.button>
         </.link>
       </div>
     </div>
diff --git a/lib/proptrackr_web/controllers/properties_html/show.html.heex b/lib/proptrackr_web/controllers/properties_html/show.html.heex
new file mode 100644
index 0000000000000000000000000000000000000000..c045baddfada33d5bc0408db9dc308ae3cb08bd6
--- /dev/null
+++ b/lib/proptrackr_web/controllers/properties_html/show.html.heex
@@ -0,0 +1,84 @@
+<.flash_group flash={@flash} />
+
+<.header>
+  <%= @property.title %>
+  <:actions>
+    <%= if @can_edit do %>
+      <.link
+        href={~p"/properties/#{@property.reference}/edit"}
+        class="bg-zinc-900 hover:bg-zinc-700 text-white px-4 py-2 rounded-md mr-4"
+        id="edit-property"
+      >
+        Edit Property
+      </.link>
+    <% end %>
+    <.link href={~p"/"}>
+      Back to listings
+    </.link>
+  </:actions>
+</.header>
+
+<div class="mt-8 space-y-8">
+  <div class="bg-white shadow rounded-lg p-6">
+    <dl class="grid grid-cols-1 md:grid-cols-2 gap-4">
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Type</dt>
+        <dd class="mt-1 text-sm text-gray-900">
+          <%= String.capitalize(to_string(@property.type)) %>
+        </dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Property Type</dt>
+        <dd class="mt-1 text-sm text-gray-900">
+          <%= String.capitalize(to_string(@property.property_type)) %>
+        </dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Status</dt>
+        <dd class="mt-1 text-sm text-gray-900">
+          <%= String.capitalize(to_string(@property.state)) %>
+        </dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Location</dt>
+        <dd class="mt-1 text-sm text-gray-900"><%= @property.location %></dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Price</dt>
+        <dd class="mt-1 text-sm text-gray-900">
+          €<%= :erlang.float_to_binary(@property.price, decimals: 2) %>
+        </dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Area</dt>
+        <dd class="mt-1 text-sm text-gray-900"><%= @property.area %> mآ²</dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Rooms</dt>
+        <dd class="mt-1 text-sm text-gray-900"><%= @property.room_count %></dd>
+      </div>
+      <div>
+        <dt class="text-sm font-medium text-gray-500">Floor</dt>
+        <dd class="mt-1 text-sm text-gray-900">
+          <%= @property.floor %>/<%= @property.floor_count %>
+        </dd>
+      </div>
+    </dl>
+  </div>
+
+  <div class="bg-white shadow rounded-lg p-6">
+    <h3 class="text-lg font-medium text-gray-900">Description</h3>
+    <p class="mt-4 text-sm text-gray-600"><%= @property.description %></p>
+  </div>
+
+  <div class="bg-white shadow rounded-lg p-6">
+    <h3 class="text-lg font-medium text-gray-900">Contact Information</h3>
+    <div class="mt-4">
+      <p class="text-sm text-gray-600">
+        Listed by <%= @property.user.name %> <%= @property.user.surname %>
+      </p>
+      <p class="text-sm text-gray-600">Phone: <%= @property.user.phone_number %></p>
+      <p class="text-sm text-gray-600">Email: <%= @property.user.email %></p>
+    </div>
+  </div>
+</div>
diff --git a/lib/proptrackr_web/router.ex b/lib/proptrackr_web/router.ex
index 8ee37317db2db1949cb18f9c7c390b56f43cb9d6..059a73406dd60c6502a875fd0101a3240806d82e 100644
--- a/lib/proptrackr_web/router.ex
+++ b/lib/proptrackr_web/router.ex
@@ -34,7 +34,9 @@ defmodule PropTrackrWeb.Router do
     get "/", PropertiesController, :index
     get "/properties/new", PropertiesController, :new
     post "/properties", PropertiesController, :create
-    get "/properties/:id", PropertiesController, :show
+    get "/properties/:reference", PropertiesController, :show
+    get "/properties/:reference/edit", PropertiesController, :edit
+    put "/properties/:reference", PropertiesController, :update
   end
 
   # Other scopes may use custom stacks.
diff --git a/test/proptrackr_web/controllers/properties_controller_test.exs b/test/proptrackr_web/controllers/properties_controller_test.exs
index ba200f7c2b1802650f63825e17b99a655ffb59c8..2f1e46eb76cf5d08fb456aea12759080e6ec6ebb 100644
--- a/test/proptrackr_web/controllers/properties_controller_test.exs
+++ b/test/proptrackr_web/controllers/properties_controller_test.exs
@@ -6,7 +6,7 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
 
   @valid_data %{
     title: "Apartment",
-    description: "Small apartment",
+    description: "Small apartment with a beautiful view of the city center",
     type: "rent",
     property_type: "apartment",
     location: "Tartu, Estonia",
@@ -30,6 +30,19 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     price: -1.0,
   }
 
+  @update_data %{
+    title: "Updated Apartment",
+    description: "Newly renovated small apartment in the heart of the city with modern amenities",
+    type: "sell",
+    property_type: "apartment",
+    location: "Tallinn, Estonia",
+    room_count: 2,
+    area: 15.0,
+    floor: 3,
+    floor_count: 5,
+    price: 500.0,
+  }
+
   setup do
     user = %User{
       name: "Test",
@@ -43,7 +56,20 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     }
     user = Repo.insert!(user)
 
-    {:ok, %{user: user}}
+    other_user = %User{
+      name: "Other",
+      surname: "User",
+      birth_date: "2000-01-01",
+      phone_number: "111",
+      bio: "Hey",
+      email: "other.user@gmail.com",
+      password: "testing",
+      confirm_password: "testing",
+    }
+    other_user = Repo.insert!(other_user)
+
+    {:ok, %{user: user, other_user: other_user}}
+
   end
 
   test "Authenticated user should be able to create a new property advertisement with valid data", %{ conn: conn, user: user } do
@@ -123,6 +149,83 @@ defmodule PropTrackrWeb.PropertiesControllerTest do
     assert html_response(conn, 200) =~ Float.to_string(@valid_data[:area])
   end
 
+  #Update tests
+  test "owner can update their property with valid data", %{conn: conn, user: user} do
+    property = %Property{
+      reference: Ecto.UUID.generate(),
+      user_id: user.id
+    }
+    property = property
+    |> Property.changeset(@valid_data)
+    |> Repo.insert!()
+
+    conn = conn |> setup_session(user)
+    conn = put(conn, ~p"/properties/#{property.reference}", property: @update_data)
+
+    assert redirected_to(conn) == ~p"/properties/#{property.reference}"
+
+    conn = get(conn, ~p"/properties/#{property.reference}")
+    assert html_response(conn, 200) =~ "Property updated successfully"
+
+    updated_property = Repo.get_by!(Property, reference: property.reference)
+    assert updated_property.title == @update_data[:title]
+    assert updated_property.description == @update_data[:description]
+    assert updated_property.type == String.to_atom(@update_data[:type])
+    assert updated_property.property_type == String.to_atom(@update_data[:property_type])
+    assert updated_property.location == @update_data[:location]
+    assert updated_property.room_count == @update_data[:room_count]
+    assert updated_property.area == @update_data[:area]
+    assert updated_property.floor == @update_data[:floor]
+    assert updated_property.floor_count == @update_data[:floor_count]
+    assert updated_property.price == @update_data[:price]
+  end
+
+  test "owner cannot update property with invalid data", %{conn: conn, user: user} do
+    property = %Property{
+      reference: Ecto.UUID.generate(),
+      user_id: user.id
+    }
+    property = property
+    |> Property.changeset(@valid_data)
+    |> Repo.insert!()
+
+    conn = conn |> setup_session(user)
+    conn = put(conn, ~p"/properties/#{property.reference}", property: @invalid_data)
+
+    assert html_response(conn, 200) =~ "must be greater than 0"
+
+    unchanged_property = Repo.get_by!(Property, reference: property.reference)
+    assert unchanged_property.title == @valid_data[:title]
+  end
+
+  test "non-owner cannot update property", %{conn: conn, user: user, other_user: other_user} do
+    property = %Property{
+      reference: Ecto.UUID.generate(),
+      user_id: user.id
+    }
+    property = property
+    |> Property.changeset(@valid_data)
+    |> Repo.insert!()
+
+    conn = conn |> setup_session(other_user)
+    conn = put(conn, ~p"/properties/#{property.reference}", property: @update_data)
+
+    assert redirected_to(conn) == ~p"/properties/#{property.reference}"
+    assert get_flash(conn, :error) == "You don't have permission to update this property."
+
+    unchanged_property = Repo.get_by!(Property, reference: property.reference)
+    assert unchanged_property.title == @valid_data[:title]
+  end
+
+  test "cannot update non-existent property", %{conn: conn, user: user} do
+    conn = conn |> setup_session(user)
+    conn = put(conn, ~p"/properties/non-existent-reference", property: @update_data)
+
+    assert redirected_to(conn) == "/"
+    assert get_flash(conn, :error) == "Property not found."
+  end
+
+
   defp setup_session(conn, user) do
     conn = conn |> post("/login", email: user.email, password: user.password)
     conn = get conn, redirected_to(conn)