Categories
Vue 3 Testing

Testing Vue 3 Apps — Form Triggered Events and Set Values of Form Elements

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Testing Form Triggered Events

We can test the events that are triggered when we submit the form.

For example, we can write:

import { mount } from '@vue/test-utils'

const EmailInput = {
  template: `
    <div>
      <input type="email" v-model="email">
      <button @click="submit">Submit</button>
    </div>
  `,
  data() {
    return {
      email: ''
    }
  },
  methods: {
    submit() {
      this.$emit('submit', this.email)
    }
  }
}

test('sets the value', async () => {
  const wrapper = mount(EmailInput)
  const input = wrapper.find('input')
  await input.setValue('abc@mail.com')
  expect(input.element.value).toBe('abc@mail.com')
})

test('submit event is triggered', async () => {
  const wrapper = mount(EmailInput)
  await wrapper.find('button').trigger('click')
  expect(wrapper.emitted()).toHaveProperty('submit')
})

In the 2nd test, we get the button and trigger the click event.

Then we check that the submit event is emitted with the wrapper.emitted method.

We can check what the event triggered with the argument that it’s emitted with.

For example, we can write:

import { mount } from '@vue/test-utils'

const EmailInput = {
  template: `
    <div>
      <input type="email" v-model="email">
      <button @click="submit">Submit</button>
    </div>
  `,
  data() {
    return {
      email: ''
    }
  },
  methods: {
    submit() {
      this.$emit('submit', this.email)
    }
  }
}

test('emits the input to its parent', async () => {
  const wrapper = mount(EmailInput)
  await wrapper.find('input').setValue('abc@mail.com')
  await wrapper.find('button').trigger('click')
  expect(wrapper.emitted('submit')[0][0]).toBe('abc@mail.com')
})

We mount the EmailInput .

Then we call setValue on the input to set its value.

Then we trigger the click event on the button.

And we check that the submit event is emitted with the input value.

Working with Various Form Elements

We can manipulate other form elements in our tests.

For instance, we can write:

import { mount } from '@vue/test-utils'

const FormComponent = {
  template: `
    <div>
      <form @submit.prevent="submit">
        <input type="email" v-model="form.email">
        <textarea v-model="form.description"/>

        <select v-model="form.city">
          <option value="new-york">New York</option>
          <option value="toronto">Toronto</option>
        </select>

        <input type="checkbox" v-model="form.subscribe"/>
        <input type="radio" value="weekly" v-model="form.interval"/>
        <input type="radio" value="monthly" v-model="form.interval"/>

         <button type="submit">Submit</button>
      </form>
    </div>
  `,
  data() {
    return {
      form: {
        email: '',
        description: '',
        city: '',
        subscribe: false,
        interval: ''
      }
    }
  },
  methods: {
    async submit() {
      this.$emit('submit', this.form)
    }
  }
}

test('submits a form', async () => {
  const wrapper = mount(FormComponent)
  await wrapper.find('input[type=email]').setValue('name@mail.com')
  await wrapper.find('textarea').setValue('Lorem ipsum')
  await wrapper.find('select').setValue('toronto')
  await wrapper.find('input[type=checkbox]').setValue()
  await wrapper.find('input[type=radio][value=monthly]').setValue()
})

We can use the setValue method with textarea , selecrt , checkboxes and radio buttons.

Also, we can trigger complex events.

For instance, we can write:

import { mount } from '@vue/test-utils'

const FormComponent = {
  template: `
    <div>
      <form @submit.prevent="submit">
        <input type="email" v-model="form.email">
        <textarea v-model="form.description"/>

        <select v-model="form.city">
          <option value="new-york">New York</option>
          <option value="toronto">Toronto</option>
        </select>

        <input type="checkbox" v-model="form.subscribe"/>
        <input type="radio" value="weekly" v-model="form.interval"/>
        <input type="radio" value="monthly" v-model="form.interval"/>

        <button type="submit">Submit</button>
      </form>
    </div>
  `,
  data() {
    return {
      form: {
        email: '',
        description: '',
        city: '',
        subscribe: false,
        interval: ''
      }
    }
  },
  methods: {
    async submit() {
      this.$emit('submit', this.form)
    }
  }
}

test('submits a form', async () => {
  const wrapper = mount(FormComponent)
  const email = 'name@mail.com'
  const description = 'Lorem ipsum'
  const city = 'toronto'
  await wrapper.find('input[type=email]').setValue(email)
  await wrapper.find('textarea').setValue(description)
  await wrapper.find('select').setValue(city)
  await wrapper.find('input[type=checkbox]').setValue()
  await wrapper.find('input[type=radio][value=monthly]').setValue()
  await wrapper.find('form').trigger('submit.prevent')
  expect(wrapper.emitted('submit')[0][0]).toMatchObject({
    email,
    description,
    city,
    subscribe: true,
    interval: 'monthly',
  })
})

We have the same component.

In the test, we mount the component and call setValue to set the value of each field.

Then we check if the object we emitted with the submit event matches the expected object with the toMatchObject method.

We test the this.form object in the submit method matches what we have in the last line.

Conclusion

We can test form triggered events and set the values of various form elements in our Vue 3 component tests with Vue Test Utils.

Categories
Vue 3 Testing

Testing Vue 3 Apps — Reactive Properties and Form Handling

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Passing Data to Components

We can pass data to components.

For example, we can write:

import { mount } from '@vue/test-utils'

const Name = {
  template: `
    <div>
      <input v-model="name">
      <div v-if="error">{{ error }}</div>
    </div>
  `,
  props: {
    minLength: {
      type: Number
    }
  },
  computed: {
    error() {
      if (this.name.length < this.minLength) {
        return `Name must be at least ${this.minLength} characters.`
      }
      return
    }
  }
}

test('renders an error if length is too short', () => {
  const wrapper = mount(Name, {
    props: {
      minLength: 10
    },
    data() {
      return {
        name: 'short'
      }
    }
  })
  expect(wrapper.html()).toContain('Name must be at least 10 characters')
})

We have the Name component with an input field and an error display.

The error computed property checks if the name is too short and show an error message if it is.

In the test, we pass in the minLength prop to the component.

And the data method has the name reactive property set.

Then we show the error message since the name value’s length is shorter than 10.

Using setProps

We can also use the setProps method to set the props.

For example, we can write:

import { mount } from '@vue/test-utils'

const Show = {
  template: `
    <div>
      <div v-if="show">{{ greeting }}</div>
    </div>
  `,
  props: {
    show: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      greeting: 'Hello'
    }
  }
}

test('renders a greeting when show is true', async () => {
  const wrapper = mount(Show)
  expect(wrapper.html()).toContain('Hello')
  await wrapper.setProps({ show: false })
  expect(wrapper.html()).not.toContain('Hello')
})

We test the Show component and check if the 'Hello' is rendered in the component.

Then we call setProps to set the show prop to false .

Then we check that 'Hello' isn’t rendered.

Test Form Handling

We can test form handling by interacting with form elements.

For example, we can write:

import { mount } from '@vue/test-utils'

const EmailInput = {
  template: `
    <div>
      <input type="email" v-model="email">
      <button @click="submit">Submit</button>
    </div>
  `,
  data() {
    return {
      email: ''
    }
  },
  methods: {
    submit() {
      this.$emit('submit', this.email)
    }
  }
}

test('sets the value', async () => {
  const wrapper = mount(EmailInput)
  const input = wrapper.find('input')
  await input.setValue('abc@mail.com')
  expect(input.element.value).toBe('abc@mail.com')
})

We have an EmailInput component with an input component.

Then we add a test to mount the EmailInput component.

Then we get the input with find .

And then we call input.setValue to set its value.

Then we get the value from the input with input.element.value .

Conclusion

We can pass in the data for the props and test the rendered Vue 3 components with Vue Test Utils.

Also, we can test form inputs with this.

Categories
Vue 3 Testing

Testing Vue 3 Apps — Testing Event Handling

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Event Handling

We can test event handling in our Vue 3 components easily with Vue Test Utils.

For example, we can write:

import { mount } from '@vue/test-utils'

const Counter = {
  template: '<button @click="handleClick">Increment</button>',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count += 1
      this.$emit('increment', this.count)
    }
  }
}

test('emits increment event when button is clicked', () => {
  const wrapper = mount(Counter)
  wrapper.find('button').trigger('click')
  expect(wrapper.emitted()).toHaveProperty('increment')
})

We have the Counter component that has a button that runs the handleclick method when we click it.

The handleClick method emits the increment event.

In the test, we mount the Counter component.

Then we get the button with find and call trigger with the click method.

And then we check if the increment event is emitted with the wrapper.emitted method.

The returned object has the event names as the key.

We can do other checks in our tests with regard to events.

For instance, we can write:

import { mount } from '@vue/test-utils'

const Counter = {
  template: '<button @click="handleClick">Increment</button>',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count += 1
      this.$emit('increment', this.count)
    }
  }
}

test('emits increment event when button is clicked', () => {
  const wrapper = mount(Counter)
  wrapper.find('button').trigger('click')
  expect(wrapper.emitted()).toHaveProperty('increment')
  const incrementEvent = wrapper.emitted('increment')
  expect(incrementEvent).toHaveLength(1)
  expect(incrementEvent[0]).toEqual([1])

})

We get the increment event object with:

const incrementEvent = wrapper.emitted('increment')

Then we check how many time it’s emitted with:

expect(incrementEvent).toHaveLength(1)

And we check the value that it’s emitted with, which the 2nd argument of this.$emit with:

expect(incrementEvent[0]).toEqual([1])

Asserting Complex Events

We can test more complex event objects.

For example, we can write:

import { mount } from '@vue/test-utils'

const Counter = {
  template: '<button @click="handleClick">Increment</button>',
  data() {
    return {
      count: 0
    }
  },
  methods: {
    handleClick() {
      this.count += 1
      this.$emit('increment', {
        count: this.count,
        isEven: this.count % 2 === 0
      })
    }
  }
}

test('emits increment event when button is clicked', () => {
  const wrapper = mount(Counter)
  wrapper.find('button').trigger('click')
  wrapper.find('button').trigger('click')
  expect(wrapper.emitted('increment')).toHaveLength(2)
  const [event1, event2] = wrapper.emitted('increment')
  expect(event1).toEqual([
    {
      count: 1,
      isEven: false
    }
  ])
  expect(event2).toEqual([
    {
      count: 2,
      isEven: true
    }
  ])
})

We trigger the click event on the button twice.

Then we check the number of times the increment event is emitted with:

expect(wrapper.emitted('increment')).toHaveLength(2)

Then we get the event objects that are emitted with:

const [event1, event2] = wrapper.emitted('increment')

Then we check the event object that we emitted with the event with:

expect(event1).toEqual([{
  count: 1,
  isEven: false
}])
expect(event2).toEqual([{
  count: 2,
  isEven: true
}])

Conclusion

We can test event emissions with Vue 3 and Vue Test Utils.

Categories
Vue 3 Testing

Getting Started with Testing Vue 3 Apps

With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.

In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.

Getting Started with Testing

We can get started with testing by creating the project with Vue CLI.

We add the ‘unit testing’ option when we create then project.

Then the files and settings for creating and running unit tests will be added.

We should see the tests folder with the test files.

Now we can create our own test by writing:

import { mount } from '@vue/test-utils'

const MessageComponent = {
  template: '<p>{{ msg }}</p>',
  props: ['msg'],
}

test('displays message', () => {
  const wrapper = mount(MessageComponent, {
    props: {
      msg: 'Hello world'
    }
  })
  expect(wrapper.text()).toContain('Hello world')
})

Then we can run npm run test:unit to run the test.

We should see a checkmark since ‘Hello World’ is rendered as the prop.

We call mount to mount the MessageComponent .

And the props has the props.

Then we call wrapper.text to get the text of the rendered component.

test takes a string that has the test description and the callback has the test code.

Conditional Rendering

We can test conditional rendering as we do in the first example.

For example, we can write:

import { mount } from '@vue/test-utils'

const Nav = {
  template: `
    <nav>
      <a id="profile" href="/profile">Profile</a>
      <a v-if="admin" id="admin" href="/admin">Admin</a>
    </nav>
  `,
  data() {
    return {
      admin: false
    }
  }
}

test('displays profile', () => {
  const wrapper = mount(Nav)
  const profileLink = wrapper.get('#profile')
  expect(profileLink.text()).toEqual('Profile')
})

We have the Nav component and get the element with the ID profile with wrapper.get .

Then we get the text with the text method.

We can check whether an element with the given selector exists with:

import { mount } from '@vue/test-utils'

const Nav = {
  template: `
    <nav>
      <a id="profile" href="/profile">Profile</a>
      <a v-if="admin" id="admin" href="/admin">Admin</a>
    </nav>
  `,
  data() {
    return {
      admin: false
    }
  }
}

test('displays profile', () => {
  const wrapper = mount(Nav)
  const profileLink = wrapper.get('#profile')
  expect(profileLink.text()).toEqual('Profile')
})

test('does not render an admin link', () => {
  const wrapper = mount(Nav)
  expect(wrapper.find('#admin').exists()).toBe(false)
})

wrapper.find(‘#admin’).exists() tries to find the element with the given selector.

Also, we can pass in our own data to change the value of the admin reactive property and test it:

import { mount } from '@vue/test-utils'

const Nav = {
  template: `
    <nav>
      <a id="profile" href="/profile">Profile</a>
      <a v-if="admin" id="admin" href="/admin">Admin</a>
    </nav>
  `,
  data() {
    return {
      admin: true
    }
  }
}

test('renders an admin link', () => {
  const wrapper = mount(Nav, {
    data() {
      return {
        admin: true
      }
    }
  })
  expect(wrapper.get('#admin').text()).toEqual('Admin')
})

We pass in our own data function in the test so we set admin to true .

And now we can check that the Admin text is rendered along with the link.

Conclusion

We can test rendered Vue 3 components with Vue Test Utils.

Categories
Careers

Ways to Make Money as a Developer — Apps, Games, and Subscriptions

Software development is a great skill to have in the modern world.

We can take advantage of it by making money in multiple ways.

In this article, we’ll look at some ways we can make money as a developer.

Create Your Own Apps

With your programming skills, you can create your own apps easily.

Just create a prototype version and let people test to see if they want it.

If people want it, then double down and finish the apps.

Now you got something that you can sell.

API Programming

If you know back end technologies like AWS or Azure well, then you’re a great asset to lots of people.

Back end is complex, so any expertise is welcome by companies.

This is something that will get anyone money if they know it well.

However, there’re many parts to these cloud services, so mastering them all is going to be a long journey.

Get Social

It’s time to get social if you want more opportunities.

As a developer, you can help lots of developers with your experience.

Many people get stuck on problems that you can answer.

They may ask on social media or on forums like Stack Overflow.

If you appear enough times, they’ll know you exist.

Paid Guest Posts

There’re some websites that’ll pay people to guest post on there.

As developers, you can contribute technical articles to these sites.

They include:

  • Clubhouse.io ($350–600)
  • Honey Badger ($500+)
  • Twilio ($500)
  • Digital Ocean ($300/$400)
  • Log Rocket (up to $350)
  • Real Python (up to $300)
  • Linode ($100/$300+)
  • Hasura ($100-$300)
  • Code Tuts+ ($100–250)
  • Smashing Magazine (up to $200)
  • GitLab (up to $200)
  • Scotch ($150)
  • Soshace ($100)
  • SitePoint (~$100)

Some of these are harder to get accepted than others.

But you can try them all and see how far you get.

The quantity of work must be good.

And you should submit original articles to these sites.

Write Games

You can write games to make money as a developer.

Games are harder to write than apps, so they’ll take more time.

Like writing apps, you should test the waters with your game by building a prototype before building a full version.

If people like it, then build a full version.

You can provide premium features like purchases and currencies.

Also, you can launch a paid version or sell merchandise in your game.

Subscriptions

Selling subscription services is another way to make money.

You can have a paid section in your blog or course.

Or you can add paid sections to your app or game.

Conclusion

You can create apps, sell subscriptions, or sell games to make money as a developer.