<?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: Mary</title>
    <description>The latest articles on Forem by Mary (@sifrious).</description>
    <link>https://forem.com/sifrious</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%2F975249%2Fc4f8db62-9d88-43ef-9e91-c296d6a8681a.jpeg</url>
      <title>Forem: Mary</title>
      <link>https://forem.com/sifrious</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sifrious"/>
    <language>en</language>
    <item>
      <title>Pest-Driven Development: Testing Routes For Authenticated Users in Laravel Jetstream</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Mon, 18 Sep 2023 17:15:45 +0000</pubDate>
      <link>https://forem.com/sifrious/pest-driven-development-testing-routes-for-authenticated-users-in-laravel-jetstream-32m3</link>
      <guid>https://forem.com/sifrious/pest-driven-development-testing-routes-for-authenticated-users-in-laravel-jetstream-32m3</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm blogging along with the laracasts series &lt;a href="https://laracasts.com/series/pest-driven-laravel" rel="noopener noreferrer"&gt;Pest Driven Laravel&lt;/a&gt; created by &lt;a href="https://twitter.com/christophrumpel" rel="noopener noreferrer"&gt;Christoph Rumpel&lt;/a&gt; as I work on a project I hope to open source. I'm just documenting how I'm working, the resources I'm using, the problems I run into and some cool things I'm reminded of as I develop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm moving forward with a new understanding of my goal, and already I can tell that my goalpost has shifted. This past week involved a lot of failing. I'm excited about that because while I do enjoy all the resources I wrote about in &lt;a href="https://dev.to/sifrious/pest-driven-development-learning-iterating-and-project-planning-50e0"&gt;my last blog post&lt;/a&gt;, I always learn the most by breaking things in new ways and paying a lot of attention while I fix it. It's easier to pay attention when I'm trying to fix something. This year's Laracon had an excellent talk by Joel  Clermont about &lt;a href="https://www.youtube.com/watch?v=23McCP-_9BE" rel="noopener noreferrer"&gt;getting unstuck&lt;/a&gt; which had a particularly tricky debugging situation as its final example. No spoilers, but I knew exactly what the problem was because I've done it in Python. &lt;/p&gt;

&lt;p&gt;I also moved to a new blog writing method now that I've put out all the fires I can find so everything's going to be in past tense this time.&lt;/p&gt;

&lt;p&gt;I made a new test file just for &lt;code&gt;task.show&lt;/code&gt;. This is the named route we're going to be talking about today. It displays a navigation bar and the details of one task that's already been created.&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;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\Models\Task&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nn"&gt;Pest\Laravel\&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful redirect response for unauthenticated users for the tasks.show page'&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&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;'tasks.show'&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="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'task'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$task&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;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&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 test ran and it passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failing With A Default &lt;code&gt;Factory&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The next step was to actually test the routes with a logged-in user. Building on the principles I laid out for myself, I decided to test the smallest thing I can: the &lt;code&gt;show&lt;/code&gt; method for a single task. So I wrote this based on the progress I've made in the course so far:&lt;/p&gt;

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

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'can be accessed by verified 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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&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;$task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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="c1"&gt;// Act &amp;amp; Assert&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;'tasks.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;assertOk&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;It failed. Normally that's step 1, but in this case I already had a task view written and I was expecting it to pass. This test has some new stuff going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$user = User::factory()-&amp;gt;create();&lt;/code&gt;&lt;/strong&gt;: Here, we return a facade which uses a factory to create and store a new instance of &lt;code&gt;User&lt;/code&gt; in the testing database. These records are created during the test instantiation and destroyed when the test is complete, so they'll look different every time pest is run. Pest manages the creation and deletion of these records for you. It relies on &lt;a href="https://fakerphp.github.io/" rel="noopener noreferrer"&gt;php faker&lt;/a&gt; to seed random data so you don't have to write seeders. There's also a &lt;a href="https://faker.readthedocs.io/en/master/" rel="noopener noreferrer"&gt;python faker&lt;/a&gt; for my fellow polygots who may or may not have spent a bunch of hours writing their own seeder only to be told Laravel already has a good one. Turns out Python has a good one too. Oops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$this-&amp;gt;actingAs($user)&lt;/code&gt;...&lt;/strong&gt;: I still cannot tell you what &lt;code&gt;$this&lt;/code&gt; is with confidence (is it the testing context??), but I can tell you that &lt;code&gt;actingAs($user)&lt;/code&gt; is a chained method which accepts our temporary &lt;code&gt;$user&lt;/code&gt; as a parameter and allows us to make requests to a route as that fake user. This comes from &lt;a href="https://laravel.com/docs/10.x/passport#testing" rel="noopener noreferrer"&gt;Laravel Passport&lt;/a&gt;, the dependency jetstream uses to spin up an OAuth2 server implementation for us. I've been working through &lt;a href="https://learning.oreilly.com/library/view/oauth-2-in/9781617293276/" rel="noopener noreferrer"&gt;a book about OAuth2&lt;/a&gt; for almost 3 years. It is so refreshing to bump into OAuth2 while searching docs as opposed to bending to its will.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$this-&amp;gt;actingAs($user)&lt;/code&gt;&lt;strong&gt;&lt;code&gt;-&amp;gt;get(route(tasks.show))&lt;/code&gt;...&lt;/strong&gt;: Now we've come to same old version of our previous get request. This time it's being called with more contextual information stored in &lt;code&gt;$this&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The error comes from eloquent, the built-in Laravel dbms. Our &lt;code&gt;create()&lt;/code&gt; method tried to commit a &lt;code&gt;Task&lt;/code&gt; to the database without required attributes. It's calling out the &lt;code&gt;sheets_id&lt;/code&gt; attribute because it's listed first, but there's going to be a few more problems we can fix by writing a &lt;code&gt;[Factory]()&lt;/code&gt; right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task Factory
&lt;/h2&gt;

&lt;p&gt;When I created my &lt;code&gt;task&lt;/code&gt; model, I specified I wanted a factory to be automatically created for me. It's already there in &lt;code&gt;{{root}}\database\factories\TaskFactory&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also already have a working &lt;code&gt;user&lt;/code&gt; factory provided by Laravel. It's in &lt;code&gt;/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php&lt;/code&gt;. More general code for factories is also already in your app at &lt;code&gt;/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In general, we can use &lt;a href="https://fakerphp.github.io/#create-fake-data" rel="noopener noreferrer"&gt;&lt;code&gt;faker&lt;/code&gt; generators&lt;/a&gt;; you can find the generator class in your &lt;code&gt;./vendor/fakerphp/faker/src/Faker/generator.php&lt;/code&gt; directory if you want to see a list real quick. In this case, a few attributes I'm going to keep consistent just so I'm seeing consistent data across a test if I need to see it with &lt;code&gt;dump()&lt;/code&gt; later.&lt;/p&gt;

&lt;p&gt;Here's the factory I ended up with:&lt;/p&gt;

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

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskFactory&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Define the model's default state.
     *
     * @return array&amp;lt;string, mixed&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;definition&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="c1"&gt;// get a date sometime in the next two months&lt;/span&gt;
        &lt;span class="nv"&gt;$currentDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Carbon&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$dateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$currentDateTime&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rand&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="mi"&gt;60&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;toDateString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$currentDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$currentDateTime&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toDateString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$name&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="n"&gt;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$sheetsId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$currentDateTime&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="s1"&gt;'sheets_created_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$sheetsId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;randomDigitNotNull&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'author'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'start_date'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$dateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'start_time'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$dateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;rand&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'client_address'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;streetAddress&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'destination'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;streetAddress&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s1"&gt;'volunteer'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'status'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"unassigned"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'contact_information'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;text&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;The other line to notice here is &lt;code&gt;$currentDateTime = Carbon::now()&lt;/code&gt; and &lt;code&gt;$dateTime = $currentDateTime-&amp;gt;addDays(rand(2,60))-&amp;gt;toDateString();&lt;/code&gt;. I wanted to create a &lt;code&gt;start_date&lt;/code&gt; and &lt;code&gt;start_time&lt;/code&gt; between now and 2 months for now, because that's about the amount of time I'm seeing most tasks scheduled. If that was all I wanted I could use &lt;code&gt;$dateTime = Carbon::now()-&amp;gt;addDays(rand(2,60))-&amp;gt;toDateString();&lt;/code&gt;, but I also want to see a &lt;code&gt;sheets_created_at&lt;/code&gt; with a really similar timestamp to the &lt;code&gt;created_at&lt;/code&gt; in my database timestamps.&lt;/p&gt;

&lt;p&gt;I'm using carbon to get my epic &lt;code&gt;$currentDateTime&lt;/code&gt; timestamp (&lt;a href="https://www.epoch101.com/PHP" rel="noopener noreferrer"&gt;pun intended&lt;/a&gt; this &lt;a href="http://www.quickmeme.com/img/f5/f55393d22cd9449ff1fed73933768ce840796a9c8528e816963516960db93bb5.jpg" rel="noopener noreferrer"&gt;time&lt;/a&gt;). I know of Carbon from &lt;a href="https://www.amazon.com/Laravel-Running-Framework-Building-Modern/dp/109815326X" rel="noopener noreferrer"&gt;Laravel Up And Running&lt;/a&gt;, so I used these handy digitalocean tutorials on &lt;a href="https://www.digitalocean.com/community/tutorials/easier-datetime-in-laravel-and-php-with-carbon" rel="noopener noreferrer"&gt;Getting an Easy Datetime in Laravel&lt;/a&gt; and &lt;a href="https://www.digitalocean.com/community/tutorials/easier-datetime-in-laravel-and-php-with-carbon#manipulating-the-date-and-time" rel="noopener noreferrer"&gt;Manipulating The Date And Time&lt;/a&gt; to copy and paste. Then I googled again to &lt;a href="https://stackoverflow.com/questions/50692147/how-to-convert-a-carbon-into-string-to-take-the-date-only" rel="noopener noreferrer"&gt;assign it to my attributes as a string&lt;/a&gt;. I'm going to format this output later but right now I have my test set up and nothing is &lt;code&gt;null&lt;/code&gt; that shouldn't be &lt;code&gt;nullable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So far I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;wrote a failing test to hit the route as authenticated&lt;/li&gt;
&lt;li&gt;wrote a blade template&lt;/li&gt;
&lt;li&gt;added my route to &lt;code&gt;web.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;told &lt;code&gt;TaskController.php&lt;/code&gt; what to do when a request hits the route&lt;/li&gt;
&lt;li&gt;modified my test to include &lt;code&gt;$actingAs&lt;/code&gt; before the &lt;code&gt;get&lt;/code&gt; and include &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Task&lt;/code&gt; factories through facades&lt;/li&gt;
&lt;li&gt;wrote a &lt;code&gt;Task&lt;/code&gt; factory and used &lt;code&gt;dump()&lt;/code&gt; to check that my creates a complete, random &lt;code&gt;$task&lt;/code&gt; I can pass to my &lt;code&gt;route&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's everything the course teaches about showing detail, I think. It should pass now, right? Right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Failing Without a User Group
&lt;/h2&gt;

&lt;p&gt;No, it didn't pass. Now I'm getting an error from my navigation bar template in blade that wants the name and id of the organization associated with my user. I have a fake user, a fake task, and no fake organization. Not going to lie, it took me a while to realize what this error meant. There's not much we can do in jetstream without running into this issue because the navigation bar is on every page and users really should be associated with teams at all times.&lt;/p&gt;

&lt;p&gt;This is a problem I signed up for. I'm coding along with the course instead of going ahead through it because I want to make all of these mistakes now. I'm VERY tempted to reach out and ask for help (or thank people for being awesome and making course content), but I can be pretty thick-headed and I know that if I don't understand why I'm doing these things and fix them as I break them I'll learn them for ever ever. If I don't, I'll lose time (potentially for years) forgetting things I don't rememeber learning. That's why I'm not a copy and paste from stack overflow person and never will be. Unless it's a super elegant one-liner like &lt;code&gt;public&lt;/code&gt;: &lt;a href="https://stackoverflow.com/questions/19222716/get-random-boolean-true-false-in-php" rel="noopener noreferrer"&gt;rand(0, 1) == 1&lt;/a&gt; which I'm sure I understand fully before I use it. Should I compromise? Yes. Would I compromise if I was being compensated for my time? Also yes. Moving on.&lt;/p&gt;

&lt;p&gt;In order to display my template, I need to create a user organization, but it can't just be any user organization. They have to have a relationship or the test will still fail. My &lt;code&gt;$user&lt;/code&gt; is going to have a &lt;a href="https://laravel.com/docs/10.x/eloquent-factories#belongs-to-relationships" rel="noopener noreferrer"&gt;belongs to relationship&lt;/a&gt; to the &lt;code&gt;personal_team&lt;/code&gt; provided by jetstream. I will sometimes refer to this &lt;code&gt;personal_team&lt;/code&gt; it a team because that is what jetstream named it. I also sometimes call it an organization, because that is what it represents in my problem domain. There's this &lt;a href="https://laracasts.com/discuss/channels/laravel/user-factory-with-jetstream-team?page=1&amp;amp;replyId=660679" rel="noopener noreferrer"&gt;great solution on laracasts.com&lt;/a&gt;, which helped me find the &lt;a href="https://laravel.com/docs/10.x/http-tests#session-and-authentication" rel="noopener noreferrer"&gt;Laravel Documentation addressing the problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now my test looks like this:&lt;/p&gt;

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

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'returns 200 on GET request for authenticated user @ tasks.show'&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&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="nc"&gt;Team&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;state&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;array&lt;/span&gt; &lt;span class="nv"&gt;$attributes&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="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="s1"&gt;'user_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="s1"&gt;'personal_team'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="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;$task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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="c1"&gt;// Act &amp;amp; Assert&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;'tasks.show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'task'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$task&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="p"&gt;]))&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And it passes. There's NOTHING like a passing test case.&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%2Fynrs4s9m1d24rdhmf5ac.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%2Fynrs4s9m1d24rdhmf5ac.png" alt="One Passing Test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;After getting &lt;code&gt;tasks.show&lt;/code&gt; to pass for authenticated users, I added new files for each view that already existed in my previous &lt;code&gt;SuccessfulGetResponse2.php&lt;/code&gt; except &lt;code&gt;/home&lt;/code&gt;. Then I used variations of the method described above to produce this output:&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%2F5jlnhspz2m2mdzd3eq7k.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%2F5jlnhspz2m2mdzd3eq7k.png" alt="Suite of Passing Tests"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>pest</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Don't Care How You Pronounce SQL</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Sun, 17 Sep 2023 04:52:29 +0000</pubDate>
      <link>https://forem.com/sifrious/i-dont-care-how-you-pronounce-sql-43bc</link>
      <guid>https://forem.com/sifrious/i-dont-care-how-you-pronounce-sql-43bc</guid>
      <description>&lt;p&gt;For some reason The Algorithm(TM) keeps showing me posts about weather SQL should be pronounced S-Q-L or sequel. It's renting space in my head and it's Saturday so I wanted to rant about it. &lt;/p&gt;

&lt;p&gt;When I was in college, I was publicly corrected for pronouncing SQL 'es-quel' and it caused a lot of shame. 'es-quel' is more on the sequel side of the argument, but I haven't run into it since. It's also how the instructor of the only database course I had ever taken pronounced it in the videos. I don't know if this was because he was saying it as a part of PostgreSQL or because he had a particular accent, but he was the only person I'd ever heard say SQL out loud before. &lt;/p&gt;

&lt;p&gt;I was at a really exciting point in my own learning, because I was just moving from writing html/css/js to actually displaying data from queries in my projects on localhost. This felt extremely powerful and exciting. I was a freshman and taking an intro course in C as part of my actual coursework, but this SQL was independent learning and I was excited to talk about it with people who knew more than me. In this case, upperclassmen. I was considering joining the campus ACM chapter. &lt;/p&gt;

&lt;p&gt;The room was full of CS and IST majors on the S-Q-L side, and the feedback was devastating. It was only a few sentences but I suddenly felt really, really small. I didn't just start a conversation by saying "hey, guess what guys? I know how to pronounce es-quel", either. I was going to ask a question about a join which is now long-forgotten and never got asked because I was absolutely flushed with embarrassment. I never did join that chapter of the ACM. But I did go home and google it to find that either pronunciation is acceptable and it seemed like a cruel punchline for the rejection I was feeling.&lt;/p&gt;

&lt;p&gt;It's been a few years and I've developed a list of context-specific terms I use to actively avoid pronouncing SQL: schema, DBMS, database, postgres, query, join/select, store. They're never quite right for the context but I have also never been called out on it.&lt;/p&gt;

&lt;p&gt;I'm reminded my experience is not unique (though it's a little overblown by rumination) through some comments I'm seeing tonight and because of conversations I've had with people in the decade since I went to college irl. I've noticed anecdotally that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;people who have read it and haven't heard it said and/or learned mySQL first tend to say S-Q-L&lt;/li&gt;
&lt;li&gt;people who have taken courses with audio especially about PostgreSQL or Microsoft SQL Server tend to say sequel&lt;/li&gt;
&lt;li&gt;people who use SQLite are kind of wildcards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think there's a subtle form of unintentional gatekeeping going on here. Many people stick to the form they themselves have been corrected to and correct others to that form with good intentions. Maybe it was lucky that the first time it happened to me was in a conversation during which a few other problematic things were said, because that prompted me to actually look it up and ask a few professors who all said it really doesn't matter, usually with the caveat of their preference and why. I had multiple office hours where professors basically reacted with the exact same vibe D. Richard Hipp has in &lt;a href="https://changelog.com/podcast/201"&gt;this changelog episode&lt;/a&gt;. But the time it takes to correct someone on pronunciation that truly doesn't matter sometimes prevents the thing that person was going to say next like it did with me. &lt;/p&gt;

&lt;p&gt;These conversations mostly happen when someone is trying to establish context before explaining something or asking a question. Even if they're just expressing enthusiasm, I think it's important to consider the vulnerability happening in conversation about code. If someone has just said the "wrong" pronunciation for the first time, there's almost certainly an experience mismatch or the element of entering into a conversation about this topic. As far as courses go, I think it would have been cool if the instructor in the first course I took mentioned that you can pronounce it either way, but creating course material is also a pretty specific scenario.&lt;/p&gt;

&lt;p&gt;I always appreciate professors who remember to mention that either way is ok to their students during a lecture. It's something I might not have noticed if I didn't have such a bad experience, but honestly I think if "it doesn't matter" was the accepted stance, there might be fewer arbitrarily truncated conversations in this particular arena between students/jrs. Or maybe they'd just be arguing about tabs v spaces or the best editor or pineapple on pizza instead. I think SQL/sequel is different, though, because when you're learning a topic and get checked on your speech on what is basically the name of the topic, internal monologue can get to "I thought I understood this at least a little, but I don't even know what it's called" pretty fast. With tabs v spaces, we all know we're right and we're absolutely going to keep doing whatever we've been doing.&lt;/p&gt;

&lt;p&gt;A few years ago, I had a conversation with someone who was really into inclusive pedagogy and taught math but coded a bit as well. He pronounced it squill (rhymes with 'quill') intentionally &lt;em&gt;every&lt;/em&gt;. &lt;em&gt;time&lt;/em&gt;. It sounded a bit meme-y (a la chat gippity) and a lot ridiculous. It was actually kind of infuriating for a few conversations. Then, as I got used to it, I started to check my motives about being "right" and correcting people who are "wrong" about it.&lt;/p&gt;

&lt;p&gt;It kind of reminds me of the process I went through when I moved to a city for the first time and realized that people who use 'incorrect'/'improper' grammar are (a) completely intelligible and (b) not wrong for doing it. I let go of my hard-won feeling of being the most "correct" at grammar and realized maybe I was doing talking wrong. It wasn't until I came to this realization that I started to understand rich layers of meaning in speech I used to hear but wrote off in lieu of listening. &lt;/p&gt;

&lt;p&gt;I still feel like I'm pretty good at diagramming sentences, but I stopped letting that be a determining factor in conversations before they even started. The reason I ever did was because I worked so hard to be good at English grammar. I worked so hard to get good at English grammar was because I was given positive feedback for speech and writing that was academically correct and disproportionately harsh feedback when I made mistakes. My sense of self was wrapped up in it. Now, when I remember the times I corrected other people for how they said something as I assumed I understood what they were saying. I'm sure I missed out on a lot. Plus: it would take me at least 60% more time to write a blog post if I edited it to what my standards used to be before publishing it.&lt;/p&gt;

&lt;p&gt;This post is not directed at any person in particular. Posts on x are very different than real-life conversations and it's a good place to just have a take and really commit to it. I genuinely like the idea of squill or even &lt;a href="https://twitter.com/ThePrimeagen/status/1703196414153511205"&gt;squeal&lt;/a&gt; because they're jarring. Considering why we think something is correct can prepare us for how important that correctness is going to be in a conversation that will maybe someday happen. I've been practicing taking myself less seriously and my enthusiasm about learning and talking about code more seriously. I'm still not there. I have become much more comfortable saying "I don't know" and jumping straight through the sting of embarrassment into actually listening to the answer.&lt;/p&gt;

&lt;p&gt;I don't care &lt;em&gt;how&lt;/em&gt; you pronounce SQL. I care very much &lt;em&gt;that&lt;/em&gt; you said SQL, and I would love to hear what you're going to say next. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pest-Driven Development: Learning, Iterating and Project Planning</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Thu, 14 Sep 2023 15:13:48 +0000</pubDate>
      <link>https://forem.com/sifrious/pest-driven-development-learning-iterating-and-project-planning-50e0</link>
      <guid>https://forem.com/sifrious/pest-driven-development-learning-iterating-and-project-planning-50e0</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm blogging along with the laracasts series &lt;a href="https://laracasts.com/series/pest-driven-laravel" rel="noopener noreferrer"&gt;Pest Driven Laravel&lt;/a&gt; created by &lt;a href="https://twitter.com/christophrumpel" rel="noopener noreferrer"&gt;Christoph Rumpel&lt;/a&gt; as I work on a project I hope to open source. I'm just documenting how I'm working, the resources I'm using, the problems I run into and some cool things I'm reminded of as I develop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is another &lt;a href="https://dev.to/sifrious/pest-driven-development-in-a-laravel-app-project-planning-1j84"&gt;relatively nontechnical post&lt;/a&gt;. It's a longer one about learning and TDD. This series has been conversational. It's a little bit of an exercise in failure, part performance review. Here's a whole bunch of opinions: &lt;/p&gt;

&lt;p&gt;I think there comes a points in every developer's career when they understand the fundamentals, understand a bunch of "known unknowns" about what they need to learn (in the sense of information consumption/acquisition), know a few "known unknowns" about what they need to improve (in the sense of mindset/style) and then see what they're able to produce. This is the stage of any new discipline when I start to engage with how I'm learning. I do this in lots of ways: consuming information about &lt;em&gt;known knowns&lt;/em&gt; (&lt;a href="https://laracasts.com" rel="noopener noreferrer"&gt;taking courses&lt;/a&gt;, &lt;a href="https://bootcamp.laravel.com" rel="noopener noreferrer"&gt;following tutorials&lt;/a&gt;, &lt;a href="https://laravel.com/docs/10.x" rel="noopener noreferrer"&gt;reading documentation&lt;/a&gt;, &lt;a href="https://www.oreilly.com/online-learning/" rel="noopener noreferrer"&gt;reading books&lt;/a&gt;, &lt;a href="https://www.youtube.com/c/LaravelDaily" rel="noopener noreferrer"&gt;watching videos&lt;/a&gt;) and &lt;em&gt;known unknowns&lt;/em&gt; (watching streamers with a &lt;em&gt;lot&lt;/em&gt; of experience and/or a systems-thinking approach, &lt;a href="https://larapeeps.com/groups/podcasters" rel="noopener noreferrer"&gt;listening to podcasts where people discuss coding in more abstract terms&lt;/a&gt;, reading books like '&lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/" rel="noopener noreferrer"&gt;the pragmatic programmer&lt;/a&gt;' and '&lt;a href="https://www.oreilly.com/library/view/clean-code-a/9780136083238/" rel="noopener noreferrer"&gt;clean code&lt;/a&gt;', &lt;a href="https://github.com/laravel" rel="noopener noreferrer"&gt;reading code that is well written&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;So I get this input and I have to deal with how that doesn't line up with my "known knowns". I see it in my output, and I want to get better, but it's not possible to prepare for unknown unknowns or to avoid them. Whenever one is learning a new skill, the unknown unknowns are the most important pieces. &lt;/p&gt;

&lt;h2&gt;
  
  
  A New State of Mind
&lt;/h2&gt;

&lt;p&gt;It's good to take a break and think about how to get from point A to point B in the following series of things. Here's some definitions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. output&lt;/strong&gt;: producing code that is fine, I guess, but could be implemented better (known knowns). Your body of work until now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A′&lt;/strong&gt; (A "prime"): producing output that is pretty ok. Your current project(s). You don't have to google much to work in this area&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. improved output&lt;/strong&gt;: the a body of work you're currently challenged when youre interacting with, where you start ennumerating and sometimes incorporating things you know you should know (known unknowns)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C. improved thinking and processes&lt;/strong&gt;: finding a better way to incorporate things you know you should know (known unknowns)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;X. idealized output&lt;/strong&gt;: producing code that contains things you know you should know with a better process than you have now (&lt;a href="https://en.wikipedia.org/wiki/There_are_unknown_unknowns" rel="noopener noreferrer"&gt;unknown unknowns&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%2Fn467fonsn4up1e81mtu3.jpeg" 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%2Fn467fonsn4up1e81mtu3.jpeg" alt="A State Diagram about Learning. Call it State of Mind."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is my personal opinion that no one ever gets to point X (idealized output). Instead, we aim to shift the goalpost. And as this happens, point A (output) improves until the output looks like point X (idealized output) to someone else. Let's call that space A′ (current output that seems a little better than previous output). And all the things that happen at point B ("reach" output) and the behavior that happens at point C (improved thinking) are too much to impart directly to another human because &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it would take too long&lt;/li&gt;
&lt;li&gt;expressing everything that happened during a shift like this delays or even prevents another&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The production of educational material for other people is a side effect of C (improved thinking/processes). But writing code productively at point A′(current code after learning something) and writing the best tutorial or course material after learning something are not the same activity at all. The best tutorial you can write at a given point A is more like an emergent property than a part of this system at all. &lt;/p&gt;

&lt;p&gt;The ability to talk about code as you're doing it can also be a side effect of point A′ (live coding in your comfort level or describing code you've already completed) but also a completely separate process. It's harder to verbalize code at point B (improved output) and REALLY hard at point C (improved thinking) before a new concept has been integrated into long term memory and can be applied to additional processes. Interview prep and pairing can increase our capacity to describe what we're doing and thinking as we code as it is being written.&lt;/p&gt;

&lt;p&gt;Because it's difficult to ask a person about what they're learning and easy to ask a person about what they're comfortable with, I think it's also a limitation of live coding interviews. I also think evaluating more recently integrated concepts and how comfortable a person is at point C (improved thinking) is a more valuable evaluation of a programmer than their A′ (body of work). This makes the methodology of producing and grading performance evaluations vastly more complicated. It's also a valuable quality to be comfortable going through this &lt;strong&gt;A-&amp;gt;B-&amp;gt;C-&amp;gt;A′&lt;/strong&gt;; progression in rapid succession over and over and over again. There's a marginal increase in cognitive load and discomfort in these iterations. ESPECIALLY for new programmers.&lt;/p&gt;

&lt;p&gt;Occasionally when you're trying to improve, you encounter a complete dumpster fire of a situation and have to think about how to recover from it, like a Giselle in the wild shaking itself off after it realizes that it's been debugging in the wrong directory for like 8 hours. Mixed metaphor there. There can be an emotional aversion that comes with this type of block.&lt;/p&gt;

&lt;p&gt;I'm taking this course where I'm watching code being written in the frameworks I'm using in my project. But when I finish the course, I'm not going to be at the instructor's point A when he wrote the course. I'm going to be at my point X from when I started asking questions about TDD. &lt;/p&gt;

&lt;h2&gt;
  
  
  Updated Goals
&lt;/h2&gt;

&lt;p&gt;Now that I've learned a bit more, I realize it is useful to reorganize my first post in this series with some takeaways I've gotten up the point where I am now. I reserve the right to take all of this back, btws.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pause after every new test passes and ask yourself what you're going to do next.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;This is my favorite takeaway from this course. We don't just see coding, we see pausing. This is probably even more important than code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It stops me from making reckless decisions and breaking the code I just ensured is working. This is apparently one of &lt;a href="https://xkcd.com/559/" rel="noopener noreferrer"&gt;my hobbies&lt;/a&gt;. It's been pointed out to me by other people "a couple two three" times. &lt;/li&gt;
&lt;li&gt;I can only choose one next thing to do. If something occurs to me after I've made a decision and have begun writing code, I often just forget about it. Once I've reached a milestone with code behavior, an opportunity arises. Valid options of next steps present themselves. Multiple decisions can be made in this moment, but if you rush you may think of a bunch of possibilities, choose one, and go off without fully separating it from the other possibilities. It's hard to stay task-focused with numerous possibilities in mind. I sometimes experience leakage from discarded or postponed options as I pursue the task I've selected. This is not great for code quality.&lt;/li&gt;
&lt;li&gt;Thought is habitual. The patterns we're used to using become learned and the coding patterns we use tend to affect the way we live and vice versa. It's called neuroplasticity (if you are unfamiliar and want to google it) and it's incredible. Coding is a subset active thinking, programmers have a disproportionate responsibility to take regular breaks and manage distractions and &lt;a href="https://stackoverflow.blog/2018/09/10/developer-flow-state-and-its-impact-on-productivity/" rel="noopener noreferrer"&gt;interruptions&lt;/a&gt;; we also tend to have sprint assignments and meeting-filled schedules and slack/discord channels that sabotage this. If we are impulsive or self-critical or doubt-filled in our coding, we risk the amplification of these tendencies during other activities. There's this concept of "&lt;a href="https://jackkornfield.com/the-sacred-pause/" rel="noopener noreferrer"&gt;the sacred pause&lt;/a&gt;" in mindfulness. Mindfulness is the real benefit of TDD that causes the &lt;a href=""&gt;well-documented side effect of clean code&lt;/a&gt; despte the &lt;a href="https://dev.to/codenameone/why-i-dont-do-tdd-1j71"&gt;potential drawbacks&lt;/a&gt;. I've already seen an improvement in my overall well-being since I started making blade templates just from the randomly generated quotes produced by the &lt;a href="https://laravel.com/api/6.x/Illuminate/Foundation/Inspiring.html" rel="noopener noreferrer"&gt;inspiring class&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It gives you the opportunity to write the other possible avenues 
down and contributes to your &lt;a href="https://hackernoon.com/you-should-be-using-a-software-engineering-daybook" rel="noopener noreferrer"&gt;engineering daybook&lt;/a&gt;. There's this idea that we value a group of potential choices in comparison to each other. Since one can best follow one train of thought at a time, programmers usually have exactly one choice they can pick at each of these opportunity points. We choose the best right thing at the cost of not implementing the other choices. In economics this is called &lt;a href="https://www.thebehavioralscientist.com/glossary/opportunity-cost-neglect" rel="noopener noreferrer"&gt;opportunity cost&lt;/a&gt;. A forgotten possibility that was the 2nd best or 3rd best option at a moment of opportunity might be more valuable than the 1st best option that comes to mind at the next juncture. It's easy, even probable, to forget about a current task's substitutes while writing code for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I'm in a flow, I'm much more likely to make a choice in my comfort zone and postpone a task I know I would have to research. But I definitely won't research it later if I forget I was going to do it. This is why I've been meaning to look into redis for years. YEARS. Taking time to write down alternative options to implement but aren't choosing to implement now retains value.&lt;/p&gt;

&lt;p&gt;Here's the flowchart:&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%2Fslc8lzfyuk7a8zpu5hu4.jpeg" 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%2Fslc8lzfyuk7a8zpu5hu4.jpeg" alt="The Flowchart I Drew in Apple Notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Test the smallest thing possible so you have a test.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write a more complicated test later. Or refactor the test later. When you're in the moment, you want a test that works. Avoid hard coded values in completed tests, but use them when you're making sure your test doesn't break the very time you write it. A failing test is the starting point of the last decision you made, not the final product. Even if the imaginary people who are going to make fun of your code and call you stupid (ignore this if you're not relating, but if you are &lt;a href="https://github.com/readme/guides/publishing-your-work" rel="noopener noreferrer"&gt;read this&lt;/a&gt; or &lt;a href="https://www.youtube.com/watch?v=2YaEtaXYVtI" rel="noopener noreferrer"&gt;watch it&lt;/a&gt;) are looking at your public github repo, they're not going to your test suites first. That would be insane. So you can be clunky at first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Take time to refactor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's a whole video about this in the course. Watch it. Tell me what you think in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Don't make your tests clever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(See point no 2.) The functional utility of a test is pretty much self-contained unless you're working with arbitrary coverage requirements imposed on you by someone else. If you care about your coverage the simpler the tests you write are the more confident you can be that your code is working as expected. If you have to choose between brittle/fancy and robust/simple, &lt;a href="https://thevaluable.dev/kiss-principle-explained/" rel="noopener noreferrer"&gt;KISS&lt;/a&gt;. If you are being forced to test for information that is not useful, whoever imposed those requirements doesn't deserve your clever. Save it for leetcode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updated Project planning
&lt;/h2&gt;

&lt;p&gt;I'm pausing after the introduction to jetstream to re-evaluate my previous project planning. I made &lt;a href="https://github.com/sifrious/reteer/tree/main/reteer-app/public/wireframes/task%20views" rel="noopener noreferrer"&gt;a bunch of wireframes&lt;/a&gt; (as suggested). That really helped me think about what behavior I wanted to have and how that should be implemented (as promised). Previously, I had organized my goals by role. Now I want to think about testing the smallest thing possible, and planning coverage to match the parts of ui that matter the most. So I'm going to sort them into actions instead, because this is how I will implement (policies)[&lt;a href="https://laravel.com/docs/10.x/authorization#creating-policies%5D:" rel="noopener noreferrer"&gt;https://laravel.com/docs/10.x/authorization#creating-policies]:&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;create&lt;/code&gt; (organizers and administrators only)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;a new task&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;read&lt;/code&gt; (all users)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;a single task&lt;/li&gt;
&lt;li&gt;a list of tasks&lt;/li&gt;
&lt;li&gt;a list of tasks that are currently unassigned&lt;/li&gt;
&lt;li&gt;sorted lists of tasks&lt;/li&gt;
&lt;li&gt;a list of all tasks assigned to a single user&lt;/li&gt;
&lt;li&gt;dashboard including paginated, limited tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;update&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;assign one's self to the volunteer attribute of a task (&lt;code&gt;[volunteer](#confirm-organizers-and-adminstrators-only)&lt;/code&gt;) (all users)&lt;/li&gt;
&lt;li&gt;all fields (organizers and administrators)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;delete&lt;/code&gt; (adminstrators)
&lt;/h3&gt;

&lt;p&gt;Deletes a task completely.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cancel&lt;/code&gt; (organizers and administrators)
&lt;/h3&gt;

&lt;p&gt;This marks a task as cancelled but does not remove it from the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mark &lt;code&gt;complete&lt;/code&gt; (all users)
&lt;/h3&gt;

&lt;p&gt;Indicates the task is done to be &lt;code&gt;confirm&lt;/code&gt;ed by an admin or organizer managing a contract&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;confirm&lt;/code&gt; (organizers and adminstrators only)
&lt;/h3&gt;

&lt;p&gt;Indicates the task was done correctly and (eventually) updates the status of the task as it relates to the contract&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;volunteer&lt;/code&gt;/&lt;code&gt;un-volunteer&lt;/code&gt; (all users)
&lt;/h3&gt;

&lt;p&gt;The only update action a volunteer role permits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;volunteer&lt;/code&gt;: Update a task to store the current user as the volunteer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;un-volunteer&lt;/code&gt;: Remove current user currently assigned to a task from the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;assign&lt;/code&gt;/&lt;code&gt;un-assign&lt;/code&gt;/&lt;code&gt;reassign&lt;/code&gt; (organizers and administrators only)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assign&lt;/code&gt;: Store any user id associated with an organization to a task.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;un-assign&lt;/code&gt;: Remove a user id associated with an organization from a task.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reassign&lt;/code&gt;: Update a task to store a new user id from a task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  inb4 Laravel Was Never Bad
&lt;/h2&gt;

&lt;p&gt;I'm starting generally to make a point about dilution. There's been much of discussion lately about &lt;a href="https://www.youtube.com/watch?v=ZRV3pBuPxEQ" rel="noopener noreferrer"&gt;PHP Doesn't Suck Anymore&lt;/a&gt;, a title potentially offensive to people who never thought PHP sucked but generally embraced by many people who like memes and have ever been on the internet. PHP is not my favorite language. I didn't really choose to learn it. &lt;a href="https://dev.to/tylerlwsmith/is-php-a-gnarly-language-yes-yes-it-is-2gm"&gt;It's kind of gnarly&lt;/a&gt;. However, Laravel is definitely my favorite web framework. So as a person trying to learn PHP and a fan of sincere posting, I have seen this video several times. I also watched &lt;a href="https://www.youtube.com/watch?v=Hh72yCYlaww" rel="noopener noreferrer"&gt;the primegean&lt;/a&gt; react to it live so I could get context and listened to several podcast episodes in which it's discussed. It's basically a list of things in modern PHP that are good with code examples and names of things so you can research them. If you really get into it and spend like 20 hours reading the docs on every feature listed (an example you know really happened because it's too specific to be made up) you can learn tons about how PHP is different from other languages and intuit what it's good for and some best practices. &lt;/p&gt;

&lt;p&gt;I also spent several hours on &lt;a href="https://php.watch/versions/8.2/dnf-types" rel="noopener noreferrer"&gt;DNF form&lt;/a&gt; alone because I love relational databases more than anything else in computing and as a consequence I love (beginner level) &lt;a href="https://stackoverflow.com/questions/1734711/relational-databases-and-mathematics" rel="noopener noreferrer"&gt;set theory&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Relational_algebra" rel="noopener noreferrer"&gt;relational algebra&lt;/a&gt;. Then, I started looking into &lt;a href="https://php.watch/versions/8.2/dnf-types" rel="noopener noreferrer"&gt;DNF type&lt;/a&gt;s. Then, I started looking into how these are implemented in the C family and Java. Then, I went down a rabbit hole of opinion posts on reddit and quora and stackoverflow about &lt;a href="https://stackoverflow.com/questions/2690544/what-is-the-difference-between-a-strongly-typed-language-and-a-statically-typed" rel="noopener noreferrer"&gt;why it's even good when languages are strongly typed&lt;/a&gt; (the top answer will surprise you). Then, I took all of this knowledge and made &lt;a href="https://twitter.com/sifrious/status/1692397658936098824/photo/1" rel="noopener noreferrer"&gt;what I consider to be the best meme I've ever made in my whole life&lt;/a&gt;. Then, I sent it to my buddy Tyler. My buddy Tyler is my closest friend, teacher and career mentor. We have spent hundreds of hours chatting about code and tech and the like, so we have a pretty established language and understand pretty well what the other person knows about. He hadn't seen the video yet but he is a professional PHP developer and when he didn't immediately get this super specific meme I was absolutely shook. He has since seen it and now gets it but here's what I am trying to say: it's really difficult to say a complicated thing to another person when you know about it while respecting the amount of concepts and sheer jargon that make up a language or framework. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The main dangers lie in the "unknown knowns"—the disavowed beliefs, suppositions and obscene practices we pretend not to know about, even though they form the background of our public values." - Slavoj Žižek&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is so difficult to distill experience into understandable technical communication that I can be totally blindsided by saying a thing that is clear to me and maybe 5 other people to a 6th person who isn't familiar with the exact group of concepts you are talking about. We contend not only with our own unknown unknowns but with our audience's unknown unknowns when we communicate and produce educational material and write documentation. That's why pest and especially the pest documentation is so impressive.&lt;/p&gt;

&lt;p&gt;If you check out &lt;a href="https://pestphp.com/docs/expectations" rel="noopener noreferrer"&gt;the pest documentation expectation API&lt;/a&gt; you'll get an overwhelming list of test cases that are extremely readable and applicable for specific groups of tests. That is a LOT of distilled testing experience just sitting there waiting to be considered. And you can bet that each of them have a use case because no one just make a random function, who has time for that? Nobody at PHPUnit, either, who have additional &lt;a href="https://docs.phpunit.de/en/10.0/assertions.html" rel="noopener noreferrer"&gt;assertion docs &lt;/a&gt; which I found because I was reading Pest docs. Also: no matter how you feel about PHP, it is extremely popular. I heard Wordpress alone powers &lt;a href="https://www.npr.org/sections/money/2008/10/remember_98_of_all_statistics_are_made_up.html" rel="noopener noreferrer"&gt;98% of the web&lt;/a&gt;. I think this list is an incredible resource not just for writing tests with pest but also for understanding what is a useful thing to test for. Here's a bullet point version of some of "the many uses of tests" from &lt;a href="https://themissingreadme.com/" rel="noopener noreferrer"&gt;The Missing Readme&lt;/a&gt; on pg 89:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check that your code runs and behaves as expected&lt;/li&gt;
&lt;li&gt;protect code from changes that may unintentionally alter behavior&lt;/li&gt;
&lt;li&gt;encourage clean code&lt;/li&gt;
&lt;li&gt;force developers to use their own APIs&lt;/li&gt;
&lt;li&gt;document how components are to be interacted with&lt;/li&gt;
&lt;li&gt;serve as a playground for experimentation&lt;/li&gt;
&lt;li&gt;force a developer to think about the interface and implementation of their new program (as well as the dependencies they choose)&lt;/li&gt;
&lt;li&gt;serve as documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is true of Laravel documentation in general. I'm really going out of my way here not to accidentally imply that Laravel got better recently after starting with that anecdote about PHP Doesn't Suck Anymore. One thing I've heard from Laravel developers in podcasts and in the conversations I've been privileged to have with some of them recently is this: read the entire documentation. This is getting back to &lt;a href="https://www.youtube.com/watch?v=SSgnN1tMOtU" rel="noopener noreferrer"&gt;The Curse of Knowledge&lt;/a&gt; territory again and I know it sounds dangerously close to 'just read the docs', but when I get the same advice from like 30 people in the span of a month I want to pass it on. I also recently got &lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;RayCast&lt;/a&gt; and have been using the shortcuts for &lt;a href="https://www.raycast.com/vimtor/tailwindcss" rel="noopener noreferrer"&gt;tailwind&lt;/a&gt; and &lt;a href="https://www.raycast.com/indykoning/laravel-docs" rel="noopener noreferrer"&gt;laravel&lt;/a&gt; and &lt;a href="https://www.raycast.com/ajaypremshankar/vim-bro" rel="noopener noreferrer"&gt;vim&lt;/a&gt; and let me tell you: peak experience. 10/10 highly recommend.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Learn Laravel", they said. "It Will Make You Better", they said.
&lt;/h2&gt;

&lt;p&gt;This is more about personal stuff than pest, but if you're still reading I'm glad you're here.&lt;/p&gt;

&lt;p&gt;As a python developer who likes memes and have ever been on the internet, I had some opinions about PHP for a long time and let me tell you, they were not positive. During all those hours of talking to Tyler about code, I would tell him an idea I had for a &lt;a href="https://pythonbasics.org/what-is-flask-python/" rel="noopener noreferrer"&gt;flask&lt;/a&gt; project and he'd say some variation of 'yeah, that's a useful thing but Laravel already has it'. After like a year of this I broke down and started learning more about it and was really surprised about how much I understood intuitively about the packages and how they worked. I started learning Laravel to learn PHP in a way that made more sense to me after looking at frameworks in other languages, but I didn't expect how much it would teach me about how websites are structured. It's opinionated in so excellent a way it's accidentally broadly educational.&lt;/p&gt;

&lt;p&gt;I've wanted to blog for a really long time, but I've never felt like I had anything to say that other people didn't already know. I've read many articles on DEV in the past decade and I wanted a DEV hat for a while. So after coding for a while as a hobby for myself for a while, I decided to try to meet people and maybe find a mentor. I got a DEV hat because I know the DEV community is wonderful and wore it to laracon because I heard the Laravel community is wonderful. But I was really not expecting how wonderful it is. I have learned so much and got to speak to so many wonderful people that my brain kind of can't handle it. And when I finally got it together to take up the challenge of working in public despite being super introverted and freaked out about it, it got reposed by some of those wonderful people almost immediately and I cannot express how included I felt or how rad I think it is that you're reading this.&lt;/p&gt;

&lt;p&gt;And then I got a comment on my DEV post from someone in a DEV hat and I was like-- this is it. I've peaked.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>pest</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Pest-Driven Development: Minimum Viable Routing</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Fri, 08 Sep 2023 07:07:40 +0000</pubDate>
      <link>https://forem.com/sifrious/pest-driven-development-minimum-viable-routing-2k2p</link>
      <guid>https://forem.com/sifrious/pest-driven-development-minimum-viable-routing-2k2p</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm blogging along with the laracasts series &lt;a href="https://laracasts.com/series/pest-driven-laravel"&gt;Pest Driven Laravel&lt;/a&gt; created by &lt;a href="https://twitter.com/christophrumpel"&gt;Christoph Rumpel&lt;/a&gt; as I work on a project I hope to open source. I'm just documenting how I'm working, the resources I'm using, the problems I run into and some cool things I'm reminded of as I develop.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Now that I am passing a test when I hit the &lt;code&gt;'home'&lt;/code&gt; route, I'm going to add all the other routes that are already part of the app. &lt;code&gt;tests/Feature/ExampleTest.php&lt;/code&gt; doesn't say a lot about what's happening when I run my &lt;code&gt;pest&lt;/code&gt; command, so I'm going to rename the file and add all my tests for routes there with the format:&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="nf"&gt;it&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the &amp;lt;page_name&amp;gt; page'&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="p"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;page_name&lt;/span&gt;&lt;span class="o"&gt;&amp;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;assertStatus&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I am putting this in bold and a quote because it is &lt;em&gt;important&lt;/em&gt;: &lt;strong&gt;You Must End Your Test File Name With the Word Test&lt;/strong&gt; or it will not be executed. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A habit I've been getting into since I've been working with laravel is searching for the name of a file or variable I'd like to rename and check out where else it appears in the app. I'm trying not to look at too much source code right now, but I do also check out the first few functions if the naming conventions are unfamiliar to me or the syntax looks interesting. So when I look for the whole path, I see it's in &lt;code&gt;vendor/pestphp/pest/src/Plugins/init.pub&lt;/code&gt;. This looks like it gets run during install and there's a lot more files in the &lt;code&gt;tests/Feature&lt;/code&gt; directory than are listed here. &lt;/p&gt;

&lt;p&gt;Little story here: when I was on the smoker's deck at Laracon meandering in to a conversation about event sourcing that I think may have been &lt;a href="https://noplanstomerge.com/120"&gt;immortalized in this episode of no plans to merge&lt;/a&gt;, I met Filip (&lt;a href="https://twitter.com/ganyicz"&gt;@ganyicz&lt;/a&gt;) and told everyone I'm new to Laravel. &lt;a href="https://twitter.com/zuzana_kunckova"&gt;Zuzana&lt;/a&gt; had just given her talk "&lt;a href="https://twitter.com/taylorotwell/status/1684985457946578944?s=20"&gt;The Curse of Knowledge&lt;/a&gt;" and we were all thinking about it, so he didn't want to say "just read the documentation". I know this because he said "Well, I'm not going to say 'just read the documentation anymore". So basically the first advice he gave me was that Laravel source code is easy to find, written very well and maybe even better than the documentation. He has since showed me how to source dive from inside the ide and a bunch of other useful things. &lt;/p&gt;

&lt;p&gt;This is a habit I have really enjoyed so far and it has definitely improved my ability to read and write code. Hacks to the game right there. Sometimes, like this time, I don't find any necessary takeaways but I become aware of something I wouldn't have seen otherwise. &lt;/p&gt;

&lt;p&gt;Making a new pest file is pretty easy with &lt;code&gt;php artisan make:test&lt;/code&gt; and prompts. When I'm prompted for a test type I select &lt;code&gt;Feature (Pest)&lt;/code&gt; and name it &lt;code&gt;tests/Feature/SuccessfulGetResponseTest.php&lt;/code&gt;. I also uncommented &lt;code&gt;Illuminate\Foundation\Testing\RefreshDatabase::class&lt;/code&gt; in the &lt;code&gt;uses&lt;/code&gt; method of &lt;code&gt;tests/Pest.php&lt;/code&gt;. When I run &lt;code&gt;pest&lt;/code&gt; I get 10 failed tests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fdZOMquJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iifwaoreuzj9aho29gr2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fdZOMquJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iifwaoreuzj9aho29gr2.png" alt="pest output with 10 failing tests and 6 passing tests visible" width="634" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is wonderful news because while I did import my &lt;code&gt;routes\web.php&lt;/code&gt; file, I have not updated my &lt;code&gt;Http\Controllers\RouteController.php&lt;/code&gt; since it was created with empty methods and this code should fail. This feels like TDD is actually happening, and I have clearly a clearly defined goal: get the &lt;code&gt;TaskController&lt;/code&gt; to work so this feature test suite passes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the Test Suite to Pass
&lt;/h2&gt;

&lt;p&gt;I'm writing this as I work, so I am currently fighting every impulse I have to completely rewrite the entire application. I absolutely hate the code that's running now and the user interface makes me shudder. But this is not a development goal, it is a copy and paste goal. &lt;/p&gt;

&lt;p&gt;Debugging when you're copying and pasting code is mostly soul-crushing. I hear that other people &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/10a0sg6/copying_and_pasting_from_stack_overflow_essential/"&gt;adhere to this methodology&lt;/a&gt; but I come from &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/83qv81/googling_the_error_messages/"&gt;a different philosophy of iterative development&lt;/a&gt; and I'm really struggling to even copy and paste my own code. &lt;/p&gt;

&lt;h2&gt;
  
  
  One Eternity Later
&lt;/h2&gt;

&lt;p&gt;It finally occurred to me that the component structure I was using before is too complicated. I wanted to just move the previous blade component structures that compose my views, but it's not even code I want in my completed app. It was only when I took a step back that I realized that a few of the errors I was getting had changed to 302s, which actually is the desired behavior from the app.&lt;/p&gt;

&lt;p&gt;So I reorganize the tests I've written and sort them by what I'm looking for:&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="c1"&gt;// expect 302 Routes&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.board page'&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="p"&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;'tasks.board'&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;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.index page'&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="p"&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;'tasks.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;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// ... 2 more tests of the same format &lt;/span&gt;

&lt;span class="c1"&gt;// expect 200 routes&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the home page'&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="p"&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;'home'&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;assertStatus&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="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// expect 200 routes with variables&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.display page'&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="p"&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;'tasks.display'&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;assertStatus&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="p"&gt;});&lt;/span&gt;
&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.confirmCreate page'&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="p"&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;'tasks.confirmCreate'&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;assertStatus&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="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// ... 5 more tests of the same format&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when I run &lt;code&gt;pest&lt;/code&gt; again I see that 5/10 tests are passing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Viewing Expected Data On Routes
&lt;/h2&gt;

&lt;p&gt;I made some assumptions about what I should be testing for that really complicated things. The next part of the course includes a test that made me think that writing a test for &lt;code&gt;tasks.display&lt;/code&gt; should look something like this:&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.display page'&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="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// create tasks using the factory() model&lt;/span&gt;
    &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;// assert that the tasks are visible on the page&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;'tasks.display'&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;assertSeeText&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'Test Task 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 2'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 3'&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 order to get this output, I needed to start with a visible route. It took a LOT of time to clean up my existing/broken components so I could actually view this route, and digging through my messy code and sorting through what I needed to keep and get rid of just to pass variables through nested blade (the php templating language I'm using with laravel and jetstream) components had me absolutely philosophizing about trees, completely unaware of the forest. &lt;/p&gt;

&lt;p&gt;At one point during this process, something happened with git that duplicated every file in my &lt;code&gt;vendor&lt;/code&gt; folder and broke all of my tests except the example unit test that confirms that &lt;code&gt;true==true&lt;/code&gt; by attempting to run each migration twice every time I ran a test. Since I was distracted by refactoring components and I thought most of the changes I'd made were in related to either components or pest, I thought that the issues with the database were related to the &lt;code&gt;Illuminate\Foundation\Testing\RefreshDatabase::class&lt;/code&gt;. Then, when I tried to refresh the database with &lt;code&gt;php artisan migrate:fresh&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;php artisan migrate:refresh&lt;/code&gt; and they &lt;em&gt;both&lt;/em&gt; failed, I started going down the rabbit hole of sqlite and testing environments and yada yada yada. I rarely open my &lt;code&gt;vendor&lt;/code&gt; folder (or its equivalent in other frameworks) or even think about it, so it was a pretty frustrating thing to debug. By this point in the forest metaphor I was basically staring at a leaf in a magnifying glass. Rough 24 hours.&lt;/p&gt;

&lt;p&gt;So I finally had a visual confirmation of the component and exactly one vendor folder, and I started to refactor my code for the &lt;code&gt;tasks.display&lt;/code&gt; route:&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.display page'&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="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// create tasks&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="o"&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;$task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Test Task &lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$descriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tasks&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;array_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$descriptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$task&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;task_description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&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;'tasks.display'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'tasks'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$tasks&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;assertSeeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$descriptions&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;^ &lt;strong&gt;definitely don't do this, it does not pass and is cringe&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before I realized that (1) this is a really bad test to start with and (2) this is almost definitely a really bad way to think about this endpoint.&lt;/p&gt;

&lt;p&gt;It's a bad test to start with because my &lt;code&gt;tasks.display&lt;/code&gt; should only list upcoming tasks a user already assigned to themselves. &lt;code&gt;tasks.show&lt;/code&gt; should display all the tasks with filters and pagination and the like and &lt;code&gt;tasks.board&lt;/code&gt; shows a volunteer dashboard that emphasizes upcoming unassigned tasks and other tasks marked as important. Plus, I was too busy considering trees and leaves and the like to really consider what text I should be checking for and designing how the route should work. Woof.&lt;/p&gt;

&lt;p&gt;It's almost definitely a really bad way to think about this endpoint because if I can figure out how to test simpler endpoints (ones that have tasks that should be visible to everyone, and then ones that have tasks that should be visible to everyone with some tasks being filtered out), I'll have a much better sense of how I want to go about presenting tasks a user has signed up for. &lt;/p&gt;

&lt;p&gt;So I realized all of the tests here should be rewritten to just check if a page loads or not. I'm going to add other behavior to other test files later. I finally wrote a passing test I feel ok with for &lt;code&gt;tasks.display&lt;/code&gt; because I thought this through: when I build out this method in the controller, I don't want to pass anything at all; I can get the user from the &lt;code&gt;$request&lt;/code&gt; object&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the tasks.display page'&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="p"&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;'tasks.display'&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;assertStatus&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails with a 302. And then I renamed the route from &lt;code&gt;'/tasks/user/{user}'&lt;/code&gt; to &lt;code&gt;'/tasks/user'&lt;/code&gt; in &lt;code&gt;app/routes/web.php&lt;/code&gt; and rewrote the &lt;code&gt;display()&lt;/code&gt; function in my &lt;code&gt;app/Http/TaskController.php&lt;/code&gt; to:&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;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&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="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$userTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// change this when assignment is working&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tasks.display'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'tasks'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$userTasks&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="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;But I'm not sure why I'm getting a 302. At least I've gotten to a level where I realized that a lot of the tests I considered to be passing actually aren't because I'm getting &lt;code&gt;302&lt;/code&gt;s instead of &lt;code&gt;200&lt;/code&gt;s and I don't have that many redirects in my routes. So I intentionally changed the controller to pass &lt;code&gt;['tasks' =&amp;gt; $userTasks, 'user' =&amp;gt; $user]&lt;/code&gt; and checked it out in the network part of the console. &lt;code&gt;500&lt;/code&gt;. And THEN the lightbulb went off-- I had already added authentication middleware on all the methods I'm getting &lt;code&gt;302&lt;/code&gt;s for, but I'm not writing tests for authenticated users. I guess I could spin it in a more positive way and say I'm already doing some work for testing my security groups, or hope someone else completely new learns from my mistakes. It's pretty frusterating right now. A &lt;code&gt;302&lt;/code&gt; (redirect) is still information -- it's not a &lt;code&gt;404&lt;/code&gt; (not found) or any other kind of error, and that was the goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  10 Passing Tests
&lt;/h2&gt;

&lt;p&gt;The final version of the test that &lt;code&gt;tasks.display&lt;/code&gt; is working turned out to be:&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful redirect response for unauthenticated users for the tasks.display page'&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="p"&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;'tasks.display'&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;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&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;Generally, the format for the tests on protected routes is:&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful redirect response for unauthenticated users for the &amp;lt;route name&amp;gt; page'&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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="s1"&gt;'task_description'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test Task 1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sheets_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&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;'&amp;lt;route name&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'task'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$task&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;assertStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;302&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 the one exception of &lt;code&gt;'tasks.confirmStore'&lt;/code&gt;. This route gets a &lt;code&gt;405&lt;/code&gt; (Method Not Allowed) because it should only be accessed by a redirect after a task is stored by a user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mk4IPm1J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f91h1uitd1xztuepj06o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mk4IPm1J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f91h1uitd1xztuepj06o.png" alt="the output of 10 successful tests in the terminal" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Since I published the first blog post, I've heard opinions from a few people who said they've tried TDD but couldn't stick to it and some more people that said they've never tried it but have been meaning to get around to it. I've heard from exactly one person who says he uses TDD as a methodology, and that was the instructor of the course. In the course recording. Before I started writing this. There's definitely problems with sampling here, but maybe the most important takeway I've had is that this is absolutely not required.&lt;/p&gt;

&lt;p&gt;I started writing this post about 48 hours ago, and I was hoping to have it published at least yesterday. Completing it has been a milestone that kept me focused on TDD, and TDD has been a practice that allowed me to solve a pretty overwhelming bug. Normally I would have completely given up by this point, or started greenfield. So I can confidently say at this point that this is a methodology I really like for projects, especially if you're like me and just like liking things so much that you can get distracted when the next bug or endpoint calls. But it's a very cognitively challenging practice to implement these tests if you don't start out with them and let the test suite grow with the app. Too many spinning plates.&lt;/p&gt;

&lt;p&gt;My buddy Tyler told me when he writes tests, he usually looks for access to a resource and validation rules and very little else. And then there's people who don't write any tests.&lt;/p&gt;

&lt;p&gt;I'm making a commitment to myself to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finish the entire course&lt;/li&gt;
&lt;li&gt;Add the types of testing described in the course to the project until I meet the (limited) goals I made in &lt;a href="https://dev.to/sifrious/pest-driven-development-in-a-laravel-app-project-planning-1j84"&gt;the first post in this series&lt;/a&gt;.
Then I'll decide what to do as the project expands.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>laravel</category>
      <category>testing</category>
      <category>opensource</category>
      <category>pest</category>
    </item>
    <item>
      <title>Pest-Driven Development: Literally The First Test</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Fri, 08 Sep 2023 03:12:18 +0000</pubDate>
      <link>https://forem.com/sifrious/pest-driven-development-in-a-volunteering-coordination-application-literally-the-first-test-3dn5</link>
      <guid>https://forem.com/sifrious/pest-driven-development-in-a-volunteering-coordination-application-literally-the-first-test-3dn5</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm blogging along with the laracasts series &lt;a href="https://laracasts.com/series/pest-driven-laravel" rel="noopener noreferrer"&gt;Pest Driven Laravel&lt;/a&gt; created by &lt;a href="https://twitter.com/christophrumpel" rel="noopener noreferrer"&gt;Christoph Rumpel&lt;/a&gt; as I work on a project I hope to open source. I'm just documenting how I'm working, the resources I'm using, the problems I run into and some cool things I'm reminded of as I develop.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;The next step is to actually install pest. If I was truly practicing TDD, I would have done this when I started my laravel application because &lt;a href="https://www.agilealliance.org/glossary/tdd#q=~(infinite~false~filters~(postType~(~'page~'post~'aa_book~'aa_event_session~'aa_experience_report~'aa_glossary~'aa_research_paper~'aa_video)~tags~(~'tdd))~searchTerm~'~sort~false~sortDirection~'asc~page~1)" rel="noopener noreferrer"&gt;Test-Driven Development is a lifestyle with a history and a community&lt;/a&gt;  I may as well take a moment to put my hand over my heart and remember out loud that I'm &lt;a href="https://agilemanifesto.org/" rel="noopener noreferrer"&gt;uncovering better ways of developing software&lt;/a&gt;.  But that's okay, because pest works 'on top of' an existing repository, and when you install it a folder of tests is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer require pestphp/pest &lt;span class="nt"&gt;--dev&lt;/span&gt; &lt;span class="nt"&gt;--with-all-dependencies&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; php artisan pest:install
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer require pestphp/pest-plugin-laravel &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Protip for my fellow beginners and tired people: definitely run these commands &lt;em&gt;inside&lt;/em&gt; the directory that contains the &lt;code&gt;app&lt;/code&gt; folder; it's not a global install. I also &lt;a href="https://laracasts.com/discuss/channels/testing/no-definition-found-use-function-pestlaravelget" rel="noopener noreferrer"&gt;forgot to add the pest plugin and curly braces&lt;/a&gt; which threw me for an hour or so, so do remember that last line. We'll need it, and vs code is different than phpstorm. &lt;/p&gt;

&lt;p&gt;Also, it's my personal opinion that when your terminal asks you to give a star to &lt;a href="https://github.com/pestphp/pest" rel="noopener noreferrer"&gt;a repository on github that's going to save you hours of toil and heartache&lt;/a&gt;, actually taking the time to do it is the same thing as unlocking an achievement in real life. And then you can go back someday and see all those stars and realize how connected you are to all these people who are a lot like you and how much you learned from their hard work. But again, I digress.&lt;/p&gt;

&lt;p&gt;Then you can open your &lt;code&gt;/tests/Feature/pest.php&lt;/code&gt; file and check out your new pest file, which looks like this on my fresh install:&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\Unit&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;PHPUnit\Framework\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;ExampleTest&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 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_that_true_is_true&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;$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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the very first test in the course confirms that a request to a route returns a status code of 200. We'll take out all of the code in the file and replace it with&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the home page'&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="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="s1"&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;assertStatus&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="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;So what's happening here? I think it's a fair time to stop and think about this question, especially because the code contains &lt;code&gt;it&lt;/code&gt; and &lt;code&gt;this&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Let's just talk about &lt;code&gt;it&lt;/code&gt; for a minute.
&lt;/h3&gt;

&lt;p&gt;From passing knowledge, to me &lt;code&gt;it&lt;/code&gt; indicates &lt;a href="https://en.wikipedia.org/wiki/Keyword-driven_testing" rel="noopener noreferrer"&gt;Keyword-driven testing&lt;/a&gt;, which "separates the documentation of test cases – including both the data and functionality to use – from the prescription of the way the test cases are executed". Pest isn't the only option for testing, even in laravel, but I'm choosing it because its 'claim to fame' is allowing a developer to use less code to write tests and allow that code to be more readable. So it makes sense that people new to testing (me) are going to run into some unfamiliar keywords. The apperance of &lt;code&gt;it&lt;/code&gt; combined with the extremely human-readable description as the first function parameter gave me pause. So I looked &lt;a href="https://github.com/pestphp/pest/blob/2b0aa4b9c93138c033a6da27cbbd3bd9bbd2d218/src/Functions.php#L139" rel="noopener noreferrer"&gt;&lt;code&gt;it&lt;/code&gt; up the pest source code&lt;/a&gt;, and got&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;function_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'it'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Adds the given closure as a test. The first argument
     * is the test description; the second argument is
     * a closure that contains the test expectations.
     *
     * @return Expectable|TestCall|TestCase|mixed
     */&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;TestCall&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'it %s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="cd"&gt;/** @var TestCall $test */&lt;/span&gt;
        &lt;span class="nv"&gt;$test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$closure&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;$test&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;It looks like &lt;code&gt;it&lt;/code&gt; takes the description, adds it to the string 'it' and formats it to use it as a label for the callback we're passing in the second parameter. Then, when pest actually calls &lt;code&gt;test()&lt;/code&gt; we have the super readable label and the function. &lt;code&gt;test()&lt;/code&gt; has the same method description as &lt;code&gt;it&lt;/code&gt;, but now our description is formatted for later and we can see things starting to really move inside the &lt;code&gt;test()&lt;/code&gt; function (despite the syntax of the two function calls looking similar):&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;function_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Adds the given closure as a test. The first argument
     * is the test description; the second argument is
     * a closure that contains the test expectations.
     *
     * @return Expectable|TestCall|TestCase|mixed
     */&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;HigherOrderTapProxy&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nc"&gt;TestCall&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nc"&gt;TestSuite&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getInstance&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;test&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;\PHPUnit\Framework\TestCase&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HigherOrderTapProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestSuite&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getInstance&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;test&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Backtrace&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;testFile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TestCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestSuite&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$closure&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;&lt;code&gt;it&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; mean so much in the context of testing they mean almost nothing, so I think this bit of new context is enough to give a little more meaning to what I'm reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  What even is &lt;code&gt;this&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;I want to take a minute to dive into &lt;code&gt;this&lt;/code&gt;, but I won't. Without fail, when I'm in a pairing situation and I ask a php dev what &lt;code&gt;this&lt;/code&gt; is, I'm told we'll 'get to it later' and then we write actual code and that's probably a good thing. I know that &lt;code&gt;this&lt;/code&gt; refers to the calling object, and there's always a moment when I'm reading or writing code in laravel as a beginner where I guess at what &lt;code&gt;this&lt;/code&gt; is in a new context. This is no exception. I'm definitely going to come back to it in a later post, but if someone wants to have mercy and just tell me what I am calling &lt;code&gt;get&lt;/code&gt; on (is it the whole app??) that would be great.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some More Setup
&lt;/h3&gt;

&lt;p&gt;Before I stepped back, I took a minute to create a pest alias. By default, you can run a test with &lt;code&gt;./vendor/bin/pest&lt;/code&gt; but I changed it to &lt;code&gt;pest&lt;/code&gt;. If you're reading this and you haven't already-- don't forget to alias &lt;code&gt;sudo&lt;/code&gt; to &lt;code&gt;please&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Then I hopped into the &lt;code&gt;phpunit.xml&lt;/code&gt; to uncomment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"DB_CONNECTION"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"sqlite"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;env&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"DB_DATABASE"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;":memory:"&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;which results in a super lightweight and separate testing database. And that reminded me of &lt;a href="https://show.nocompromises.io/episodes/lots-of-different-ways-to-test-record-creation" rel="noopener noreferrer"&gt;this one episode of No Compromises that I heard while driving to Nashville&lt;/a&gt;. Super hype for my first testing database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Pesty
&lt;/h3&gt;

&lt;p&gt;The next part is to refactor the test code to make it more read more pest-y. First, we'll &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;change &lt;code&gt;$response = $this-&amp;gt;get('/');&lt;/code&gt; to &lt;code&gt;get('/');&lt;/code&gt;. That requires &lt;code&gt;use Pest\Laravel\get&lt;/code&gt;, but it looks much nicer.&lt;/li&gt;
&lt;li&gt;specify a named route using the &lt;code&gt;route()&lt;/code&gt; helper instead of passing the string &lt;code&gt;/&lt;/code&gt;. Now we have &lt;code&gt;get(route('home'))&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;remove &lt;code&gt;$response-&amp;gt;assertStatus(200);&lt;/code&gt; and call &lt;code&gt;assertStatus(200)&lt;/code&gt; passing the 200 OK status code as a parameter. Now the entire file looks like:
&lt;/li&gt;
&lt;/ol&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;use&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nn"&gt;Pest\Laravel\&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gives back successful response for the home page'&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="p"&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;'home'&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;assertStatus&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another tangent: I listened to &lt;a href="https://podcasts.apple.com/us/podcast/the-laravel-podcast/id653204183?i=1000503209050" rel="noopener noreferrer"&gt;APIs, with Jess Archer&lt;/a&gt; on &lt;a href="https://laravelpodcast.com/" rel="noopener noreferrer"&gt;The Laravel Podcast&lt;/a&gt; today and there's a ton of useful information about returning HTTP status codes and why being specific about them is useful, and I'm really looking forward to seeing what can be done with that and pest.&lt;/p&gt;

&lt;p&gt;Since I'm using jetstream, I saw a lot of output. They're listed by path alphabetically. But check it out: it &lt;em&gt;does&lt;/em&gt; gives back successful response for the home page. Feels good, man. &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%2Fgs0wx8nfaqdy6pjm3eiv.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%2Fgs0wx8nfaqdy6pjm3eiv.png" alt="A screenshot of pest output with passing tests and warnings listed"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>pest</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>Pest-Driven Development: Project Planning</title>
      <dc:creator>Mary</dc:creator>
      <pubDate>Thu, 07 Sep 2023 18:43:45 +0000</pubDate>
      <link>https://forem.com/sifrious/pest-driven-development-in-a-laravel-app-project-planning-1j84</link>
      <guid>https://forem.com/sifrious/pest-driven-development-in-a-laravel-app-project-planning-1j84</guid>
      <description>&lt;p&gt;&lt;em&gt;I'm blogging along with the laracasts series &lt;a href="https://laracasts.com/series/pest-driven-laravel"&gt;Pest Driven Laravel&lt;/a&gt; created by &lt;a href="https://twitter.com/christophrumpel"&gt;Christoph Rumpel&lt;/a&gt; as I work on a project I hope to open source. I'm just documenting how I'm working, the resources I'm using, the problems I run into and some cool things I'm reminded of as I develop.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;The project I'm making is very similar to a to-do app in many ways, which is great because I've made 5 or 6 of them in other languages already. This is my first CRUD app in Laravel, so I'm trying to balance learning a new framework and philosophy with trying to keep my MVP simple and usable. It's a real struggle so far.&lt;/p&gt;

&lt;p&gt;In episode 1, Christoph discusses the benefits of test driven development including a focused method of iterative development (I'm paraphrasing) and the practice of refactoring integrated into the development process. These both sound fantastic-- how many of us have (the benefits of) &lt;em&gt;real tests&lt;/em&gt;? TDD is a topic of contention in whichever language you choose, and generally so far I've taken the advice: if you don't have users, you don't need tests. I've eschewed cleaner coding practices for a more complicated, bloated, and completed program. Then, I've proceeded to use those programs myself and look at my code months later while considering adding a new feature and wonder: who even WROTE this? But today is different. Today, I have users. &lt;/p&gt;

&lt;p&gt;I'm going to start describing this project by including some behaviors I want users to be able to experience when they use the app. This is also an exercise in the first video of the course. I will write a clearer summary soon, and part of describing it requires separating types of behaviors and the authentication roles required to interact with each type of behavior. For example, the to-do behavior of the application has different 'user stories' for events (tasks that are associated with an appointment date and time) than for a more general task class. So let's start by just talking about the event-type tasks-- not because this is the way I'd ideally like to develop, but because appointments are more urgent to the users of the app than tasks are(1).&lt;/p&gt;

&lt;h2&gt;
  
  
  Volunteers
&lt;/h2&gt;

&lt;p&gt;The future 'about' section of the app (currently a draft) describes volunteers of the application as: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[users] who have already established functional processes through experience in their domains and are willing to provide insight to contributing developers and to administrators about how technical solutions may improve their ability to help others in their community &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Volunteers should be the most numerous user group type, the type of user that can see the fewest features of the app. But the app is mostly for them. So I'm thinking about designing the interface mostly around what the volunteers will be able to see. Unlike a typical to-do app, volunteers don't make the tasks; the user dashboard will be kind of like a job board in that way. But they should be able to sign up for tasks, interact with tasks they've signed up for, and get more information about those tasks &lt;em&gt;really&lt;/em&gt; easily. Even if that usability comes at the expense of extra bloat the Administrators and Organizers-- because the goal is to get feedback to improve functionality, and I don't expect much useful feedback from users who are bogged down in complicated flows and don't have a solid understanding of how to do what they need to do. But I digress.&lt;/p&gt;

&lt;p&gt;For now I'm going to focus on testing that volunteers: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  can view a list of tasks&lt;/li&gt;
&lt;li&gt;  can view sorted lists of tasks (tasks assigned to them, budget, etc)&lt;/li&gt;
&lt;li&gt;  can sign up for a task&lt;/li&gt;
&lt;li&gt;  can remove themselves from a task&lt;/li&gt;
&lt;li&gt;  can add additional info for a task&lt;/li&gt;
&lt;li&gt;  can mark a task as completed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Organizers
&lt;/h2&gt;

&lt;p&gt;The 'about' section of the app refers to organizers generally: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Administrators and employees of nonprofit organizations who (a) can benefit from project organization and task automation, especially in cases where the reduction of time allocation for administrative tasks may be allocated towards the scope/scale of their organization's output and (b) are willing to advocate within their organization for more effective and compassionate processes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Employees are actually a different auth group from organizers, but that about isn't written as a way to think about code. So I'm taking the time to consider more clearly. Administrators have a more global idea of what needs to be done in the organization. But a less granular goal for behavior doesn't translate into a more obvious design. Because they know what needs to be assigned and has to get done and are responsible for creating tasks and maintaining them to completion, and because volunteers need to have a very simple experience, designing for administrators means considering complexity and bloat. These users aren't necessarily more available (to use and learn the app) or more technical than the volunteers-- I think these are assumptions that other organizations can make more safely.&lt;/p&gt;

&lt;p&gt;Organizers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  can view a list of tasks&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;can create tasks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;can edit all task fields&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  can view sorted lists of tasks (tasks assigned to them, budget, etc); can sign up for a task; can remove themselves from a task (this is the same behavior volunteers should have)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;can assign a volunteer to a task&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;can unassign a volunteer from a task&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;can cancel a task&lt;/strong&gt; (this shouldn't delete the task)&lt;/li&gt;
&lt;li&gt;  can &lt;strong&gt;delete a task created in error&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  can add additional info for a task (&lt;em&gt;optionally in response to requests for additional information&lt;/em&gt;-- let's handle this later)&lt;/li&gt;
&lt;li&gt;  can mark a task as completed and &lt;strong&gt;confirm a task has been completed&lt;/strong&gt;; a confirmation from this role means something different for the state of the task (and the checklist) than a volunteer's confirmation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Administrators
&lt;/h2&gt;

&lt;p&gt;For now, administrator roles mostly have additional functionality with behaviors that aren't directly related to events. Paid employees who choose to use the app fall into this category, as do some organizers who need escalated permissions.&lt;/p&gt;

&lt;p&gt;One of these behaviors is going to be adding Organizers and Volunteers. Most of this behavior is going to be handled through the Teams feature of Jetstream (yay!) but there's some domain-specific logic that I'm also going to ignore for right now. Another behavior will be handling contracts, groups of tasks not unlike a Jira epic. Contracts and tasks will both have similar completion states, and this is something that also has to be on the back burner while designing these tests.&lt;/p&gt;

&lt;p&gt;So that's the first post about reteer. And my first DEV post. I'm hoping to write my first tests today and get some additional functionality by the end of the day. Anything worth doing is worth doing badly-- and I think this is a project worth doing. If you do too, say hey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh, and the project is:
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Reteer is an open source application being designed to reduce organizational overhead within volunteer organizations. It is designed for groups with extremely low budgets who rely on donations and volunteer work to do good.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;(1). Actually, there's going to be at least two more role types in the application than we're going to discuss now. I have a brainstorming &lt;a href="https://github.com/sifrious/reteer/blob/main/reteer-app/docs/actions.md"&gt;User Actions&lt;/a&gt; document that has more behaviors and groups than this post contains, and I'm trying to be okay with letting them sit for a while. &lt;/p&gt;

</description>
      <category>laravel</category>
      <category>pest</category>
      <category>opensource</category>
      <category>todos</category>
    </item>
  </channel>
</rss>
