Saturday, February 23, 2019

How to start Electron

Electron

Electron framework is used to make desktop application with Javascript and APIs.
Electron enables you to create desktop applications with pure JavaScript by providing a runtime with rich native (operating system) APIs. You could see it as a variant of the Node.js runtime that is focused on desktop applications instead of web servers. -- Electron official site
If you already know how to write Javascript, Electron can be a nice choice to develop desktop applications. Official quick start is here.

At first

What I do here is exactly same as what the official tutorial does. Please note that this is just a memo of what I did.

Prerequisites

  • OS: Ubuntu 18.04.2 LTS

Create an app with Electron

Install necessary modules

At first, check if you have nodejs and npm.
$ nodejs -v
$ npm -v
If you don't have them, install them:
$ sudo apt install nodejs
$ sudo apt install npm

Create a .json file

Create a new folder and run npm init in the folder:
$ cd {YourNewFoldersPath}
$ npm init
You can make a package.json by the command. The content of the json file should be like this:
{
  "name": "test-app",
  "version": "0.0.1",
  "description": "test.",
  "main": "main.js"
}
Just add command to start the electron to change it an electron app:
{
  "name": "test-app",
  "version": "0.0.1",
  "description": "test.",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  }
}

Install electron

From the folder we made, run this command to install electron:
$ cd {YourNewFoldersPath}
$ npm install --save-dev electron 

Execute electron app

Create main.js in the same folder:
$ cd {YourNewFoldersPath}
$ touch ./main.js
Write as follows inside and save it:
const { app, BrowserWindow } = require('electron')

function createWindow () {
  // Create the browser window.
  let win = new BrowserWindow({ width: 800, height: 600 })

  // and load the index.html of the app.
  win.loadFile('index.html')
}

app.on('ready', createWindow)
Execute the app.
$ npm start
You can see that a simple browser running.

Read index.html

Create index.html in the same folder:
$ cd {YourNewFoldersPath}
$ touch ./index.html
Write as follows inside and save it:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>
Execute the app.
$ npm start
You can see that the browser reads the index.html:

Saturday, February 16, 2019

How to use phpunit in Laravel 5.7

Table of contents
1. how to start
2. create a basic user creation page
3. create unit tests for Laravel 5.7

How to use phpunit in Laravel 5.7

We can use phpunit and phpspec by default in Laravel 5.7. The test files have to be saved in /vagrant/laravel/tests/Unit/vagrant/laravel/tests/Feature (or /vagrant/laravel/tests/Browser if you use dusk). Also you can simply use the artisan command to create unit tests:
$ cd /vagrant/laravel
# Test file will be saved in laravel/tests/Feature directory
$ php artisan make:test UserTest
# Test file will be saved in laravel/tests/Unit directory
$ php artisan make:test UserTest --unit
You can see the generated file in /vagrant/laravel/tests/Feature or in /vagrant/laravel/tests/Unit. The code in the file is like this:
namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}
You can see that the UserTest class is extending TestCase class. When you write unit tests by yourself, you need to extend TestCase class. Or just run the artisan make:test command and customize the generated file.

Run Unit tests

To run the unit tests, use this command:
$ cd /vagrant/laravel
# Run all unit tests
$ vendor/bin/phpunit
# Run only unit tests in Unit directory
$ vendor/bin/phpunit tests/Unit
# Run only unit tests in Feature directory
$ vendor/bin/phpunit tests/Feature

Create Unit tests

We learned how to create base unit test files. In this section, we will see examples of unit tests. You can see various examples in the official laravel documentation; HTTP TestsConsole TestsBrowser TestsDatabase TestingMocking. So please check the website for the detailed information.
This is one of the examples. To check if a page returns 200:
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

Unit test to check if user is successfully created

Dusk
If you have followed these posts: Set up LaravelCreate a basic user creation page, you should have a /submit page to create a user. I wrote a unit test for the page.
For the browser test, you need to install dusk at first.
$ cd /vagrant/laravel
$ composer require --dev laravel/dusk
$ php artisan dusk:install
$ composer dump-autoload
We need to install the chrome binary in CentOS 7.
$ vi /etc/yum.repos.d/google.chrome.repo
Write inside the file this and save it:
[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub
Install the chrome binary:
$ sudo yum update
$ sudo yum install google-chrome-stable
By default, Dusk uses Google Chrome and a standalone ChromeDriver installation to run your browser tests. To use other browser, see this explanation.
To make a base unit test:
$ php artisan dusk:make LoginTest
You can find the file in /vagrant/laravel/tests/browser.
<?php

namespace Tests\Browser;

use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class LoginTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                    ->assertSee('Laravel');
        });
    }
}
Change it like this. This is the test to check if users can be created.
<?php

namespace Tests\Browser;

use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class LoginTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testUserCreation()
    {
        $this->browse(function (Browser $browser) {
            $datetime = date('Y_d_m_h_i_s_a', time());
            $browser->visit('/submit')
                ->type('name', 'test_'.$datetime)
                ->type('email', 'test'.$datetime.'@test.com')
                ->type('password', 'password_'.$datetime)
                ->click('#submitBtn')
                ->assertPathIs('/');
        });
    }
}
You can run the browser test by the following command:
$ cd /vagrant/laravel
$ php artisan dusk
The test result is:

References

Sunday, February 10, 2019

Laravel How to create a basic user creation page

Table of contents
1. how to start
2. create a basic user creation page
3. create unit tests for Laravel 5.7

Create tables

At first, we will create these tables:
  • user table
  • password reset table
Actually these tables are prepared by default in /vagrant/laravel/database/migrations folder.
Open the "2014_10_12_000000_create_users_table.php". You can see the code inside:
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}
The function up() is executed to apply changes to the database when this file is migrated by the "migration" command of artisan. The function down() is executed when you revert the migration. Let's migrate the migration files. But before migrating, as of Laravel Framework 5.7.25, according to this stackoverflow question, we need to modify and add some code to a file.
Open /vagrant/laravel/app/Providers/AppServiceProvider.php. Change it as follows:
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema; //Here. Import Schema!!!!!

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191); //Increase the StringLength!!!!
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
Now you can migrate the migration files:
$ cd /vagrant/laravel
$ php artisan migrate
Then the tables are created in the database:

Create a new migration file and a table

To create new migration file, just run this command:
$ php artisan make:migration {table name}
To create a table named "articles", run this command:
$ php artisan make:migration articles
Then the migration file for articles table will be added:
2019_02_10_131250_articles.php is the migration file for the articles table. Open the migration file for articles and change it as follows:
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Articles extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
            Schema::create('articles', function (Blueprint $table) {
                    $table->increments('id');
                    $table->integer('user_id')->unsigned(); 
                    $table->string('name');
                    $table->string('detail');
                    $table->rememberToken();
                    $table->timestamps();
                    //foreign key
                    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
                    $table->index('user_id');
            });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('articles', function($table) {
            $table->dropForeign('articles_user_id_foreign');
            $table->dropIndex('articles_user_id_index');
            $table->dropColumn('user_id');
        });
        Schema::dropIfExists('articles');
    }
}
Now migrate it:
$ php artisan migrate
Then the articles table is added in the database.

Create models and controllers

We will make corresponding models:
$ php artisan make:model User
$ php artisan make:model Article
And controllers:
$ php artisan make:controller UserController
$ php artisan make:controller ArticleController
For your information, to make models and controllers at the same time:
$ php artisan make:model User -c
$ php artisan make:model Article -c
Create factories for testing:
$ php artisan make:factory UserFactory
$ php artisan make:factory ArticleFactory
Now seeders:
$ php artisan make:seeder UsersTableSeeder
$ php artisan make:seeder ArticlesTableSeeder
You can see the
models in /vagrant/laravel/app/
controllers in /vagrant/laravel/app/Http/Controller/
Factories in /vagrant/laravel/database/factories/
Seeders in /vagrant/laravel/database/seeds/.

Create 10 users for testing

Let's make 10 users for testing. Open the UsersTableSeeder and change the run() function as follows:
public function run()
{
    factory(App\User::class, 10)->create();
}
Open the DatabaseSeeder.php and change the run function as follows:
public function run()
{
    $this->call(UsersTableSeeder::class);
}
Then migrate it with seed option:
$ php artisan migrate --seed
10 users are created in the database:
You can initialize all the tables and insert the 10 users at the same time with migrate:fresh:
$ php artisan migrate:fresh --seed

Access DB and pass the data to View in Web.php

Open /vagrant/laravel/routes/web.php. If you followed instructions written here, the code inside should be like this:
<?php
Route::get('/', function () {
    return view('welcome');
});

Route::get('/test', function () {
    return view('test');
});
Change it as follows:
<?php
Route::get('/', function () {
    $users = \App\User::all();
    return view('welcome', ['users' => $users]);
});

Route::get('/test', function () {
    return view('test');
});
Now you can use the $users variable in the welcome page's view. Add the following somewhere in the body of /vagrant/laravel/resources/views/welcome.blade.php.
<ul>
    @foreach ($users as $user)
      <li>{{ $user->name }}</li>
    @endforeach
<ul>
Like this:
If you open the welcome page http://192.168.33.10, you can see all of the 10 users are iterated:

Page to create users

At first, we will create a view for the page. Save the following as layout.blade.phpin /vagrant/laravel/resources/views/.
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@yield('title')</title>
</head>
<body>
    <div class="container">
        @yield('content')
    </div>
</body>
Then save the following as submit.blade.php in /vagrant/laravel/resources/views/.
@extends('layout')

@section('title', 'submit')

@section('content')
    <div class="container">
        <div class="row">
            <h1>Submit a user</h1>
            <form action="/submit" method="post">
                {!! csrf_field() !!}

                <div class="form-group">
                    <label for="name">Name</label>
                    <input type="text" class="form-control" id="name" name="name" placeholder="name">
                </div>

  <div class="form-group">
                    <label for="email">Email</label>
                    <input type="text" class="form-control" id="email" name="email" placeholder="email">
                </div>

                <div class="form-group">
                    <label for="password">Password</label>
                    <input type="text" class="form-control" id="password" name="password" placeholder="password">
                </div>

                <button id="submitBtn" type="submit" class="btn btn-default">Submit</button>
            </form>
        </div>
    </div>
@endsection
We will add the following in /vagrant/laravel/routes/web.php.
use Illuminate\Http\Request;

Route::get('/submit', function () {
    return view('submit');
});

Route::post('/submit', function (Request $request) {
    $data = $request->validate([
        'name' => 'required | max:255',
        'email'  => 'required | max:255',
        'password' => 'required | max:255',
    ]);

    $user = new App\User($data);
    $user->save();

    return redirect('/');
});
Like this:
<?php
use Illuminate\Http\Request;

Route::get('/', function () {
    $users = \App\User::all();
    return view('welcome', ['users' => $users]);
});

Route::get('/submit', function () {
    return view('submit');
});

Route::post('/submit', function (Request $request) {
    $data = $request->validate([
        'name' => 'required | max:255',
        'email'  => 'required | max:255',
        'password' => 'required | max:255',
    ]);

    $user = new App\User($data);
    $user->save();

    return redirect('/');
});

Route::get('/test', function () {
    return view('test');
});

Route:get is the function to be executed when user access the url with the GET method. Route:get is the function to be executed when user access the url with POST method.
See http://192.168.33.10/submit from your browser and you can see users can be now added.

Refactoring the code

We have a working code now, but all of the process is written in the web.php, which is not the correct way to implement. To write clean code, we must separate operation in Model, Controller (and in Request).

Request

At first, we will move the validation process to Request. To make Request for the users table, run the following command:
$ php artisan make:request UserRequest
You can find the UserRequest in /vagrant/laravel/app/Http/Requests/. Open and change it as follows:
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        // The validation here
        return [
            'name' => 'required | max:255',
            'email'  => 'required | max:255',
            'password' => 'required | max:255',
        ];
    }
}

You can see that $validator->fails() is not implemented in the file because Laravel automatically prevents users to go to the page where users are supposed to go only if the validation is success. Also you can use $errors variable in the view without defining it here.

Controller

Open /vagrant/laravel/app/Http/Controller/UserController.php and change it as follows:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;
use App\Http\Requests\UserRequest;

class UserController extends Controller
{
    public function submitGet(Request $request){
        return view('/submit');
    }

    public function submitPost(UserRequest $request){
        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = $request->password;
        $user->save();
        return redirect('/');
    }
}
By using UserRequest for the type hinting of submitPost() function, only if the validation process has no error, the process inside the function is executed.

Routing

Now open the /vagrant/laravel/routes/web.php and change it as follows:
<?php
use Illuminate\Http\Request;

Route::get('/', function () {
    $users = \App\User::all();
    return view('welcome', ['users' => $users]);
});

Route::get('/submit','UserController@submitGet');
Route::post('/submit','UserController@submitPost');

Route::get('/test', function () {
    return view('test');
});

Check if these work

Go to http://192.168.33.10/submit and create a user:
You can see the created user is added in the database: