Mario Cardinal

"The real voyage of discovery consists, not in seeking new landscapes, but in having new eyes" – Marcel Proust


Leave a comment

Mounting (with the Cypress Component Testing Tool) a Vue component requiring Vuetify

I’m writing this post to make sure that a recipe on mounting (with the Cypress Component Testing Tool) a Vue component requiring the Vuetify framework is documented somewhere on the web. Thus, with the help of Google search, those who will have the same goal in the future will find the right answer easily.

Cypress is a front-end test automation framework built for the modern web. It is a very powerful tool that enables developers to write End-to-End as well as Rest APIs tests entirely in JavaScript, directly accessing everything within the browser. At To-Do Studio, we use Cypress with success.

In the last year, Cypress added the ability to automate testing of Vue or React components. Besides the automation, what is very interesting is that with a little ingenuity we can also use Cypress to obtain a playground to visualize the rendering of the components. I saw not only the ability to automate but also an opportunity to replace Storybook for component visualization.

However, the challenge when you want to use the Cypress component testing tool with Vue is that some frameworks such as Vuetify require a global vuetify object on the Vue instance as well as all components to be wrapped in the VApp component, otherwise it triggers warnings in the simplest cases and doesn’t work at all in more complex situations.

Unfortunately, the documented way on mounting a Vue component does not work with Vuetify.

While waiting for a more elegant solution from Cypress and Vuetify here is what we use as a workaround:


// Spec File with VBtn as component: xxx.spec.ts
import { mount } from '@cypress/vue';
import { VApp, VBtn } from 'vuetify/lib';
import vuetify from '../plugins/vuetify';
import i18n from '../plugins/i18n';

describe('Cypress CT with Vuetify', () => {
  it('playground', { viewportWidth: 360, viewportHeight: 667 }, () => {
    mount({
      vuetify,
      render: h => h(VApp,
        [
          h(VBtn, { props: { color: 'primary', height: '40', width: '250' } },
            [
              'Button Title',
            ]),
        ],
      ),
    }, { extensions: { plugins: [vuetify, i18n] } });
  });
});

and here is the Vuetify plugin:


// Vuetify plugin: ../plugins/vuetify.ts
import Vue from 'vue';
import Vuetify, {
  VApp, VBtn,
} from 'vuetify/lib';
import 'roboto-fontface/css/roboto/roboto-fontface.css';

Vue.use(Vuetify, {
  components: {
    VApp,
    VAppBar,
  },
});

export default new Vuetify({
  icons: {
    iconfont: 'mdiSvg',
  },
  customProperties: true,
  // add theme...
  // add breakpoint...
});

To give you a glimpse of how we use it in real life scenario at To-Do Studio, here is a sample of a real spec file:


import { mount } from '@cypress/vue';
import { VApp } from 'vuetify/lib';
import vuetify from '../plugins/vuetify';
import i18n from '../plugins/i18n';
import THeader from './THeader.vue';

describe('THeader', () => {
  it('playground', { viewportWidth: 360, viewportHeight: 667 }, () => {
    const user = null;
    const studioId = '00000000-0000-0000-0000-000000000000';
    const activeStudios = [ ];

    mount({
      vuetify,
      render: h => h(VApp,
        [h(THeader, {
          props: { routeName: 'studio-tips', studioId: studioId, activeStudios: activeStudios, user: user },
        })]),
    }, { extensions: { plugins: [vuetify, i18n] } });
  });
});


6 Comments

Configuring Cypress in CI with Azure DevOps Pipelines

Cypress is a front-end test automation framework built for the modern web. It is open source and written entirely in JavaScript. It addresses the key pain points developers and QA engineers face when testing modern applications:

  • A rich yet simple API for interactions with automatic waiting
  • Mocha, Chai, and Sinon bundled in
  • A sleek dashboard with automatic reloads for Test-Driven Development
  • Easy debugging
  • Network traffic control for validation and mocking
  • Automatic screenshots and videos

It is a very powerful tool that enables developers to write End-to-End tests entirely in JavaScript, directly accessing everything within the browser. It is also a versatile tool that can be used to test REST APIs.

At To-Do Studio, we use Cypress to test End-to-End scenarios, as well as REST APIs.

On developers’ computers, we install the Cypress Test Runner and write tests locally. Everything works perfectly. However, for CI/CD testing, we must configure Cypress with Azure DevOps Pipelines. The recipe for configuring Cypress is not as simple as it may seem at first. I’m writing this post to make sure that a configuration recipe is documented somewhere on the web to explain how to configure Cypress in Continuous Integration (CI) with Azure DevOps Pipelines. Thus, with the help of Google search, those who will have the same goal in the future will find the right answer easily.

Here is diagram presenting an overview of the major elements of the solution:

Deployment_overview

First, ensure during the build phase that the cypress tests files are zipped and published to the artifacts drop.

build

Second, during the release phase hosted on an Ubuntu agent, extract the zipped test files,run the tests using Cypress and publish the tests results. Here are the detailed steps:

1. Extract the zip file containing the tests

Extract the zip file that was published to the artifacts drop by the build pipeline.

extract

2. Run the tests

Start by creating the Cypress config file. Define the location of your tests with the integrationFolder configuration value. Do not use the testFiles configuration value or –spec command line option.

{
  "integrationFolder": "tests/e2e/specs",
  "baseUrl": "https://info-staging.to-do.studio",
  "projectId": "<insert your project Id>",
  "reporter": "junit",
  "reporterOptions": {
    "mochaFile": "tests/test-output-[hash].xml",
    "toConsole": true,
    "attachments": true
    },
  "video": false,
  "pluginsFile": "tests/e2e/plugins/index.js",
  "supportFile": "tests/e2e/support/index.js",
  "env": {
    "urlEnv": "staging"
  }
}

cypress_config

Follow by running the tests with Cypress using the command: npx cypress run –record –key <insert your record key>. npx install and run Cypress in a single step. npx is a npm package runner (x stands for eXecute). The typical use is to download and run a package temporarily. Please note that if you intent to record screenshots and videos with Cypresss Dashboard Service, you need to add the unique projectId into your cypress.json and pass the record key into the command. If you do not need visual results, simply omit the recording option and projectId.

run_tests

3. Publish the tests results

Here you will publish the junit mocha files created during the tests run. Make sure that your merge test results and that it fails if there are test failures.

publish_tests


1 Comment

How to clean up the wwwroot folder on the Azure Web App using PowerShell

I’m writing this post to make sure that a PowerShell recipe to remove all the files in the wwwroot directory on the Azure Web App is documented somewhere on the web. Thus, with the help of Google search, those who will have the same goal in the future will find the right answer easily.

Recently, when deploying the To-Do Studio website with Azure DevOps, I needed to clean the wwwroot directory before deploying. It is usually a simple configuration setting when running the release on a hosted VS2017 agent. When using the Azure App Service Deploy task with the Publish using Web Deploy option, there is an additional option to Remove Additional Files at Destination. Unfortunately, in order to roll the automated E2E tests with Cypress, we must run the release script on a Linux agent. This Remove Additional Files at Destination option is not available anymore on Linux. So I had to automate the cleanup  with an Azure Pipeline task.

At first, to fill this gap, I thought about using the “Azure WebApp Virtual File System Tasks” available in the Azure DevOps marketplace. Unfortunately, this task did not work. So I had to automate the cleanup with a Powershell script.

The non-automated (manual) way to delete files / folders in Azure Web App is to use the Kudu console. For those who like me want to automate this operation with PowerShell, there is KUDU Virtual File System (VFS) Rest API.

Without further ado, here is the script.  You can download it from my Personal GitHub repos or you can copy and paste without restraint from the script below.

$WebAppName = “insert Web App name”
$slotName = “insert Slot Name”
$username = ‘insert the username from the publish profile’ #From the publish profile
$password = “insert the password from the publish profile” #From the publish profile
# Initialize parameters for Invoke-RestMethod
if ($slotName -ne “”){
    $apiUrl = https://$webAppName`-$slotName.scm.azurewebsites.net/api/vfs/site/wwwroot/”
}
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((“$($username):$($password)”)))
$headers = @{
    Authorization=“Basic $($base64AuthInfo)”
    ‘If-Match’ = ‘*’
}
$userAgent = “powershell/2.0”
# Define a reursive function to delete files
function DeleteKuduDir ($content, $dir)
{
    foreach($c in $content)
    {      
        if($c.mime -eq “inode/directory”)
        {
            # Get listing of directory as an array
            $childContent = Invoke-RestMethod Uri $c.href Headers $headers UserAgent $userAgent Method GET ContentType “application/json”
           
            # Delete directory
            $newDir = $dir + (Split-Path $c.href leaf) + “\”
            DeleteKuduDir content $childContent dir $newDir
        }
        # Delete file
        $file = Split-Path $c.href leaf
        Write-Host “Deleting” $dir$file    
        $result = Invoke-RestMethod Uri $c.href Headers $headers UserAgent $userAgent Method DELETE ContentType “application/json”
    }
}
# Get listing of wwwroot as an array
$rootContent = Invoke-RestMethod Uri $apiUrl Headers $headers UserAgent $userAgent Method GET ContentType “application/json”
# Delete files and directory in wwwroot
DeleteKuduDir content $rootContent dir “\”
Write-Host “Done!”