Mike  Kozey

Mike Kozey

1668598642

Guide to Unit Testing Vue Components

This article serves as a guide to unit testing Vue components.

We'll first look at why unit testing is important for creating maintainable software and what you should test. Then, we'll detail how to:

  1. Create and run a unit test for a Vue component
  2. Test different aspects of a Vue component
  3. Use mocks to test asynchronous functions
  4. Check the code coverage of your unit tests
  5. Structure your unit test files

If you're interested in learning more about Vue, check out my course: Learn Vue by Building and Deploying a CRUD App.

Dependencies:

The source code (along with detailed installation instructions) for the Vue Weather App project that's used in this article can be found on GitLab: Vue Weather App.


This is part one of a two-part series on testing Vue applications:

  1. Guide to Unit Testing Vue Components (this article!)
  2. Testing Pinia Data Stores in Vue

Objectives

By the end of this article, you should be able to:

  1. Explain why unit testing is important
  2. Describe what you should (and should not) unit test
  3. Develop a unit test suite for a Vue component
  4. Run the unit tests for a Vue project
  5. Utilize the beforeEach() and afterEach() functions within a unit test suite
  6. Write unit tests for testing the implementation details of a Vue component
  7. Write unit tests for testing the behavioral aspects of a Vue component (click events, etc.)
  8. Explain how mocking can help simplify unit tests
  9. Write unit tests for mocking a library and testing asynchronous functions
  10. Check the code coverage of your unit tests
  11. Develop a well-structured unit test file for testing a Vue component

Why Unit Test?

In general, testing helps ensure that your app will work as expected for your end users.

Software projects with high test coverage are never perfect, but it's a good initial indicator of the quality of the software. Additionally, testable code is generally a sign of a good software architecture, which is why advanced developers take testing into account throughout the entire development lifecycle.

Tests can be considered at three levels:

  1. Unit
  2. Integration
  3. End-to-end

Unit tests test the functionality of an individual unit of code isolated from its dependencies. They are the first line of defense against errors and inconsistencies in your codebase. Unit testing is a fundamental part of the Test-Driven Development (TDD) process.

Unit testing improves the maintainability of your code.

Maintainability refers to making bug fixes or enhancements to your code or to another developer needing to update your code in the future.

Unit testing should be combined with a Continuous Integration (CI) process to ensure that your unit tests are constantly being executed, ideally on each commit to your repository. A solid suite of unit tests can be critical to catching defects quickly and early in the development process before your end users come across them in production.

What to Test

What should you test? Or, more importantly: What should you not test?

There are three types of testing to consider with unit testing:

  1. Implementation details: the underlying business logic that a component uses to produce a result based on a given input
  2. Public interface/design contract: specific inputs (or props, in this case) produce specific results
  3. Side effects: "if this, then that"; e.g. when a button is clicked something happens

Since you can't test all the things, what should you focus on?

Focus on testing inputs and outputs that the end user will interact with. The experience that the users of your product have is paramount!

  1. Inputs: data, props, user interaction, lifecycle methods, data store (Pinia/Vuex), route params, query strings
  2. Outputs: rendered output, events, data results, data store (Pinia/Vuex) updates, dispatches

By focusing on testing the inputs/outputs of a software module (e.g., a Vue component), you are testing the key aspects that the end user will experience.

There may be other internal logic in a software module that is complex and needs to be unit tested, but these types of tests are most likely to need updating during a code refactor.

App Overview

Before discussing how to unit test Vue components, I want to give a short overview of the Vue Weather App that we'll be testing.

After cloning down the repo, install the dependencies, and add the API key.

Review the project's README for more info on creating and adding the API key from Open Weather.

Once done, the Vue Weather App can be run on your local computer by starting the development server:

$ npm run dev

Once the app is built, you will see a success message similar to:

vite v2.9.14 dev server running at:

 > Local: http://localhost:3000/
 > Network: use `--host` to expose

 ready in 543ms.

At this point, the development server will be up and running. You can see the Vue app by navigating to http://localhost:3000 in your favorite web browser. When you first load the app, no data is displayed; you'll just see an input field to enter the city that you'd like to get the weather for:

Vue Weather App Walkthrough - Step 1

Without any data entered, both the 'Search' and 'Clear' buttons are disabled.

Once you start entering data for a city (as soon as the first character is added), both the 'Search' and 'Clear' buttons will be enabled:

Vue Weather App Walkthrough - Step 2

If you click on 'Search' after entering a valid city, the weather data will be displayed for that city:

Vue Weather App Walkthrough - Step 3

At this point, clicking on the 'Clear Weather Data' button will cause the weather data to be cleared:

Vue Weather App Walkthrough - Step 4

However, the city that was entered will remain in the input field.

If you click on 'Clear' now, the input field will be cleared and the 'Search' and 'Clear' buttons will become disabled once again:

Vue Weather App Walkthrough - Step 5

What happens if you enter an invalid city? What if you click 'Clear' before 'Clear Weather Data'? What other states of the app can you find?

Unit Testing in Vue

Since components are the building blocks of Vue (and really any SPA framework, for that matter), they are the most crucial part of your app as a whole. So, spend the majority of your allotted testing time writing unit tests that test your app's components.

Based on my experience with unit testing Vue components, I've found that the testing tools and framework -- Vite and Vitest -- satisfy the key aspects of a good test environment:

  • tests are easy and fun to write
  • tests can be written quickly
  • tests can be executed with a single command
  • tests run quickly

Hopefully, you'll find that unit testing your Vue components is an enjoyable experience, as I think that's key to encouraging more testing.

Unit Testing Tools

There are two tools that we're going to use for unit testing the Vue components:

  1. Vitest - unit test framework
  2. Vue Test Utils - unit testing utility library for Vue

Vitest is a unit test framework that aims to be framework-agnostic, so it can be used to test Vue, React, Svelte, Lit, and other projects. Vitest is configured to run with Vite, which results in fast test execution.

If you're familiar with Jest, switching to use Vitest is very straightforward as the API for Vitest is compatible with Jest.

When writing unit tests for a Vue component, Vitest and Vue Test Utils provide the following functionality:

Vitest

  • Command-line tool to run the tests and check the test coverage
  • User interface to visually see test results and coverage results
  • Functions for writing unit tests (it, describe)
  • Functions for checking against expected values (expect, toMatch, toContain, etc.)
  • Mocking (mockResolvedValue, mockRejectedValue)
  • Setup (beforeEach, beforeAll) / Teardown (afterEach, afterAll)

Vue Test Utils

  • Mounting components (mount, shallowMount)
  • Setting props data (setProps)
  • Finding HTML components for testing (findAll('h2'))
  • Utility for flushing all Promises (flushPromises())
  • Utility for triggering click events (trigger)
  • Utility for checking emitted events (emitted)

Vitest provides the generic functionality to write unit tests while Vue Test Utils provides the Vue-specific test utilities.

Unit Testing Overview

For starters, let's discuss the naming convention for unit tests in Vue. The unit test file should be of the following format:

  • <ComponentName>.spec.js

Per the Vue Style Guide, component names should be multiple words (WeatherHeader instead of just Header) to prevent conflicts with HTML elements.

You should typically have one unit test file for each component in your Vue project. Within each unit test file, there can be a single unit test suite or multiple unit test suites.

The unit test files should be placed in a sub-folder within the Components folder (src/components/__tests__):

$ tree -d -L 2
.
├── node_modules
├── public
├── src
    ├── assets
    └── components
        └── __tests__

Running the Tests

Vitest can be used to run the unit tests like so:

$ npm run test:unit

✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
    Tests  22 passed (22)
     Time  2.38s (in thread 640ms, 371.13%)

All the available commands to run via npm for your Vue project are defined in the scripts field in package.json.

The default configuration for Vitest is to run the tests in watch mode, which means that the test suite will be re-executed on each save to an applicable file. To change this configuration so that Vitest only runs once (without "watch mode"), update the test:unit configuration in package.json to include the run argument:

"test:unit": "vitest run --environment jsdom",

Examples

Using the Vue Weather App, let's look at some examples for testing Vue components.

Example 1 - Unit Test Introduction

Let's jump right into an example of a unit test file in Vue! The first unit test file is found in src/components/__tests__/WeatherHeader.spec.js and it tests the WeatherHeader component:

import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import WeatherHeader from '../WeatherHeader.vue'


describe('WeatherHeader.vue Test', () => {
  it('renders message when component is created', () => {
    // render the component
    const wrapper = shallowMount(WeatherHeader, {
      propsData: {
        title: 'Vue Project'
      }
    })

    // check that the title is rendered
    expect(wrapper.text()).toMatch('Vue Project')
  })
})

Mounting

The first line in this file imports the test functions from Vitest that are used in this file.

If you want the Vitest API to be available globally (like how Jest works), then add test: {globals: true} in the defineConfig() function in vite.config.js. For more details, check out the Vitest documentation.

The second line in this file imports a function called shallowMount from the Vue Test Utils library. The idea of 'mounting' means the loading of an individual component to be able to test it. There are two methods for this in Vue Test Utils:

  • shallowMount() - creates a wrapper for the Vue component, but with stubbed child components
  • mount() - creates a wrapper for the Vue component, including mounting any child components

Since our focus is on testing an individual component (the WeatherHeader component), we'll use shallowMount().

shallowMount() is better for testing an individual component in isolation, as child components are stubbed out. This is the ideal situation for unit testing.

Additionally, using shallowMount() for testing a component with a lot of child components can improve the execution time of the unit test as there's no cost (in terms of time) for rendering the child components.

mount() is useful when you want to include testing the behavior of the child components.

The third line imports the Vue component that is going to be tested, WeatherHeader.vue.

Describe Blocks

After the import statements, there's a describe block that defines a unit test suite.

Within a unit test file, there can be multiple describe blocks that define different unit test suites. Similarly, each describe block can contain multiple unit tests, where each unit test is defined by an it block.

I think about this distinction as:

  • describe block - unit test suite
  • it block - individual unit test function

What's nice about unit testing with Vitest is that there are several built-in encouragements for adding comments. For example, the first argument for describe should clearly explain which Vue component is being tested:

describe('WeatherHeader.vue Test', () => { ... })

For each it block, the first argument is a description of the test function, which should be a short description of what this specific test is doing. In the example above, the it block tests that the component 'renders message when component is created'.

Expects

As far as the actual unit testing, the first step is to mount the Vue component so that it can be tested:

// render the component
const wrapper = shallowMount(WeatherHeader, {
  propsData: {
    title: 'Vue Project'
  }
})

The shallowMount function returns a wrapper object, which contains the mounted component and the methods to test that component. The wrapper object allows us to test all aspects of the HTML generated by the Vue component and all properties (such as data) of the Vue component.

Additionally, the props, passed into the WeatherHeader component, are passed in as the second argument to shallowMount().

The actual check performed in the unit test is:

// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')

This line uses wrapper to check if the title generated by the component is 'Vue Project'. Since this check does a string comparison, it's recommended to use toMatch().

Test Helpers

While the checks in the unit test file for the WeatherHeader component are only checking string values, there are [lots of options available from Vitest to perform checks:

  • Booleans:
    • toBeTruthy() - checks that a variable/statement is true
    • toBeFalsy() - checks that a variable/statement is false
  • Defined:
    • toBeNull() - checks if a variable matches only null
    • toBeUndefined() - checks if a variable is not defined
    • toBeDefined() - checks if a variable is defined
  • Numbers:
    • toBeGreaterThan() - checks if a number is greater than the value specified
    • toBeGreaterThanOrEqual() - checks if a number is greater than or equal to the value specified
    • toBeLessThan() - checks if a number is less than the value specified
    • toBeLessThanOrEqual() - checks if a number is less than or equal to the value specified
    • toBe() and toEqual() - checks if a number is the same as the value specified (these functions are equivalent for numbers)
    • toBeCloseTo() - checks if a number is equal to the value specified within a small tolerance (useful for floating-point numbers)
  • Strings:
    • toMatch() - checks if a string is equal to the value specified (Regex can be used as the value specified!)
  • Arrays:
    • toContain() - checks if an array contains the specified value

Additionally, the not qualifier can be used with most of these checks:

expect(wrapper.text()).not.toMatch('Node Project')

For a full list of checks available, check out the Vitest API reference.

Example 2 - Testing Initial Conditions

This example shows how to test the initial conditions (or state) of the WeatherResult component.

Here's an outline of the unit test file (defined in src/components/__tests__/WeatherResult.spec.js):

import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import WeatherResult from '@/components/WeatherResult.vue'


describe('WeatherResult.vue Implementation Test', () => {
  let wrapper = null

  // SETUP - run before to each unit test
  beforeEach(() => {
    // render the component
    wrapper = shallowMount(WeatherResult, {
      propsData: {
        city: '',
        weatherSummary: '',
        weatherDescription: '',
        currentTemperature: 0.0,
        lowTemperature: 0.0,
        highTemperature: 0.0
      }
    })
  })

  // TEARDOWN - run after to each unit test
  afterEach(() => {
    wrapper.unmount()
  })

  it('initializes with correct elements', () => { ... })

  it('processes valid props data', async () => { ... })

  it('emits a custom event when the Clear Weather Data button is clicked', () => { ... })
})

The unit test file utilizes the shallowMount() function for rendering the WeatherResult component, as this component is tested as an individual component in isolation.

beforeEach and afterEach Blocks

Within the unit test suite (defined within the describe block), there are two new functions defined:

  • beforeEach() - called before the execution of each unit test within this unit test suite
  • afterEach() - called after the execution of each unit test within this unit test suite

The beforeEach() function is used to set a consistent state before running each unit test. This concept is very important to make sure that the order of running the unit tests does not impact the results of the unit tests as a whole.

In this example, the beforeEach() function renders the component with a default set of prop data:

// SETUP - run before to each unit test
beforeEach(() => {
  // render the component
  wrapper = shallowMount(WeatherResult, {
    propsData: {
      city: '',
      weatherSummary: '',
      weatherDescription: '',
      currentTemperature: 0.0,
      lowTemperature: 0.0,
      highTemperature: 0.0
    }
  })
})

The afterEach() function is used to clean up any processing performed during the unit test.

In this example, the afterEach() function un-mounts the wrapper used during the unit test, so that the wrapper can be re-initialized for the next unit test in the beforeEach():

// TEARDOWN - run after to each unit test
afterEach(() => {
  wrapper.unmount()
})

If you want to run code that is executed before or after the overall unit test suite is run, you can use:

beforeAll(() => {
  /* Runs before all tests */
})
afterAll(() => {
  /* Runs after all tests */
})

Expects

The first unit test checks the initial conditions of the WeatherResult component:

it('initializes with correct elements', () => {
  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City:')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary:')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details:')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 0° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 0° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 0° F')
})

Checks:

  1. The first section of expects check that the two headers (defined as h2 elements) are as expected.
  2. The second section of expects check that the six data fields (defined as p elements) are as expected.

Example 3 - Testing Props

The second unit test checks that valid data passed in as prop data is handled correctly by the WeatherResult component:

it('processes valid props data', async () => {
  // Update the props passed in to the WeatherResult component
  wrapper.setProps({
    city: 'Chicago',
    weatherSummary: 'Cloudy',
    weatherDescription: 'Cloudy with a chance of rain',
    currentTemperature: 45.1,
    lowTemperature: 42.0,
    highTemperature: 47.7
  })

  // Wait until the DOM updates
  await flushPromises()

  // check that the prop data is stored as expected within the component
  expect(wrapper.vm.city).toMatch('Chicago')
  expect(wrapper.vm.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.currentTemperature).toEqual(45.1)
  expect(wrapper.vm.lowTemperature).toBeCloseTo(42.0)
  expect(wrapper.vm.highTemperature).toBe(47.7)

  // check that the heading text is rendered
  expect(wrapper.findAll('h2').length).toEqual(2)
  expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
  expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')

  // check that 6 fields of data for the temperature are displayed
  expect(wrapper.findAll('p').length).toEqual(6)
  expect(wrapper.findAll('p').at(0).text()).toMatch('City: Chicago')
  expect(wrapper.findAll('p').at(1).text()).toMatch('Summary: Cloudy')
  expect(wrapper.findAll('p').at(2).text()).toMatch('Details: Cloudy with a chance of rain')
  expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 45.1° F')
  expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 47.7° F')
  expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 42° F')
})

Since the beforeEach() function provides a default set of prop data, we need to override the prop data using the setProps() function.

To ensure that the prop data causes the expected updates in the WeatherResult, the test needs to wait for all the DOM updates to take effect:

// Wait until the DOM updates
await flushPromises()

NOTE: The use of await is only possible if the function is defined with async!

Checks:

  1. With the props data updated, we can check that the prop data was properly stored within the WeatherResult component by checking the data elements (using wrapper.vm).
  2. The second section of expects check that the two headers (defined as h2 elements) are as expected.
  3. The last set of expects check that the prop data is used to set the six data fields (defined as p elements) as expected.

Example 4 - Testing User Input (Click Event)

The third unit test checks that the clear-weather-data event is emitted by the WeatherResult component when the user clicks on the 'Clear Weather Data' button:

it('emits a custom event when the Clear Weather Data button is clicked', () => {
  // trigger an event when the 'Clear Weather Data' button is clicked
  wrapper.findAll('button').at(0).trigger('click')

  // check that 1 occurrence of the event has been emitted
  expect(wrapper.emitted('clear-weather-data')).toBeTruthy()
  expect(wrapper.emitted('clear-weather-data').length).toBe(1)
})

To trigger a click event, the button element must be found in the wrapper and then the trigger function is called to trigger the click event.

Once the button is clicked, the unit test checks that only one custom event (with the name of clear-weather-data) is emitted.

Mocking Examples

Within the App component, when a user searches for the weather for a city, an HTTP GET call is made to Open Weather to retrieve the data via a third-party library called Axios:

const searchCity = (inputCity) => {
  // GET request for user data
  axios.get('http://api.openweathermap.org/data/2.5/weather?q=' + inputCity + '&units=imperial&APPID=' + openweathermapApiKey.value)
    .then((response) => {
      // handle success
      console.log(response)

      weatherData.value.city = response.data.name
      weatherData.value.weatherSummary = response.data.weather[0].main
      weatherData.value.weatherDescription = response.data.weather[0].description
      weatherData.value.currentTemperature = response.data.main.temp
      weatherData.value.lowTemperature = response.data.main.temp_min
      weatherData.value.highTemperature = response.data.main.temp_max
      validWeatherData.value = true
    })
    .catch((error) => {
      // handle error
      messageType.value = 'Error'
      messageToDisplay.value = 'ERROR! Unable to retrieve weather data for ' + inputCity + '!'
      console.log(error.message)
      resetData()
    })
    .finally((response) => {
      // always executed
      console.log('HTTP GET Finished!')
    })
}

When thinking about how to test making the HTTP GET calls, two scenarios come to mind, each testing the side effect of the actual API call:

  • HTTP GET response succeeds (happy path)
  • HTTP GET response fails (exception path)

When testing code that utilizes an external API, it's often easier to not make the actual call to begin with by replacing the call with a mock. There are pros and cons to this approach, though.

Pros:

  1. The tests won't be dependent on a network request
  2. They won't break if the API goes down
  3. They will run much faster

Cons:

  1. You'll need to update the tests whenever the API schema changes
  2. It's difficult to keep up with API changes in a microservice architecture
  3. Mocking is a difficult concept to grasp and they can add a lot of clutter to your test suites

At some point you should check the full integration to ensure the shape of the API response hasn't changed.

Since this article is focused on unit testing, we're going to mock the Axios library.

Mocking provides a means to mimic the expected behavior of a software module. Although mocking can be used in production code (very dangerous!), it's typically used during development and testing.

Loading data from an external API takes time. While it typically takes less than one or two seconds to load the data from Open Weather in this app, other external APIs can be more time-consuming. Additionally, we want a way to easily check if the HTTP GET request fails. So, we'll add mocks to specify how the GET request would respond.

Example 5 - Testing Asynchronous Code (Successful Case)

The unit tests for the App component are located in the src/components/__tests__/App.spec.js file.

To get started, we need to import the Axios library:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
import App from '../../App.vue'
import axios from 'axios'

However, we don't want to use the actual Axios library as is done in the source code (App.vue). Instead, we want to create a mock of the Axios library so we don't actually call the external API:

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});

This code block tells Vitest that the get() method within the axios library should be mocked.

In the unit test file (src/components/__tests__/App.spec.js), for the App component, we're:

  1. Simulating a successful HTTP GET request
  2. Simulating a failed HTTP GET request

To start, let's handle the nominal situation where the HTTP GET request is successful.

describe('Implementation Test for App.vue with Successful HTTP GET', () => {
  let wrapper = null

  beforeEach(() => {
    const responseGet = { data:
      {
        name: 'Chicago',
        weather: [
          {
            main: 'Cloudy',
            description: 'Cloudy with a chance of rain'
          }
        ],
        main: {
          temp: 56.3,
          temp_min: 53.8,
          temp_max: 58.6
        }
      }
    }

    // Set the mock call to GET to return a successful GET response
    axios.get.mockResolvedValue(responseGet)

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  ...

})

beforeEach and afterEach Blocks

In the beforeEach() function, we set the response that should occur when axios.get() is called. The response is the pre-canned weather data that looks similar to what we get from Open Weather, if we actually made the request. The key line in this section is:

// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)

This line is the key as it lets Vitest know that it should return the responseGet array when axios.get() is called in the App component instead of actually making an HTTP GET call using Axios.

The next section of the unit test suite defines the afterEach() function:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

The afterEach() function, which is called after each unit test executes, clears the mock of axios.get() that was created during the unit test execution. This approach is a good practice to clean up any mocks after running a test, so that any subsequent tests start from a known state.

Expects

Now we can define the unit test:

it('does load the weather data when a successful HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  // Wait until the DOM updates
  await flushPromises()

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // check that the user data is properly set
  expect(wrapper.vm.weatherData.city).toMatch('Chicago')
  expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
  expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
  expect(wrapper.vm.validWeatherData).toBe(true)
})

Since we already went through the steps of defining the mock and rendering the component (via shallowMount()), this unit test can focus on performing checks.

The unit test starts by calling the searchCity() function:

wrapper.vm.searchCity('Chicago')

To ensure that the searchCity() function causes the expected updates in the App component, the test needs to wait for all the Promises to be resolved and for the DOM updates to take effect:

// Wait until all Promises are resolved and the DOM updates
await flushPromises()

We check that axios.get() was called only once and that the HTTP GET call included the correct city name:

expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

To be very thorough, the weather data also checks for the instance of the App component rendered in this unit test to make sure it matches the pre-canned data returned from the mock of axios.get():

// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)

Example 6 - Testing Asynchronous Code (Failure Case)

While it's nice to test when things go as expected, it's also important to check how our software reacts to negative conditions. With that in mind, let's create a second unit test suite for checking a failed HTTP GET request:

describe('Implementation Test for App.vue with Failed HTTP GET', () => { ... })

There's no problem with having multiple unit test suites within a single unit test file (.spec.js).

Since the mocks are created in the beforeEach() function, there needs to be separate unit test suites with different beforeEach() implementations for both successful and failed HTTP GET responses.

beforeEach and afterEach Blocks

The beforeEach() function in this unit test suite is quite different:

beforeEach(() => {
  // Set the mock call to GET to return a failed GET request
  axios.get.mockRejectedValue(new Error('BAD REQUEST'))

  // Render the component
  wrapper = shallowMount(App)
})

Instead of setting a response to return from the axios.get() call, we are now returning a failed Promise object with the response of 'BAD REQUEST'.

The afterEach() function for this unit test suite is identical to the other unit test suite:

afterEach(() => {
  axios.get.mockReset()
  wrapper.unmount()
})

Expects

Here's the unit test function for testing a failed HTTP GET request:

it('does not load the weather data when a failed HTTP GET occurs', async () => {
  wrapper.vm.searchCity('Chicago')

  expect(axios.get).toHaveBeenCalledTimes(1)
  expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))

  // Wait until the DOM updates
  await flushPromises()

  // Check that there is no user data loaded when the GET request fails
  expect(wrapper.vm.weatherData.city).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherSummary).toMatch(/^$/)
  expect(wrapper.vm.weatherData.weatherDescription).toMatch(/^$/)
  expect(wrapper.vm.weatherData.currentTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.lowTemperature).toEqual(0)
  expect(wrapper.vm.weatherData.highTemperature).toEqual(0)
  expect(wrapper.vm.validWeatherData).toBe(false)

  // check that the banner message indicates failure
  expect(wrapper.vm.messageToDisplay).toMatch('ERROR! Unable to retrieve weather data for Chicago!')
  expect(wrapper.vm.messageType).toMatch('Error')
})

Just like in the previous unit test suite, we check that only one instance of axios.get() is called and then there's a check that no weather data was loaded into the App component.

Code Coverage

When developing unit tests, it can be nice to get an understanding of how much of the source code is actually tested. This concept is known as code coverage.

I need to be very clear that having a set of unit tests that cover 100% of the source code is by no means an indicator that the code is properly tested.

This metric means that there are a lot of unit tests and a lot of effort has been put into developing the unit tests. The quality of the unit tests still needs to be checked by code inspection.

The other extreme where this is a minimal set (or none!) of unit tests is a very bad indicator.

Vitest provides code coverage by using the --coverage flag.

To easily run Vitest with coverage results, I like to include the following items in the script section of package.json:

{
  "name": "vue-weather-app",
  "version": "1.0.0",
  "scripts": {
    ...
    "test:unit": "vitest run --environment jsdom",
    "test:coverage": "vitest run --environment jsdom --coverage",
    "test:ui": "vitest --environment jsdom --coverage --ui"
  },
  ...
}

When npm run test:unit is run, the unit tests are executed:

$ npm run test:unit
...
 ✓ src/components/__tests__/WeatherBanner.spec.js (5)
 ✓ src/components/__tests__/WeatherSearch.spec.js (5)
 ✓ src/components/__tests__/WeatherFooter.spec.js (1)
 ✓ src/components/__tests__/WeatherHeader.spec.js (1)
 ✓ src/components/__tests__/WeatherResult.spec.js (3)
 ✓ src/components/__tests__/App.spec.js (7)

Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  2.81s (in thread 536ms, 524.89%)

When npm run test:coverage is run, the unit tests are executed and the coverage is reported:

$ npm run test:coverage
...
Test Files  6 passed (6)
     Tests  22 passed (22)
      Time  3.38s (in thread 660ms, 512.10%)

--------------------|---------|----------|---------|---------|-------------------
File                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files           |   99.15 |    96.55 |     100 |   99.15 |
 src                |   97.31 |    85.71 |     100 |   97.31 |
  App.vue           |   97.31 |    85.71 |     100 |   97.31 | 60-63
 src/components     |     100 |      100 |     100 |     100 |
  WeatherBanner.vue |     100 |      100 |     100 |     100 |
  WeatherFooter.vue |     100 |      100 |     100 |     100 |
  WeatherHeader.vue |     100 |      100 |     100 |     100 |
  WeatherResult.vue |     100 |      100 |     100 |     100 |
  WeatherSearch.vue |     100 |      100 |     100 |     100 |
--------------------|---------|----------|---------|---------|-------------------

The npm run test:ui will load the test and coverage results in your default web browser, which can be convenient for visually seeing where the test coverage is missing.

Unit Test Structure

After going through many different unit test files, I recommend the following structure for the unit test file for a Vue component:

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue'  // Import Vue component to test
import axios from 'axios'    // Import libraries to mock

// Mock the axios library
vi.mock("axios", () => {
  return {
    default: {
      get: vi.fn(),
    },
  };
});


describe('Tests for the ... Component', () => {
  let wrapper = null

  beforeEach(() => {
    // set any initial data and create the mocks of libraries

    // render the component
    wrapper = shallowMount(App)
  })

  afterEach(() => {
    axios.get.mockReset()
    wrapper.unmount()
  })

  it('check successful events', () => { ... })

  it('check failure events', () => { ... })
})

Key items:

  • Each unit test suite has a related set of unit tests
  • Utilize the beforeEach() and afterEach() functions to create independent unit test functions
  • Create mocks of any libraries used within the Vue component that's tested
  • Render the components in the beforeEach() function and update prop data within the unit test functions
  • Utilize shallowMount() over mount() to focus on testing individual components

Conclusion

This article provides a guide for unit testing Vue components, focusing on:

  1. Why you should write unit tests
  2. What you should (and should not) unit test
  3. How to write unit tests

Put simply, when considering what to test, focus on testing the inputs and outputs (actual results), not the underlying business logic (how the results are produced). With this in mind, take a minute or two to review the examples again, taking note of the inputs and outputs tested.

Again, if you're interested in learning more about Vue, check out my course: Learn Vue by Building and Deploying a CRUD App.


This is part one of a two-part series on testing Vue applications:

  1. Guide to Unit Testing Vue Components (this article!)
  2. Testing Pinia Data Stores in Vue

Original article source at: https://testdriven.io/

#vue #unit #testing 

Guide to Unit Testing Vue Components
Rupert  Beatty

Rupert Beatty

1667590440

Viewinspector: Runtime Introspection and Unit Testing Of SwiftUI Views

ViewInspector 🕵️‍♂️ for SwiftUI

ViewInspector is a library for unit testing SwiftUI views. It allows for traversing a view hierarchy at runtime providing direct access to the underlying View structs.

Why?

SwiftUI view is a function of state. We could provide it with the input, but were unable to verify the output... Until now!

Helpful links

Use cases

1. Search the view of a specific type or condition

Use one of the find functions to quickly locate a specific view or assert there are none of such:

try sut.inspect().find(button: "Back")

try sut.inspect().findAll(ViewType.Text.self,
                          where: { try $0.attributes().isBold() })

Check out this section in the guide for the reference.

2. Read the inner state of the standard views

Standard SwiftUI views are no longer a black box:

let sut = Text("Completed by \(72.51, specifier: "%.1f")%").font(.caption)

let string = try sut.inspect().text().string(locale: Locale(identifier: "es"))
XCTAssertEqual(string, "Completado por 72,5%")

XCTAssertEqual(try sut.inspect().text().attributes().font(), .caption)

Each view has its own set of inspectable parameters, you can refer to the API coverage document to see what's available for a particular SwiftUI view.

3. Verify your custom view's state

Obtain a copy of your custom view with actual state and references from the hierarchy of any depth:

let sut = try view.inspect().find(CustomView.self).actualView()
XCTAssertTrue(sut.viewModel.isUserLoggedIn)

The library can operate with various types of the view's state, such as @Binding, @State, @ObservedObject and @EnvironmentObject.

4. Trigger side effects

You can simulate user interaction by programmatically triggering system-controls callbacks:

try sut.inspect().find(button: "Close").tap()

let list = try view.inspect().list()
try list[5].view(RowItemView.self).callOnAppear()

The library provides helpers for writing asynchronous tests for views with callbacks.

FAQs

Which views and modifiers are supported?

Check out the API coverage. There is currently almost full support for SwiftUI v1 API, the v2 and v3 support is under active development.

Is it using private APIs?

ViewInspector is using official Swift reflection API to dissect the view structures. So it'll be production-friendly even if you could somehow ship the test target to the production.

How do I add it to my Xcode project?

Assure you're adding the framework to your unit-test target. Do NOT add it to the main build target.

Swift Package Manager

https://github.com/nalexn/ViewInspector

Carthage

github "nalexn/ViewInspector"

CocoaPods

pod 'ViewInspector'

How do I use it in my project?

Please refer to the Inspection guide. You can also check out my other project that harnesses the ViewInspector for testing the entire UI.

Other questions, concerns or suggestions?

Ping me on Twitter or just submit an issue or a pull request on Github.


Download Details:

Author: Nalexn
Source Code: https://github.com/nalexn/ViewInspector 
License: MIT license

#swift #unit #testing #best 

Viewinspector: Runtime Introspection and Unit Testing Of SwiftUI Views
Elian  Harber

Elian Harber

1665110220

A Golang tool That Does Static analysis, Unit Testing, Code Review

Goreporter   

A Golang tool that does static analysis, unit testing, code review and generate code quality report. This is a tool that concurrently runs a whole bunch of those linters and normalizes their output to a report:

Template

  • html template file which can be loaded via -t <file>.

Todo List

  • This version will re-design the template.
  • Add interfacer and safesql and gofmt(-s),govet linter.

Installing

Requirements

Quickstart

Install goreporter (see above).

go get -u github.com/360EntSecGroup-Skylar/goreporter

Run it:

NOTE

You have to confirm that your project is operational. In particular, the problem with vendor, when the package is not found in the default path, goreporter will look again from the possible vendor path.

goreporter -p [projectRelativePath] -r [reportPath] -e [exceptPackagesName] -f [json/html/text]  {-t templatePathIfHtml}
  • -version Version of GoReporter.
  • -p Must be a valid Golang project path.
  • -r Save the path to the report.
  • -e Exceptional packages (multiple separated by commas, for example: "linters/aligncheck,linters/cyclo" ).
  • -f report format json, html OR text.
  • -t Template path,if not specified, the default template will be used.

By default, the default template is used to generate reports in html format.

Example

goreporter-display

you can see result detail:online-example-report

Supported linters

  • gofmt - Checks if the code is properly formatted and could not be further simplified.
  • govet - Reports variables that may have been unintentionally shadowed.
  • golint - Golint is a linter for Go source code.
  • unittest - Golang unit test status.
  • deadcode - Finds unused code.
  • gocyclo - Computes the cyclomatic complexity of functions.
  • varcheck - Find unused global variables and constants.
  • structcheck - Find unused struct fields.
  • aligncheck - Warn about un-optimally aligned structures.
  • errcheck - Check that error return values are used.
  • copycode(dupl) - Reports potentially duplicated code.
  • gosimple - Report simplifications in code.
  • staticcheck - Statically detect bugs, both obvious and subtle ones.
  • godepgraph - Godepgraph is a program for generating a dependency graph of Go packages.
  • misspell - Correct commonly misspelled English words... quickly.
  • countcode - Count lines and files of project.
  • interfacer - Suggest narrower interfaces that can be used.
  • depth - Count the maxdepth of go functions.
  • flen - Flen provides stats on functions/methods lengths in a Golang package.

Credits

Logo is designed by Ri Xu

Download Details:

Author: qax-os
Source Code: https://github.com/qax-os/goreporter 
License: Apache-2.0 license

#go #golang #unit #testing

A Golang tool That Does Static analysis, Unit Testing, Code Review

PHPunit: The PHP Unit Testing Framework

PHPUnit

PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks.

Installation

We distribute a PHP Archive (PHAR) that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file:

$ wget https://phar.phpunit.de/phpunit-X.Y.phar

$ php phpunit-X.Y.phar --version

Please replace X.Y with the version of PHPUnit you are interested in.

Alternatively, you may use Composer to download and install PHPUnit as well as its dependencies. Please refer to the "Getting Started" guide for details on how to install PHPUnit.

Contribute

Please refer to CONTRIBUTING.md for information on how to contribute to PHPUnit and its related projects.

List of Contributors

Thanks to everyone who has contributed to PHPUnit! You can find a detailed list of contributors on every PHPUnit related package on GitHub. This list shows only the major components:

A very special thanks to everyone who has contributed to the documentation and helps maintain the translations:

Download Details:

Author: Sebastianbergmann
Source Code: https://github.com/sebastianbergmann/phpunit 
License: BSD-3-Clause license

#php #unit #testing #tools 

PHPunit: The PHP Unit Testing Framework

UnitfulChainRules.jl: ChainRules.jl integration for Unitful.jl

UnitfulChainRules.jl

UnitfulChainRules.jl adds support for differentiating through scalar Unitful.Quantity construction and arithmetic. The arithmetic rules are drawn from the existing ChainRules.jl scalar rules, so this package provides the Quantity autodiff rules and utilities.

Right now, this includes rrule, frule implementations for the Quantity construction and the ProjectTo utility. We implement projection onto Quantitys and projection of Quantitys onto Real, Complex numbers.

Usage

To import the rules, all that is required is importing UnitfulChainRules.jl in addition to Unitful.jl.

using Unitful: W, μm, ms
using UnitfulChainRules
using Zygote

Zygote.gradient((x,y) -> (x*W)/(y*μm)/ms, 3.0*W, 2.0*μm)
# (0.5 W μm^-2 ms^-1, -0.75 W^2 μm^-3 ms^-1)

Zygote.gradient((x,y) -> (x*ms + 9*y*ms)/μm, 2.0*W, 3.0*W)
# (1.0 ms μm^-1, 9.0 ms μm^-1)

Array Rules

This package does not yet include compatibility for operations between arrays of Unitful.Quantitys, like most LinearAlgebra ops. An issue is open for discussing how to best add array rules.

Related Packages

  • Unitful.jl - Implements dimensional numerical quantities for Julia
  • ChainRules.jl - Provides a standard set of rules for interfacing with various autodiff backends in Julia

Download Details:

Author: SBuercklin
Source Code: https://github.com/SBuercklin/UnitfulChainRules.jl 
License: MIT license

#julia #unit 

UnitfulChainRules.jl: ChainRules.jl integration for Unitful.jl

NaturallyUnitful.jl: Facilities for using Natural Units with Unitful

NaturallyUnitful.jl

This package reexports Unitful.jl alongside two extra functions:

natural, a function for converting a given quantity to the Physicist's so-called "natural units", in which

ħ = c = ϵ₀ = kb = 1

julia> using NaturallyUnitful

julia> natural(1u"m")
5.067730759202785e6 eV^-1

julia> natural(3e8u"m/s")
1.000692285594456

natural also accepts a keyword argument base (defaults to electron volts) which determines what unit your natural quantity is constructed from. Currently, the base unit must have dimensions of energy.

julia> natural(1u"m", base=u"GeV")
5.067730759202785e15 GeV^-1

unnatural, a function for converting from natural units to a given unnatural unit such as meters

julia> unnatural(u"m", 5.067730759202785e6u"eV^-1")
1.0 m

julia> unnatural(u"m/s", 1)
2.99792458e8 m s^-1

Installation Instructions

To install, simply open the pkg prompt from the julia REPL by pressing ], and type:

pkg> add NaturallyUnitful

Download Details:

Author: MasonProtter
Source Code: https://github.com/MasonProtter/NaturallyUnitful.jl 
License: MIT license

#julia #unit 

NaturallyUnitful.jl: Facilities for using Natural Units with Unitful

Solve for The Adimensional Pi Groups in A List Of Unitful Parameters

UnitfulBuckinghamPi

This package is for solving for the adimensional Pi groups (or Π groups) in a given list of parameters, according to the Buckingham-Pi Theorem.

We use the package Unitful.jl in order to facilitate the construction of the parameters and to easily handle the dimensions associated with each parameter.

This package is inspired by a similar package written in python: ian-r-rose/buckinghampy.

Examples

Let us consider a couple of examples.

Simple pendulum

We start with the period of a simple pendulum.

The parameters taken for consideration are the length of the rod, the mass of the bob, the acceleration of gravity, the angle of the rod with respect to the downwards vertical direction, and the period of the swinging pendulum.

We define these parameters as Unitful.FreeUnits. Except for the acceleration of gravity, which is a constant and is given as a Unitful.Quantity value, and for the period, for which we do not associate any unit, only a dimension, just for fun.

To tell UnitfulBuckinghamPi that these are the parameters to consider, we use the macro @setparameters. Then, we find the adimensional Π groups with the function pi_groups(), which returns the groups as a vector. It can either be a vector of strings, with pi_groups(:String), or of expressions, with pi_groups(:Expr), which is the default.

julia> using Unitful

julia> using UnitfulBuckinghamPi

julia> ℓ = u"m"
m

julia> g = 9.8u"m/s^2"
9.8 m s⁻²

julia> m = u"g"
g

julia> T = u"𝐓"
𝐓

julia> θ = u"NoDims"
NoDims

julia> @setparameters ℓ g m T θ
[ Info: Parameter(s) registered:
[ Info:  ℓ = m
[ Info:  g = 9.8 m s⁻²
[ Info:  m = g
[ Info:  T = 𝐓
[ Info:  θ = NoDims

julia> Π_str = pi_groups(:String)
2-element Vector{String}:
 "ℓ^(-1//2)*g^(1//2)*T^(1//1)"
 "θ^(1//1)"

julia> Π = pi_groups(:Expr)
2-element Vector{Expr}:
 :(ℓ ^ (-1 // 2) * g ^ (1 // 2) * T ^ (1 // 1))
 :(θ ^ (1 // 1)) 

There are two adimensional groups, Π[1] and Π[2].

One can use korsbo/Latexify.jl to display the groups in Latex format, simply with

julia> using Latexify

julia> latexify(Π_str[1])
L"$g^{\frac{1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot T^{\frac{1}{1}}$"

This produces $g^{\frac{1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot T^{\frac{1}{1}}$.

With the parameters above, one cannot evaluate the adimensional group since that would amount to multiplying Unitful.FreeUnits or Unitful.Quantities like the Unitful.Dimensions parameter T. That i not allowed by Unitful.jl. One can solve that, however, by substituting T with a unit. Then, we can either parse each element in the vector of strings returned by pi_groups_str() and evaluate that or we can use pi_groups() to obtain directly the corresponding expressions and evaluate the expressions.

julia> τ = u"s"
s

julia> @setparameters ℓ g m τ θ
[ Info: Parameter(s) registered:
[ Info:  ℓ = m
[ Info:  g = 9.8 m s⁻²
[ Info:  m = g
[ Info:  τ = s
[ Info:  θ = NoDims

julia> Π = pi_groups()
2-element Vector{Expr}:
 :(ℓ ^ (-1 // 2) * g ^ (1 // 2) * τ ^ (1 // 1))
 :(θ ^ (1 // 1))

julia> eval(Π[1])
3.1304951684997055

julia> eval(Π[2])
NoDims

As expected, both are adimensional.

Adimensional groups are not unique. Even if you find a single group, any power of it is also adimensional. If there is more than one adimensional group, then you can linearly combine them to find many others. They are associated to the span of the null space of a "parameter-to-dimension" matrix. The solver here will just pick one combination from the basis obtained for the null space.

Finally, one can add parameters to a given set of registered parameters and solve for the new set.

julia> v = u"m/s"
m s⁻¹

julia> @addparameters v
[ Info: Parameter(s) registered:
[ Info:  ℓ = m
[ Info:  g = 9.8 m s⁻²
[ Info:  m = g
[ Info:  τ = s
[ Info:  θ = NoDims
[ Info:  v = m s⁻¹

julia> pi_groups()
3-element Vector{Expr}:
 :(ℓ ^ (-1 // 2) * g ^ (1 // 2) * τ ^ (1 // 1))
 :(θ ^ (1 // 1))
 :(ℓ ^ (-1 // 2) * g ^ (-1 // 2) * v ^ (1 // 1))

With korsbo/Latexify.jl, these yield

julia> latexify.(pi_groups())
3-element Vector{LaTeXStrings.LaTeXString}:
 L"$g^{\frac{1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot \tau^{\frac{1}{1}}$"
 L"$\theta^{\frac{1}{1}}$"
 L"$g^{\frac{-1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot v^{\frac{1}{1}}$"

which look like

  • $g^{\frac{1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot \tau^{\frac{1}{1}}$
  • $\theta^{\frac{1}{1}}$
  • $g^{\frac{-1}{2}} \cdot \ell^{\frac{-1}{2}} \cdot v^{\frac{1}{1}}$

Reynolds number

Another classical example of adimensional group is the Reynolds number.

What could characterize how complicate a fluid flow is? We should certainly consider the parameters characterizing the fluid, such as density and viscosity. Then, there is the velocity the fluid moves. Less obvious is the lenght scale we consider, which we can consider as a length scale associated with the injection of energy into the system, such as the width of an obstacle, the distance between the walls of channel, the distance between the bars of a grids, and so on.

With these parameters, the only possible adimensional group is the Reynolds number (or powers of it).

julia> ρ = u"g/m^3"
g m⁻³

julia> μ = u"g/m/s"
g m⁻¹ s⁻¹

julia> u = u"m/s"
m s⁻¹

julia> ℓ = u"m"
m

julia> @setparameters ρ μ u ℓ
[ Info: Parameter(s) registered:
[ Info:  ρ = g m⁻³
[ Info:  μ = g m⁻¹ s⁻¹
[ Info:  u = m s⁻¹
[ Info:  ℓ = m

julia> pi_groups()
1-element Vector{String}:
 "ρ^(1//1)*μ^(-1//1)*u^(1//1)*ℓ^(1//1)"

Again, we can use korsbo/Latexify.jl to display the adimensional group in Latex format:

$\rho^{\frac{1}{1}} \cdot \mu^{\frac{-1}{1}} \cdot u^{\frac{1}{1}} \cdot \ell^{\frac{1}{1}}$

One can recognize this as the Reynolds number

$$ \mathrm{Re} = \frac{\rho u \ell} {\mu} $$

The internals

The Buckingham-Pi Theorem relies on the Rank-nulity Theorem. A "parameter-to-dimension" matrix is composed, in which the columns correpond to the parameters and the rows to the collection of dimensions involved in the parameters. Each element in row i and column j corresponds to the power of the dimension i in the parameter j.

The number of adimensional groups is the dimension of the kernel of the matrix. And the adimensional groups are obtained from a basis of the null space.

When the powers are integers or rational numbers, which is usually the case, it is desirable to keep the type of these parameters when composing the matrix and when finding the null space and the associated adimensional Π groups.

While ian-r-rose/buckinghampy uses SymPy for symbolic manipulation of the powers of the parameters, to retain these types, we simply rely on the strong type system of the Julia language.

The LinearALgebra.nullspace, however, uses the LinearAlgebra.svd factorization, which does not preserve the Rational type. The first version of our packaged used instead the ability of the LU decomposition in the LinearAlgebra standard package to retain the Rational eltype of the matrices. However LinearAlgebra.lu factorization implements only partial pivoting and fails with singular matrices.

For this reason, we implemented our own LU factorization algorithm UnitfulBuckinghamPi.lu_pq(), with full pivoting. Then, we find the null space from the U factor of the decomposition and by properly taking into account the column permutations used in the pivoting process.

Download Details:

Author: Rmsrosa
Source Code: https://github.com/rmsrosa/UnitfulBuckinghamPi.jl 
License: MIT license

#julia #unit 

Solve for The Adimensional Pi Groups in A List Of Unitful Parameters

A Extension Of Unitful.jl for Converting Between Equivalent Quantities

UnitfulEquivalences

This package extends the Unitful.jl package to enable conversion between quantities of different dimensions, related by an equivalence (e.g., conversion between mass and energy using the mass–energy equivalence E = mc²). For its usage, see the documentation.

Installation

This package is compatible with Julia ≥ 1.0 and Unitful ≥ 1.0. It can be installed by typing

] add UnitfulEquivalences

in the Julia REPL.

Example usage

julia> using Unitful, UnitfulEquivalences

julia> uconvert(u"keV", 1u"me", MassEnergy()) # electron rest mass equals ≈511 keV
510.9989499961642 keV

Download Details:

Author: Sostock
Source Code: https://github.com/sostock/UnitfulEquivalences.jl 
License: View license

#julia #unit 

A Extension Of Unitful.jl for Converting Between Equivalent Quantities

UnitfulLatexify.jl: Pretty Print Units and Quantities in LaTeX format

UnitfulLatexify 

Adds Latexify recipes for Unitful units and quantities.

Because Github doesn't display \\LaTeX strings very well, I recommend reading the documentation instead of the README.

Installation

] add UnitfulLatexify

Usage

julia> using Unitful, Latexify, UnitfulLatexify;

julia> q = 612.2u"nm";

julia> u = u"kg*m/s^2";

julia> latexify(q)
L"$612.2\;\mathrm{nm}$"

julia> latexify(q,unitformat=:siunitx)
L"\qty{612.2}{\nano\meter}"

julia> latexify(u,unitformat=:mathrm) # explicit default
L"$\mathrm{kg}\,\mathrm{m}\,\mathrm{s}^{-2}$"

julia> latexify(u,unitformat=:siunitx)
L"\unit{\kilo\gram\meter\per\second\tothe{2}}"

Results

Results

Download Details:

Author: Gustaphe
Source Code: https://github.com/gustaphe/UnitfulLatexify.jl 
License: MIT license

#julia #unit 

UnitfulLatexify.jl: Pretty Print Units and Quantities in LaTeX format
Nat  Grady

Nat Grady

1661510531

Reactor: Unit Testing for Shiny Reactivity

reactor

When developing Shiny apps there is a lot of reactivity problems that can arise when one reactive or observe element triggers other elements. In some cases these can create cascading reactivity (the horror). The goal of reactor is to diagnose these reactivity problems and then plan unit tests to avert them during development to make development less painful.

Installation

And the development version from GitHub with:

# install.packages("remotes")
remotes::install_github("yonicd/reactor")

Usage

Reactor is a pipeline driven api where the user does not need to learn RSelenium in order to be able to drive their applications

Initializing Reactor

Start by creating a reactor class object

library(reactor)
obj <- init_reactor()
obj
#> reactor:
#>   application: ~
#>   driver: ~

Populating Specifications

You can see it is expecting to be populated by two objects

  • application: Specifications for the background process that will host the application
  • driver: Specifications for the webdriver that will interact with the application in the background process

Reactor comes with functions to help you create these specifications

  • application:
    • set_runapp_args() : Assumes that the application is located in a path on the machine and uses shiny::runApp as the function to launch the application
    • set_golem_args(): Assumes that the application is a golem package and uses the golem logic to launch the application.
  • driver:
    • set_chrome_driver(): Launches RSelenium with a chrome webdriver
    • set_firefox_driver(): Launches RSelenium with a firefox (gecko) webdriver
obj <- obj%>%
  set_runapp_args(
    appDir = system.file('examples/good_app.R',package = 'reactor')
  )%>%
  set_chrome_driver()
#> Adding runApp Settings
#> Adding chrome Settings

reactor object 

reactor:
  application:
    runApp:
      test_port: 41896
      test_path: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn
      test_ip: 127.0.0.1
      appDir: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/reactor/examples/good_app.R
  driver:
    chrome:
      test_path: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn
      verbose: no
      port: 11136
      opts:
        args:
        - --headless
        - --disable-gpu
        - --window-size=1280,800
        prefs:
          profile.default_content_settings.popups: 0
          download.prompt_for_download: no
          download.directory_upgrade: yes
          safebrowsing.enabled: yes
          download.default_directory: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn

If you want turn off headless mode you can update the object

obj <- obj%>%
  set_chrome_driver(
     opts = chrome_options(headless = FALSE)
  )
#> Updating chrome Settings

reactor object 

reactor:
  application:
    runApp:
      test_port: 41896
      test_path: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn
      test_ip: 127.0.0.1
      appDir: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/reactor/examples/good_app.R
  driver:
    chrome:
      test_path: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn
      verbose: no
      port: 14336
      opts:
        args:
        - --disable-gpu
        - --window-size=1280,800
        prefs:
          profile.default_content_settings.popups: 0
          download.prompt_for_download: no
          download.directory_upgrade: yes
          safebrowsing.enabled: yes
          download.default_directory: /var/folders/kx/t4h_mm1910sb7vhm_gnfnx2c0000gn/T//Rtmp2f3Exn

Starting Reactor

Once we have specifications in place we can start reactor using start_reactor().

obj%>%
  start_reactor()

Interacting with the application

Now that the app is running we can send to the webdriver to interact with the application

  • set_id_value():
    • expects an input id and the new value
    • returns back the reactor object
obj%>%
  set_id_value('n',500)

The user can use the following utility functions to interact and query with an application

Inject:

  • Inputs
    • set_id_value(): Sets a value for a shiny input object by id
  • JavaScript
    • execute(): Executes a JavaScript call

Query:

  • Inputs
    • query_input_names(): Returns names of the shiny input ids
    • query_input_id(): Returns current values of a shiny input by id
  • Outputs
    • query_output_names(): Returns names of the shiny output ids
    • query_output_id(): Returns current values of a shiny output by id
  • JavaScript
    • query(): Returns a value from JavaScript call

Closing Reactor

To safely close reactor and all the child processes use kill_app():

obj%>%
  kill_app()

Pipeline Operations

Because each function is returning the reactor object it is simple to create reactor pipelines.

Reactor will wait for shiny to finish each action before proceeding to the next one.

init_reactor()%>%
  set_runapp_args(
    appDir = system.file('examples/good_app.R',package = 'reactor')
  )%>%
  set_chrome_driver()%>%
  start_reactor()%>%
  set_id_value('n',500)%>%
  set_id_value('n',300)%>%
  kill_app()

Testing Expectations

Finally reactor tests reactivity expectations in a testthat framework using the builtin expect_reactivity() function

init_reactor()%>%
  set_runapp_args(
    appDir = system.file('examples/good_app.R',package = 'reactor')
  )%>%
  set_chrome_driver()%>%
  start_reactor()%>%
  set_id_value('n',500)%>%
  expect_reactivity('hist',1)%>%
  set_id_value('n',200)%>%
  expect_reactivity('hist',2)%>%
  kill_app()

Download Details:

Author: Yonicd
Source Code: https://github.com/yonicd/reactor 
License: Unknown, MIT licenses found

#r #unit #testing 

Reactor: Unit Testing for Shiny Reactivity

Unitful Quantity-valued Functions in Your Integrals

UnitfulIntegration

This package enables integration of physical quantity-valued functions, using the Quantity types implemented in Unitful.jl.

This package currently supports QuadGK.jl, which was originally in Julia Base. We do not support QuadGK as implemented in Julia 0.5. To use this package with Julia 0.5, you need to install the QuadGK package and qualify all invocations of QuadGK functions with the module name (e.g. import QuadGK; QuadGK.quadgk(...)).

PRs for other integration packages are welcome.

Code

*.jl.cov
*.jl.*.cov
*.jl.mem
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
  - linux
julia:
  - 0.7
  - 1.0
  - nightly
notifications:
  email: false
# uncomment the following lines to override the default test script
#script:
#  - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
#  - julia -e 'Pkg.clone(pwd()); Pkg.build("UnitfulIntegration"); Pkg.test("UnitfulIntegration"; coverage=true)'
after_success:
  # push coverage results to Coveralls
  - julia -e 'cd(Pkg.dir("UnitfulIntegration")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
  # push coverage results to Codecov
  - julia -e 'cd(Pkg.dir("UnitfulIntegration")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'

Download Details:

Author: PainterQubits
Source Code: https://github.com/PainterQubits/UnitfulIntegration.jl 
License: View license

#julia #unit 

Unitful Quantity-valued Functions in Your Integrals

UnitfulPlots.jl: Plots with Unit Labels, Automatically

UnitfulPlots

Enables automatic labeling of units on axes of plots generated with Plots.jl. The unitful quantities are created in the first place using Unitful.jl.

To use, simply type using UnitfulPlots in Julia 0.7 or higher and plot arrays of quantities as you usually would.

This package is experimental, please report unexpected behavior or submit pull requests.

Code

*.jl.cov
*.jl.*.cov
*.jl.mem
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
  - linux
  - osx
julia:
  - release
  - nightly
notifications:
  email: false
# uncomment the following lines to override the default test script
#script:
#  - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
#  - julia -e 'Pkg.clone(pwd()); Pkg.build("UnitfulPlots"); Pkg.test("UnitfulPlots"; coverage=true)'
after_success:
  # push coverage results to Coveralls
  - julia -e 'cd(Pkg.dir("UnitfulPlots")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
  # push coverage results to Codecov
  - julia -e 'cd(Pkg.dir("UnitfulPlots")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'

Download Details:

Author: PainterQubits
Source Code: https://github.com/PainterQubits/UnitfulPlots.jl 
License: View license

#julia #unit 

UnitfulPlots.jl: Plots with Unit Labels, Automatically

UnitfulRecipes.jl: Plots.jl Recipes for Unitful.jl Arrays

UnitfulRecipes.jl

for plotting data with units seamlessly in Julia   

UnitfulRecipes.jl makes it easy to plot data with units.

It works by providing recipes for the Plots.jl package that can deal with units from Unitful.jl. For a quick example,

using Unitful, UnitfulRecipes, Plots
const a = 1u"m/s^2"
v(t) = a * t
x(t) = a/2 * t^2
t = (0:0.01:100)*u"s"
plot(x.(t), v.(t), xlabel="position", ylabel="speed")

should give something like

UnitfulRecipeExample

Head over to the documentation for more examples!

Acknowledgements

Inspired by UnitfulPlots.jl.

Download Details:

Author: jw3126
Source Code: https://github.com/jw3126/UnitfulRecipes.jl 
License: MIT license

#julia #plot #unit 

UnitfulRecipes.jl: Plots.jl Recipes for Unitful.jl Arrays

UnitfulMoles.jl: Utilities for Working with Mole Units For The Julia

UnitfulMoles

This package provides a set of predefined conventional elemental mol units (like molC for moles of carbon) and a standardised method for defining custom mol units for the Julia language. It essentially extends the Unitful.jl package.

Conventional mol units

Units are available as u"molXX" for most of the elements of the periodic table (just replace XX with the element's symbol).

julia> using UnitfulMoles

julia> 3u"mmolFe" / 10u"molC"
0.3 mmolFe molC⁻¹

You can also directly load the iron mmol and carbon mol units via

julia> using UnitfulMoles: mmolFe, molC

julia> 3mmolFe / 10molC
0.3 mmolFe molC⁻¹

Molecular weight conversions

Molar weights are provided for free, so you can convert from moles to grams effortlessly with Unitful's uconvert function (or the |> symbol):

julia> using UnitfulMoles

julia> uconvert(u"g", 5u"mmolFe")
0.279225 g

julia> 200u"molC" |> u"kg"
2.4021999999999997 kg

Note:
Atomic weights taken from Atomic weights of the elements 2013 (IUPAC Technical Report) doi:10.1515/pac-2015-0305. Weights in g are provided with 5 digit precision, using "Conventional" weights where a range is provided instead of a specific value.

Compounds

And you can create custom compounds with the @compound macro:

julia> using UnitfulMoles, Unitful

julia> @compound H2O
molH₂O

julia> 10molH₂O |> u"g" # Molecular weight is calculated automatically!
180.15 g

julia> @compound CH₄ # subscripts work as well (and look nicer, too!)
molCH₄

julia> 1molCH₄ |> u"g"
16.043 g

Custom mol units

For custom mol units, the main command is the @mol macro:

julia> using UnitfulMoles, Unitful

julia> @mol A
molA

This allows for stoichiometric ratios to be expressed more naturally:

julia> @mol B
molB

julia> 0.5molA/molB
0.5 molA molB⁻¹

Custom molar weights

You can also assign a molar weight to the unit to allow conversion between mol and g:

julia> @mol Foo 14.0067
molFoo

julia> uconvert(u"g", 5molFoo)
70.0335 g

Compose and convert on the fly

You can use these macros in assignments:

julia> using UnitfulMoles, Unitful

julia> x = (100@compound CO2) / 25u"L"
4.0 molCO₂ L⁻¹

julia> x |> u"g/L"
176.036 g L⁻¹

C-mol and others

The @xmol macro creates fractional moles scaled to one mole of an element in a compound. The best example is the C-mole, which measure the amount of a compound relative to one mole of C:

julia> using UnitfulMoles

julia> @xmol C C₈H₁₀N₄O₂
C-molC₈H₁₀N₄O₂

julia> uconvert(molC₈H₁₀N₄O₂, 1CmolC₈H₁₀N₄O₂)
0.125 molC₈H₁₀N₄O₂

julia> uconvert(CmolC₈H₁₀N₄O₂, 1molC₈H₁₀N₄O₂)
8.0 C-molC₈H₁₀N₄O₂

julia> uconvert(u"g", 1CmolC₈H₁₀N₄O₂)
24.27425 gg

 

Use in a package

To use UnitfulMoles.jl in a package you will need to register your package with Unitful.jl, by adding this code in the main package module.

function __init__()\
    Unitful.register(YourPackageName)
end

Without this you will likely have errors with using e.g. a @compound you define in the package. See the Unitful docs for details.

Download Details:

Author: Rafaqz
Source Code: https://github.com/rafaqz/UnitfulMoles.jl 
License: View license

#julia #unit 

UnitfulMoles.jl: Utilities for Working with Mole Units For The Julia

An Extension Of Unitful.jl for Working with Atomic Units

UnitfulAtomic  

This package extends the Unitful.jl package to facilitate working with atomic units.

Functions

This package provides three functions that enable easy conversion from and to Hartree atomic units:

  • aunit(x) returns the appropriate atomic unit for x, where x can be a Unitful.Quantity, Unitful.Units, or Unitful.Dimensions:
julia> aunit(2.3u"cm")
a₀

julia> aunit(u"T")
ħ a₀^-2 e^-1
  • auconvert can be used to convert from and to atomic units. It has two methods:
    • auconvert(x::Unitful.Quantity) converts a quantity to the appropriate atomic unit:
julia> auconvert(13.6u"eV")
0.499790781587053 Eₕ

julia> auconvert(20u"nm")
377.94522492515404 a₀
  • auconvert(u::Unitful.Units, x::Number) interprets x as a quantity in atomic units and converts it to the unit u:
julia> auconvert(u"eV", 1)  # convert 1 Eₕ to eV
27.211386246088992 eV

julia> auconvert(u"m", 1)   # convert 1 a₀ to m
5.29177210903e-11 m
  • austrip(x::Unitful.Quantity) converts a quantity to the appropriate atomic unit and then strips the units. This is equivalent to Unitful.ustrip(auconvert(x)):
julia> austrip(13.6u"eV")
0.499790781587053

julia> austrip(20u"nm")
377.94522492515404

Defined units

The package defines the following atomic units (suffixed with _au), from which all other atomic units are derived:

Furthermore, this package defines some units that are not atomic units, but are common in atomic physics:

Download Details:

Author: Sostock
Source Code: https://github.com/sostock/UnitfulAtomic.jl 
License: View license

#julia #unit 

An Extension Of Unitful.jl for Working with Atomic Units