Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing Drupal pages: Help Please :-) #49

Closed
laceysanderson opened this issue Jun 2, 2018 · 10 comments
Closed

Testing Drupal pages: Help Please :-) #49

laceysanderson opened this issue Jun 2, 2018 · 10 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@laceysanderson
Copy link
Member

Hi, I would like to test a specific Drupal page (Http Requests) but it requires a privileged user to be logged in. How would I go about that?

For example, I want to test the node creation form: [mysite]/node/add/blastdb. This is what I have so far:

  /**
   * Test Creating a BlastDB Node.
   */
  public function testBlastDBNodeCreate() {

    // Go to the node creation page.
    $response = $this->get('/node/add/blastdb');

    // Verify you can see the page.
    $response->assertStatus(200)
             ->assertSee('Create Blast Database');
  }

and this is what I get

./vendor/bin/phpunit
PHPUnit 5.7.27 by Sebastian Bergmann and contributors.

Runtime:       PHP 5.6.7-1
Configuration: ./phpunit.xml

.F                                                                  2 / 2 (100%)

Time: 559 ms, Memory: 42.75MB

There was 1 failure:

1) Tests\BlastDBNodeTest::testBlastDBNodeCreate
Failed to send GET request to http://127.0.0.1/node/add/blastdb. Client error: `GET http://127.0.0.1/node/add/blastdb` resulted in a `404 Not Found` response:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found (truncated...)

./vendor/statonlab/tripal-test-suite/src/Concerns/MakesHTTPRequests.php:131
./vendor/statonlab/tripal-test-suite/src/Concerns/MakesHTTPRequests.php:32
./tests/BlastDBNodeTest.php:40

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
@laceysanderson
Copy link
Member Author

Looking at the output made me realize I have a bigger problem then just the expected one: It's assuming my site is at http://127.0.0.1/ but it would actually be at http://127.0.0.1/dev/clone.

Furthermore, it's behind an HTAccess wall so I would need to be able to enter username/password... Could this be done in the .env file?

@almasaeed2010
Copy link
Contributor

We've encountered this issue before and attempted to fix it but we unfortunately couldn't find a simple solution. From what I saw on other testing frameworks for drupal 7, you have to add and activate the "drupal RESTful" module to be able to authenticate as a privileged user. I am not sure how to deal with HTTP Basic Auth (htaccess). I am sure that GuzzleHTTP (a dependency of TripalTestSuite) can handle it so I'll add that as feature request :). However, there are other limitations to HTTP Testing.

Currently, here are the limitations of http testing:

  • Signing in is not possible without an additional module.
  • If you are adding data in a DBTransaction within a test, the data won't be available when requesting via HTTP since that's the expected behavior in transactions.

We found that HTTP testing at this stage can only be useful to test unpriviledged pages that rely on data pre-existing in the database :(. I love HTTP testing in Laravel and find it very useful so we should work on finding a solution to those couple of issues.

@almasaeed2010
Copy link
Contributor

almasaeed2010 commented Jun 2, 2018

One way to solve both these issues is to execute the menu item's callback instead of actually calling the URL. We can then use the silent() helper method to collect output and simulate a proper HTTP response with data that's added in a transaction being available. This will also prevent any side-effects to the database from happening if we wanted to run the test in a transaction.

@almasaeed2010 almasaeed2010 added enhancement New feature or request question Further information is requested labels Jun 2, 2018
@laceysanderson
Copy link
Member Author

I found a way 🎉

First to get around my .htaccess restriction for my test site I created a .env file like so:

BASE_URL=http://user:pass@htaddressofhost
DRUPAL_ROOT=/actual/full/path/to/drupal/root

Then to get around the requirement for an authenticated user

    // Log in the god user.
    global $user;
    $user = user_load(1);

    // Do what you need to do
    // Can't use the TripalTest get/post methods here
    // have to call the functions specifically.
    // @see next code block for an example.

    // log out the god user.
    $user = drupal_anonymous_user();

and finally, I executed the Dupal node form within the above authentication block as follows:

    // Create a blank node of the correct type.
    $node = array('type' => 'blastdb');

    // Fill in the form.
    $form_state = array(
      'values' => array(
        'db_name' => 'Test Blast Database',
        'db_path' => '/fake/path/here',
        'db_dbtype' => 'nucleotide',
        'dbxref_linkout_type' => 'none',
        'op' => t('Save'),  // CRITICAL!
      ),
    );

    // Execute the node creation form.
    drupal_form_submit('blastdb_node_form', $form_state, (object) $node);

    // Retrieve any errors.
    $errors = form_get_errors();

    $this->assertEmpty($errors);

Thoughts?

@bradfordcondon
Copy link
Member

bradfordcondon commented Jun 5, 2018

  • uname/pass: should we add as variables in .env? Or is @laceysanderson 's solution sufficient? If thats the case, lets add it to the documentation

As for the rest... I think thats really interesting, I'm glad it works for you.

I had been previously thinking that checking form errors/submission was better done by directly calling the method that drupal_form_submit would invoke. Validation could be tested by calling form_validate() directly, i think.

Not sure what the advantages/disadvantages of each are. I think it is going to depend on how comlpicated the form is: for complex forms, you'll want to do it this way I bet. So again I wonder if this example should get documented....

@almasaeed2010
Copy link
Contributor

almasaeed2010 commented Jun 5, 2018

IMO, this approach for uname/pass is sufficient and will be consistent across all http service providers (Apache2, Nginx...).

I think form testing should always be done in this way since going through the Drupal menu will require us to obtain a CSRF token which can be hard to deal with (goes in a cookie and in the form as a hidden input).

As for authentication, we had a method $this->actingAs($user_id) that automatically authenticates a user and resets the sessions to it's original state when the test is over. I need to check to make sure it still exists. After we removed some HTTP methods that were malfunctioning, I think we removed this too but we should bring it back.

@almasaeed2010
Copy link
Contributor

almasaeed2010 commented Jun 5, 2018

Another note, we should probably make sure to empty the $_SESSION['messages'] variables since it will hold form errors if any exist and therefore will be present in the next testing function. This is good to add into the setUp and tearDown methods.

@laceysanderson
Copy link
Member Author

Yes, the nice thing about calling drupal_form_submit() is that it calls all the hooks and alters to make sure you end up with the exact form and validation the user will get.

A better way to authenticate a user would be much appreciated! This still feels hacky. Ideally there would be a way to authenticate the god user without hard-coding the password in the file or even needing to know what it is.

@laceysanderson
Copy link
Member Author

Note: you need to add the following before drupal_form_submit() of node forms or they will fail on travis CI

module_load_include('inc', 'node', 'node.pages');

@almasaeed2010
Copy link
Contributor

So we added an authentication method that takes out all of the cumbersome work of authenticating and reverting to anonymous. It also manages the session state correctly as recommended by Drupal.

Documentation here: https://github.com/statonlab/TripalTestSuite#user-authentication

🎊🎊🎊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants