susanBuck / e15-spring22

0 stars 0 forks source link

How to check for redirect in Codeception? #73

Closed pllealfunes closed 2 years ago

pllealfunes commented 2 years ago

Hi guys,

For my project after a user deletes a post they should be redirected back to the home page and see a flash message saying 'Your Post was Deleted'. Right now for my test I can only test up to $I->amOnPage('/posts/1/delete'); after that I am unsure on how to check that I was redirected back to the home page and see the flash message. Below is what I currently have.

Post Controller

public function destroy($id)
    {
        $post = Post::find($id);

        # Before we delete this post we first have to delete
        # any relationships connected to this user

        $post->user()->dissociate();

        $post->delete();

        return redirect('/')->with(['flash-alert' => 'Your Post was Deleted.']);
    }

Routes

Route::delete('/posts/{id}/delete', [PostController::class, 'destroy']);

ShowPageCest

public function loginDeletePost(AcceptanceTester $I)
    {
        $I->amOnPage('/test/login-as/1');
        $I->amOnPage('/');
        $I->click('[test=post-link-1]');
        $I->see('Crochet 101');
        $I->click('[test=delete-post-button]');

        $I->amOnPage('/posts/1/delete');
       /* $I->seeCurrentUrlEquals('/');
        $I->see('Your Post was Deleted'); */
    }
susanBuck commented 2 years ago

Hi @pllealfunes - FYI looking at this now and will reply shortly.

susanBuck commented 2 years ago

This should do the trick:

$url = $I->grabFromCurrentUrl();
$I->assertEquals('/', $url);
pllealfunes commented 2 years ago

@susanBuck I got the following after adding your suggestion.

1) ShowPostPageCest: Login delete post
 Test  tests/acceptance/ShowPostPageCest.php:loginDeletePost
 Step  Assert equals "/","/posts/1/delete"
 Fail  Failed asserting that two strings are equal.
- Expected | + Actual
@@ @@
-'/'
+'/posts/1/delete'

Here is how I added it

public function loginDeletePost(AcceptanceTester $I)
    {
        $I->amOnPage('/test/login-as/1');
        $I->amOnPage('/');
        $I->click('[test=post-link-1]');
        $I->see('Crochet 101');
        $I->click('[test=delete-post-button]');

        $I->amOnPage('/posts/1/delete');
        $url = $I->grabFromCurrentUrl();
        $I->assertEquals('/', $url);
        $I->see('Your Post was Deleted');
    }
susanBuck commented 2 years ago

I believe you want to remove this line:

$I->amOnPage('/posts/1/delete');

You don't want to actually navigate to /posts/1/delete.

Instead, you click the delete post button ($I->click('[test=delete-post-button]');) and it should redirect you to the homepage. Then you do the check of the URL.

pllealfunes commented 2 years ago

I removed the line but I still get the below Screen Shot 2022-05-10 at 5 49 12 PM

Screen Shot 2022-05-10 at 5 47 36 PM .

susanBuck commented 2 years ago

The test is saying that the URL is reading as "/posts/1/delete" - so it appears the redirect isn't happening. When you manually test it directly in the browser does it work as expected?

I just tried to do a deletion and it appears there's an error you will need to resolve:

image

This issue is covered here: https://hesweb.dev/e15/notes/laravel/db-bookmark-list#deleting-rows-associated-with-foreign-keys

pllealfunes commented 2 years ago

I was able to resolve the deletion issue but now I am unable to display the name of the user who has written the post.

I know you said for my Post Model it would be $this->belongsToMany(User::class,'comments'); but when I tried to do $post->user->name to display the name of the user who wrote the post it wouldn't work. So I changed the Model to $this->belongsTo(User::class); and was able ti display the name but I guess I lost the ability to delete a post.

How can I display the name now that I changed back to thebelongsToMany in my Model? Using $post->user I get an empty array.

Update

The test also continues to fail with Screen Shot 2022-05-10 at 7 34 49 PM

susanBuck commented 2 years ago

One moment - I'm going to log into your server to take a closer look at your current code. Will reply shortly.

susanBuck commented 2 years ago

Ok - I made the following changes to your code on your server to help sort this out:

You had relationships to associate posts and users for comments, but there was no relationship to establish the connection between a post and user as the author of a post.

To address this I added the following method to your Post model:

public function user()
{
    return $this->belongsTo(User::class);
}

And renamed the relationship method connecting users and posts for commenting purposes from user to comments

public function comments()
{
    return $this->belongsToMany(User::class, 'comments');
}

Likewise, in the User model, I set up the following methods:

public function comments()
{
    return $this->belongsToMany(Post::class, 'comments');
}

public function posts()
{
    return $this->belongsToMany(Post::class);
}

With this set up, we can now output the "written by" info on the show page:

<p>Written by: <a test='user-profile-link' href='/profile/{{ $post->user->id }}'>{{ $post->user->name }}</a></p>

Please let me know if you have any questions about the above changes

pllealfunes commented 2 years ago

@susanBuck Thank you for the help.

I ran my tests again and I got the error below but I was able to fix it by adding onDelete('cascade') to the end of my Posts foreign key in my Comments table. Now all my tests pass.

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (p3.comments, CONSTRAINTcomments_post_id_foreignFOREIGN KEY (post_id) REFERENCESposts(id))

Comments Table

 public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->text('comment');
            $table->bigInteger('post_id')->unsigned();
            $table->bigInteger('user_id')->unsigned();

        # Make foreign keys
        $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
        $table->foreign('user_id')->references('id')->on('users');
        });
    }

Post Controller

public function destroy($id)
    {
        $post = Post::find($id);

        # Before we delete this post we first have to delete
        # any relationships connected to this user

        $post->user()->dissociate();

        $post->delete();

        return redirect('/')->with(['flash-alert' => 'Your Post was Deleted.']);
    }
susanBuck commented 2 years ago

Glad you got it all sorted out 👍