Twitter From Scratch Using Laravel: Create Tweet


In our previous lesson we've learned about how to verify users email and how to test email. In this lesson we will be talking about how we can give the user the ability to create tweet.

As always let's create a test first in our tests/Feature/UserTest.php. In our lesson called "Our First Test" we already have a route for creating a tweet right? because we're using a resource controller. So, let's use that now. Remember your can always use php artisan route:list to see what are the routes available in your application:
/** @test */
public function a_user_can_create_a_tweet()
{
    $user = factory('App\User')->create();
    $tweet = 'My first tweet';

    $this->post(route('tweet.store', ['username' => $user->username]), [
        'body' => $tweet
    ]);

    $this->assertDatabaseHas('tweets', ['body' => $tweet]);
}
phpunit --filter a_user_can_create_a_tweet
There was 1 error:

1) Tests\Feature\UserTest::a_user_can_create_a_tweet
Failed asserting that a row in the table [tweets] matches the attributes {
    "body": "My first tweet"
}.

The table is empty.

Next, let's update our User\TweetController.php. First, let's make sure the user is logged in when they hit the create, store, edit, update, and destroy methods in this controller by adding the auth middleware into the constructor:
class TweetController extends Controller
{
    /**
     *  Create a new controller instance
     */
    public function __construct()
    {
        $this->middleware('auth', [
                'only' => ['create', 'store', 'edit', 'update', 'destroy']
            ]);
    }
}
phpunit --filter a_user_can_create_a_tweet
There was 1 error:

1) Tests\Feature\UserTest::a_user_can_create_a_tweet
Illuminate\Auth\AuthenticationException: Unauthenticated.

Next, let's use the actingAs() method in our test to simulate an authenticated user:
$this->actingAs($user)
     ->post(route('tweet.store', ['username' => $user->username]), [
    'body' => $tweet
]);

Next, let's add some logic into the store method in our User\TweetController.php:
public function store(Request $request)
{
    $this->validate($request, [
        'body' => 'required'
    ]);

    return $request->user()->tweets()->create($request->only(['body']));
}
phpunit --filter a_user_can_create_a_tweet
There was 1 error:


1) Tests\Feature\UserTest::a_user_can_create_a_tweet
BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::tweets()
What we're doing here is we make sure that the body of the tweet is not empty using the validate method which will throw an exception and a proper error response automatically when the validation fails. Then, we get the authenticated user from the $request variable and call a tweets and create method. In this way we don't have to figure out what's the id of the user is, Laravel will automatically attach the user_id in the tweet for us.

Next, let's create that tweets relationship in our User model:
/**
 *  Get all the user tweets
 * 
 *  @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function tweets()
{
    return $this->hasMany(Tweet::class);
}
phpunit --filter a_user_can_create_a_tweet
There was 1 error:


1) Tests\Feature\UserTest::a_user_can_create_a_tweet
Illuminate\Database\Eloquent\MassAssignmentException: body

Next, let's make that body column fillable in our Tweet model:
class Tweet extends Model
{
    /**
     *  The attributes that are mass assignable.
     * 
     *  @var array
     */
    protected $fillable = ['body'];
}
phpunit --filter a_user_can_create_a_tweet

OK (1 test, 1 assertion)

That's all for this lesson. In our next lesson we will try to make a browser test for this using Laravel Dusk. As always if you have any questions please write it down in the comment below. See you in the next lesson. Thanks!

View the source code for this lesson on GitHub.

Previous: Email Verification with TestNext: Create Tweet with Laravel Dusk