DEV Community

ashleygraf_
ashleygraf_

Posted on • Updated on

CI with Laravel/MySQL/Cypress using Github Actions

For one of my projects, I decided to combine learning Cypress and putting together a CI pipeline, adding in some realism by finding an existing project online, the fantastic Laragram by Luis Panta.

End result

name: CI
on:
  pull_request:
    branches: [master, development]
jobs:
  build-and-run-tests:
    runs-on: ubuntu-16.04

    services:
      mysql:
        image: mysql:5.7
        env:
          MYSQL_ROOT_PASSWORD: forge
          MYSQL_DATABASE: forge
          DB_HOST: 127.0.0.1
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping" 
          --health-interval=10s 
          --health-timeout=5s 
          --health-retries=3
    steps:
    - name: Checkout
      uses: actions/checkout@v1

    - name: Lint
      uses: overtrue/phplint@master

    - name: Copy ENV Laravel Configuration for CI
      run: php -r "file_exists('.env') || copy('.env.ci', '.env');"

    - name: Use Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '12.x'

    - name: Install Dependencies (PHP vendors)
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist && npm ci

    - name: Generate key
      run: php artisan key:generate

    - name: Build site
      run: npm run dev

    - name: Execute unit tests via PHPUnit
      run: vendor/bin/phpunit
      env: 
        MYSQL_DATABASE: forge
        DB_USERNAME: root
        DB_PASSWORD: forge
        DB_PORT: ${{ job.services.mysql.ports[3306] }}

    - name: Migrate MySQL DB
      env: 
        DB_CONNECTION: mysql
        DB_DATABASE: forge
        DB_PORT: 3306
        DB_USER: root
        DB_PASSWORD: forge
      run: php artisan migrate:fresh --seed

    - name: Cypress run
      uses: cypress-io/github-action@v1
      with:
        browser: chrome
        install: false
        start: npm start
        wait-on: http://localhost:8000
        config-file: cypress.json
        spec: cypress/integration/laragram/laragram.spec.js

    - uses: actions/upload-artifact@master
      # there might be no screenshots created when:
      # - there are no test failures
      # so only upload screenshots if previous step has failed
      if: failure()
      with:
        name: screenshots
        path: cypress/screenshots
    # video should always be generated
    - uses: actions/upload-artifact@master
      with:
        name: videos
        path: cypress/videos
Enter fullscreen mode Exit fullscreen mode

Journey

As part of this, I decided that most of the env characteristics would be immutable. I could not change them. However, I did create a .env.ci file. I also thought that the test environment should echo the production environment as much as possible.

CI/CD is new to me, so I decided I would start small. I would use the agile principle below, and write with verbosity.

  1. Make it work, then try and break it
  2. Make it right
  3. Make it fast

I had a couple of ideas in mind for the tests I would add to it

  • check the code style is consistent
  • run all the unit tests
  • create UI tests for the core user journeys so I would run a linter, unit tests, and Cypress.

My first goal was to create a custom Docker image by imitating the setup on my local environment. So I looked at the Readme's setup instructions and the .env files to get an idea of where to start.

Then once I got it working, I would try some things to see if I added anything unnecessary, then add Continuous Deployment. Right now, I'm at 'got it working', time to delete any unnecessary cruft. This was a fascinating process.

Extra learning exercise

I built my own version of cypress-io/github-action@v1, and ran it on my local environment, because I couldn't work out why my build wasn't working and I wanted to rule it out. It turned out I migrated my database incorrectly, but here's the code that imitates cypress-io/github-action@v1 anyway for our education cases.

"npm run server:test": "start-server-and-test start 8000 test:ci"
Enter fullscreen mode Exit fullscreen mode

which calls

"test:ci": "npx cypress run --spec cypress/integration/laragram/laragram.spec.js --env CYPRESS_BASE_URL=http://l27.0.0.1:8000 --browser chrome"
Enter fullscreen mode Exit fullscreen mode

this does the same thing as

     - name: Cypress run
      uses: cypress-io/github-action@v1
      with:
        browser: chrome
        install: false
        start: npm start
        wait-on: http://localhost:8000
        config-file: cypress.json
        spec: cypress/integration/laragram/laragram.spec.js  
Enter fullscreen mode Exit fullscreen mode

Starting and using a MySQL DB with Laravel on Github Actions

    services:
      mysql:
        image: mysql:5.7
        env:
          MYSQL_ROOT_PASSWORD: forge
          MYSQL_DATABASE: forge
          DB_HOST: 127.0.0.1
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping" 
          --health-interval=10s 
          --health-timeout=5s 
          --health-retries=3

    - name: Migrate MySQL DB
      env: 
        DB_CONNECTION: mysql
        DB_DATABASE: {DATABASE}
        DB_PORT: 3306
        DB_USER: {USER}
        DB_PASSWORD: {PASSWORD}
run: php artisan migrate:fresh --seed
Enter fullscreen mode Exit fullscreen mode

PS: A green build doesn't always indicate success.

Tests didn't start as Node needed to be downloaded first. Still green

Tests didn't start as Cypress wasn't downloaded properly. Still green

Top comments (0)