Creating a project template using Laravel, Vue 3, and Tailwind - Part 2
Tags: tdd, jest, laravel
Published: 2021-03-24 16:28:29

*This article was originally published at [projectrebel.io](https://projectrebel.io).*

## Creating a project template using Laravel, Vue 3, and Tailwind
  * [Part 1](https://dev.to/heynolnor/creating-a-project-template-using-laravel-vue-3-and-tailwind-part-1-2518)
  * Part 2 *<- you are here*
  * [Part 3](https://dev.to/heynolnor/creating-a-project-template-using-laravel-vue-3-and-tailwind-part-3-1klj)
  * Part 4

Today we are going to take our simple project template and bring it to the next level by adding [Laravel Breeze](https://laravel.com/docs/8.x/starter-kits#laravel-breeze) for simple authentication and set up our TDD workflow using [PHPUnit](https://phpunit.de/) and [Jest](https://jestjs.io/). If you missed the [last post](https://projectrebel.io/blog/creating-a-project-template-using-laravel-vue-3-tailwind-part-1), I'd suggest checking it out. It'll only take a few minutes for you to catch up but if you can also download the source code on [Github](https://github.com/projectrebel/laravue3).

## Installing Breeze
Just as it was when installing the Laravel framework, adding Breeze is incredibly simple. Just a few commands will add everything that we need.
```
composer require laravel/breeze --dev
php artisan breeze:install
npm install
npm run dev
```

The `breeze:install` command will add a ton of files to your project structure. In the `resources` folder, you'll see several views added that are specific to authentication. These are things like login, register, or password reset views. You'll have a new `components` folder also. These are [Laravel Components](https://laravel.com/docs/8.x/blade#components) which are blade templates but with some additional horsepower that work together to make them more programmatic in nature. We won't go into detail on them here so if you want to learn more, take a look at the docs. We have a `layouts` folder for our navigation as well as layouts for guests and authenticated users. Finally, `dashboard.blade.php` will be added to the root level of our `views` folder. This is the view that is returned when a user successfully login into the application. There are corresponding classes in `app\View\Components`.

Several controllers have been added to `app\Http\Controllers\Auth` as well as a `LoginRequest` in `app\Http\Requests\Auth`. We have new routes added via `routes/auth.php` and in `routes/web.php`. Our `RouteServiceProvider` has also been updated to redirect users to `/dashboard` once they authenticate. There are also tests for our authentication process but we'll get to those in a minute. Before we get to testing, we'll need to visit some files that Breeze overwrites and merge the new changes with our previous versions of the files.

In our `package.json`, you'll see that some of the versions of packages that we already had installed might have changed. These aren't too important so I'll leave it up to you if you want to revert to our previous versions or not. What is important is that a few new packages have been added. `@tailwindcss/forms`, `alpinejs`, and `postcss-import` are all needed by the Breeze starter kit. Making use of these new packages requires changes to `app.js`, `webpack.mix.js`, and `tailwind.config.js`.
```js
// resources/js/app.js
require("./bootstrap");
require('alpinejs');

import { createApp, h } from "vue";
...
```
```js
// webpack.mix.js
...
mix.js('resources/js/app.js', 'public/js').vue();
mix.postCss('resources/css/app.css', 'public/css', [
        require('postcss-import'),
        require('tailwindcss'),
        require('autoprefixer'),
    ]);
```
```js
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');

module.exports = {
    purge: ['./storage/framework/views/*.php', './resources/views/**/*.blade.php'],
    darkMode: false, // or 'media' or 'class'
    theme: {
        extend: {
            fontFamily: {
                sans: ['Nunito', ...defaultTheme.fontFamily.sans],
            },
        },
    },
    variants: {
        extend: {
            opacity: ['disabled'],
        },
    },
    plugins: [require('@tailwindcss/forms')],
};
```

The changes to the first two files are pretty simple. We are just adding `alpinejs` to our main javascript file and including `postcss-import` and `autoprefixer` in our CSS build process. The `tailwind.config.js` changes are a little bigger although the only one that is truly necessary is adding the official tailwind [forms plugin](https://tailwindcss.com/docs/plugins#forms) to our configuration. The last change to mention is in `resources/css/app.css`. Breeze updates this file to use an alternate syntax for including the tailwind base styles. I like the brevity of the `@tailwind` syntax, but either option works.

Let's add links for the login and register pages to our `welcome` view.
```html
// resources/views/welcome.blade.php
...
<body>
    @if (Route::has('login'))
    <div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
        @auth
        <a href="{{ url('/dashboard') }}" class="text-sm text-gray-700 underline">Dashboard</a>
        @else
        <a href="{{ route('login') }}" class="text-sm text-gray-700 underline">Login</a>

        @if (Route::has('register'))
        <a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 underline">Register</a>
        @endif
        @endauth
    </div>
    @endif

    <div id="app" class="flex items-center bg-gray-100 min-h-screen">
        <home />
    </div>
...
```

You should see the links in the top right of our welcome view. We'll want to register a new user but first, we need to create a database for our application. Once it is set up, run `php artisan migrate` and then we can register our user. After registering you should be redirected to the dashboard which was created by Breeze. Our authentication system is in place!

## Configuring PHPUnit
Laravel has some [great tools](https://laravel.com/docs/8.x/testing) which extend the functionality of PHPUnit making TDD an excellent fit for any Laravel project. We'll just make a couple of extra config changes before we move onto the javascript portion of our testing setup. In our `phpunit.xml` file, let's uncomment the 2 entries within the PHP section so our tests will use sqlite in memory when testing.
```xml
// phpunit.xml
...
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
...
```

You will be able to run the tests using `vendor/bin/phpunit` but Laravel has an awesome feature called [parallel testing](https://laravel.com/docs/8.x/testing#running-tests-in-parallel) which greatly decreases the testing time of large test suites by running tests on multiple cores. There might not be a significant improvement at this point but we'll add it regardless. Running `php artisan test --parallel` will prompt you to install `brianium/paratest`. Once it is installed, the same command will run the test suite for us.
```
php artisan test --parallel
```
![Testing with Jest](https://project-rebel-prod.s3.us-east-2.amazonaws.com/blog/images/parallel-testing.png)

## Javascript testing via Jest
The last goal we want to accomplish in this version of our project template is having automated testing capabilities for our frontend. There are lots of ways to do this in the javascript ecosystem. We will use Jest as our main testing tool and [Vue Test Utils](https://next.vue-test-utils.vuejs.org/) to allow testing of our Vue single file components (SFCs).

We can add all the packages we need in one go by running the following command.
```
npm install --save-dev jest vue-jest@~5.0.0-alpha babel-jest @babel/core @babel/preset-env @vue/test-utils@next
```

We need some extra configuration for Jest and Babel to get these packages working together to provide us a usable testing environment. You can either add new config files specific to each package in your root directory (`jest.config.js` and `babel.config.js`) or just add the relevant sections to `package.json`.
```json
// package.json
...
"jest": {
        "testRegex": "tests/components/.*.test.js$",
        "moduleFileExtensions": [
            "js",
            "vue"
        ],
        "moduleNameMapper": {
            "^@/(.*)$": "<rootDir>/resources/js/$1"
        },
        "transform": {
            "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
            ".*\\.vue$": "<rootDir>/node_modules/vue-jest"
        }
    },
    "babel": {
        "presets": [
            [
                "@babel/preset-env",
                {
                    "targets": {
                        "node": "current"
                    }
                }
            ]
        ]
    }
```

At the very beginning of our Jest configuration, we have an entry for `testRegex`. This is the pattern that Jest will use to find our test files. I am going to add a new folder called `components` inside of the `tests` folder. Now Jest should find any files in this folder that end with `test.js`. Another common standard to use is `spec.js`. Let's add a simple test for our `Home` component.
```js
// tests/components/Home.test.js
import Home from '../../resources/js/components/Home.vue';
import { mount } from '@vue/test-utils'

test('displays message', () => {
  const wrapper = mount(Home);

  expect(wrapper.text()).toContain('Home component')
});
```

The last step is to add scripts to run Jest against our test suite.
```json
// package.json
...
"scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production",
        "test": "jest",
        "testing": "jest --watch"
    },
...
```

Let's see it in action.
```
npm run test
```
![Testing with Jest](https://project-rebel-prod.s3.us-east-2.amazonaws.com/blog/images/js-testing.png)

# Conclusion and next steps
While the basic version of our project template is helpful to simplify the start-up process of the most basic experiments, this version with authentication and a working test driven development workflow is much more practical for a real project. Therefore, we are saving much more time getting up and running with a template like this one. You can find the working template on [Github](https://github.com/projectrebel/laravue3-breeze) once again. Next time we are going to set up a single page application template for projects that need more interactivity with the user.