Thursday, 1 February 2024

Fake data & Testing withLaravel Dusk other system

I. Fake Data with Laravel for other system

- Build laravel project

- Config to connect databases of other system, with files

.env, config/database.php

- Using models, factories, migrations, seeders, faker inlaravel to fake data 


II. Using Laravel Dusk to test for other system

1. Install Laravel Dusk

composer require laravel/dusk --dev

php artisan dusk:install


More detail: https://laravel.com/docs/10.x/dusk 

2. Generating & Run Tests

Generating Test

php artisan dusk:make LoginTest


Example: test login success

<?php


namespace Tests\Browser\External;


use App\Models\User;

use Laravel\Dusk\Browser;

use Tests\DuskTestCase;


class ExternalTest extends DuskTestCase

{

    public function test_login_successful(): void

    {

        $this->browse(function (Browser $browser) {

            $browser->visit('http://demo.test/login')

                    ->type('email', 'admin@example.com')

                    ->type('password', 'password')

                    ->click('#login-button')

                    ->assertSee('Login successful');

        });

    }

}



Example: test create object error with error message

<?php


namespace Tests\Browser\External;


use App\Models\User;


use Laravel\Dusk\Browser;

use Tests\DuskTestCase;


class External2Test extends DuskTestCase

{


    public function test_page_create_post_then_return_error_mgs(): void

    {

        $this->browse(function (Browser $browser) {

            $browser->visit('http://demo.test/admin/post/create')

            ->type('title', ‘post’')

            ->type('keyword', 'demo ')

            ->type('content', 'Your text goes here')
            ->attach('input[name="image"]', __DIR__.'/files/your-file.jpg')  

            ->click('#bt-submit-form-post')

            ->pause(1000)

            ->assertSee('Trường tiêu đề bài viết phải lớn hơn 5 ký tự.');

        });

    }

}



Run Tests

php artisan dusk


3. Methods supoort when test with laravel dusk

* Support interact with browser
- InteractsWithAuthentication: loginAs, logout, currentUserInfo, assertAuthenticated...
- InteractsWithCookies: cookie, plainCookie, addCookie, deleteCookie…
- InteractsWithElements: elements, clickLink, type, typeSlowly, append, clear, select, radio, check, uncheck, attach, press, pressAndWaitFor, drag, acceptDialog, typeInDialog, dismissDialog...
- InteractsWithJavascript: script
- InteractsWithKeyboard: withKeyboard,parseKeys
- InteractsWithMouse: moveMouse, mouseover, click, clickAtXPath, clickAndHold, doubleClick, rightClick…
- WaitsForElements: whenAvailable, waitFor, waitUntilMissing, waitUntilMissingText, waitForText, waitForTextIn, waitForLink, waitForInput, waitForRoute, waitUntilEnabled, waitForDialog, waitForReload, waitForEvent….
* Support assert results
- MakesAssertions: assertTitle, assertHasCookie, assertSee, assertDontSee, assertSeeIn, assertSourceHas… (too many)
- MakesUrlAssertions: assertUrlIs, assertHostIs, assertPortIs, assertPathIs, assertPathIsNot, assertRouteIs
Thank you

References: https://laravel.com/docs/10.x/dusk

Tuesday, 2 January 2024

Terraform with GCP roadmap leaning

* IAC, Terraform & Installation
Terraform - Infrastructure as Code
Install Terraform
* Terraform Basics & Installation
Terraform Workflow - Hello World
Terraform init, Plan, Apply
Terraform - local_file arguments
Terraform - Multiple Resources
Random Provider
Introduction to Variables
Types of Variable - I
Types of Variable - II
Using Variables
Multiple Providers
Output Block
Lifecycle Rules
Provider Version
Data Source - Read File
* Terraform with Google Cloud
Google Cloud Free Trial Account
Google Cloud Project - Service Account
Google Provider & version
Connect Terraform with GCP - I (username/password)
Connect Terraform with GCP - II (Cloud Shell VM)
Connect Terraform with GCP - III (Service Account)
Approach to Resource Provision
* Google Cloud Storage with Terraform
[Hands-on] Getting started with Cloud Storage
[Hands-on] Google Cloud Storage with Terraform - I
[Hands-on] Google Cloud Storage with Terraform - II
[Hands-on] Google Cloud Storage with Terraform - III
* GCP Networking with Terraform
[Hands-on] Create VPC from Console
[Hands-on] Create VPC with Terraform Script
[Hands-on] Create Subnet - Terraform
[Hands-on] Create Firewall Rule - Terraform
* Google Compute Engine with Terraform
[Hands-on] Create Compute Engine - Console
[Hands-on] Compute Engine - Terraform - I
[Hands-on] Compute Engine - Terraform - II
[Hands-on] Update Compute Engine parameter - Tearraform
[Hands-on] Service Account - Terraform
[Hands-on] Attach Disk - Terraform
Destroy GCE resources
* Google Cloud Run with Terraform
[Hands-on] Cloud Run Provision using Cloud Console
[Hands-on] Cloud Run + Terraform - I
[Hands-on] Cloud Run + Terraform - II (allow Public access)
[Hands-on] Cloud Run + Terraform - III (Deploy new revision)
Destroy Cloud Run Services
* Google Cloud Function with Terraform
[Hands-on] Deploy Cloud Function - Console
[Hands-on] Cloud Function - Terraform (Create Bucket) - I
[Hands-on] Cloud Function - Terraform (Deploy Function) - II
[Hands-on] Cloud Function - Terraform (allow public access) - III
Destroy Cloud Functions
* Cloud BigQuery with Terraform
[Hands-on] BigQuery with (Console + Terraform)

Thank you

Monday, 25 December 2023

Testing with Laravel Dusk

Example

<?php

namespace Tests\Browser;

use App\Models\User;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;

class PageListRonzanNotRecordedTest extends DuskTestCase
{
    /**
     * test_after_login_goto_list_ronzan_not_recorded
     */
    public function test_after_login_goto_list_ronzan_not_recorded(): void
    {
        $user = User::factory()->create();

        $this->browse(function (Browser $browser) use ($user) {
            $browser
                ->loginAs($user)
                ->visit('/ronzan-contract/list-not-record')
                ->assertSee('ロンザン 未計上一覧')
                ->assertSee('お選びください')
                ->assertSee('オプション');
        });
    }

     /**
     * test_click_menu_and_show_menus
     */
    public function test_click_menu_and_show_menus(): void
    {
        $user = User::factory()->create();

        $this->browse(function (Browser $browser) use ($user) {
            $browser
                ->loginAs($user)
                ->visit('/ronzan-contract/list-not-record')
                ->click('#app > div > nav > div.space-y-6.div-main > div > div:nth-child(1) > div > i')
                ->assertSee('社員マスタ');
        });
    }

    /**
     * test_click_menu_and_show_menus
     */
    public function test_click_select_action(): void
    {
        $user = User::factory()->create();

        $this->browse(function (Browser $browser) use ($user) {
            $browser
                ->loginAs($user)
                ->visit('/ronzan-contract/list-not-record')
                ->waitFor('main > div > div > div.bg-dropDownOption > div > select')
                ->click('main > div > div > div.bg-dropDownOption > div > select')
                ->assertSee('お選びください')
                ->assertSee('CSVデータインポート')
                ->assertSee('新規案件を取得する')
                ->assertSee('再度吸い上げて編集する')
                ->assertSee('吸い上げずに編集する')
                ->assertSee('仮計上する')
                ->assertSee('本計上する')
                ->assertSee('削除する')
                ->assertSee('CSVデータインポート');
        });
    }

    /**
     * test_click_menu_and_show_menus
     */
    public function test_click_select_load_new_contract(): void
    {
        $user = User::factory()->create();

        $this->browse(function (Browser $browser) use ($user) {
            $browser
                ->loginAs($user)
                ->visit('/ronzan-contract/list-not-record')
                ->waitFor('main > div > div > div.bg-dropDownOption > div > select')
                ->click('main > div > div > div.bg-dropDownOption > div > select')
                ->waitFor('main > div > div > div.bg-dropDownOption > div > select > option:nth-child(3)')
                ->click('main > div > div > div.bg-dropDownOption > div > select > option:nth-child(3)')
                ->waitForText('新規案件を取得しますか?')
                ->waitForText('はい')
                ->waitFor('#headlessui-portal-root > div > div > div > div > div > div > div > button:nth-child(1)')
                ->click('#headlessui-portal-root > div > div > div > div > div > div > div > button:nth-child(1)')
                ->waitForText('新規案件を取得するのが成功しました');
        });
    }
}

 Thank you

Thursday, 21 December 2023

Laravel + Inertia + Vue3 + Typescript add plugin multi languages vue-i18n

1. Install package i18n

npm install vue-i18n

2. Add files languages

 resources\lang\en.json

{
    "world": "HELLO EN"
}

 resources\lang\vi.json

{
    "world": "HELLO VI"
}

3. Add plugin resources\js\plugins\langPlugin.ts

import { App } from 'vue';
import { createI18n, type I18nOptions } from 'vue-i18n';
import en from '../../lang/en.json';
import vi from '../../lang/vi.json';

const langPlugin = {
install(app: App, pluginOptions: any) {
const langOptions: I18nOptions = {
legacy: false,
locale: pluginOptions.locale ? pluginOptions.locale : 'en',
messages: {
en: en,
vi: vi,
},
};
const i18n = createI18n(langOptions);
app.use(i18n);
console.log(app);
},
};

export default langPlugin;

* need: legacy: false, see more >>

4. Update resources\js\app.ts

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue)
            .use(langPlugin, {})
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});

5. Using I18n

- In template

   {{ $t('world') }}

- in <script setup>

import { useI18n } from 'vue-i18n';
const { t } = useI18n();
console.log(t('hello'));

Thank you

Tuesday, 17 October 2023

Using Cors in Adonisjs 5

1: enable false => true

/*
|--------------------------------------------------------------------------
| Enabled
|--------------------------------------------------------------------------
|
| A boolean to enable or disable CORS integration from your AdonisJs
| application.
|
| Setting the value to `true` will enable the CORS for all HTTP request. However,
| you can define a function to enable/disable it on per request basis as well.
|
*/
enabled: true,

2. set origin value


// You can also use a function that return true or false.
// enabled: (request) => request.url().startsWith('/api')

/*
|--------------------------------------------------------------------------
| Origin
|--------------------------------------------------------------------------
|
| Set a list of origins to be allowed for `Access-Control-Allow-Origin`.
| The value can be one of the following:
|
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
| Boolean (true) - Allow current request origin.
| Boolean (false) - Disallow all.
| String - Comma separated list of allowed origins.
| Array - An array of allowed origins.
| String (*) - A wildcard (*) to allow all request origins.
| Function - Receives the current origin string and should return
| one of the above values.
|
*/
origin: ['http://localhost'],



Thank you


Sunday, 15 October 2023

Open port for PostgreSQL

=====================

- sudo nano /etc/postgresql/{version}/main/postgresql.conf

+ listen_addresses = '*'

// + port = 5433 (no needed)

- sudo nano /etc/postgresql/{version}/main/pg_hba.conf

+ host    all             all             [Your_IP_Can_Access]/32        md5 

- sudo service postgresql restart

- sudo ufw allow 5433/tcp
=====================
- access as root
$ sudo -u postgres psql
- show all dbs
$ \l

Connect to the PostgreSQL Database 
\c taximailinhdb;

Grant all privileges on the database:
GRANT ALL PRIVILEGES ON DATABASE hangchatgiagocdb TO hangchatgiagocuser;

Grant all privileges on all existing tables in the database: 
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO hangchatgiagocuser;

Grant all privileges on all sequences (if you are using sequences): 
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO hangchatgiagocuser;

Optionally, grant privileges on all future tables and sequences:
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO hangchatgiagocuser;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO hangchatgiagocuser;

Step 3: Verify Permissions (Optional) 
\dp

Publish npm package

  Để publish   pav-kit  lên NPM, bạn hãy làm theo các bước dưới đây. Tôi đã tạo thêm file  index.js  để đảm bảo gói tin hợp lệ. Bước 1: Tạo ...