Difference between feature and browser tests - laravel

I was at the point where I felt familiar with feature and unit tests in Laravel. But recently I created a new project and discovered Laravel Dusk. After its installation there now also is a Browser directory where I can put my tests in. But now I'm confused, what is the difference between a feature and a browser test? For example where would I put tests like
a_visitor_can_signup()
the_index_page_shows()
the_contact_form_validates()
..
Is browser behavior (interaction) a typical browser test? And would request-like tests like testing endpoints for a HTTP status 200 to ensure nothing is broken at that point be feature tests?

A feature test would be a test, which tests a feature product may have asked for while a browser behavior test would test a specific action.
Feature Test: User can sign up.
Browser Behavior Test: When user clicks the button it submits the form.
Basically, the feature test is the end-to-end test. While the browser behavior test is a unit or integration test testing a single behavior.
In general, you want to have unit tests—each of which test a single behavior. One main reason being maintainability.
For example, if testing a javascript form, you may have behavioral javascript tests like the following:
describe("form#user-profile", function(){
context("when a click event is triggered", function(){
describe("`foo` is called with arguments a, b and c", function(){
expect(foo).to.be.calledWith(a,b,c)
})
})
})
Which will read out as "form#user-profile, when a click event is triggered, foo is called with arguments a, b and c." This in essence is a unit test which tests a "browser behavior"
References
Mocha
Chai
Sinon

I would summarize like this:
If there is javascript involve in the test, use laravel dusk (browser test).
If there is none, stick to feature test.

Related

How do you test response contains string in Inertia unit tests?

I am using Inertia and would like to run some tests to check whether the response contains a certain string.
->assertInertia(
fn (AssertableInertia $page) => $page->component('UsersPage')->has('profile')->dd('profile.0.buttons')
);
so the above works and i can dump the profile.0.buttons and see the string i want to check for, but how do i automatically test that this string exists? normal unit tests, i'd use assertSee. whereContains also doesn't work.
I think that Inertia page about testing has done a great job in summing the testing option for Laravel/Inertia.
Endpoint tests (assertInertia) are feature tests, and you can use them to check if a controller is sending the right components and data to Inertia.
Your question is going more in the direction of "Client-side unit tests" e.g. Jest, where you can send some data to React/Vue component and see how that data has been rendered.
There are "End-to-end tests": Cypress is great but lacks nice integration with setting up Laravel enviroment and seeders in test.
That leave us with Laravel Dusk. I love this tool because it give us best of both worlds (backend and frontend).
You can set up your test with seeders or Model factories, and in the same test you can fire up virtual browser and see how Inertia rendered page. Best thing is that you can use helpers for typing and clicking so you can realy test your app and how it behaves.

How to test Capybara?

I have a script that use Capybara to publish links in Google+. I would like to have tests to cover this functionality. Usually Capybara is using as a tool for writing Integration tests. In may case i need to test Capybara itself.
I see 3 possible ways:
stub capybara's method (but in this case i test nothing but just stubbed methods)
test capybara agains saved HTML/JS page (that will help me understand that i did not break anything during refactoring)
do not test at all (no comments here)
Have you ever faced such a problem?
If you register different drivers for your app and your test code, possibly manage the sessions manually depending on how you're using it in your app, and make sure you're careful with Capybaras setting's you should be able to go with option 2. You have to be careful with Capybaras settings because most of them are global so changing them for your tests will also change them for your app.

Codeception, Laravel, Acceptance tests

I'm developping an acceptance test with Codeception Laravel 5.
I see in the docs that module Laravel 5 should not be used in acceptance tests.
Now, I would like to use function like: Auth::xxx, factory(User::class)->create(), etc... but those functions are not recognized.
I can use them in my funcional tests, because I include Laravel 5 Module.
Does it mean I will not be able to use them in acceptance test, or is there a trick to do it???
The documentation clearly outlines the answer to your question:
You should not use this module for acceptance tests. If you want to use Laravel functionality with your acceptance tests, for example to do test setup, you can initialize the Laravel functionality by adding the following lines of code to your suite _bootstrap.php file:
So this is what you add:
require 'bootstrap/autoload.php';
$app = require 'bootstrap/app.php';
$app->loadEnvironmentFrom('.env.testing');
$app->instance('request', new \Illuminate\Http\Request);
$app->make('Illuminate\Contracts\Http\Kernel')->bootstrap();
This means you can use the Laravel functionality in your Acceptance Tests, however, you can't use the Codeception Laravel 5 module for your Acceptance Tests.
Hopefully this clears things up.
When in acceptance testing, you have two instances, yours (codeception) and the app's (website).
This means anything laravel you use in your instance won't work in the app's instance.
Here Auth::check() has no meaning, as acceptance testing must be decoupled from the app. You should assert if you are seeing Log In or Log Out in the rendered html for example.
Eloquent is the only thing you can get away with when in acceptance testing.

Select list for QUnit modules in test runner bar?

I recall having seen at some point screen shots of a select list of QUnit test modules in the test runner toolbar of QUnit. My impression was that selecting one of the modules in the select list would cause that module's tests to be run.
Question: Does such a feature actually exist OOB for QUnit? I know one can set filter via the URL but I would like a more "discoverable" option.
Thanks!
The select list only shows itself if you have defined more than one module in your test suite.
Also, make sure that your test suite is ready before QUnit initializes itself. i.e. QUnit initializes itself when the page finishes loading (the onload event). If you happen to define your test suite after this, then you have to call the (undocumented) QUnit.load() method to notify QUnit that your test suite has been defined.
Demo: http://jsfiddle.net/brianpeiris/98fc8/show/

How do you figure out what test will best represent the feature you want to create?

Test driven development on wikipedia says first develop a test that will fail because the feature does not exist. Then build the code to pass the test. What does this test look like?
How do you figure out what test will best represent the feature you want to create?
Can someone give an example?
Like if I make a logout button feature to a web application then would the test be hitting the page looking for the button? or what?
I heard test driven is nice for regression testing, I just don't know how to start integrating it with my work.
Well obviously there are areas that are more suited for TDD than others, and running frontend development is one of the areas that I find difficult to do TDD on. But you can.
You can use WATIN or WebAii to do that kind of test. You could then:
Write a test that checks if a button exists on the page ... fail it, then implement it, and pass
Write a test that clicks the button, and checks for something to change on the frontend, fail it, implement feature and pass the test.
But normally you would test the logic behind the actions that you do. You would test the logout functionality on your authenticationservice, that is called by your eventhandler in webforms, or the controller actions in MVC.
What does this test look like?
A test has 3 parts.
it sets up a context
it performs an action
it makes an assertion that the action did what it was supposed to do
How do you figure out what test will best represent the feature you want to create?
Tests are not based on features (unless you are talking about a high level framework like cucumber), they are based on "units" of code. Typically a unit is a function, and you will write multiple tests to assert all possible behaviors of that function are working correctly.
Can someone give an example?
It really varies based on the framework you use. Personally, my favorite is shoulda, which is an extension to the ruby Test::Unit framework
Here is a shoulda example from the readme. In the case of a BDD framework like this, contextual setup happens in its own block
class UserTest < Test::Unit::TestCase
context "A User instance" do
setup do
#user = User.find(:first)
end
should "return its full name" do
assert_equal 'John Doe', #user.full_name
end
context "with a profile" do
setup do
#user.profile = Profile.find(:first)
end
should "return true when sent #has_profile?" do
assert #user.has_profile?
end
end
end
end
Like if I make a logout button feature to a web application then would the test be hitting the page looking for the button? or what?
There are 3 main types of tests.
First you have unit tests (which is what people usually assume you are talking about when you talk about TDD testing). A unit test tests a single unit of work and nothing else. This means that if your method usually hits a database, you make sure that it doesn't actually hit that database for the duration of the test (using a technique called "mocking").
Next, you have integration tests. An integration test usually involves interaction with the infrastructure, and are more "full stack" testing. So from your top level API, if you have an insert method, you would go through the full insert, and then test the resulting data in the database. Because there is more setup in these sorts of tests, they shouldn't really be run from developer machines (it is better to automate these on your build server)
Finally, you have UI testing. This is the most unreliable, and requires a UI scripting framework like Selenium or Waitr to automate clicking around your UI. Don't go crazy with this sort of testing, because these tests are notoriously fragile (a small change can break them), and they wont catch whole classes of issues anyways (like styling).
the unit test would be calling the logout function and verifying that the expected results occurred (user login record ended, for example)
clicking the logout button would be more like an acceptance test - which is also a good thing to do, and (in my opinion) well within the scope of TDD, but it tests TWO features: the button, and the resulting action
It depends on what platform you are using as to how your tests would appear. TDD is much harder in ASP.NET WebForms than ASP.NET MVC because it's very difficult to mock up the HTTP environment in WebForms to get the expected state of Session, Application, ViewState etc. as opposed to ASP.NET MVC.
A typical test is built around Arrange Act Assert.
// Arrange
... setup needed elements for this atomic test
// Act
... set values and/or call methods
// Assert
... test a single expected outcome
It's very difficult to give deeper examples unless you let us know the platform you plan to code with. Please give us more information.
Say I want to make a function that will add one to a number (really simple example).
First off, write a test that says f(10) == 11, then do one that says f(10) != 10. Then write a function that passes those tests. If you realise the function needs more capabilities, add more tests.
The test would be making sure that when the logout function was executed, the user was successfully logged out. Generally a unit testing framework such as NUnit or MSTest (for .Net stuff) would be used.
Web applications are notoriously hard to unit test because of all the contextual information generally required for the execution of server code on a web server. However, a typical example would mock up that information and call the logout logic, and then verify that the correct result was returned. A loose example is an MVC type test using NUnit and Moq:
[Test]
public void LogoutActionShouldLogTheUserOut()
{
var mockController = new Mock<HomeController>() { CallBase = true };
var result = mockController.Object.Logout() as ViewResult;
Assert.That(result.ViewName == "LogoutSuccess",
"Logout function did not return logout view!");
}
This is a loose example because really it's just testing that the "LogoutSuccess" view was returned, and not that any logout logic was executed. In a real test I would mock an HttpContext and ensure the session was cleared or whatever, but I just copied this ;)
Unit tests would not be testing that a UI element was properly wired up to an event handler. If you wanted to ensure that the whole application was working from top to bottom, this would be called integration testing, and you would use something besides unit tests for this. Tools such as Selenium are commonly used for web integration tests, whereas macro recording programs are often used for desktop applications.

Resources