Plots2: System Tests: Comments [Outreachy]

Created on 9 Dec 2020  Â·  11Comments  Â·  Source: publiclab/plots2

@jywarren @cesswairimu @sagarpreet-chadha I could use a little guidance on how to write tests for async comment testing. I realized that I don't fully understand what _async_ means in this context.

This planning Google Doc mentions it on page 14:

_(Test for)_ Comment boxes created asynchronously (like, reply form on a just-posted comment) rather than on a freshly loaded page

That's talking about this kind of action _(except for the weird email that opens in the tab, I think that only happens locally for some reason)_:
Untitled 5

I guess this would actually be an asynchronous comment response. Would a good test for this basically be:

  • navigate to page, and stay on it
  • post a comment
  • wait asynchronously for the DOM to update with the comment
  • then post a reply to the comment you just posted(?)

Second Question:

  • What's an example of posting an asynchronous comment (different from the comment _response_ I posted above)? So far I know two different methods for posting a comment... Would the tests for either of these be considered async? If not what?
outreachy testing

Most helpful comment

Okay, finally have some insight, making AJAX requests in the browser console was indeed super-helpful.

Here's what my simulated AJAX request looks like when it's received by the Rails console:

  Started GET "/comment/update/13?body=nyah+nyah&_=1608601205240" for 127.0.0.1 at 2020-12-21 17:42:01 -0800
  Processing by CommentController#update as */*
  Parameters: {"body"=>"nyah nyah", "_"=>"1608601205240", "id"=>"13"}

Here's what a typical AJAX request looks like when received via the edit comment form, as normal:

  Started POST "/comment/update/13" for 127.0.0.1 at 2020-12-21 17:51:29 -0800
  Processing by CommentController#update as HTML
  Parameters: {"authenticity_token"=>"nbOcOGXMKihOckFT5QOxDrWlHF2HEM4ONsoC9D64Qwb/CsO3BpXo5MueR5nTiu42zbVc26IYAmZ1m41Fc8v+wQ==", "image"=>{"photo"=>""}, "body"=>"nyah nyah!!!", "id"=>"13"}

🤦 GET vs POST! Luckily config/routes.rb can accommodate both GET and POST requests to /comment/update, and routes them toward the same comment#update action.

That's not all though, turns out that the edit form has an authenticity token embedded in it:
https://github.com/publiclab/plots2/blob/6505f539cabcb9aa4eb9fc5c00af6cf9584351a2/app/views/comments/_edit.html.erb#L5
I'm not sure what this authenticity token does per se, it doesn't seem to be required to update comment content, since the comment updates just fine without it-- Is this maybe a security issue? comment#update does check for current.uid FYI.

The most interesting thing I found was this, which is the XHR responseText:

"Turbolinks.clearCache()\nTurbolinks.visit(\"http://localhost:3000/notes/user/12-08-2020/can-i-ask-a-question?_=1608604257\", {\"action\":\"replace\"})"

This looks like some under-the-hood Rails stuff which is the piece that actually does the redirect?

Just posting this here as a big old FYI. It's pretty interesting, but just confirms my decision to write all the tests manually from now on. 😅

All 11 comments

Yes, this sounds like a good workflow. One thing that may simplify things
(worth trying) is that Capybara, which runs our system tests, automatically
waits a bit until it can find a CSS match for an assertion in a test. So,
if you do the action and then do a CSS assertion, it'll wait until the
action has completed and the page is finished loading/reloading to try the
assertion. I think there's a timeout but as everything is local it should
be a pretty fast response from the server in any case.

I think we've even left some comments in the code of the system tests
noting this technique!

On Wed, Dec 9, 2020 at 3:18 AM noi5e notifications@github.com wrote:

@jywarren https://github.com/jywarren @cesswairimu
https://github.com/cesswairimu @sagarpreet-chadha
https://github.com/sagarpreet-chadha I could use a little guidance on
how to write tests for async comment testing. I realized that I don't fully
understand what async means in this context.

This planning Google Doc
https://docs.google.com/document/d/1hOqa4tC0jqEuSaur1zKMtnxnknkARui3HTKqO3AUFMA/edit
mentions it on page 14:

(Test for) Comment boxes created asynchronously (like, reply form on a
just-posted comment) rather than on a freshly loaded page

That's talking about this kind of action (except for the weird email
that opens in the tab, I think that only happens locally for some reason)

:
[image: Untitled 5]
https://user-images.githubusercontent.com/4361605/101602225-a29b9800-39b2-11eb-9ecb-d214a5c5facd.gif

I guess this would actually be an asynchronous comment response. Would
a good test for this basically be:

  • navigate to page, and stay on it
  • post a comment
  • wait asynchronously for the DOM to update with the comment
  • then post a reply to the comment you just posted(?)

Second Question:

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/publiclab/plots2/issues/8810, or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAF6JYCENEGHEIE7RBYYITST4XDXANCNFSM4UTD6JKA
.

perhaps the 2 levels of testing here are:

  1. the one you've proposed -- posting a comment and without a page refresh, replying to it
  2. trying some other action upon a newly created (by AJAX/JS) comment form - like uploading an image - and ensuring that it appears in the correct box and not in any others

My thought is that it's good to keep in mind that we want to be confirming the "normal" behavior of the form and comment editor that was just created -- so using it to post a reply is just one way we can confirm this. What do you think?

except for the weird email that opens in the tab, I think that only happens locally for some reason

This btw is apparently some Ruby gem that intercepts mails locally and opens them in a browser tab, to make debugging easier without having to set up an email service. I forget what it's called though!

@jywarren Thanks for the pointers earlier this week BTW. I'm working on a test right now for editing a _freshly posted_ comment.

We already have one test for editing an _existing_ comment. This test works manually via JQuery, selecting CSS elements and clicking on them:

      # Wait for comment to upload
      wait_for_ajax
      # Edit the comment
      page.execute_script <<-JS
        var comment = $(".comment")[1];
        var commentID = comment.id;
        var editCommentBtn = $(comment).find('.navbar-text #edit-comment-btn')
        // Toggle edit mode
        $(editCommentBtn).click()
        var commentTextarea = $('#' + commentID + 'text');
        $(commentTextarea).val('Updated comment.')
        var submitCommentBtn = $('#' + commentID + ' .control-group .btn-primary')[1];
        $(submitCommentBtn).click()
      JS
      message = find('.alert-success', match: :first).text
      assert_equal( "×\nComment updated.", message)

I thought I would go the other route by skipping the manual part, and instead doing a direct POST request to /comment/update:

      page.execute_script(<<~JS, comment_id_num)
        ((commentID) => {
          const requestBody = { body: "nyah nyah" }
          sendFormSubmissionAjax(requestBody, "/comment/update/" + commentID)
        })(arguments[0])
      JS
      message = find('.alert-success', match: :first).text
      assert_equal( "×\nComment updated.", message)
      assert_selector("#{comment_id} p", text: 'nyah nyah')

For some reason the test fails and I get the following error:
Screen Shot 2020-12-17 at 8 30 09 PM

I can think of a few possibilities here:

SIDE NOTE: Edit Comment Triggers Page Reload?

Editing a comment triggers a page reload, but posting doesn't.
Untitled 5

Questions:

  • Any thoughts on why the test is failing?
  • Where in the code is making the page reload on edit comment? Is it possible to rewrite this?

Did more research on the edit comment flow, logged a lot of variables to the console. Still don't understand why I don't get a page & comment reload when I simulate a POST request to comment#update, instead of manually clicking on buttons.

It's also not that urgent. There is already one update comment test for wikis that is all manually submitted... Upon thinking about it some more, I think it makes sense that most of the system tests should be manual anyway. Because that's the point of a system test, right? So I shouldn't be trying to simulate AJAX submissions, instead I should be simulating button clicks.

I do still kind of want to know more about the edit comment flow I posted about above. But am focusing my energy elsewhere for the time being, particularly these system tests (in order of completion):

  1. post fresh note/question/wiki, then comment on it
  2. multiple comment boxes open, post/reply/upload image, and see if something breaks.
  3. formatting crosswiring: bold and italics in the right place, even if multiple comment boxes open

I think I might start to see failing tests for the last two, which I hope will be a good transition toward focusing more energy on bug-fixing.

Hi, @noi5e -- just a quick response here, sorry i didn't get to this on Friday. A few ideas here, and you may know better than I which is most helpful:

Were you able to try running these JS steps exactly in the JS console? That may be the easiest way to see if your test is running properly.

instead I should be simulating button clicks

Yes, i think that makes sense. Otherwise they're more like unit tests of our JS, which are also valuable but should be more narrowly designed. Let me see if I can trace exactly the sequence of events for this...

OK, with regard to the flash[:notice] style alerts, these only get rendered when the page is refreshed - it persists the message to the next page render -- so /after/ the render statement, or after a redirect statement.

I don't see a way that sendFormSubmissionAjax is set up to make a message... hmm. Aha! Ok, so it's triggering an event called ajax:success upon completion; that activates this segment of code:

https://github.com/publiclab/plots2/blob/484bf69ead7a1f69c9047a25b3f63b9d6f875728/app/assets/javascripts/comment.js#L5-L13

Does that make sense? As to why the returned message is not activating that, let's first confirm that it happens when done manually in the console. If you do it you can also watch the Rails console at the same time to confirm that the POST request succeeds with a 200 success status.

If it succeeds locally/manually, then the problem may be that we need to wait for the returned AJAX to trigger that event and insert the message /before/ asserting the message content, so there may be a kind of wait_for_ajax type method we do to insert some wait time. See how that works here!

https://github.com/publiclab/plots2/blob/876d0fc084064aaecc23f8003630d7d1ab858fa1/test/system/rich_text_editor_test.rb#L35-L39

I think the actual code behind wait_for_ajax is here; https://github.com/publiclab/plots2/blob/876d0fc084064aaecc23f8003630d7d1ab858fa1/test/application_system_test_case.rb#L52

Hopefully that helps get this test running! Please reach out if you get stuck but i'll also be online all tomorrow as usual so we can pair up on this if it's helpful too.

Thanks @noi5e for sticking with this one! These are challenging tests and somewhat tangled code; you can see why we may want to at least insert more comments explaining how this works, and at best, perhaps refine the code structure some!

@jywarren I appreciate those clarifications! That's a great tip to debug JS in the browser console. I didn't even think about that but of course it makes sense.

Even though I know to focus more on manual testing, I'll look at this to get a better general understanding of mechanics... I'm sure I'll get more insight. Thanks again.

Okay, finally have some insight, making AJAX requests in the browser console was indeed super-helpful.

Here's what my simulated AJAX request looks like when it's received by the Rails console:

  Started GET "/comment/update/13?body=nyah+nyah&_=1608601205240" for 127.0.0.1 at 2020-12-21 17:42:01 -0800
  Processing by CommentController#update as */*
  Parameters: {"body"=>"nyah nyah", "_"=>"1608601205240", "id"=>"13"}

Here's what a typical AJAX request looks like when received via the edit comment form, as normal:

  Started POST "/comment/update/13" for 127.0.0.1 at 2020-12-21 17:51:29 -0800
  Processing by CommentController#update as HTML
  Parameters: {"authenticity_token"=>"nbOcOGXMKihOckFT5QOxDrWlHF2HEM4ONsoC9D64Qwb/CsO3BpXo5MueR5nTiu42zbVc26IYAmZ1m41Fc8v+wQ==", "image"=>{"photo"=>""}, "body"=>"nyah nyah!!!", "id"=>"13"}

🤦 GET vs POST! Luckily config/routes.rb can accommodate both GET and POST requests to /comment/update, and routes them toward the same comment#update action.

That's not all though, turns out that the edit form has an authenticity token embedded in it:
https://github.com/publiclab/plots2/blob/6505f539cabcb9aa4eb9fc5c00af6cf9584351a2/app/views/comments/_edit.html.erb#L5
I'm not sure what this authenticity token does per se, it doesn't seem to be required to update comment content, since the comment updates just fine without it-- Is this maybe a security issue? comment#update does check for current.uid FYI.

The most interesting thing I found was this, which is the XHR responseText:

"Turbolinks.clearCache()\nTurbolinks.visit(\"http://localhost:3000/notes/user/12-08-2020/can-i-ask-a-question?_=1608604257\", {\"action\":\"replace\"})"

This looks like some under-the-hood Rails stuff which is the piece that actually does the redirect?

Just posting this here as a big old FYI. It's pretty interesting, but just confirms my decision to write all the tests manually from now on. 😅

Ah! The token is required for Rails POST routes, i believe, perhaps especially ones sent by JavaScript... i forget exactly how it's tracked but the idea is to prevent random JS scripts from sending such requests outside the scope of a page where they're intended. So perhaps we just aren't triggering any security in the way we're using it right now?

Oof, it looks like that's left over from our attempt to use Turbolinks to accelerate page loads, which worked, but broke our Google Analytics scripts, so we turned it off; #2132 is an entry point here. If this is causing a failure, we may need to turn that response off -- i think what it may have been doing is initiating a Turbolinks-style redirect and ensuring it got refreshed with a new page, but we don't currently use Turbolinks. Gosh, Turbolinks is a fascinating system but it touches so many parts of a platform that it seems quite brittle!

I think we're actually pretty good here, what do you think @noi5e? What other system tests are you planning to add, if any? Thank you!

@jywarren Yeah, I agree. I think I have enough of an idea of how to proceed from here. Will just be adding system tests for bugs as they appear. Closing this issue for now at least.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ebarry picture ebarry  Â·  3Comments

RuthNjeri picture RuthNjeri  Â·  3Comments

grvsachdeva picture grvsachdeva  Â·  3Comments

first-timers[bot] picture first-timers[bot]  Â·  3Comments

grvsachdeva picture grvsachdeva  Â·  3Comments