<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="218541" data-post-id="218541">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="PJUllrich" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/PJUllrich/120/15944_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  PJUllrich
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Building Table Views with Phoenix LiveView</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hello Maxim,</p>
<p>Could you share some of your testing code please? Maybe a assert_receive or such would help here?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218541" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-218541" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218541"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="218542" data-post-id="218542">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="PJUllrich" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/PJUllrich/120/15944_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  PJUllrich
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Building Table Views with Phoenix LiveView</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I also realised that the store actually always has the same <code>topic</code>. So, if you open multiple LiveViews, they’ll share the state <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"> I’m fixing this later today by adding the LiveView PID to the topic.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218542" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-218542" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218542"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="218543" data-post-id="218543">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Maxim-Filimonov" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Maxim-Filimonov/120/20878_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Maxim-Filimonov
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="PJUllrich" data-post="23" data-topic="23806">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/pjullrich/48/15944_2.png" class="avatar"> PJUllrich:</div>
<blockquote>
<p>Could you share some of your testing code please? Maybe a assert_receive or such would help here?</p>
</blockquote>
</aside>
<p>Yeah sure, here it’s:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  test "on submit creates files uploaded", %{conn: conn} do
      {:ok, view, _html} = live_isolated(conn, FileUploadView)
      file = upload_test_file(view)
      render_upload(file, "sample.jpeg")

      view |&gt; element("form") |&gt; render_submit()

      assert has_element?(view, "#files-display", "1 file uploaded")
    end

# In store:
 def files_uploaded(payload, socket) do
    IO.puts("FILES UPLOADED&gt;&gt;&gt;&gt;")
    files = payload.files

    created_files =
      Enum.map(files, fn %{meta: meta, entry: entry, url: url, bucket: bucket} -&gt;
        {:ok, file} = Files.create_file_from_s3_upload(meta, entry, %{url: url, bucket: bucket})
        file
      end)
      assign(socket, :files, created_files)
end
</code></pre>
<p>When all the file creation code was sync inside event handler no issues testing it. Now as it’s async I would need to wait on something to complete, so I’m not sure what to wait on. I tried assert_receive but it’s still too early. It needs to wait until handler actually finishes processing of files and creates all of them</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218543" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-218543" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218543"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="218546" data-post-id="218546">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="PJUllrich" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/PJUllrich/120/15944_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  PJUllrich
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Building Table Views with Phoenix LiveView</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Hmm, testing events is always a bit tricky in my experience. This is why I usually write myself a <code>ConcurrencyHelper</code> which is a sugarcoated <code>:timer.sleep</code>, but <em>a bit</em> more sophisticated. Here’s my code:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Support.ConcurrencyHelper do
  def wait_until(fun), do: wait_until(500, fun)

  def wait_until(0, fun), do: fun.()

  def wait_until(timeout, fun) do
    try do
      fun.()
    rescue
      ExUnit.AssertionError -&gt;
        :timer.sleep(100)
        wait_until(max(0, timeout - 100), fun)
    end
  end
end
</code></pre>
<p>The problem you’re describing is not necessarily caused by <code>live_ex</code>, since any event handling could cause these timing issues. My recommendation is to wrap your assertion in a <code>wait_until</code> like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">wait_until(fn -&gt;
  assert has_element?(view, "#files-display", "1 file uploaded")
end)
</code></pre>
<p><code>has_element?/3</code> actually re-renders the view every time it is called, so you can use it to re-render the view every 100ms and check whether the upload was successful.</p>
<p>As a side-note: Do you mock the <code>Files.create_file_from_s3_upload/3</code> function somehow? If it pulls the file from S3 and creates a local file, that would slow down your tests unneccessarily. You could mock the S3 call to expect a certain URL and return a random file. Also the file creation <em>could</em> lead to problems where e.g. in one test you create the file and expect it to exist and in another test you delete the file. If these tests run in parallel, you might have timing issues there as well. So, maybe consider simply returning <code>:ok</code> from the file creation if the content of a file fetched from the S3 mock equals an expected content. Just as a side-note though <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218546" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-218546" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218546"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="218548" data-post-id="218548">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Maxim-Filimonov" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Maxim-Filimonov/120/20878_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Maxim-Filimonov
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>Do you mock the <code>Files.create_file_from_s3_upload/3</code> function somehow? If it pulls the file from S3 and creates a local file,</p>
</blockquote>
<p>It might be the confusing name. We are just creating instances of File in our database not downloading anything from S3. So it’s quite predictable func.</p>
<p>I was reading through your original article and noticed that you suggest doing all the side effects in handle_info:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">
  def handle_info(%{type: "add"} = action, socket) do
    # Perform any operation with the payload here. For example:
    new_state = socket.assigns.a + action.payload

    commit("set_a", new_state, socket)
  end

  # Mutations

  def set_a(payload, socket) do
    assign(socket, :a, payload)
  end
</code></pre>
<p>I did side effects at the mutation stage, could this be the source of the issue?<br>
I did also noticed that for some reason my inner components are not detecting the change performed by the store mutation. <img src="https://forum.elixirforum.com/images/emoji/apple/expressionless.png?v=15" title=":expressionless:" class="emoji" alt=":expressionless:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218548" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-218548" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218548"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="218551" data-post-id="218551">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="PJUllrich" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/PJUllrich/120/15944_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  PJUllrich
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Building Table Views with Phoenix LiveView</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>I did side effects at the mutation stage, could this be the source of the issue?</p>
</blockquote>
<p>I’m sorry, I got that wrong back in the day. The state should only be changed in the <code>Mutation</code> and not the <code>Action</code>-Handler (which is the <code>handle_info</code>-function). Please try again according to the <a href="https://github.com/PJUllrich/live_ex#initialize-the-store" rel="noopener nofollow ugc">updated Readme</a>. However, I’m not sure whether this will fix your problem with the detection of the updated store.</p>
<p>In order for the inner components to detect a state change, they need to get the state passed into them by the parent LiveView. So, if your store looks like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyStore do
  use LiveEx

  @initial_store %{
    content: nil
  }

  def init(socket), do: init(@initial_store, socket)

  def handle_info(%{type: "set_content"} = action, socket) do
    commit("set_content", action.payload, socket)
  end

  def set_content(payload, socket) do
    assign(socket, :content, payload)
  end
end
</code></pre>
<p>You will need to pass the <code>content</code> to the <code>live_component</code> like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># In your LiveView .leex template
&lt;%= live_component, MyLiveComponent, content: @content %&gt;
</code></pre>
<p>Also, if you overwrote the <code>update(assigns, socket)</code> function in your <code>MyLiveComponent</code>, make sure that you’re actually setting the <code>content</code> assign. Like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyLiveComponent do
  use Phoenix.LiveComponent

  def render(assigns) do
    ~L"""
    &lt;div&gt;&lt;%= @content %&gt;&lt;/div&gt; 
    """
  end

  def update(assigns, socket) do
    {:ok, assign(socket, :content, assigns.content)}
  end
end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218551" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-218551" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218551"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="218556" data-post-id="218556">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Maxim-Filimonov" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Maxim-Filimonov/120/20878_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Maxim-Filimonov
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="PJUllrich" data-post="28" data-topic="23806">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/pjullrich/48/15944_2.png" class="avatar"> PJUllrich:</div>
<blockquote>
<p>In order for the inner components to detect a state change, they need to get the state passed into them by the parent LiveView.</p>
</blockquote>
</aside>
<p>Yeah, I actually figured this one out. Somehow I thought it would magically appear there as I was modifying socket. LOL</p>
<aside class="quote no-group" data-username="PJUllrich" data-post="28" data-topic="23806">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/pjullrich/48/15944_2.png" class="avatar"> PJUllrich:</div>
<blockquote>
<p>The state should only be changed in the <code>Mutation</code> and not the <code>Action</code>-Handler (which is the <code>handle_info</code>-function).</p>
</blockquote>
</aside>
<p>So i’m a bit confused - do all side effects and db changes go to mutation then ? What’s the purpose of action then ?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218556" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-218556" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218556"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="227128" data-post-id="227128">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="hudsonbay" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  hudsonbay
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Also, an Agent could be a solution instead of a GenServer, right?</p>
<p>Edit: Sorry, someone already said that before</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="227128" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/state-management-with-phoenix-liveview/23806/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-227128" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="227128"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>