This package provides the necessary boilerplate to quickly begin testing your Laravel applications using Cypress.
If you haven't already installed Cypress, that's your first step.
npm install cypress --save-dev && npx cypress open
As part of the initial npx cypress open
command, Cypress will add a ./cypress
directory to your project root,
as well as a cypress.json
configuration file.
You'll almost always want to set a baseUrl
for your Cypress tests, so do so now within cypress.json
.
{
"baseUrl": "http://my-app.test"
}
When making requests through Cypress, this baseUrl
path will be prepended to any relative URL you provide.
cy.visit('/foo'); // http://my-app.test/foo
Now you're ready to install this package through Composer. Pull it in as a development-only dependency.
composer require laracasts/cypress --dev
Finally, run the cypress:boilerplate
command to copy over the initial boilerplate files for your Cypress tests.
php artisan cypress:boilerplate
That's it! You're ready to go.
After running the php artisan cypress:boilerplate
command, you'll now have a .env.cypress
file in your project root. To get you started, this file is a duplicate of .env
. Feel free to update
it as needed to prepare your application for your Cypress tests.
Likely, you'll want to use a special database to ensure that your Cypress acceptance tests are isolated from your development database.
DB_CONNECTION=mysql
DB_DATABASE=cypress
When running your Cypress tests, this package will automatically back up your primary .env
file, and swap it out with env.cypress
.
Once complete, of course the environment files will be reset to how they originally were.
All Cypress tests run according to the environment specified in
.env.cypress
.
Each time your test suite runs, this package will fetch all named routes for your Laravel application,
and store them in memory. You'll additionally find a ./cypress/support/routes.json
file that contains a dump of this JSON.
This package overrides the base cy.visit()
method to allow for optionally passing a route
name instead of a URL.
test('it loads the about page using a named route', () => {
cy.visit({
route: 'about'
});
});
If the named route requires a wildcard, you may include it using the parameters
property.
test('it loads the team dashboard page using a named route', () => {
cy.visit({
route: 'team.dashboard',
parameters: { team: 1 }
});
});
Should you need to access the full list of routes for your application, use the Cypress.Laravel.routes
property.
// Get an array of all routes for your app.
Cypress.Laravel.routes; // ['home' => []]
Further, if you need to translate a named route to its associated URL, instead use the Cypress.Laravel.route()
method, like so:
Cypress.Laravel.route('about'); // /about-page
Cypress.Laravel.route('team.dashboard', { team: 1 }); // /teams/1/dashboard
This package will add a variety of commands to your Cypress workflow to make for a more familiar Laravel testing environment.
We allow for this by exposing a handful of Cypress-specific endpoints in your application. Don't worry: these endpoints will never be accessible in production.
Finds an existing user matching the optional attributes provided and set it as the authenticated user for the test. Create a new user record if not found.
test('authenticated users can see the dashboard', () => {
cy.login({ username: 'JohnDoe' });
cy.visit('/dashboard').contains('Welcome Back, JohnDoe!');
});
Log out the currently authenticated user. Equivalent to auth()->logout()
.
test('once a user logs out they cannot see the dashboard', () => {
cy.login({ username: 'JohnDoe' });
cy.logout();
cy.visit('/dashboard').assertRedirect('/login');
});
Use Laravel factories to create and persist a new Eloquent record.
test('it shows blog posts', () => {
cy.create('App\\Post', { title: 'My First Post' });
cy.visit('/posts').contains('My First Post');
});
Note that the cy.create()
call above is equivalent to:
factory('App\Post')->create(['title' => 'My First Post']);
You may optionally specify the number of records you require as the second argument. If provided, the attributes can be provided as the third argument.
test('it shows blog posts', () => {
cy.create('App\\Post', 3);
//
});
Alternatively, if you pass an object as the second argument to cy.create()
, you can override any default attributes for the factory call.
test('it shows blog posts', () => {
cy.create('App\\Post', { title: 'My First Post' });
//
});
Before your Cypress test suite begins, this package will automatically fetch a collection of all named routes for your Laravel app and store them in memory. You shouldn't need to manually call this method, however, it's available to you if your routing will change as side effect of a particular test.
test('it refreshes the list of Laravel named routes in memory', () => {
cy.refreshRoutes();
});
Trigger a migrate:refresh
on your test database. Often, you'll apply this in a beforeEach
call to ensure that,
before each new test, your database is freshly migrated and cleaned up.
beforeEach(() => {
cy.refreshDatabase();
});
test('it does something', () => {
// php artisan migrate:fresh has been
// called at this point.
});
Run all database seeders, or a single class, in the current Cypress environment.
test('it seeds the db', () => {
cy.seed('PlansTableSeeder');
});
Assuming that APP_ENV
in your .env.cypress
file is set to "acceptance," the call above would be equivalent to:
php artisan db:seed --class=PlansTableSeeder --env=acceptance
Trigger any Artisan command under the current environment for the Cypress test. Remember to proceed options with two dashes, as usual.
test('it can create posts through the command line', () => {
cy.artisan('post:make', {
'--title': 'My First Post',
});
cy.visit('/posts').contains('My First Post');
});
This call is equivalent to:
php artisan post:make --title="My First Post"
While not exactly in the spirit of acceptance testing, this command will allow you to trigger and evaluate arbitrary PHP.
test('it can evaluate PHP', () => {
cy.php(`
App\\Plan::first();
`).then(plan => {
expect(plan.name).to.equal('Monthly');
});
});
Be thoughtful when you reach for this command, but it might prove useful in instances where it's vital that you verify the state of the application or database in response to a certain action. It could also be used
for setting up the "world" for your test. That said, a targeted database seeder - using cy.seed()
- will typically be the better approach.
If you discover any security related issues, please email jeffrey@laracasts.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.