<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Silver343</title>
    <description>The latest articles on Forem by Silver343 (@silver343).</description>
    <link>https://forem.com/silver343</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1112516%2Fee283051-e1ec-48d2-80e6-32e4bbe4d7c2.png</url>
      <title>Forem: Silver343</title>
      <link>https://forem.com/silver343</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/silver343"/>
    <language>en</language>
    <item>
      <title>Chrip Beyond (Bootcamp) part 5 Pagination</title>
      <dc:creator>Silver343</dc:creator>
      <pubDate>Tue, 30 Jan 2024 12:09:24 +0000</pubDate>
      <link>https://forem.com/silver343/chrip-beyond-bootcamp-part-5-pagination-23a7</link>
      <guid>https://forem.com/silver343/chrip-beyond-bootcamp-part-5-pagination-23a7</guid>
      <description>&lt;p&gt;As you have built chirper you may have built up a large amount of chirps, as this number grows chirp index page will start taking longer to load.&lt;/p&gt;

&lt;p&gt;We can demonstrait this using &lt;a href="https://laravel.com/docs/10.x/seeding"&gt;seeders.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeders
&lt;/h2&gt;

&lt;p&gt;Seeders allow us to create large amounts of data. In a larger application, you may have a different seeder class for each of the models, but to keep things simple, we will update the included DatabaseSeeder.&lt;/p&gt;

&lt;p&gt;In the DatabaseSeeder we can use our model factories to create the data. We want a user with chirps, followers, and users to follow all with their own chirps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Database\Seeders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// use Illuminate\Database\Console\Seeds\WithoutModelEvents;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Chirp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Seeder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseSeeder&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Seeder&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="s1"&gt;'follows'&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="s1"&gt;'followers'&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createQuietly&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test@test.com'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are defining our users email address manually so we can easily login. To run the seeder you can use the command &lt;code&gt;php artisan db:seed&lt;/code&gt; or you can run it when refreshing your database by using the command &lt;code&gt;php artisan migrate:fresh --seed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you run one of these commands, and visit the chirp index page, you should find your application start to slow down as it loads the chirps into memory as the page is requested.&lt;/p&gt;

&lt;p&gt;Our solution to this problem will be pagination. Pagination allows us to separate the data into different pages.&lt;/p&gt;

&lt;p&gt;Laravel provides several methods of &lt;a href="https://laravel.com/docs/10.x/pagination#main-content"&gt;pagination.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we only need the url for the next page and previous page we can use the simple pagination.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new Pagination component
&lt;/h2&gt;

&lt;p&gt;Create a new file in the resources/js/Components called Pagination.vue that will contain links to the next and previous pages.&lt;/p&gt;

&lt;p&gt;The component will accept two props, the URL for the next page of results and the URL for the previous page of results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nextUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prevUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"prevUrl || nextUrl"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex place-content-around bg-white px-4 py-3 sm:px-6 mt-6 rounded-lg"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Pagination"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;        &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"prevUrl"&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"prevUrl"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Previous&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"nextUrl"&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"nextUrl"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The design of this component is based on one from &lt;a href="https://tailwindui.com/components/application-ui/navigation/pagination#component-0797a02a34692167c369d134e7a6f9c5"&gt;Tailwind UI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Controllers
&lt;/h2&gt;

&lt;p&gt;Laravel makes using pagination simple by providing eloquent methods.&lt;/p&gt;

&lt;p&gt;To use pagination within the Chirp index page, we need to update the ChirpControllers index method. Replace the get() method with the SimplePagination() method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; /**
 * Display a listing of the resource.
 */
 public function index(Request $request): Response
 {
     return Inertia::render('Chirps/Index', [
         'chirps' =&amp;gt; Chirp::with('user:id,name')
            -&amp;gt;when($request-&amp;gt;input('filter') === 'true', fn($q) =&amp;gt;
             $q-&amp;gt;whereIn(
                 'user_id',
                 Auth()-&amp;gt;user()-&amp;gt;follows-&amp;gt;pluck('id')
                 -&amp;gt;merge(Auth()-&amp;gt;id())
             )
         )
         -&amp;gt;latest()
&lt;span class="gd"&gt;-         -&amp;gt;get(),
&lt;/span&gt;&lt;span class="gi"&gt;+         -&amp;gt;simplePaginate(25)
&lt;/span&gt;        ]);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now using pagination, but if you return to the Chirp Index page, it will no longer work.&lt;/p&gt;

&lt;p&gt;When using pagination, not only is the collection of models returned but other information too, for example, the next page URL. The collection of models is wrapped around a data property, so we need to update our Chirps/Index.vue page to use this new data property. We can also use the pagination component we created earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import Chirp from '@/Components/Chirp.vue';
 import InputError from '@/Components/InputError.vue';
 import PrimaryButton from '@/Components/PrimaryButton.vue';
 import Tabs from '@/Components/Tabs.vue';
 import { useForm, Head } from '@inertiajs/vue3';
&lt;span class="gi"&gt;+ import Pagination from '@/Components/Pagination.vue';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;defineProps(['chirps']);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const tabs = [
&lt;/span&gt;    {href:route('chirps.index', { filter: 'false'}), active:route().current('chirps.index', { filter: 'false'}), only:['chirps'], text:'All'},
    {href:route('chirps.index', { filter: 'true'}), active:route().current('chirps.index', { filter: 'true'}), only:['chirps'],  text:'Following'},
]
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const form = useForm({
&lt;/span&gt;    message: '',
});
&amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;&amp;lt;template&amp;gt;
    &amp;lt;Head title="Chirps" /&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;    &amp;lt;AuthenticatedLayout&amp;gt;
        &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
            &amp;lt;form @submit.prevent="form.post(route('chirps.store'), { onSuccess: () =&amp;gt; form.reset() })"&amp;gt;
                &amp;lt;textarea
                    v-model="form.message"
                    placeholder="What's on your mind?"
                    class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
                &amp;gt;&amp;lt;/textarea&amp;gt;
                &amp;lt;InputError :message="form.errors.message" class="mt-2" /&amp;gt;
                &amp;lt;PrimaryButton class="mt-4"&amp;gt;Chirp&amp;lt;/PrimaryButton&amp;gt;
            &amp;lt;/form&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;            &amp;lt;Tabs :tabs="tabs"/&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;            &amp;lt;div class="mt-6 bg-white shadow-sm rounded-lg divide-y"&amp;gt;
                &amp;lt;Chirp
&lt;span class="gd"&gt;-                    v-for="chirp in chirps"
&lt;/span&gt;&lt;span class="gi"&gt;+                    v-for="chirp in chirps.data"
&lt;/span&gt;                    :key="chirp.id"
                    :chirp="chirp"
                /&amp;gt;
            &amp;lt;/div&amp;gt;
&lt;span class="gi"&gt;+            &amp;lt;Pagination :nextUrl="chirps.next_page_url" :prevUrl="chirps.prev_page_url"/&amp;gt;
&lt;/span&gt;        &amp;lt;/div&amp;gt;
    &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have more than 15 chirps in your app you should now see a next button at the bottom of the page, after clicking it you will see &lt;code&gt;?page=2&lt;/code&gt; at the end of the URL and a new list of chirps.&lt;/p&gt;

&lt;p&gt;There are a couple of improvements we can make to our pagination experience. As you navigate between the pages of chirps, you will notice that the filter query parameter is not carried from the first page. It can be included in the pagination links by adding &lt;code&gt;-&amp;gt;withQueryString()&lt;/code&gt; after the &lt;code&gt;simplePagination()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;If you visit the second page of chirps and then update or delete a Chirp, you will be redirected to the first page of results with no filter query string. To resolve this update the &lt;code&gt;update()&lt;/code&gt; and &lt;code&gt;destroy()&lt;/code&gt; methods of the chirpController to not return to a specific route but to return to the request route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;     /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Chirp $chirp): RedirectResponse
    {
        $this-&amp;gt;authorize('update', $chirp);
&lt;span class="err"&gt;
&lt;/span&gt;        $validated = $request-&amp;gt;validate([
            'message' =&amp;gt; 'required|string|max:255'
        ]);
&lt;span class="err"&gt;
&lt;/span&gt;         $chirp-&amp;gt;update($validated);
&lt;span class="gd"&gt;-        return redirect(route('chirps.index'));
&lt;/span&gt;&lt;span class="gi"&gt;+        return back();
&lt;/span&gt;    }
&lt;span class="err"&gt;
&lt;/span&gt;    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Chirp $chirp): RedirectResponse
    {
         $this-&amp;gt;authorize('delete', $chirp);
&lt;span class="err"&gt;
&lt;/span&gt;         $chirp-&amp;gt;delete();
&lt;span class="gd"&gt;-        return redirect(route('chirps.index'));
&lt;/span&gt;&lt;span class="gi"&gt;+        return back();
&lt;/span&gt;    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try again, you will stay on the same page, but you will be at the top of the page. Use the preserveScroll property of the inertia form help and link component inside the Chirp component to stop this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="p"&gt;import Dropdown from '@/Components/Dropdown.vue';
import DropdownLink from '@/Components/DropdownLink.vue';
import InputError from '@/Components/InputError.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import { Link, useForm } from '@inertiajs/vue3';
import { ref } from 'vue';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;dayjs.extend(relativeTime);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const props = defineProps(['chirp']);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const form = useForm({
&lt;/span&gt;    message: props.chirp.message,
});
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;const editing = ref(false);
&lt;/span&gt;&amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;&amp;lt;template&amp;gt;
    &amp;lt;div class="p-6 flex space-x-2"&amp;gt;
        &amp;lt;svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"&amp;gt;
            &amp;lt;path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" /&amp;gt;
        &amp;lt;/svg&amp;gt;
        &amp;lt;div class="flex-1"&amp;gt;
            &amp;lt;div class="flex justify-between items-center"&amp;gt;
                &amp;lt;div&amp;gt;
                    &amp;lt;Link :href="route('profile.show', chirp.user.id)" class="text-gray-800 hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-900 capitalize"&amp;gt;{{ chirp.user.name }}&amp;lt;/Link&amp;gt;
                    &amp;lt;small class="ml-2 text-sm text-gray-600"&amp;gt;{{ dayjs(chirp.created_at).fromNow() }}&amp;lt;/small&amp;gt;
                    &amp;lt;small v-if="chirp.created_at !== chirp.updated_at" class="text-sm text-gray-600"&amp;gt; &amp;amp;middot; edited&amp;lt;/small&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;Dropdown v-if="chirp.user.id === $page.props.auth.user.id"&amp;gt;
                   &amp;lt;template #trigger&amp;gt;
                        &amp;lt;button&amp;gt;
                           &amp;lt;svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor"&amp;gt;
                               &amp;lt;path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" /&amp;gt;
                           &amp;lt;/svg&amp;gt;
                       &amp;lt;/button&amp;gt;
                   &amp;lt;/template&amp;gt;
                   &amp;lt;template #content&amp;gt;
                        &amp;lt;button class="block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:bg-gray-100 transition duration-150 ease-in-out" @click="editing = true"&amp;gt;
                            Edit
                        &amp;lt;/button&amp;gt;
&lt;span class="gd"&gt;-                        &amp;lt;DropdownLink as="button" :href="route('chirps.destroy', chirp.id)" method="delete"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+                        &amp;lt;DropdownLink as="button" :href="route('chirps.destroy', chirp.id)" method="delete" :only="['chirps', 'errors']" preserveScroll&amp;gt;
&lt;/span&gt;                            Delete
                        &amp;lt;/DropdownLink&amp;gt;
                    &amp;lt;/template&amp;gt;
                &amp;lt;/Dropdown&amp;gt;
            &amp;lt;/div&amp;gt;
&lt;span class="gd"&gt;-            &amp;lt;form v-if="editing" @submit.prevent="form.put(route('chirps.update', chirp.id), { onSuccess: () =&amp;gt; editing = false })"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+            &amp;lt;form v-if="editing" @submit.prevent="form.put(route('chirps.update', chirp.id), { onSuccess: () =&amp;gt; editing = false, only:['chirps', 'errors'], preserveScroll:true})"&amp;gt;
&lt;/span&gt;                &amp;lt;textarea v-model="form.message" class="mt-4 w-full text-gray-900 border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"&amp;gt;&amp;lt;/textarea&amp;gt;
                &amp;lt;InputError :message="form.errors.message" class="mt-2" /&amp;gt;
                &amp;lt;div class="space-x-2"&amp;gt;
                    &amp;lt;PrimaryButton class="mt-4"&amp;gt;Save&amp;lt;/PrimaryButton&amp;gt;
                    &amp;lt;button class="mt-4" @click="editing = false; form.reset(); form.clearErrors()"&amp;gt;Cancel&amp;lt;/button&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/form&amp;gt;
            &amp;lt;p v-else class="mt-4 text-lg text-gray-900"&amp;gt;{{ chirp.message }}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Profile Controller
&lt;/h2&gt;

&lt;p&gt;To use pagination within the &lt;code&gt;show()&lt;/code&gt; method of our profileController, we must separate retrieving the Chirps and setting their user relationship, we can use a temporary variable to accomplish this.&lt;/p&gt;

&lt;p&gt;we can then use the new &lt;code&gt;$chirps&lt;/code&gt; variable in the &lt;code&gt;Inertia::render()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function show(User $user): Response
 {
&lt;span class="gi"&gt;+        $chirps =  $user-&amp;gt;chirps()-&amp;gt;latest()-&amp;gt;simplePaginate(25);
+        $chirps-&amp;gt;map(fn (Chirp $chirp) =&amp;gt; $chirp-&amp;gt;setRelation('user',$user));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;        return Inertia::render('Profile/Show',[
            'user' =&amp;gt; fn() =&amp;gt; $user-&amp;gt;loadCount(['followers', 'follows'])-&amp;gt;only(['id', 'name', 'created_at', 'followers_count', 'follows_count']),
&lt;span class="gd"&gt;-            'chirps' =&amp;gt; $user-&amp;gt;chirps()-&amp;gt;latest()-&amp;gt;get()-&amp;gt;map(fn (Chirp $chirp) =&amp;gt; $chirp-&amp;gt;setRelation('user',$user)),
&lt;/span&gt;&lt;span class="gi"&gt;+            'chirps' =&amp;gt; $chirps,
&lt;/span&gt;            'following' =&amp;gt; fn () =&amp;gt; Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;where('user_id', $user-&amp;gt;id)-&amp;gt;exists(),
        ]);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the Profile/Show.vue page to use the now paginated Chirps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import Heading from '@/Components/Heading.vue';
 import Chirp from '@/Components/Chirp.vue';
&lt;span class="gi"&gt;+import Pagination from '@/Components/Pagination.vue';
&lt;/span&gt; import { Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; defineProps(['user','chirps', 'following']);
 &amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;template&amp;gt;
     &amp;lt;Head :title="user.name" /&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;AuthenticatedLayout&amp;gt;
         &amp;lt;Heading :user="user" :following="following"/&amp;gt;
         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
             &amp;lt;div class="mt-6 bg-white shadow-sm rounded-lg divide-y"&amp;gt;
                 &amp;lt;Chirp
&lt;span class="gd"&gt;-                    v-for="chirp in chirps"
&lt;/span&gt;&lt;span class="gi"&gt;+                    v-for="chirp in chirps.data"
&lt;/span&gt;                     :key="chirp.id"
                     :chirp="chirp"
                 /&amp;gt;
             &amp;lt;/div&amp;gt;
&lt;span class="gi"&gt;+            &amp;lt;Pagination :nextUrl="chirps.next_page_url" :prevUrl="chirps.prev_page_url"/&amp;gt;
&lt;/span&gt;         &amp;lt;/div&amp;gt;
     &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Follow Controller and ListFollowers
&lt;/h2&gt;

&lt;p&gt;We did need to separate the fetching of the data and hiding the pivot data in the followController and ListFollowersController &lt;code&gt;index&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;followController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function index(User $user): Response
 {
        $following = $user
                -&amp;gt;follows()
                -&amp;gt;orderByPivot('created_at','desc')
                -&amp;gt;select('user_id as id', 'name')
                -&amp;gt;addSelect(['following' =&amp;gt; function ($query) {
                $query-&amp;gt;select('id as following')
                    -&amp;gt;from('follower_user')
                    -&amp;gt;whereColumn('follower_id', Auth()-&amp;gt;id())
                    -&amp;gt;whereColumn('user_id', 'users.id');
                }])
&lt;span class="gd"&gt;-                -&amp;gt;get()-&amp;gt;makeHidden('pivot');
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;simplePaginate(25, []);
+        $following-&amp;gt;map(fn ($user) =&amp;gt; $user-&amp;gt;makeHidden('pivot'));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;        return Inertia::render('Follow/Index', [
            'user' =&amp;gt; $user-&amp;gt;only(['id', 'name']),
            'users' =&amp;gt; fn() =&amp;gt; $following,
        ]);
&lt;span class="err"&gt;
&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;listFollowersController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;namespace App\Http\Controllers;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;use App\Models\User;
use Inertia\Response;
use Inertia\Inertia;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class ListFollowers extends Controller
&lt;/span&gt;{
    /**
     * Handle the incoming request.
     */
    public function __invoke(User $user): Response
    {
        $followers = $user
            -&amp;gt;followers()
            -&amp;gt;orderByPivot('created_at','desc')
            -&amp;gt;select('follower_id as id', 'name')
            -&amp;gt;addSelect(['following' =&amp;gt; function ($query) {
                $query-&amp;gt;select('id as following')
                    -&amp;gt;from('follower_user')
                    -&amp;gt;whereColumn('follower_id', Auth()-&amp;gt;id())
                    -&amp;gt;whereColumn('user_id', 'users.id');
            }])
&lt;span class="gd"&gt;-            -&amp;gt;get()-&amp;gt;makeHidden('pivot');
&lt;/span&gt;&lt;span class="gi"&gt;+            -&amp;gt;simplePaginate(25, []);
+            $followers-&amp;gt;map(fn ($user) =&amp;gt; $user-&amp;gt;makeHidden('pivot'));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;        return Inertia::render('Follow/Index', [
            'user' =&amp;gt; $user-&amp;gt;only(['id', 'name']),
            'users' =&amp;gt; fn() =&amp;gt; $followers,
        ]);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the Follow/index.vue page to use the now paginated data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="gi"&gt;+import Pagination from '@/Components/Pagination.vue';
&lt;/span&gt; import Tabs from '@/Components/Tabs.vue';
 import UserCard from '@/Components/UserCard.vue';
 import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import { Link, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; const props = defineProps(['user', 'users']);
&lt;span class="err"&gt;
&lt;/span&gt; const tabs = [
     {href:route('followers', props.user.id), active:route().current('followers', props.user.id), text:'Followers'},
     {href:route('follow.index', props.user.id), active:route().current('follow.index', props.user.id), text:'Following'},
 ]
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
      &amp;lt;Head&amp;gt;
         &amp;lt;title v-if="route().current('followers')"&amp;gt;{{ user.name }} Followers&amp;lt;/title&amp;gt;
         &amp;lt;title v-else&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
      &amp;lt;/Head&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;         &amp;lt;h1 class="bg-white p-6 lg:p-8"&amp;gt;
             &amp;lt;Link :href="route('profile.show',user.id)" class="text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&amp;gt;{{ user.name }} &amp;lt;/Link&amp;gt;
         &amp;lt;/h1&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
             &amp;lt;Tabs :tabs="tabs"/&amp;gt;
             &amp;lt;div class="divide-y bg-white mt-6 rounded-lg"&amp;gt;
                 &amp;lt;UserCard
&lt;span class="gd"&gt;-                    v-for="user in users"
&lt;/span&gt;&lt;span class="gi"&gt;+                    v-for="user in users.data"
&lt;/span&gt;                     :user="user"
                 /&amp;gt;
             &amp;lt;/div&amp;gt;
&lt;span class="gi"&gt;+            &amp;lt;Pagination :nextUrl="users.next_page_url" :prevUrl="users.prev_page_url"/&amp;gt;
&lt;/span&gt;         &amp;lt;/div&amp;gt;
     &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;if you run the test command &lt;code&gt;php artisan test&lt;/code&gt; Several tests fail, these tests need updating to take into account the model data is inside the pagination object.&lt;/p&gt;

&lt;h3&gt;
  
  
  ChirpControllerTest
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    public function test_index_has_chirps()
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $chirp = Chirp::factory(1)-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user);
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;get(route('chirps.index'))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Chirps/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('chirps', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('message', $chirp-&amp;gt;first()-&amp;gt;message)
-                    -&amp;gt;etc()
-                    -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
-                        -&amp;gt;where('id', $chirp-&amp;gt;first()-&amp;gt;user_id)
-                        -&amp;gt;where('name', $chirp-&amp;gt;first()-&amp;gt;user-&amp;gt;name)
-                        -&amp;gt;missing('password')
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('chirps', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('message', $chirp-&amp;gt;first()-&amp;gt;message)
+                        -&amp;gt;etc()
+                        -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
+                            -&amp;gt;where('id', $chirp-&amp;gt;first()-&amp;gt;user_id)
+                            -&amp;gt;where('name', $chirp-&amp;gt;first()-&amp;gt;user-&amp;gt;name)
+                            -&amp;gt;missing('password')
+                        )
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
&lt;/span&gt;                )
            );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_only_chirps_by_people_the_user_follows_are_returned_if_filter_is_true()
    {
        $following = User::factory()
            -&amp;gt;has(Chirp::factory())
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $user = User::factory()
            -&amp;gt;hasAttached($following,[],'follows')
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $nonFollowedChirps = Chirp::factory(10)-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('chirps.index', ['filter' =&amp;gt; 'true']))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Chirps/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('chirps', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('message', $following-&amp;gt;chirps-&amp;gt;first()-&amp;gt;message)
-                    -&amp;gt;etc()
-                    -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
-                        -&amp;gt;where('id', $following-&amp;gt;id)
-                        -&amp;gt;where('name', $following-&amp;gt;name)
-                        -&amp;gt;missing('password')
-                        -&amp;gt;missing('email')
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('chirps', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('message', $following-&amp;gt;chirps-&amp;gt;first()-&amp;gt;message)
+                        -&amp;gt;etc()
+                        -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
+                            -&amp;gt;where('id', $following-&amp;gt;id)
+                            -&amp;gt;where('name', $following-&amp;gt;name)
+                            -&amp;gt;missing('password')
+                            -&amp;gt;missing('email')
+                        )
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
&lt;/span&gt;                )
        );
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to update the &lt;code&gt;test_chirp_can_be_updated&lt;/code&gt; test and the &lt;code&gt;test_chirp_can_be_deleted&lt;/code&gt; test as we are now using the &lt;code&gt;back(&lt;/code&gt;) method to redirect the user, this can be fixed by visiting the Chirp Index page in the test before making the update or delete action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function test_chirp_can_be_updated()
 {
     $chirp = Chirp::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;     $this-&amp;gt;actingAs($chirp-&amp;gt;user);
&lt;span class="gi"&gt;+    $this-&amp;gt;get(route('chirps.index'));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;     $response = $this-&amp;gt;patch(route('chirps.update', $chirp),['message' =&amp;gt; 'test new message']);
&lt;span class="err"&gt;
&lt;/span&gt;     $this-&amp;gt;assertDatabaseHas('chirps', [
         'message' =&amp;gt; 'test new message',
     ]);
&lt;span class="err"&gt;
&lt;/span&gt;     $response-&amp;gt;assertRedirect(route('chirps.index'));
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function test_chirp_can_be_deleted()
 {
     $chirp = Chirp::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;     $this-&amp;gt;assertDatabaseCount('Chirps',1);
&lt;span class="err"&gt;
&lt;/span&gt;     $this-&amp;gt;actingAs($chirp-&amp;gt;user);
&lt;span class="gi"&gt;+    $this-&amp;gt;get(route('chirps.index'));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;     $response = $this-&amp;gt;delete(route('chirps.destroy',$chirp));
&lt;span class="err"&gt;
&lt;/span&gt;     $response-&amp;gt;assertRedirect(route('chirps.index'));
&lt;span class="err"&gt;
&lt;/span&gt;     $this-&amp;gt;assertDatabaseEmpty('chirps');
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ProfileTest
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function test_chirps_belonging_to_profile_owner_are_included(): void
&lt;/span&gt;    {
        $user = User::factory()
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $profileUser = User::factory()
                    -&amp;gt;has(User::factory()-&amp;gt;count(2),'followers')
                    -&amp;gt;has(User::factory()-&amp;gt;count(3),'follows')
                    -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('profile.show',$profileUser-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Profile/Show')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $profileUser-&amp;gt;id)
                    -&amp;gt;where('name', $profileUser-&amp;gt;name)
                    -&amp;gt;where('followers_count', $profileUser-&amp;gt;followers()-&amp;gt;count())
                    -&amp;gt;where('follows_count', $profileUser-&amp;gt;follows()-&amp;gt;count())
                    -&amp;gt;missing('email')
                    -&amp;gt;missing('password')
                    -&amp;gt;etc()
                )
&lt;span class="gd"&gt;-                -&amp;gt;has('chirps', 5, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('message', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;message)
-                    -&amp;gt;etc()
-                    -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
-                        -&amp;gt;where('id', $profileUser-&amp;gt;id)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('chirps', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 5, fn(Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('message', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;message)
&lt;/span&gt;                        -&amp;gt;etc()
&lt;span class="gi"&gt;+                        -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
+                            -&amp;gt;where('id', $profileUser-&amp;gt;id)
+                            -&amp;gt;etc()
+                        )
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
&lt;/span&gt;                )
                -&amp;gt;has('following')
        );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_chirps_belonging_to_other_uses_are_not_included(): void
    {
        $user = User::factory()
                -&amp;gt;has(User::factory()-&amp;gt;count(2),'followers')
                -&amp;gt;has(User::factory()-&amp;gt;count(3),'follows')
                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()
                    -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('profile.show',$user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Profile/Show')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $user-&amp;gt;id)
                    -&amp;gt;where('name', $user-&amp;gt;name)
                    -&amp;gt;where('followers_count', $user-&amp;gt;followers()-&amp;gt;count())
                    -&amp;gt;where('follows_count', $user-&amp;gt;follows()-&amp;gt;count())
                    -&amp;gt;missing('email')
                    -&amp;gt;missing('password')
                    -&amp;gt;etc()
                )
&lt;span class="gd"&gt;-                -&amp;gt;has('chirps',0)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('chirps.data',0)
&lt;/span&gt;                 -&amp;gt;has('following')
            );
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  FollowControllerTest
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function test_users_can_see_who_each_other_are_following()
    {
        $user = User::factory()
            -&amp;gt;has(User::factory(3),'follows')
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($otherUser)
            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $user-&amp;gt;id)
                    -&amp;gt;where('name', $user-&amp;gt;name)
                    -&amp;gt;missing('password')
                    -&amp;gt;missing('email')
                )
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 3, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
-                    -&amp;gt;where('following', null)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 3, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                        -&amp;gt;where('following', null)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_follow_property_depends_on_auth_user()
    {
        $following = User::factory();
&lt;span class="err"&gt;
&lt;/span&gt;        $user = User::factory()
            -&amp;gt;has($following,'follows')
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($otherUser)
            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
-                    -&amp;gt;where('following', null)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                        -&amp;gt;where('following', null)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
-                    -&amp;gt;whereNot('following', null)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                        -&amp;gt;whereNot('following', null)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
&lt;span class="err"&gt;
&lt;/span&gt;    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ListFollowersTest&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function test_users_can_see_who_is_following_a_particular_user()
&lt;/span&gt;    {
        $user = User::factory()
            -&amp;gt;has(User::factory(3),'followers')
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($otherUser)
            -&amp;gt;get(route('followers', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $user-&amp;gt;id)
                    -&amp;gt;where('name', $user-&amp;gt;name)
                    -&amp;gt;missing('password')
                    -&amp;gt;missing('email')
                )
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 3, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('name', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;name)
-                    -&amp;gt;where('following', null)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 3, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('name', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;name)
+                        -&amp;gt;where('following', null)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_follow_property_depends_on_auth_user()
    {
        $follower = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $user-&amp;gt;follows()-&amp;gt;attach($follower);
        $user-&amp;gt;followers()-&amp;gt;attach($follower);
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($otherUser)
            -&amp;gt;get(route('followers', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;id)
-                    -&amp;gt;where('name', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;name)
-                    -&amp;gt;where('following', NULL)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;id)
+                        -&amp;gt;where('name', $user-&amp;gt;followers()-&amp;gt;first()-&amp;gt;name)
+                        -&amp;gt;where('following', NULL)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('followers', $user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Follow/Index')
&lt;span class="gd"&gt;-                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
-                    -&amp;gt;where('id', $follower-&amp;gt;id)
-                    -&amp;gt;where('name', $follower-&amp;gt;name)
-                    -&amp;gt;whereNot('following', null)
&lt;/span&gt;&lt;span class="gi"&gt;+                -&amp;gt;has('users', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;has('data', 1, fn (Assert $page) =&amp;gt; $page
+                        -&amp;gt;where('id', $follower-&amp;gt;id)
+                        -&amp;gt;where('name', $follower-&amp;gt;name)
+                        -&amp;gt;whereNot('following', null)
&lt;/span&gt;                    )
&lt;span class="gi"&gt;+                    -&amp;gt;has('next_page_url')
+                    -&amp;gt;has('prev_page_url')
+                    -&amp;gt;etc()
+                )
&lt;/span&gt;            );
&lt;span class="err"&gt;
&lt;/span&gt;    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>php</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Chirp Beyond (Bootcamp) part 4 Who's Following Who</title>
      <dc:creator>Silver343</dc:creator>
      <pubDate>Wed, 27 Dec 2023 17:15:21 +0000</pubDate>
      <link>https://forem.com/silver343/chirp-beyond-bootcamp-part-4-whos-following-who-d2l</link>
      <guid>https://forem.com/silver343/chirp-beyond-bootcamp-part-4-whos-following-who-d2l</guid>
      <description>&lt;p&gt;Previously we added the ability for users to follow each other, but there is no way for users to see who is following them and who they are following.&lt;/p&gt;

&lt;p&gt;We can solve this with a couple of new pages where we list the followers or users who are user are following.&lt;/p&gt;

&lt;p&gt;Before we add the new pages, there is an issue we overlooked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notifying users who aren’t verified
&lt;/h2&gt;

&lt;p&gt;We set up the app so that users must verify their email addresses before they can follow each other, but the user they are following may have yet to verify their email address; this is an issue as we may now be sending email notifications to an unverified email.&lt;/p&gt;

&lt;p&gt;We can solve this by checking if the user's email address is verified before notifying them in our SendNewFollowerNotifications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&amp;lt;?php
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;namespace App\Listeners;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;use App\Events\UserFollowed;
use App\Notifications\NewFollower;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class SendNewFollowerNotifications implements ShouldQueue
&lt;/span&gt;{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }
&lt;span class="err"&gt;
&lt;/span&gt;    /**
     * Handle the event.
     */
    public function handle(UserFollowed $event): void
    {
&lt;span class="gi"&gt;+        if(! $event-&amp;gt;user-&amp;gt;hasVerifiedEmail()){
+            return;
+        }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;        $event-&amp;gt;user-&amp;gt;notify(new NewFollower($event-&amp;gt;follower));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We check if the user has verified their email and if they haven’t we return early.&lt;/p&gt;

&lt;p&gt;We will add a new test to the SendNewFollowerNotificationsTest file to check this works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_notification_is_not_sent_to_unverified_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unverified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$follower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserFollowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;New&lt;/span&gt; &lt;span class="nc"&gt;SendNewFollowerNotifications&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$listener&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertNothingSent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who are you following
&lt;/h2&gt;

&lt;p&gt;To create a new page to list the other users followed by a particular user, we will use the index method of the FollowController for this.&lt;/p&gt;

&lt;p&gt;Let's create a new route that points to the index method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users/{user}/following'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;FollowController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'index'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verified'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.index'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the index method, we want to return a new page and include the user whose information we are looking at and a list of the users they are following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function index(User $user): Response
&lt;/span&gt;&lt;span class="gd"&gt;-   //
&lt;/span&gt;&lt;span class="gi"&gt;+    {
+        $following = $user
+                -&amp;gt;follows()
+                -&amp;gt;orderByPivot('created_at','desc')
+                -&amp;gt;select('user_id as id', 'name')
+                -&amp;gt;addSelect(['following' =&amp;gt; +function ($query) {
+                $query-&amp;gt;select('id as following')
+                    -&amp;gt;from('follower_user')
+                    -&amp;gt;whereColumn('follower_id', Auth()-&amp;gt;id())
+                    -&amp;gt;whereColumn('user_id', 'users.id');
+                }])
+                -&amp;gt;get()-&amp;gt;makeHidden('pivot');
+        return Inertia::render('Follow/Index', [
+            'user' =&amp;gt; $user-&amp;gt;only(['id', 'name']),
+            'following' =&amp;gt; fn() =&amp;gt; $following,
+        ]);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As well as querying the users followed by the authenticated user, we are also using a subquery to confirm if each of the users is being followed by the authenticated user.&lt;/p&gt;

&lt;p&gt;Let’s create a new page to render our data. Create a new Vue file at resources/js/Pages/Follow/Index.vue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AuthenticatedLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Layouts/AuthenticatedLayout.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;following&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;Head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt; Follows&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;/Head&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;AuthenticatedLayout&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white p-6 lg:p-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"route('profile.show',user.id)"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt; Follows&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/AuthenticatedLayout&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will create a new component UserCard, to render the users details.&lt;/p&gt;

&lt;p&gt;In UserCard we want to show the user's name and give them an option to follow or unfollow the user unless the user is the authenicated user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PrimaryButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./PrimaryButton.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SecondaryButton&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./SecondaryButton.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;follow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unfollow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-center justify-between space-x-6 p-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex gap-x-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"min-w-0 flex-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"route('profile.show', user.id)"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-md font-semibold leading-6 text-gray-800 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"user.id !== $page.props.auth.user.id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"!user.following"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;submit.prevent=&lt;/span&gt;&lt;span class="s"&gt;"follow.post(route('follow.store'), &lt;/span&gt;{
                preserveScroll: true,
                only:['following']
            })"&amp;gt;
                &lt;span class="nt"&gt;&amp;lt;PrimaryButton&amp;gt;&lt;/span&gt;Follow&lt;span class="nt"&gt;&amp;lt;/PrimaryButton&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"user.following"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;submit.prevent=&lt;/span&gt;&lt;span class="s"&gt;"unfollow.delete(route('follow.destroy', user.id), &lt;/span&gt;{
                preserveScroll: true,
                only:['following']
            })"&amp;gt;
                &lt;span class="nt"&gt;&amp;lt;SecondaryButton&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Unfollow&lt;span class="nt"&gt;&amp;lt;/SecondaryButton&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The styling for this component is adapted from this &lt;a href="https://tailwindui.com/components/application-ui/lists/stacked-lists#component-6a56f3c03589dfa48dc4e7eec7fbf6d0"&gt;Tailwind UI component. &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add this component to the Index page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import { Link, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; const props = defineProps(['user', 'following']);
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
   &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
   &amp;lt;/Head&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;h1 class="bg-white p-6 lg:p-8"&amp;gt;
        &amp;lt;Link :href="route('profile.show',user.id)" class="text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&amp;gt;{{ user.name }} Follows&amp;lt;/Link&amp;gt;
     &amp;lt;/h1&amp;gt;
&lt;span class="gi"&gt;+     &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
+       &amp;lt;div class="divide-y bg-white mt-6 rounded-lg"&amp;gt;
+           &amp;lt;UserCard
+             v-for="user in following"
+         :key="user.id"
+         :user="user"
+        /&amp;gt;
+         &amp;lt;/div&amp;gt;
+      &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Who follows me?
&lt;/h3&gt;

&lt;p&gt;We have a page to show who a user follows. We now need a page to show all the users who follow a particular user.&lt;/p&gt;

&lt;p&gt;First, create a new controller and route.&lt;/p&gt;

&lt;p&gt;To create the controller, run the command &lt;code&gt;php artisan make:controller ListFollowers --invokable&lt;/code&gt;. The &lt;code&gt;invokable&lt;/code&gt; option creates a controller with only a __invoke() method.&lt;/p&gt;

&lt;p&gt;Update the method to return the authenticated user and their followers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inertia\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inertia\Inertia&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ListFollowers&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cd"&gt;/**
  * Handle the incoming request.
  */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nv"&gt;$followers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;
             &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
             &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderByPivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follower_id as id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addSelect&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'following'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                 &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id as following'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follower_user'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                     &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follower_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                     &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereColumn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'users.id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
             &lt;span class="p"&gt;}])&lt;/span&gt;
             &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;makeHidden&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pivot'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Inertia&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Follow/Index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
         &lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
         &lt;span class="s1"&gt;'followers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$followers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll create a route for this new page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users/{user}/followers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ListFollowers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verified'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'followers'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ListFollowers __invoke() method returns the authenticated user and the users who follow them; this is the same data structure the followingController Index method uses, the only difference being the key used for users. We can generalize the controllers' methods to use the same Follow/index component for both pages.&lt;/p&gt;

&lt;p&gt;In the FollowController's index method, update the name of the &lt;code&gt;following&lt;/code&gt; prop to &lt;code&gt;users&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function index(User $user): Response
&lt;/span&gt;{
     $following = $user
             -&amp;gt;follows()
             -&amp;gt;orderByPivot('created_at','desc')
             -&amp;gt;get(['user_id', 'name'])
             -&amp;gt;map(function ($item) {
                 return array_merge($item-&amp;gt;makeHidden('pivot')-&amp;gt;toArray(), [
                     'following' =&amp;gt; Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;where('user_id', $item-&amp;gt;user_id)-&amp;gt;exists()
                 ]);
             });
&lt;span class="err"&gt;
&lt;/span&gt;    return Inertia::render('Follow/Index', [
        'user' =&amp;gt; $user-&amp;gt;only(['id', 'name']),
&lt;span class="gd"&gt;-       'following' =&amp;gt; fn() =&amp;gt; $following,
&lt;/span&gt;&lt;span class="gi"&gt;+       'users' =&amp;gt; fn() =&amp;gt; $following,
&lt;/span&gt;      ]);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do the same in the newly created ListFollowersController.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;{
  /**
  * Handle the incoming request.
  */
  public function __invoke(User $user): Response
  {
     $followers = $user
             -&amp;gt;followers()
             -&amp;gt;orderByPivot('created_at','desc')
             -&amp;gt;select('follower_id as id', 'name')
             -&amp;gt;addSelect(['following' =&amp;gt; function ($query) {
                 $query-&amp;gt;select('id as following')
                     -&amp;gt;from('follower_user')
                     -&amp;gt;whereColumn('follower_id', Auth()-&amp;gt;id())
                     -&amp;gt;whereColumn('user_id', 'users.id');
             }])
             -&amp;gt;get()-&amp;gt;makeHidden('pivot');
&lt;span class="err"&gt;
&lt;/span&gt;     return Inertia::render('Follow/Index', [
         'user' =&amp;gt; $user-&amp;gt;only(['id', 'name']),
&lt;span class="gd"&gt;-        'followers' =&amp;gt; fn() =&amp;gt; $followers,
&lt;/span&gt;&lt;span class="gi"&gt;+        'users' =&amp;gt; fn() =&amp;gt; $followers,
&lt;/span&gt;     ]);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the Follow/Index page to accept the users prop and update the component to use users rather than following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import { Link, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-const props = defineProps(['user', 'following']);
&lt;/span&gt;&lt;span class="gi"&gt;+const props = defineProps(['user', 'users']);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
   &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
   &amp;lt;/Head&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;h1 class="bg-white p-6 lg:p-8"&amp;gt;
        &amp;lt;Link :href="route('profile.show',user.id)" class="text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&amp;gt;{{ user.name }} Follows&amp;lt;/Link&amp;gt;
     &amp;lt;/h1&amp;gt;
     &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
       &amp;lt;div class="divide-y bg-white mt-6 rounded-lg"&amp;gt;
           &amp;lt;UserCard
&lt;span class="gd"&gt;-            v-for="user in following"
&lt;/span&gt;&lt;span class="gi"&gt;+            v-for="user in users"
&lt;/span&gt;            :key="user.id"
            :user="user"
         /&amp;gt;
         &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use &lt;code&gt;route().current()&lt;/code&gt; to determine the route that is using the page and set the title to reflect this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import { Link, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; const props = defineProps(['user', 'following']);
 const props = defineProps(['user', 'users']);
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
   &amp;lt;Head&amp;gt;
&lt;span class="gd"&gt;-      &amp;lt;title&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+      &amp;lt;title v-if="route().current('followers')"&amp;gt;{{ user.name }} Followers&amp;lt;/title&amp;gt;
+      &amp;lt;title v-else&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
&lt;/span&gt;   &amp;lt;/Head&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;h1 class="bg-white p-6 lg:p-8"&amp;gt;
        &amp;lt;Link :href="route('profile.show',user.id)" class="text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&amp;gt;{{ user.name }} Follows&amp;lt;/Link&amp;gt;
     &amp;lt;/h1&amp;gt;
     &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
       &amp;lt;div class="divide-y bg-white mt-6 rounded-lg"&amp;gt;
           &amp;lt;UserCard
               v-for="user in following"
               v-for="user in users"
           :key="user.id"
           :user="user"
         /&amp;gt;
         &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;   &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Navigating to our user lists.
&lt;/h2&gt;

&lt;p&gt;We will create two new links in our profile page to allow users to navigate to the newly created user list pages.&lt;/p&gt;

&lt;p&gt;We will update the profileController's show method to load the relationship counts for the 'follows' and 'followers' relationships and display the count in the links.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function show(User $user): Response
 {
     return Inertia::render('Profile/Show',[
&lt;span class="gd"&gt;-        'user' =&amp;gt; $user-&amp;gt;only(['id', 'name', 'created_at']),
&lt;/span&gt;&lt;span class="gi"&gt;+        'user' =&amp;gt; fn() =&amp;gt; $user-&amp;gt;loadCount(['followers', 'follows'])-&amp;gt;only(['id', 'name', 'created_at', 'followers_count', 'follows_count']),
&lt;/span&gt;         'chirps' =&amp;gt; $user-&amp;gt;chirps()-&amp;gt;latest()-&amp;gt;get()-&amp;gt;map(fn (Chirp $chirp) =&amp;gt; $chirp-&amp;gt;setRelation('user',$user)),
         'following' =&amp;gt; fn () =&amp;gt; Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;where('user_id', $user-&amp;gt;id)-&amp;gt;exists(),
     ]);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use these counts in the Heading component.&lt;/p&gt;

&lt;p&gt;We will also update the forms to follow and unfollow so the user prop is updated with the new relationship count when the page reloads.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
&lt;span class="p"&gt;import dayjs from 'dayjs';
import PrimaryButton from './PrimaryButton.vue';
import SecondaryButton from './SecondaryButton.vue';
&lt;/span&gt; import { Link } from '@inertiajs/vue3'
 const props = defineProps(['user']);
 &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
     &amp;lt;div class="bg-white"&amp;gt;
         &amp;lt;div class="max-w-7xl mx-auto pb-1 px-4 sm:px-6 lg:px-8 p-4 sm:py-6 lg:py-8 sm:flex sm:items-center sm:justify-between sm:space-x-5"&amp;gt;
             &amp;lt;div class="flex items-start space-x-5"&amp;gt;
                 &amp;lt;div class="pt-1.5"&amp;gt;
                     &amp;lt;h1 class="text-2xl font-bold text-gray-900 capitalize"&amp;gt;{{ user.name }}&amp;lt;/h1&amp;gt;
                     &amp;lt;p class="text-sm font-medium text-gray-500"&amp;gt;
                    Joined
                        &amp;lt;time :datetime="dayjs(user.created_at).format('YYYY-MM')"&amp;gt;
                        {{ dayjs(user.created_at).format('MMMM YYYY') }}
                        &amp;lt;/time&amp;gt;
                     &amp;lt;/p&amp;gt;
&lt;span class="gi"&gt;+                    &amp;lt;div class="mt-3 sm:mt-3"&amp;gt;
+                       &amp;lt;Link :href="route('follow.index', user.id)"&amp;gt;
+                           &amp;lt;span&amp;gt;{{ user.follows_count }}&amp;lt;/span&amp;gt;
+                           &amp;lt;span class="text-sm font-medium text-gray-500"&amp;gt; Following&amp;lt;/span&amp;gt;
+                       &amp;lt;/Link&amp;gt;
+                       &amp;lt;Link :href="route('followers', user.id)"&amp;gt;
+                           &amp;lt;span class="ml-4"&amp;gt;{{ user.followers_count }}&amp;lt;/span&amp;gt;
+                           &amp;lt;span class="text-sm font-medium text-gray-500"&amp;gt; Followers&amp;lt;/span&amp;gt;
+                       &amp;lt;/Link&amp;gt;
+                   &amp;lt;/div&amp;gt;                 
&lt;/span&gt;                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div v-if="user.id === $page.props.auth.user.id" class="my-3 flex flex-col-reverse justify-stretch sm:mt-0 sm:pr-3"&amp;gt;
                &amp;lt;Link :href="route('profile.edit')" class="inline-flex items-center justify-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150"&amp;gt;Edit Profile&amp;lt;/Link&amp;gt;
            &amp;lt;/div&amp;gt;
           &amp;lt;div v-else class="my-3 flex flex-col-reverse justify-stretch space-y-4 space-y-reverse sm:justify-end sm:space-x-3 sm:space-y-0 sm:mt-0 sm:flex-row sm:pr-3"&amp;gt;
          &amp;lt;form class="flex flex-col" @submit.prevent="follow.post(route('follow.store'), {
     preserveScroll: true,
&lt;span class="gd"&gt;-    only:['following']
&lt;/span&gt;&lt;span class="gi"&gt;+    only:['following', 'user']
&lt;/span&gt;  })"&amp;gt;
             &amp;lt;PrimaryButton class="justify-center"&amp;gt;Follow&amp;lt;/PrimaryButton&amp;gt;
         &amp;lt;/form&amp;gt;
         &amp;lt;form class="flex flex-col" @submit.prevent="unfollow.delete(route('follow.destroy', user.id), {
            preserveScroll: true,
&lt;span class="gd"&gt;-           only:['following']
&lt;/span&gt;&lt;span class="gi"&gt;+           only:['following', 'user']
&lt;/span&gt;    })"&amp;gt;
           &amp;lt;SecondaryButton class="justify-center" type='submit'&amp;gt;Unfollow&amp;lt;/SecondaryButton&amp;gt;
        &amp;lt;/form&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Navigating between the pages
&lt;/h2&gt;

&lt;p&gt;We will use the FilterTabs component to navigate between the Follow index and Following index pages created for the chirp filter. The FilterTabs component was built only for the Chirps index page; we will refactor it to allow us to reuse it.&lt;/p&gt;

&lt;p&gt;Rename the FilterTabs component to Tabs.&lt;br&gt;
In the newly renamed Tabs component, we shall pass the tabs down from the parent component,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import { Link } from '@inertiajs/vue3'
&lt;span class="gi"&gt;+defineprops(['tabs'])
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;template&amp;gt;
     &amp;lt;nav class="isolate flex divide-x mt-6 divide-gray-200 rounded-lg shadow overflow-hidden" aria-label="Tabs"&amp;gt;
         &amp;lt;Link
             :href="route('chirps.index', { filter: 'false'})"
             :only="['chirps']"
             :class="[route().current('chirps.index', { filter: 'false'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700','group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
             :aria-current="route().current('chirps.index', { filter: 'false'}) ? 'page' : undefined"&amp;gt;
             &amp;lt;span&amp;gt; All &amp;lt;/span&amp;gt;
             &amp;lt;span aria-hidden="true" :class="[route().current('chirps.index', { filter: 'false'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
         &amp;lt;/Link&amp;gt;
         &amp;lt;Link
             :href="route('chirps.index', { filter: 'true'})"
             :only="['chirps']"
             :class="[route().current('chirps.index', { filter: 'true'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700', 'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
             :aria-current="route().current('chirps.index', { filter: 'true'}) ? 'page' : undefined"&amp;gt;
             &amp;lt;span&amp;gt;Following &amp;lt;/span&amp;gt;
             &amp;lt;span aria-hidden="true" :class="[route().current('chirps.index', { filter: 'true'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
         &amp;lt;/Link&amp;gt;
     &amp;lt;/nav&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Separate the actual links to a new component called TabLink. The new tabLink component requires the data for the tab, its position within the tabs component, and the total number of tabs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="gd"&gt;-import { Link } from '@inertiajs/vue3'
&lt;/span&gt;&lt;span class="gi"&gt;+import Tablink from './Tablink.vue';
&lt;/span&gt; defineprops(['tabs'])
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;template&amp;gt;
     &amp;lt;nav class="isolate flex divide-x mt-6 divide-gray-200 rounded-lg shadow overflow-hidden" aria-label="Tabs"&amp;gt;
&lt;span class="gd"&gt;-         &amp;lt;Link
-             :href="route('chirps.index', { filter: 'false'})"
-             :only="['chirps']"
-             :class="[route().current('chirps.index', { filter: 'false'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700','group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
-            :aria-current="route().current('chirps.index', { filter: 'false'}) ? 'page' : undefined"&amp;gt;
-            &amp;lt;span&amp;gt; All &amp;lt;/span&amp;gt;
-            &amp;lt;span aria-hidden="true" :class="[route().current('chirps.index', { filter: 'false'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
-       &amp;lt;/Link&amp;gt;
-       &amp;lt;Link
-           :href="route('chirps.index', { filter: 'true'})"
-           :only="['chirps']"
-           :class="[route().current('chirps.index', { filter: 'true'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700', 'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
-           :aria-current="route().current('chirps.index', { filter: 'true'}) ? 'page' : undefined"&amp;gt;
-           &amp;lt;span&amp;gt;Following &amp;lt;/span&amp;gt;
-           &amp;lt;span aria-hidden="true" :class="[route().current('chirps.index', { filter: 'true'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
-       &amp;lt;/Link&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+       &amp;lt;template v-for="(tab, index) in tabs"&amp;gt;
+      &amp;lt;TabLink :tab="tab" :tabIdx="index" :tabLength="tabs.length"&amp;gt;
+           &amp;lt;span&amp;gt; {{ tab.text }}&amp;lt;/span&amp;gt;
+      &amp;lt;/TabLink&amp;gt;
+       &amp;lt;/template&amp;gt;
&lt;/span&gt;    &amp;lt;/nav&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the total number of tabs and the tabLinks position to apply selective tailwind classes.&lt;/p&gt;

&lt;p&gt;resources/js/Components/Tablink.vue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tabIdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tabLength&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt;
        &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;tab.href&lt;/span&gt;
        &lt;span class="na"&gt;:only=&lt;/span&gt;&lt;span class="s"&gt;tab.only&lt;/span&gt;
        &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"[
            tab.active ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700',
            tabIdx === 0 ? 'rounded-l-lg' : '',
            tabIdx === tabLength - 1 ? 'rounded-r-lg' : '',
            'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10'
        ]"&lt;/span&gt;
        &lt;span class="na"&gt;:aria-current=&lt;/span&gt;&lt;span class="s"&gt;"tab.active ? 'page' : undefined"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;slot/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"[tab.active ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the Tabs component can be used in multiple pages, we can update the Chirp/Index page and the New Follow/Index page.&lt;/p&gt;

&lt;p&gt;resources/js/Pages/Chirps/Index.vue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import Chirp from '@/Components/Chirp.vue';
 import InputError from '@/Components/InputError.vue';
 import PrimaryButton from '@/Components/PrimaryButton.vue';
&lt;span class="gd"&gt;-import FilterTabs from '@/Components/FilterTabs.vue';
&lt;/span&gt;&lt;span class="gi"&gt;+import Tabs from '@/Components/Tabs.vue';
&lt;/span&gt; import { useForm, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; defineProps(['chirps']);
&lt;span class="gi"&gt;+const tabs = [
+    {href:route('chirps.index', { filter: 'false'}), active:route().current('chirps.index', { filter: 'false'}), only:['chirps'], text:'All'},
+    {href:route('chirps.index', { filter: 'true'}), active:route().current('chirps.index', { filter: 'true'}), only:['chirps'],  text:'Following'},
&lt;/span&gt;]
&lt;span class="err"&gt;
&lt;/span&gt; const form = useForm({
     message: '',
 });
 &amp;lt;/script&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;template&amp;gt;
     &amp;lt;Head title="Chirps" /&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;AuthenticatedLayout&amp;gt;
         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
             &amp;lt;form @submit.prevent="form.post(route('chirps.store'), { onSuccess: () =&amp;gt; form.reset() })"&amp;gt;
                 &amp;lt;textarea
                     v-model="form.message"
                     placeholder="What's on your mind?"
                     class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
                 &amp;gt;&amp;lt;/textarea&amp;gt;
                 &amp;lt;InputError :message="form.errors.message" class="mt-2" /&amp;gt;
                 &amp;lt;PrimaryButton class="mt-4"&amp;gt;Chirp&amp;lt;/PrimaryButton&amp;gt;
             &amp;lt;/form&amp;gt;
&lt;span class="gd"&gt;-            &amp;lt;FilterTabs/&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+            &amp;lt;Tabs :tabs="tabs"/&amp;gt;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;             &amp;lt;div class="mt-6 bg-white shadow-sm rounded-lg divide-y"&amp;gt;
                 &amp;lt;Chirp
                     v-for="chirp in chirps"
                     :key="chirp.id"
                     :chirp="chirp"
                 /&amp;gt;
             &amp;lt;/div&amp;gt;
         &amp;lt;/div&amp;gt;
     &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resources/js/Pages/Follow/Index.vue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="gi"&gt;+import Tabs from '@/Components/Tabs.vue';
&lt;/span&gt; import UserCard from '@/Components/UserCard.vue';
 import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
 import { Link, Head } from '@inertiajs/vue3';
&lt;span class="err"&gt;
&lt;/span&gt; const props = defineProps(['user', 'users']);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+const tabs = [
+    {href:route('followers', props.user.id), active:route().current('followers', props.user.id), text:'Followers'},
+    {href:route('follow.index', props.user.id), active:route().current('follow.index', props.user.id), text:'Following'},
&lt;/span&gt; ]
&lt;span class="err"&gt;
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
      &amp;lt;Head&amp;gt;
         &amp;lt;title v-if="route().current('followers')"&amp;gt;{{ user.name }} Followers&amp;lt;/title&amp;gt;
         &amp;lt;title v-else&amp;gt;{{ user.name }} Follows&amp;lt;/title&amp;gt;
      &amp;lt;/Head&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;     &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;         &amp;lt;h1 class="bg-white p-6 lg:p-8"&amp;gt;
             &amp;lt;Link :href="route('profile.show',user.id)" class="text-2xl font-bold text-gray-900 capitalize hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-950"&amp;gt;{{ user.name }} &amp;lt;/Link&amp;gt;
         &amp;lt;/h1&amp;gt;
&lt;span class="err"&gt;
&lt;/span&gt;         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
&lt;span class="gi"&gt;+            &amp;lt;Tabs :tabs="tabs"/&amp;gt;
&lt;/span&gt;              &amp;lt;div class="divide-y bg-white mt-6 rounded-lg"&amp;gt;
                 &amp;lt;UserCard
                     v-for="user in users"
                     :id="user.user_id ?? user.follower_id"
                     :name="user.name"
                     :following="user.following"
                 /&amp;gt;
             &amp;lt;/div&amp;gt;
         &amp;lt;/div&amp;gt;
     &amp;lt;/AuthenticatedLayout&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Alongside adding new functionality, we have updated the existing pages, so we need to update our existing tests.&lt;br&gt;
We are now including the follower and follows count in the ProfileController's show method, to test that this data is included update the tests inside the ProfileTest file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&amp;lt;?php
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;namespace Tests\Feature\Controllers;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;use App\Models\User;
use App\Models\Chirp;
use Database\Factories\ChirpFactory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use SebastianBergmann\Type\VoidType;
use Tests\TestCase;
use Inertia\Testing\AssertableInertia as Assert;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class ProfileTest extends TestCase
&lt;/span&gt;{
    use RefreshDatabase;
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_profile_page_is_displayed(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;get('/profile');
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertOk();
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_profile_information_can_be_updated(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;patch('/profile', [
                'name' =&amp;gt; 'Test User',
                'email' =&amp;gt; 'test@example.com',
            ]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response
            -&amp;gt;assertSessionHasNoErrors()
            -&amp;gt;assertRedirect('/profile');
&lt;span class="err"&gt;
&lt;/span&gt;        $user-&amp;gt;refresh();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertSame('Test User', $user-&amp;gt;name);
        $this-&amp;gt;assertSame('test@example.com', $user-&amp;gt;email);
        $this-&amp;gt;assertNull($user-&amp;gt;email_verified_at);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;patch('/profile', [
                'name' =&amp;gt; 'Test User',
                'email' =&amp;gt; $user-&amp;gt;email,
            ]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response
            -&amp;gt;assertSessionHasNoErrors()
            -&amp;gt;assertRedirect('/profile');
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertNotNull($user-&amp;gt;refresh()-&amp;gt;email_verified_at);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_can_delete_their_account(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;delete('/profile', [
                'password' =&amp;gt; 'password',
            ]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response
            -&amp;gt;assertSessionHasNoErrors()
            -&amp;gt;assertRedirect('/');
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertGuest();
        $this-&amp;gt;assertNull($user-&amp;gt;fresh());
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_correct_password_must_be_provided_to_delete_account(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;from('/profile')
            -&amp;gt;delete('/profile', [
                'password' =&amp;gt; 'wrong-password',
            ]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response
            -&amp;gt;assertSessionHasErrors('password')
            -&amp;gt;assertRedirect('/profile');
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertNotNull($user-&amp;gt;fresh());
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_public_profile_is_displayed(): void
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;get(route('profile.show',$user-&amp;gt;id));
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertOk();
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_chirps_belonging_to_profile_owner_are_included(): void
    {
        $user = User::factory()
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $profileUser = User::factory()
&lt;span class="gi"&gt;+                    -&amp;gt;has(User::factory()-&amp;gt;count(2),'followers')
+                    -&amp;gt;has(User::factory()-&amp;gt;count(3),'follows')
&lt;/span&gt;                    -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('profile.show',$profileUser-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Profile/Show')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $profileUser-&amp;gt;id)
                    -&amp;gt;where('name', $profileUser-&amp;gt;name)
&lt;span class="gi"&gt;+                    -&amp;gt;where('followers_count', $profileUser-&amp;gt;followers()-&amp;gt;count())
+                    -&amp;gt;where('follows_count', $profileUser-&amp;gt;follows()-&amp;gt;count())
&lt;/span&gt;                    -&amp;gt;missing('email')
                    -&amp;gt;missing('password')
                    -&amp;gt;etc()
                )
                -&amp;gt;has('chirps', 5, fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;id)
                    -&amp;gt;where('message', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;message)
                    -&amp;gt;etc()
                    -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                        -&amp;gt;where('id', $profileUser-&amp;gt;id)
                        -&amp;gt;etc()
                    )
                )
                -&amp;gt;has('following')
        );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_chirps_belonging_to_other_uses_are_not_included(): void
    {
        $user = User::factory()
&lt;span class="gi"&gt;+                -&amp;gt;has(User::factory()-&amp;gt;count(2),'followers')
+                -&amp;gt;has(User::factory()-&amp;gt;count(3),'follows')
&lt;/span&gt;                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $otherUser = User::factory()
                    -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                    -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;actingAs($user)
            -&amp;gt;get(route('profile.show',$user-&amp;gt;id))
            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
                -&amp;gt;component('Profile/Show')
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $user-&amp;gt;id)
                    -&amp;gt;where('name', $user-&amp;gt;name)
&lt;span class="gi"&gt;+                    -&amp;gt;where('followers_count', $user-&amp;gt;followers()-&amp;gt;count())
+                    -&amp;gt;where('follows_count', $user-&amp;gt;follows()-&amp;gt;count())
&lt;/span&gt;                    -&amp;gt;missing('email')
                    -&amp;gt;missing('password')
                    -&amp;gt;etc()
                )
                -&amp;gt;has('chirps',0)
                -&amp;gt;has('following')
            );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can add additional tests for the new index method of the FollowController in the FollowControllerTest.&lt;/p&gt;

&lt;p&gt;We want to test that the data passed to the page is as expected and that only verified logged-in users can access the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&amp;lt;?php
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;namespace Tests\Feature\Controllers;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;use App\Events\UserFollowed;
use App\Models\User;
&lt;/span&gt;&lt;span class="gi"&gt;+use Database\Factories\UserFactory;
&lt;/span&gt;&lt;span class="p"&gt;use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Event;
&lt;/span&gt;&lt;span class="gi"&gt;+use Inertia\Testing\AssertableInertia as Assert;
&lt;/span&gt;&lt;span class="p"&gt;use Tests\TestCase;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class FollowControllerTest extends TestCase
&lt;/span&gt;{
    public function test_users_can_follow_each_other()
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; $following-&amp;gt;id]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertContains($following-&amp;gt;id, $user-&amp;gt;follows-&amp;gt;pluck('id'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_followed_event_is_dispatched()
    {
        Event::fake();
&lt;span class="err"&gt;
&lt;/span&gt;        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $this
            -&amp;gt;actingAs($user)
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; $following-&amp;gt;id]);
&lt;span class="err"&gt;
&lt;/span&gt;        Event::assertDispatched(function (UserFollowed $event) use ($user) {
            return $event-&amp;gt;follower-&amp;gt;id === $user-&amp;gt;id;
        });
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_must_be_logged_in_before_following()
    {
        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this-&amp;gt;post(route('follow.store'),['id' =&amp;gt; $following-&amp;gt;id]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect(route('login'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_must_be_verified_before_following()
    {
        $user = User::factory()
            -&amp;gt;unverified()
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; $following-&amp;gt;id]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect(route('verification.notice'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_id_required()
    {
        $response = $this
            -&amp;gt;actingAs(User::factory()-&amp;gt;make())
            -&amp;gt;post(route('follow.store'));
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertSessionHasErrors([
            'id' =&amp;gt; 'The id field is required.'
        ]);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_id_must_be_a_number()
    {
        $response = $this
            -&amp;gt;actingAs(User::factory()-&amp;gt;make())
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; 'a']);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertSessionHasErrors([
            'id' =&amp;gt; 'The id field must be an integer.',
            'id' =&amp;gt; 'The id field must be a number.'
        ]);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_id_must_not_be_request_user()
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; $user-&amp;gt;id]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertSessionHasErrors([
            'id' =&amp;gt; 'The selected id is invalid.',
        ]);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_id_must_belong_to_existing_user()
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;post(route('follow.store'),['id' =&amp;gt; 999]);
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertSessionHasErrors([
            'id' =&amp;gt; 'The selected id is invalid.',
        ]);
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_users_can_unfollow_each_other()
    {
        $user = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;delete(route('follow.destroy',$following-&amp;gt;id));
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect();
&lt;span class="err"&gt;
&lt;/span&gt;        $this-&amp;gt;assertNotContains($following-&amp;gt;id, $user-&amp;gt;follows-&amp;gt;pluck('id'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_must_be_logged_in_to_unfollow()
    {
        $following = User::factory()-&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this-&amp;gt;delete(route('follow.destroy', 2));
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect(route('login'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;    public function test_user_must_be_verified_to_unfollow()
    {
        $user = User::factory()
            -&amp;gt;unverified()
            -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;        $response = $this
            -&amp;gt;actingAs($user)
            -&amp;gt;delete(route('follow.destroy', 2));
&lt;span class="err"&gt;
&lt;/span&gt;        $response-&amp;gt;assertRedirect(route('verification.notice'));
    }
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    public function test_users_can_see_who_each_other_are_following()
+    {
+        $user = User::factory()
+            -&amp;gt;has(User::factory(3),'follows')
+            -&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $otherUser = User::factory()
+            -&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $this-&amp;gt;actingAs($otherUser)
+            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
+            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
+                -&amp;gt;component('Follow/Index')
+                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;where('id', $user-&amp;gt;id)
+                    -&amp;gt;where('name', $user-&amp;gt;name)
+                    -&amp;gt;missing('password')
+                    -&amp;gt;missing('email')
+                )
+                -&amp;gt;has('users', 3, fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;where('user_id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                    -&amp;gt;where('following', false)
+                    )
+            );
+    }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    public function test_follow_property_depends_on_auth_user()
+    {
+        $following = User::factory();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $user = User::factory()
+            -&amp;gt;has($following,'follows')
+            -&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $otherUser = User::factory()-&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $this-&amp;gt;actingAs($otherUser)
+            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
+            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
+                -&amp;gt;component('Follow/Index')
+                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;where('user_id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                    -&amp;gt;where('following', false)
+                    )
+            );
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $this-&amp;gt;actingAs($user)
+            -&amp;gt;get(route('follow.index', $user-&amp;gt;id))
+            -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
+                -&amp;gt;component('Follow/Index')
+                -&amp;gt;has('users', 1, fn (Assert $page) =&amp;gt; $page
+                    -&amp;gt;where('user_id', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;id)
+                    -&amp;gt;where('name', $user-&amp;gt;follows()-&amp;gt;first()-&amp;gt;name)
+                    -&amp;gt;where('following', true)
+                    )
+            );
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    public function test_must_be_logged_in_to_view_following_index()
+    {
+        $response = $this-&amp;gt;get(route('follow.index',1));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $response-&amp;gt;assertRedirectToRoute('login');
+    }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    public function test_must_be_verifired_to_view_following_index()
+    {
+        $user = User::factory()
+            -&amp;gt;unverified()
+            -&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $response = $this-&amp;gt;actingAs($user)
+            -&amp;gt;get(route('follow.index', 1));
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        $response-&amp;gt;assertRedirect(route('verification.notice'));
+    }
+}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new test file for the ListFollowers Controller with the command &lt;code&gt;php artisan make:test Controllers/ListFollowersTest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We want to test that the correct data is passed to the page, including the list of users who follow the profile user and if the authenticated user is following them. We must test that only verified logged-in users can reach the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\RefreshDatabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inertia\Testing\AssertableInertia&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\WithFaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ListFollowersTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_users_can_see_who_is_following_a_particular_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="s1"&gt;'followers'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$otherUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$otherUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'followers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Follow/Index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'following'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_follow_property_depends_on_auth_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$follower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;follows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$otherUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$otherUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'followers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Follow/Index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'following'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'followers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Follow/Index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereNot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'following'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_must_be_logged_in_to_view_following_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirectToRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_must_be_verifired_to_view_following_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unverified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verification.notice'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>laravel</category>
      <category>php</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Chirp Beyond (Bootcamp) part 3 Follow me</title>
      <dc:creator>Silver343</dc:creator>
      <pubDate>Fri, 03 Nov 2023 11:44:43 +0000</pubDate>
      <link>https://forem.com/silver343/chirp-beyond-bootcamp-part-3-follow-me-1a47</link>
      <guid>https://forem.com/silver343/chirp-beyond-bootcamp-part-3-follow-me-1a47</guid>
      <description>&lt;p&gt;As Chirper exists at the moment, all users can see and are notified of each other's chirps, but we are now going to allow users to follow each other and filter chirps, so we only want to notify them of chirps created by the people they follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Followers and Follows
&lt;/h2&gt;

&lt;p&gt;We will create a new database table and relationship in our application. We will create a many-to-many relationship between users and other users. Create a new migration file with the command  &lt;code&gt;php artisan make:migration create_follower_user_table&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The new migration can be found at database/migrations/_create_follower_user_table.php&lt;/p&gt;

&lt;p&gt;Update the 'up()' method with two new fields a 'user_id' and 'follower_id' both of which reference the users table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
* Run the migrations.
*/&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follower_user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Blueprint&lt;/span&gt; &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follower_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cascadeOnDelete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreignId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;constrained&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cascadeOnDelete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now need to define the relationships inside our user model. Add the following two methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;BelongsToMany&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsToMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'follower_user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'follower_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withTimestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;follows&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;BelongsToMany&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;belongsToMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'follower_user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'follower_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withTimestamps&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more about defining relationships in the &lt;a href="https://laravel.com/docs/10.x/eloquent-relationships" rel="noopener noreferrer"&gt;Laravel docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Controller
&lt;/h2&gt;

&lt;p&gt;We’ll create a new controller to handle the logic. Use the following command &lt;code&gt;php artisan make:controller FollowController --resource&lt;/code&gt; to create a resource controller.&lt;/p&gt;

&lt;p&gt;This will create a new controller under the controller directory with all the resource methods defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Route
&lt;/h2&gt;

&lt;p&gt;Create two new routes. One will accept a post request to create a new follower-user relationship; the other will accept a delete request to destroy the relationship.&lt;/p&gt;

&lt;p&gt;Add the routes to web.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+use App\Http\Controllers\FollowController;
&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="gi"&gt;+Route::post('/follow', [FollowController::class, 'store'])-&amp;gt;middleware('verified')-&amp;gt;name('follow.store');
+Route::delete('/unfollow/{user}', [FollowController::class, 'destroy'])-&amp;gt;middleware('verified')-&amp;gt;name('follow.destroy');
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our new routes, we are using the verified middleware. This middleware checks to see if the user has verified their email address. If they have, the request will proceed; otherwise they will be redirect to a page notifying them to verify their email address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;namespace App\Models;
&lt;/span&gt;&lt;span class="gd"&gt;-// use Illuminate\Contracts\Auth\MustVerifyEmail;
&lt;/span&gt;&lt;span class="gi"&gt;+use Illuminate\Contracts\Auth\MustVerifyEmail;
&lt;/span&gt;&lt;span class="p"&gt;use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
&lt;/span&gt;&lt;span class="gd"&gt;-class User extends Authenticatable
&lt;/span&gt;&lt;span class="gi"&gt;+class User extends Authenticatable implements MustVerifyEmail
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Follow and unfollow
&lt;/h1&gt;

&lt;p&gt;Update the two methods in the Follow Controller that correspond with the new routes.&lt;/p&gt;

&lt;p&gt;Update the store method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+use Illuminate\Http\RedirectResponse;
&lt;/span&gt;&lt;span class="p"&gt;use Illuminate\Http\Request;
&lt;/span&gt;&lt;span class="gi"&gt;+use Illuminate\Validation\Rule;
&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt; public function store(Request $request):  RedirectResponse
 {
&lt;span class="gd"&gt;- //
&lt;/span&gt;&lt;span class="gi"&gt;+     $validated = $request-&amp;gt;validate([
+            'id' =&amp;gt; [
+            'required',
+            'integer',
+            'numeric',
+            Rule::notIn([Auth()-&amp;gt;id()]),
+            'exists:users,id'
+        ]
+    ]);
+    Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;attach($validated['id']);
+    return back();
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We validate the id passed from the request to ensure it is a number, it doesn't match the user making the request, and that it exists in the database. Do not trust data returned from the front end.&lt;/p&gt;

&lt;p&gt;Once the id is validated we create the many-to-many relationship using the &lt;code&gt;attach()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Next we’ll update the destroy method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function destroy(String $id): RedirectResponse
 {
&lt;span class="gd"&gt;- //
&lt;/span&gt;&lt;span class="gi"&gt;+    Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;detach($id);
+    return back();
&lt;/span&gt; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this method, we destroy the many-to-many relationship using the &lt;code&gt;detach()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update the Front end
&lt;/h2&gt;

&lt;p&gt;We’ve created the new routes and controller we now need to add the forms to our front end to send data to them.&lt;/p&gt;

&lt;p&gt;Our forms will live in the new heading component we made for our public profile page.&lt;/p&gt;

&lt;p&gt;Add the following to bottom of the Heading component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import dayjs from 'dayjs';
&lt;span class="gi"&gt;+import PrimaryButton from './PrimaryButton.vue';
+import SecondaryButton from './SecondaryButton.vue';
&lt;/span&gt; import { Link } from '@inertiajs/vue3'
 const props = defineProps(['user']);
 &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
     &amp;lt;div class="bg-white"&amp;gt;
         &amp;lt;div class="max-w-7xl mx-auto pb-1 px-4 sm:px-6 lg:px-8 p-4 sm:py-6 lg:py-8 sm:flex sm:items-center sm:justify-between sm:space-x-5"&amp;gt;
             &amp;lt;div class="flex items-start space-x-5"&amp;gt;
                 &amp;lt;div class="pt-1.5"&amp;gt;
                     &amp;lt;h1 class="text-2xl font-bold text-gray-900 capitalize"&amp;gt;{{ user.name }}&amp;lt;/h1&amp;gt;
                     &amp;lt;p class="text-sm font-medium text-gray-500"&amp;gt;
                    Joined
                        &amp;lt;time :datetime="dayjs(user.created_at).format('YYYY-MM')"&amp;gt;
                        {{ dayjs(user.created_at).format('MMMM YYYY') }}
                        &amp;lt;/time&amp;gt;
                     &amp;lt;/p&amp;gt;
                  &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div v-if="user.id === $page.props.auth.user.id" class="my-3 flex flex-col-reverse justify-stretch sm:mt-0 sm:pr-3"&amp;gt;
                &amp;lt;Link :href="route('profile.edit')" class="inline-flex items-center justify-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150"&amp;gt;Edit Profile&amp;lt;/Link&amp;gt;
            &amp;lt;/div&amp;gt;
&lt;span class="gi"&gt;+           &amp;lt;div v-else class="my-3 flex flex-col-reverse justify-stretch space-y-4 space-y-reverse sm:justify-end sm:space-x-3 sm:space-y-0 sm:mt-0 sm:flex-row sm:pr-3"&amp;gt;
+          &amp;lt;form class="flex flex-col" @submit.prevent="follow.post(route('follow.store'), {
+     preserveScroll: true,
+  })"&amp;gt;
+             &amp;lt;PrimaryButton class="justify-center"&amp;gt;Follow&amp;lt;/Primarybutton&amp;gt;
+         &amp;lt;/form&amp;gt;
+         &amp;lt;form class="flex flex-col" @submit.prevent="unfollow.delete(route('follow.destroy', user.id), {
+            preserveScroll: true,
+    })"&amp;gt;
+           &amp;lt;SecondaryButton class="justify-center" type='submit'&amp;gt;Unfollow&amp;lt;/Secondarybutton&amp;gt;
+        &amp;lt;/form&amp;gt;
+        &amp;lt;/div&amp;gt;
&lt;/span&gt;      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using the v-else directive to conditionally render the forms, as we only want to show them if the profile doesn't belong to the Authenticated user.&lt;/p&gt;

&lt;p&gt;Add new methods the top of the file for the new forms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;
&lt;/span&gt;&amp;lt;script setup&amp;gt;
 import dayjs from 'dayjs';
 import PrimaryButton from './PrimaryButton.vue';
 import SecondaryButton from './SecondaryButton.vue';
 import { Link } from '@inertiajs/vue3'
 const props = defineProps(['user']);
&lt;span class="gi"&gt;+const follow = useForm({
+    id: props.user.id,
+});
+const unfollow = useForm({});
&lt;/span&gt; &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of these methods use &lt;a href="https://inertiajs.com/forms" rel="noopener noreferrer"&gt;inertia’s form helper&lt;/a&gt; to simplify our code&lt;/p&gt;

&lt;p&gt;We are currently rendering both buttons as we have no way of knowing if the authenticated user is following the owner of the profile, we can fix this by checking if the relationship exisits and passing that to the front end.&lt;/p&gt;

&lt;p&gt;Update the profile controller's show method to include a ‘following’ property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; public function show(User $user): Response
 {
     return Inertia::render('Profile/Show',[
         'user' =&amp;gt; $user-&amp;gt;only(['id', 'name', 'created_at']),
         'chirps' =&amp;gt; $user-&amp;gt;chirps()-&amp;gt;latest()-&amp;gt;get()-&amp;gt;map(fn (Chirp $chirp) =&amp;gt; $chirp-&amp;gt;setRelation('user',$user)),
&lt;span class="gi"&gt;+       'following' =&amp;gt; fn() =&amp;gt; Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;where('user_id', $user-&amp;gt;id)-&amp;gt;exists(),
&lt;/span&gt;     ]);
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are querying the many-to-many relationship to see if one exists between the authenticated user and profile owner.&lt;/p&gt;

&lt;p&gt;To pass this data to our heading component, we must first pass it to our Profile/show page, and then pass it down to the Heading component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import AuthenticatedLayout from  '@/Layouts/AuthenticatedLayout.vue';
 import Heading from '@/Components/Heading.vue';
 import Chirp from '@/Components/Chirp.vue';
 import { Head } from '@inertiajs/vue3';
&lt;span class="gd"&gt;-defineProps(['user','chirps']);
&lt;/span&gt;&lt;span class="gi"&gt;+defineProps(['user','chirps', 'following']);
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
     &amp;lt;Head :title="user.name" /&amp;gt;
     &amp;lt;AuthenticatedLayout&amp;gt;
&lt;span class="gd"&gt;-        &amp;lt;Heading :user="user"/&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+        &amp;lt;Heading :user="user" :following="following"/&amp;gt;
&lt;/span&gt;         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
             &amp;lt;div class="mt-6 bg-white shadow-sm rounded-lg divide-y"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now add the property to our heading table and conditionally render the forms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import dayjs from 'dayjs';
 import PrimaryButton from './PrimaryButton.vue';
 import SecondaryButton from './SecondaryButton.vue';
 import { Link } from '@inertiajs/vue3'
&lt;span class="gd"&gt;-const props = defineProps(['user']);
&lt;/span&gt;&lt;span class="gi"&gt;+const props = defineProps(['user', 'following']);
&lt;/span&gt; &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
     &amp;lt;div class="bg-white"&amp;gt;
         &amp;lt;div class="max-w-7xl mx-auto pb-1 px-4 sm:px-6 lg:px-8 p-4 sm:py-6 lg:py-8 sm:flex sm:items-center sm:justify-between sm:space-x-5"&amp;gt;
             &amp;lt;div class="flex items-start space-x-5"&amp;gt;
                 &amp;lt;div class="pt-1.5"&amp;gt;
                     &amp;lt;h1 class="text-2xl font-bold text-gray-900 capitalize"&amp;gt;{{ user.name }}&amp;lt;/h1&amp;gt;
                     &amp;lt;p class="text-sm font-medium text-gray-500"&amp;gt;
                    Joined
                        &amp;lt;time :datetime="dayjs(user.created_at).format('YYYY-MM')"&amp;gt;
                        {{ dayjs(user.created_at).format('MMMM YYYY') }}
                        &amp;lt;/time&amp;gt;
                     &amp;lt;/p&amp;gt;
                  &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div v-if="user.id === $page.props.auth.user.id" class="my-3 flex flex-col-reverse justify-stretch sm:mt-0 sm:pr-3"&amp;gt;
                &amp;lt;Link :href="route('profile.edit')" class="inline-flex items-center justify-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150"&amp;gt;Edit Profile&amp;lt;/Link&amp;gt;
            &amp;lt;/div&amp;gt;
&lt;span class="gi"&gt;+          &amp;lt;form v-if="!following" class="flex flex-col" @submit.prevent="follow.post(route('follow.store'), {
&lt;/span&gt;&lt;span class="gd"&gt;-          &amp;lt;form class="flex flex-col" @submit.prevent="follow.post(route('follow.store'), {
&lt;/span&gt;          preserveScroll: true,
          only:['following']
           })"&amp;gt;
               &amp;lt;PrimaryButton class="justify-center"&amp;gt;Follow&amp;lt;/Primarybutton&amp;gt;
          &amp;lt;/form&amp;gt;
&lt;span class="gi"&gt;+         &amp;lt;form v-else class="flex flex-col" @submit.prevent="unfollow.delete(route('follow.destroy', user.id), {
&lt;/span&gt;&lt;span class="gd"&gt;-         &amp;lt;form class="flex flex-col" @submit.prevent="unfollow.delete(route('follow.destroy', user.id), {
&lt;/span&gt;             preserveScroll: true,
             only:['following']
     })"&amp;gt;
               &amp;lt;SecondaryButton class="justify-center" type='submit'&amp;gt;Unfollow&amp;lt;/Secondarybutton&amp;gt;
             &amp;lt;/form&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the 'following' property; this is all we need to update after the forms are submitted, this is set but adding &lt;code&gt;only:[’following’]&lt;/code&gt; to the forms.&lt;/p&gt;

&lt;p&gt;The profile page now looks like this if the authenticated user follows the profile user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbtxih6mfuz3s44xrrdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbtxih6mfuz3s44xrrdb.png" alt="Profile page with a button to unfollow the user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The profile page now looks like this if the authenticated user does not follow the profile user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysv4b7aflt9a7ip6p5wx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysv4b7aflt9a7ip6p5wx.png" alt="Profile page with a button to follow the user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering Chirps
&lt;/h2&gt;

&lt;p&gt;Our users can now follow each other but it provides no benefit. The first benefit we will add is to allow users to filter chirps so they only see chirps from people they follow.&lt;/p&gt;

&lt;p&gt;To define if the chirps returned by our index method should be filtered, we will add a new 'filter' parameter to our query string.&lt;/p&gt;

&lt;p&gt;So the URL we look like; &lt;a href="http://chirper.test/chirps?filter=false" rel="noopener noreferrer"&gt;http://chirper.test/chirps?filter=false&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This parameter will be a boolean, we’ll update existing links to set ‘filter’ to false in our navigation in Authenticated layout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavLink&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route('chirps.index', { filter: 'false'})&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route().current('chirps.index')&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponsiveNavLink&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route('chirps.index', { filter: 'false'})&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route().current('chirps.index')&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To allow users to set the filter, we will create a new Tabs component. &lt;br&gt;
Each tab will be a link to the same route but one will have the filter parameter set to false, and the other will have it set to true.&lt;/p&gt;

&lt;p&gt;Create a new file at resources/js/components called FilterTabs.vue and add the following code. The design of this component comes from &lt;a href="https://tailwindui.com/components/application-ui/navigation/tabs#component-83b472fc38b57e49a566805a5e5bb2f7" rel="noopener noreferrer"&gt;Tailwind UI&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"isolate flex divide-x mt-6 divide-gray-200 rounded-lg shadow overflow-hidden"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Tabs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt;
            &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"route('chirps.index', &lt;/span&gt;{ filter: 'false'})"
            :only="['chirps']"
            :class="[route().current('chirps.index', { filter: 'false'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700','group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
            :aria-current="route().current('chirps.index', { filter: 'false'}) ? 'page' : undefined"&amp;gt;
            &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt; All &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"[route().current('chirps.index', &lt;/span&gt;{ filter: 'false'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
        &lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt;
            &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"route('chirps.index', &lt;/span&gt;{ filter: 'true'})"
            :only="['chirps']"
            :class="[route().current('chirps.index', { filter: 'true'}) ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700', 'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10']"
            :aria-current="route().current('chirps.index', { filter: 'true'}) ? 'page' : undefined"&amp;gt;
            &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Following &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"[route().current('chirps.index', &lt;/span&gt;{ filter: 'true'}) ? 'bg-indigo-500' : 'bg-transparent', 'absolute inset-x-0 bottom-0 h-0.5']" /&amp;gt;
        &lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using &lt;code&gt;only&lt;/code&gt; on our links so only the Chirps are refreshed.&lt;/p&gt;

&lt;p&gt;Add our new component  above out chirps to the Chirps/index page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
 import AuthenticatedLayout from  '@/Layouts/AuthenticatedLayout.vue';
 import Chirp from '@/Components/Chirp.vue';
 import InputError from '@/Components/InputError.vue';
 import PrimaryButton from '@/Components/PrimaryButton.vue';
&lt;span class="gi"&gt;+import FilterTabs from '@/Components/FilterTabs.vue';
&lt;/span&gt;&lt;span class="p"&gt;import { useForm, Head } from '@inertiajs/vue3';
defineProps(['chirps']);
const form = useForm({
&lt;/span&gt;    message: '',
});
 &amp;lt;/script&amp;gt;
 &amp;lt;template&amp;gt;
     &amp;lt;Head title="Chirps" /&amp;gt;
     &amp;lt;AuthenticatedLayout&amp;gt;
         &amp;lt;div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&amp;gt;
             &amp;lt;form @submit.prevent="form.post(route('chirps.store'), { onSuccess: () =&amp;gt; form.reset() })"&amp;gt;
                 &amp;lt;textarea
                     v-model="form.message"
                     placeholder="What's on your mind?"
                     class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm"
                 &amp;gt;&amp;lt;/textarea&amp;gt;
                 &amp;lt;InputError :message="form.errors.message" class="mt-2" /&amp;gt;
                 &amp;lt;PrimaryButton class="mt-4"&amp;gt;Chirp&amp;lt;/PrimaryButton&amp;gt;
             &amp;lt;/form&amp;gt;
&lt;span class="gi"&gt;+            &amp;lt;FilterTabs/&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have a link with the filter parameters set to true. In the ChirpController, we will conditionally filter the chirps when the filter is true. Update the index method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-public function index(): Response
&lt;/span&gt;&lt;span class="gi"&gt;+public function index(Request $request): Response
&lt;/span&gt; {
     return Inertia::render('Chirps/Index', [
&lt;span class="gd"&gt;-       'chirps' =&amp;gt; Chirp::with('user:id,name')-&amp;gt;latest()-&amp;gt;get(),
&lt;/span&gt;&lt;span class="gi"&gt;+       'chirps' =&amp;gt; Chirp::with('user:id,name')
+       -&amp;gt;when($request-&amp;gt;input('filter') === 'true', fn($q) =&amp;gt;
+           $q-&amp;gt;whereIn(
+               'user_id',
+                Auth()-&amp;gt;user()-&amp;gt;follows-&amp;gt;pluck('id')
+                -&amp;gt;merge(Auth()-&amp;gt;id())
+           )
+       )
+       -&amp;gt;latest()
+       -&amp;gt;get(),
&lt;/span&gt;    ]);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the filter is true, we use a subquery so we only fetch the chirps where the user_id matches one of those in the follows() relationship, we then merge the request users id to so their chirps are also fetched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Events and listeners
&lt;/h2&gt;

&lt;p&gt;During the bootcamp you created an event and corresponding listener to send a notification when a chirp was created. The listener sent a notification to all users, as advised in the bootcamp we will now update the listener to only send the notification to those who follow the chirps author.&lt;/p&gt;

&lt;p&gt;Update the send chirp listener.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function handle(ChirpCreated $event): void
&lt;/span&gt;{
&lt;span class="gd"&gt;-   foreach (User::whereNot('id', $event-&amp;gt;chirp-&amp;gt;user_id)-&amp;gt;cursor() as $user) {
&lt;/span&gt;&lt;span class="gi"&gt;+   foreach (User::whereIn('id', $event-&amp;gt;chirp-&amp;gt;user-&amp;gt;followers-&amp;gt;pluck('id'))-&amp;gt;cursor() as $user) {
&lt;/span&gt;        $user-&amp;gt;notify(new NewChirp($event-&amp;gt;chirp));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than filtering out the author of the chirp, we are filtering out users if they do not follow the chirp's author.&lt;/p&gt;

&lt;p&gt;Users may also wish to be notified if they receive a new follower. We will create a new event, listener and notification. &lt;/p&gt;

&lt;p&gt;Create a new event with the command &lt;code&gt;php artisan make:event UserFollowed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create a new Listener with the command &lt;code&gt;php artisan make:listener SendNewFollowerNotifications&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will update the FollowController's store method to dispatch our new event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+use App\Events\UserFollowed;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; public function store(Request $request): RedirectResponse
 {
 $validated = $request-&amp;gt;validate([
     'id' =&amp;gt; [
          'required',
          'integer',
          'numeric',
          Rule::notIn([Auth()-&amp;gt;id()]),
          'exists:users,id'
      ]
 ]);
&lt;span class="err"&gt;
&lt;/span&gt; Auth()-&amp;gt;user()-&amp;gt;follows()-&amp;gt;attach($validated['id']);
&lt;span class="err"&gt;
&lt;/span&gt; $following = User::findOrFail($validated['id']);
&lt;span class="gi"&gt;+UserFollowed::dispatch($following, Auth()-&amp;gt;user());
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; return back();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to update the Event Service provider to register our new event and listener.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; namespace App\Providers;
 use App\Events\ChirpCreated;
&lt;span class="gi"&gt;+use App\Events\UserFollowed;
&lt;/span&gt; use App\Listeners\SendChirpCreatedNotifications;
&lt;span class="gi"&gt;+use App\Listeners\SendNewFollowerNotifications;
&lt;/span&gt; use Illuminate\Auth\Events\Registered;
 use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
 use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
 use Illuminate\Support\Facades\Event;
 class EventServiceProvider extends ServiceProvider
 {
     /**
      * The event to listener mappings for the application.
      *
      * @var array&amp;lt;class-string, array&amp;lt;int, class-string&amp;gt;&amp;gt;
      */
     protected $listen = [
         ChirpCreated::class =&amp;gt; [
             SendChirpCreatedNotifications::class,
         ],
&lt;span class="gi"&gt;+        UserFollowed::class =&amp;gt; [
+            SendNewFollowerNotifications::class,
+        ],
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;         Registered::class =&amp;gt; [
             SendEmailVerificationNotification::class,
         ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new userFollowed event accepts two variables, the user the authenticated user is now following, and the authenticated user. &lt;/p&gt;

&lt;p&gt;Update the UserFollowed Event to accept the variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Broadcasting\Channel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Broadcasting\InteractsWithSockets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Broadcasting\PresenceChannel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Broadcasting\PrivateChannel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Broadcasting\ShouldBroadcast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Events\Dispatchable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Queue\SerializesModels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFollowed&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dispatchable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InteractsWithSockets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SerializesModels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Create a new event instance.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Get the channels the event should broadcast on.
     *
     * @return array&amp;lt;int, \Illuminate\Broadcasting\Channel&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;broadcastOn&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrivateChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'channel-name'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the SendNewFollowerNotifications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Listeners&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\UserFollowed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Notifications\NewFollower&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Contracts\Queue\ShouldQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Queue\InteractsWithQueue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendNewFollowerNotifications&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ShouldQueue&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Create the event listener.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Handle the event.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UserFollowed&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NewFollower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follower&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the handle method, we are passing the new follower (the request user) to a new notification and sending it to the newly followed user, as with the event listener created in the Bootcamp this listener implements ShouldQueue.&lt;/p&gt;

&lt;p&gt;Create a new notification with the command &lt;code&gt;php artisan make:notification NewFollower&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command will create a new file in the App/Notifications directory.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;toMail()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;toMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="nv"&gt;$notifiable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;MailMessage&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MailMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'You have a new follower'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follower&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; started following you"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'View their profile'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follower&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Thank you for using our application!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you now follow an account, you should see an email in your test client. I am using &lt;a href="https://usehelo.com/?utm_source=website&amp;amp;utm_medium=web&amp;amp;utm_campaign=bc-hero" rel="noopener noreferrer"&gt;Helo From BeyondCode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll7q43z5l9b2sbqlz2zi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll7q43z5l9b2sbqlz2zi.png" alt="Screenshot of email in Helo from Beyond code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;If we run our full test suite with &lt;code&gt;php artisan test&lt;/code&gt; you will find our test for the sending notifications to all users when a new chirp is created fails due to our code changes, so lets update this test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-public function test_notification_is_sent_to_all_but_chirp_creator()
&lt;/span&gt;&lt;span class="gi"&gt;+public function test_notifications_are_only_sent_to_users_who_follow_author()
&lt;/span&gt; {
    Notification::fake();
&lt;span class="gd"&gt;-   $users = User::factory(2)-&amp;gt;create();
&lt;/span&gt;&lt;span class="gi"&gt;+   $user = User::factory()-&amp;gt;create();
&lt;/span&gt;&lt;span class="gd"&gt;-   $chirp = Chirp::factory()-&amp;gt;create();
&lt;/span&gt;&lt;span class="gi"&gt;+   $followers = User::factory(2)-&amp;gt;create();
+   $nonFollower = User::factory()-&amp;gt;create();
+   $user-&amp;gt;followers()-&amp;gt;attach($followers-&amp;gt;pluck('id'));
+   Chirp::factory()
+        -&amp;gt;for($user)
+        -&amp;gt;create();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    Notification::assertSentTo(
&lt;span class="gd"&gt;-       [$users], NewChirp::class
&lt;/span&gt;&lt;span class="gi"&gt;+       [$followers], NewChirp::class
&lt;/span&gt;    );
&lt;span class="err"&gt;
&lt;/span&gt;    Notification::assertNotSentTo(
&lt;span class="gd"&gt;-       [$chirp-&amp;gt;user], NewChirp::class
&lt;/span&gt;&lt;span class="gi"&gt;+       [$user, $nonFollower], NewChirp::class
&lt;/span&gt;    );
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now attaching followers to the chirp author, and then testing the notification is sent to them.&lt;/p&gt;

&lt;p&gt;Although the rest of our tests didn’t break we should update and expand them to correspond with our code changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Chirp Controller Test
&lt;/h3&gt;

&lt;p&gt;We updated our chirp controller to optionally filter the chirps, let's create a test for that.&lt;/p&gt;

&lt;p&gt;Add this test to your chirpcontrollertest.php file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_only_chirps_by_people_the_user_follows_are_returned_if_filter_is_true&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasAttached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="p"&gt;,[],&lt;/span&gt;&lt;span class="s1"&gt;'follows'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$nonFollowedChirps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'filter'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chirps/Index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;chirps&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are testing that the only chirp returned to our page is the one that was created by an author our test user follows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Profile Test
&lt;/h3&gt;

&lt;p&gt;In our profile test file, we have two tests that assert against the properties that are included in our inertia response, both of these tests need updating so the new ‘following’ property is included.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function test_chirps_belonging_to_profile_owner_are_included(): void
&lt;/span&gt;{
    $user = User::factory()
                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;    $profileUser = User::factory()
                -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;    $this-&amp;gt;actingAs($user)
        -&amp;gt;get(route('profile.show',$profileUser-&amp;gt;id))
        -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
            -&amp;gt;component('Profile/Show')
            -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                -&amp;gt;where('id', $profileUser-&amp;gt;id)
                -&amp;gt;where('name', $profileUser-&amp;gt;name)
                -&amp;gt;missing('email')
                -&amp;gt;missing('password')
                -&amp;gt;etc()
            )
            -&amp;gt;has('chirps', 5, fn (Assert $page) =&amp;gt; $page
                -&amp;gt;where('id', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;id)
                -&amp;gt;where('message', $profileUser-&amp;gt;chirps()-&amp;gt;first()-&amp;gt;message)
                -&amp;gt;etc()
                -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                    -&amp;gt;where('id', $profileUser-&amp;gt;id)
                    -&amp;gt;etc()
                )
            )
&lt;span class="gi"&gt;+           -&amp;gt;has('following')
&lt;/span&gt;    );
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;public function test_chirps_belonging_to_other_uses_are_not_included(): void
&lt;/span&gt;{
    $user = User::factory()
                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;    $otherUser = User::factory()
                -&amp;gt;has(Chirp::Factory()-&amp;gt;count(5))
                -&amp;gt;create();
&lt;span class="err"&gt;
&lt;/span&gt;    $this-&amp;gt;actingAs($user)
        -&amp;gt;get(route('profile.show',$user-&amp;gt;id))
        -&amp;gt;assertInertia(fn (Assert $page) =&amp;gt; $page
            -&amp;gt;component('Profile/Show')
            -&amp;gt;has('user', fn (Assert $page) =&amp;gt; $page
                -&amp;gt;where('id', $user-&amp;gt;id)
                -&amp;gt;where('name', $user-&amp;gt;name)
                -&amp;gt;missing('email')
                -&amp;gt;missing('password')
                -&amp;gt;etc()
            )
            -&amp;gt;has('chirps',0)
&lt;span class="gi"&gt;+           -&amp;gt;has('following')
&lt;/span&gt;        );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create FollowController Tests
&lt;/h3&gt;

&lt;p&gt;To create our test file run the command &lt;code&gt;php artisan make:test Controllers/FollowControllerTest&lt;/code&gt; and update the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\UserFollowed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\RefreshDatabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\WithFaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FollowControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_users_can_follow_each_other&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertContains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follows&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_followed_event_is_dispatched&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertDispatched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UserFollowed&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follower&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_must_be_logged_in_before_following&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_must_be_verified_before_following&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unverified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verification.notice'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_id_required&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The id field is required.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_id_must_be_a_number&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The id field must be an integer.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The id field must be a number.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_id_must_not_be_request_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The selected id is invalid.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_id_must_belong_to_existing_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The selected id is invalid.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_users_can_unfollow_each_other&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.destroy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertNotContains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$following&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;follows&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;pluck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_must_be_logged_in_to_unfollow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$following&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.destroy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_must_be_verified_to_unfollow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unverified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'follow.destroy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verification.notice'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test our new listener
&lt;/h3&gt;

&lt;p&gt;We have tested the new event is dispatched in the followControllerTest file, but now we need to test the new SendNewFollowerNotifications listener.&lt;/p&gt;

&lt;p&gt;To create the test file use the command &lt;code&gt;php artisan make:test Listeners/SendNewFollowerNotificationsTest&lt;/code&gt;. We will add two tests to our new file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Listeners&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\UserFollowed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Listeners\SendNewFollowerNotifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Notifications\NewFollower&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\RefreshDatabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\WithFaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Notification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendNewFollowerNotificationsTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_listener_is_attached_to_event&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertListening&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;UserFollowed&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;SendNewFollowerNotifications&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_notification_is_sent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$follower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserFollowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;New&lt;/span&gt; &lt;span class="nc"&gt;SendNewFollowerNotifications&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$listener&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertSentTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NewFollower&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are first testing that we have connected the event and listener. We are then testing that our listener notifies the appropriate user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the notification
&lt;/h3&gt;

&lt;p&gt;We are going to test the contents of the mail notification.&lt;/p&gt;

&lt;p&gt;To create the test file use the command &lt;code&gt;php artisan make:test Notifications/NewFollowerTest&lt;/code&gt; Add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Notifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Notifications\NewFollower&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\RefreshDatabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Testing\WithFaker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Mail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Notification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NewFollowerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * A basic feature test example.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_mail_contents&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

       &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="nv"&gt;$follower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NewFollower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertSentTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NewFollower&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nv"&gt;$mailNotification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$notification&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toMail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; started following you"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailNotification&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'View their profile'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailNotification&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;actionText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$follower&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;$mailNotification&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;actionUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the test we are asserting the contents of the mail notification are as we expect, specifically the section that uses the followers data.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Chirp Beyond (Bootcamp) part 2 public profile</title>
      <dc:creator>Silver343</dc:creator>
      <pubDate>Fri, 06 Oct 2023 14:31:08 +0000</pubDate>
      <link>https://forem.com/silver343/chirp-beyond-bootcamp-part-2-public-profile-304h</link>
      <guid>https://forem.com/silver343/chirp-beyond-bootcamp-part-2-public-profile-304h</guid>
      <description>&lt;p&gt;The first new feature we are going to tackle is a public profile page for users.&lt;/p&gt;

&lt;p&gt;On this page, we should only be able to see Chirps the profile owner has created.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Route
&lt;/h2&gt;

&lt;p&gt;To start we will add a new route in the web.php file. There are already routes for updating and deleting the user profile so we can add our new route for showing it there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;Route::middleware('auth')-&amp;gt;group(function () {
&lt;/span&gt;    Route::get('/profile', [ProfileController::class, 'edit'])-&amp;gt;name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])-&amp;gt;name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])-&amp;gt;name('profile.destroy');
&lt;span class="gi"&gt;+   Route::get('/users/{user}', [ProfileController::class, 'show'])-&amp;gt;middleware('verified')-&amp;gt;name('profile.show');
&lt;/span&gt;&lt;span class="err"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note we have added an extra middleware to our new route as we only want the public profiles to be accessible to users who have verified their email address.&lt;/p&gt;

&lt;p&gt;We must also update our user model to implement MustVerifyEmail to use the middleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- //use Illuminate\Contracts\Auth\MustVerifyEmail;
&lt;/span&gt;&lt;span class="gi"&gt;+ use Illuminate\Contracts\Auth\MustVerifyEmail;
&lt;/span&gt;  use Illuminate\Database\Eloquent\Relations\HasMany;
  use Illuminate\Database\Eloquent\Factories\HasFactory;
  use Illuminate\Foundation\Auth\User as Authenticatable;
  use Illuminate\Notifications\Notifiable;
  use Laravel\Sanctum\HasApiTokens;

+class User extends Authenticatable implements MustVerifyEmail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll notice the &lt;code&gt;{user}&lt;/code&gt; in our new route, this is a route parameter, with this parameter we will inject the id of the user whose profile we wish to show, Laravel provides a convenient way to do this via &lt;a href="https://laravel.com/docs/10.x/routing#route-model-binding"&gt;route model binding.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New method in the Profile Controller
&lt;/h2&gt;

&lt;p&gt;In the Profile controller, we will add a new show method. We want to pass the user model and their Chirps to a new Vue component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Inertia&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Profile/Show'&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;
            &lt;span class="s1"&gt;'user'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;only&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'created_at'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="s1"&gt;'chirps'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;chirps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;latest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Chirp&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setRelation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the setRelation on each of the users chirps to manually set the chirps author, this allows us to avoid loading the user for each chirp avoiding a n+1 problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Profile show page
&lt;/h2&gt;

&lt;p&gt;In our controller above, we are passing our user and chirps to a new Vue component, which we now need to create.&lt;/p&gt;

&lt;p&gt;Create a Vue file at resources/js/Pages/Profile and name it Show.vue.&lt;/p&gt;

&lt;p&gt;Add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AuthenticatedLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Layouts/AuthenticatedLayout.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Heading&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Components/Heading.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Chirp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/Components/Chirp.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chirps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Head&lt;/span&gt; &lt;span class="na"&gt;:title=&lt;/span&gt;&lt;span class="s"&gt;"user.name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;AuthenticatedLayout&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Heading&lt;/span&gt; &lt;span class="na"&gt;:user=&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-6 bg-white shadow-sm rounded-lg divide-y"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Chirp&lt;/span&gt;
                    &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"chirp in chirps"&lt;/span&gt;
                    &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"chirp.id"&lt;/span&gt;
                    &lt;span class="na"&gt;:chirp=&lt;/span&gt;&lt;span class="s"&gt;"chirp"&lt;/span&gt;
                &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/AuthenticatedLayout&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using the Authenticated Layout included with breeze in addition to the Chirp component you created in the bootcamp.&lt;/p&gt;

&lt;p&gt;There is a new Heading component above the chirps, which we will create now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the new heading component
&lt;/h2&gt;

&lt;p&gt;To create the new heading component, create a new Vue file at resources/js/components and save it as Heading.vue. Add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dayjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@inertiajs/vue3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max-w-7xl mx-auto pb-1 px-4 sm:px-6 lg:px-8 p-4 sm:py-6 lg:py-8 sm:flex sm:items-center sm:justify-between sm:space-x-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex items-start space-x-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pt-1.5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold text-gray-900 capitalize"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-sm font-medium text-gray-500"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    Joined
                    &lt;span class="nt"&gt;&amp;lt;time&lt;/span&gt; &lt;span class="na"&gt;:datetime=&lt;/span&gt;&lt;span class="s"&gt;"dayjs(user.created_at).format('YYYY-MM')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;dayjs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MMMM YYYY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"user.id === $page.props.auth.user.id"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"my-3 flex flex-col-reverse justify-stretch sm:mt-0 sm:pr-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;Link&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"route('profile.edit')"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inline-flex items-center justify-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit Profile&lt;span class="nt"&gt;&amp;lt;/Link&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This heading is based on this on included with &lt;a href="https://tailwindui.com/components/application-ui/headings/page-headings#component-ab799a0b48c911854636f6e31cb28915"&gt;Tailwind UI&lt;/a&gt;&lt;br&gt;
We have removed the avatar, and we only have one action.&lt;/p&gt;

&lt;p&gt;We are using the day.js library to format the user's created_at field to show the month and year they created their account.&lt;/p&gt;

&lt;p&gt;If a user is visiting their own profile the component renders a link to allow them to edit it, this uses the included profile.edit route included with breeze.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lQ31cKrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjbu83svq82bo8bfybze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lQ31cKrD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bjbu83svq82bo8bfybze.png" alt="Screenshot of the new profile page" width="800" height="1023"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How do we visit profiles?
&lt;/h2&gt;

&lt;p&gt;We have created our new profile page, but it is only reachable by manually updating the URL.&lt;/p&gt;

&lt;p&gt;We will add two ways to navigate to the profile screen, one in the chirp component to view the profile of the chirps author and one in the settings dropdown to allow users to view their own profile.&lt;/p&gt;

&lt;p&gt;Update your Chirp component like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;script setup&amp;gt;
&lt;span class="p"&gt;import Dropdown from '@/Components/Dropdown.vue';
import DropdownLink from '@/components/DropdownLink.vue';
import InputError from '@/Components/InputError.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
&lt;/span&gt;&lt;span class="gd"&gt;-import { useForm } from '@inertiajs/vue3';
&lt;/span&gt;&lt;span class="gi"&gt;+import { Link, useForm } from '@inertiajs/vue3';
&lt;/span&gt;&lt;span class="p"&gt;import { ref } from 'vue';
dayjs.extend(relativeTime);
&lt;/span&gt;        &amp;lt;div class="flex-1"&amp;gt;
            &amp;lt;div class="flex justify-between items-center"&amp;gt;
                &amp;lt;div&amp;gt;
&lt;span class="gd"&gt;-                    &amp;lt;span class="text-gray-800"&amp;gt;{{ chirp.user.name }}&amp;lt;/span&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+                    &amp;lt;Link :href="route('profile.show', chirp.user.id)" class="text-gray-800 hover:text-gray-500 hover:underline focus:text-gray-500 active:text-gray-900 capitalize"&amp;gt;{{ chirp.user.name }}&amp;lt;/Link&amp;gt;
&lt;/span&gt;                    &amp;lt;small class="ml-2 text-sm text-gray-600"&amp;gt;{{ dayjs(chirp.created_at).fromNow() }}&amp;lt;/small&amp;gt;
                    &amp;lt;small v-if="chirp.created_at !== chirp.updated_at" class="text-sm text-gray-600"&amp;gt; &amp;amp;middot; edited&amp;lt;/small&amp;gt;
                &amp;lt;/div&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have updated the HTML element containing the chirps author name from a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; to an Inertia.js Link. This link navigates to the profile page and uses the chirps authors ID as a parameter.&lt;/p&gt;

&lt;p&gt;To update the included settings dropdown, open the authenticated Layout component at resources/js/Layouts.&lt;/p&gt;

&lt;p&gt;Update the primary navigation dropdown like so from line 70.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;template #content&amp;gt;
&lt;span class="gd"&gt;-   &amp;lt;DropdownLink :href="route('profile.edit')"&amp;gt; Profile  &amp;lt;/DropdownLink&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+   &amp;lt;DropdownLink :href="route('profile.show', $page.props.auth.user.id)"&amp;gt; View Profile &amp;lt;/DropdownLink&amp;gt;
+   &amp;lt;DropdownLink :href="route('profile.edit')"&amp;gt; Edit Profile &amp;lt;/DropdownLink&amp;gt;
&lt;/span&gt;    &amp;lt;DropdownLink :href="route('logout')" method="post" as="button"&amp;gt;
    Log Out
    &amp;lt;/DropdownLink&amp;gt;
 &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t forget the mobile navigation at line 136, which you can update like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;div class="mt-3 space-y-1"&amp;gt;
&lt;span class="gd"&gt;-   &amp;lt;ResponsiveNavLink :href="route('profile.edit')"&amp;gt; Profile &amp;lt;/ResponsiveNavLink&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+   &amp;lt;ResponsiveNavLink :href="route('profile.show', $page.props.auth.user.id)"&amp;gt; Show Profile &amp;lt;/ResponsiveNavLink&amp;gt;
+   &amp;lt;ResponsiveNavLink :href="route('profile.edit')"&amp;gt; Edit Profile &amp;lt;/ResponsiveNavLink&amp;gt;
&lt;/span&gt;    &amp;lt;ResponsiveNavLink :href="route('logout')" method="post" as="button"&amp;gt;
    Log Out
    &amp;lt;/ResponsiveNavLink&amp;gt;
 &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing our new feature
&lt;/h2&gt;

&lt;p&gt;We need to test the public profile page renders and only include Chirps that belong to the owner of the profile page.&lt;/p&gt;

&lt;p&gt;You'll find that there are already tests for the user profile at tests/Feature/ProfileTest.php. I have moved this file to match the Chirp Controller tests created in the previous part to tests/Feature/Controllers.&lt;/p&gt;

&lt;p&gt;In your test file add the following test methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_public_profile_is_displayed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
       &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_users_must_be_verified_to_view_profiles&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unverified&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$profileUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'verification.notice'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirps_belonging_to_profile_owner_are_included&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$profileUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
               &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Profile/Show'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
               &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;chirps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;chirps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$profileUser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirps_belonging_to_other_uses_are_not_included&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$otherUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'profile.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Profile/Show'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first test, we visit a public profile page and assert a 200 'ok' response is returned. &lt;/p&gt;

&lt;p&gt;In the second test, we are asserting only a verified user can view a public profile.&lt;/p&gt;

&lt;p&gt;In the third and fourth tests, we are testing that the only chirps on the page are those which belong to the profile owner, by asserting against the props available in the Vue component.&lt;/p&gt;

&lt;p&gt;Find out more about testing with &lt;a href="https://inertiajs.com/testing"&gt;Inertia.js&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>beginners</category>
      <category>php</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Chirp Beyond (Bootcamp) part 1 The missing tests</title>
      <dc:creator>Silver343</dc:creator>
      <pubDate>Tue, 12 Sep 2023 16:59:56 +0000</pubDate>
      <link>https://forem.com/silver343/chirp-beyond-bootcamp-part-1-the-missing-tests-k51</link>
      <guid>https://forem.com/silver343/chirp-beyond-bootcamp-part-1-the-missing-tests-k51</guid>
      <description>&lt;p&gt;Welcome to Chirp Beyond (Bootcamp). This series of guides is just some of the ways you can extend and adapt Chirp the app created in the &lt;a href="https://bootcamp.laravel.com"&gt;Laravel bootcamp.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These guides will follow on from the &lt;a href="https://bootcamp.laravel.com/inertia/installation"&gt;Inertia.js path in the Laravel bootcamp.&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Tests
&lt;/h1&gt;

&lt;p&gt;To test the code you created in the Laravel Bootcamp we will use PHPUnit a testing framework for PHP which Laravel provided built-in support, additionally, both &lt;a href="https://laravel.com/docs/10.x/testing"&gt;Laravel&lt;/a&gt; and &lt;a href="https://inertiajs.com/testing"&gt;inertia.js&lt;/a&gt; provide testing helpers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Tests
&lt;/h2&gt;

&lt;p&gt;Use the command &lt;code&gt;php artisan test&lt;/code&gt; in your terminal to run the existing test suite.&lt;/p&gt;

&lt;p&gt;A total of 24 tests should run all passing.&lt;/p&gt;

&lt;p&gt;You will notice that any users and chirps you created whilst developing Chirp are now gone, this is because when testing we are using the same database as the local version of the app. We can solve this by updating the phpunit.xml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;
  &amp;lt;env name="APP_ENV" value="testing"/&amp;gt;
  &amp;lt;env name="BCRYPT_ROUNDS" value="4"/&amp;gt;
  &amp;lt;env name="CACHE_DRIVER" value="array"/&amp;gt;
&lt;span class="gd"&gt;- &amp;lt;!-- &amp;lt;env name="DB_CONNECTION" value="sqlite"/&amp;gt; --&amp;gt;
- &amp;lt;!-- &amp;lt;env name="DB_DATABASE" value=":memory:"/&amp;gt; --&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;lt;env name="DB_CONNECTION" value="sqlite"/&amp;gt;
+ &amp;lt;env name="DB_DATABASE" value="./database/test.sqlite"/&amp;gt;
+ &amp;lt;env name="DB_FOREIGN_KEYS" value="true"/&amp;gt;
&lt;/span&gt;  &amp;lt;env name="MAIL_MAILER" value="array"/&amp;gt;
  &amp;lt;env name="QUEUE_CONNECTION" value="sync"/&amp;gt;
  &amp;lt;env name="SESSION_DRIVER" value="array"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Factories
&lt;/h2&gt;

&lt;p&gt;Before creating any new tests, we need to create model factories. Factories allow our application to create model resources using predefined data. This data is often fake data supplied via a package called fakerphp/faker.&lt;/p&gt;

&lt;p&gt;To create a Chirp factory run the command &lt;code&gt;php artisan make:factory ChirpFactory&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The newly created Chirp factory can be found inside the database/factories directory.&lt;/p&gt;

&lt;p&gt;Inside the factory, we need to update the &lt;code&gt;definition()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;public function definition(): array
&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
    return [
&lt;span class="gd"&gt;-     //
&lt;/span&gt;&lt;span class="gi"&gt;+     'message' =&amp;gt; fake()-&amp;gt;paragraph(),
+     'user_id' =&amp;gt; User::Factory()
&lt;/span&gt;    ];
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see factories can be used inside other factories, here we are using the user factory included by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Base Test Case
&lt;/h2&gt;

&lt;p&gt;The tests we will be creating will extend the base test case found inside the tests directory.&lt;/p&gt;

&lt;p&gt;We will update the test case to use &lt;code&gt;LazilyRefreshDatabase&lt;/code&gt;, this will allow our database to be refreshed between tests if needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; &amp;lt;?php

 namespace Tests;

 use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
&lt;span class="gi"&gt;+use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
&lt;/span&gt;
abstract class TestCase extends BaseTestCase
&lt;span class="err"&gt;{&lt;/span&gt;

&lt;span class="gd"&gt;-    use CreatesApplication;
&lt;/span&gt;&lt;span class="gi"&gt;+    use CreatesApplication, LazilyRefreshDatabase;
&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test Structure.
&lt;/h2&gt;

&lt;p&gt;I tend to structure my test files in a similar way to my application files. This not only helps me determine where tests should reside, but can also make it easier to find tests in the future.&lt;/p&gt;

&lt;p&gt;During the creation of Chirper, we created several files that require testing. These files are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Events/ChirpCreated.php&lt;/li&gt;
&lt;li&gt;Http/Controllers/ChirpController.php&lt;/li&gt;
&lt;li&gt;Listeners/SendChirpNotifications.php&lt;/li&gt;
&lt;li&gt;Policies/ChirpPolicy.php&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Tests
&lt;/h2&gt;

&lt;p&gt;We will begin by testing ChirpPolicy.php.&lt;/p&gt;

&lt;p&gt;To create a test class, we can use the command &lt;code&gt;php artisan make:test Policies/ChirpPolicyTest&lt;/code&gt;, the newly created test can be found in tests/Feature/Policies.&lt;/p&gt;

&lt;p&gt;We need to test four aspects of the ChirpPolicy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The update method returns true if the user is the chirps author.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The update method returns false if the user is not the chirps author.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The delete method returns true if the user is the chirps author.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The delete method returns false if the user is not the chirps author.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Policies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Chirp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChirpPolicyTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_policy_returns_true_if_chirp_to_be_updated_belongs_to_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_policy_returns_false_if_chirp_to_be_updated_does_not_belongs_to_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_policy_returns_true_if_chirp_to_be_deleted_belongs_to_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'delete'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_policy_returns_false_if_chirp_to_be_deleted_does_not_belongs_to_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;can&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Chirp Controller Test
&lt;/h3&gt;

&lt;p&gt;The next set of tests we will create will be for the Chirp Controller. To begin, we will create the test file using the command &lt;code&gt;php artisan make:test Controllers/ChirpControllerTest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The test file will be created in tests/Feature/Controllers.&lt;/p&gt;

&lt;p&gt;The ChirpController has four methods we need to test, not only do we need to test the expected (happy) path but also ensure the app handles errors and unexpected events correctly, therefore the majority of the tests are testing the validation rules used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Controllers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Chirp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Inertia\Testing\AssertableInertia&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChirpControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_user_is_redirected_from_index_if_not_logged_in&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_index_returns_200&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;makeOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertOk&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_index_has_chirps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chirps/Index'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Assert&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$page&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_new_chirp_can_be_created&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_new_chirp_must_have_message&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.store'&lt;/span&gt;&lt;span class="p"&gt;),[]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field is required.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_new_chirp_message_must_be_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field must be a string.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_new_chirp_message_must_be_less_than_255_characters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field must not be greater than 255 characters.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirp_can_be_updated&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_updated_chirp_must_have_message&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),[]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field is required.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_updated_chirp_message_must_be_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field must be a string.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_updated_chirp_message_must_be_less_than_255_characters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSessionHasErrors&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'The message field must not be greater than 255 characters.'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirp_cannot_be_updated_by_non_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$wrongUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$wrongUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.update'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertForbidden&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirp_can_be_deleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.destroy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.index'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirp_cannot_be_delete_by_non_owner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$wrongUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$wrongUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.destroy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertForbidden&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertDatabaseCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chirps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests cover a range of functionality, including checking that users are redirected if not logged in, that chirps can be created, updated, and deleted, and that validation rules are enforced for chirp messages. The tests also check that only the owner of a chirp can update or delete it.&lt;/p&gt;

&lt;p&gt;To learn more about testing with Inertia.js, you can visit the &lt;a href="https://inertiajs.com/testing"&gt;official documentation.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Chirp Created Event Test
&lt;/h3&gt;

&lt;p&gt;To create the tests for the ChirpCreated event use the command &lt;code&gt;php artisan:make Events/ChirpCreatedTest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create our test file tests/Feature/Events/ChirpCreatedTest.php which we will update like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\ChirpCreated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChirpCreatedtest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * A basic feature test example.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_chirp_created_event_is_dispatched&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;actingAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'chirps.store'&lt;/span&gt;&lt;span class="p"&gt;),[&lt;/span&gt;&lt;span class="s1"&gt;'message'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'test new message'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertDispatched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChirpCreated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this single test we are ensuring that the event is dispatched when a chirp is created, you will see we are using  &lt;code&gt;Event::fake();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This allows us to prevent any listeners from executing and assert against our events, you can find more about this at the &lt;a href="https://laravel.com/docs/10.x/events#scoped-event-fakes"&gt;Laravel docs.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Send Chirp Created Notifications Test
&lt;/h3&gt;

&lt;p&gt;Create the test class for our listener using the command &lt;code&gt;php artisan make:test Listeners/SendChirpCreatedNotificationsTest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will update the new test class at tests/feature/Listeners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Feature\Listeners&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\ChirpCreated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Listeners\SendChirpCreatedNotifications&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Chirp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Notifications\NewChirp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Notification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendChirpCreatedNotificationsTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * A basic feature test example.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_listining_for_chirp_created_event&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertListening&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;ChirpCreated&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;SendChirpCreatedNotifications&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_notification_is_sent_to_all_but_chirp_creator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;fake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$chirp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Chirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertSentTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;NewChirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertNotSentTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$chirp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nc"&gt;NewChirp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are again using Event::fake() to create assertions, this time we are asserting that our listener is attached to the ChirpCreated Event.&lt;/p&gt;

&lt;p&gt;In the second test we are using Notification::fake(), this allows us to assert if and to who the notifications were sent. &lt;a href="https://laravel.com/docs/10.x/mocking#notification-fake"&gt;read more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have now created all the tests for the Chirper application. These tests cover the Chirp Policy, Chirp Controller, and ChirpCreated event. We also tested the listener responsible for sending notifications when a new chirp is created. With these tests, we can be confident that our application is working as expected.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>laravel</category>
      <category>php</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
