Categories
Node.js Basics

Node.js Basics — Add Authentication to an Express App with Passport

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Authentication

In the real world, many HTTP requests can only be made when the user is authenticated.

We can do this easily in a Node.js app.

To make our lives easier, we use the Express web framework to create our HTTP server instead of using the built-in http module.

We also need passport and passport-local to let us add authentication and the body-parser package to parse request bodies.

To install all the packages, we run:

npm install express body-parser passport passport-local

Then we can write the following code to add authentication with passport :

const express = require('express');
const bodyParser = require('body-parser');
const Passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const users = {
  foo: {
    username: 'foo',
    password: 'bar',
    id: 1
  },
  bar: {
    username: 'bar',
    password: 'foo',
    id: 2
  }
}

const localStrategy = new LocalStrategy({
    usernameField: 'username',
    passwordField: 'password'
  },
  function(username, password, done) {
    user = users[username];
    if (user === undefined) {
      return done(null, false, {
        message: 'Invalid user'
      });
    }
    if (user.password !== password) {
      return done(null, false, {
        message: 'Invalid password'
      });
    }
    done(null, user);
  })

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(express.static('public'));
app.use(Passport.initialize());
Passport.use('local', localStrategy);

app.get('/', (req, res) => {
  res.sendFile('public/index.html');
});

app.post(
  '/login',
  Passport.authenticate('local', {
    session: false
  }),
  function(request, response) {
    response.send('User Id ' + request.user.id);
  }
);

app.listen(3000, () => console.log('server started'));

We require the passport and passport-local packages.

Then we use the LocalStrategy constructor to create our authentication mechanism.

The userField and passwordField are set to the properties of the objects in the users object so that we can get the properties for the username and password.

Then in the function we passed into the 2nd argument of LocalStrategy , we check the user and check the password.

The done fucntion is called to let us return the response message we want depending on the validity of the username or password.

The last done call is run when both the username and password are valid.

Then we call Passport.use to create the 'local' authentication strategy so that we can use the code above with the Passport.authenticate function.

Then we can get the data for the authenticated user with the request.user property.

The data is obtained from calling:

done(null, user);

Now when we make a POST request to the /login route with the request body:

{
    "username": "foo",
    "password": "bar"
}

Then we get:

User Id 1

returned from the server.

If we have a username and password combination that isn’t in the users object, then we get an Unauthorized response body and a 401 status code.

Conclusion

To make adding authentication to our code easier, we can use Passport to let us add the middleware to add basic authentication easier.

Categories
Vue Testing

Unit Test Vue Apps with Vue Test Utils — Vue Router and Vuex Mocks

With the Vue Test Utils library, we can write and run unit tests for Vue apps easily.

In this article, we’ll look at how to write unit tests with the Vue Test Utils library.

Mocking $route and $router

We can mock the $route and $router objects to inject the Vue Router’s reactive properties into our mounted component.

For instance, we can write:

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

const Component = {
  template: `
    <div>
      <p>{{$route.path}}</p>
    </div>
  `
}

describe('Component', () => {
  it('renders the Component component with the path', async () => {
    const $route = {
      path: '/some/path'
    }
    const wrapper = shallowMount(Component, {
      mocks: {
        $route
      }
    })
    expect(wrapper.text()).toContain('/some/path')
  })

})

We have the Component component that renders the $route.path value.

We just put that in the mocks property so that it’ll be set with the given value when we mount the component.

Testing Vuex in Components

We can test components that depends on Vuex.

For example, if we have a Vue app that has the following code:

main.js

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <button @click="$store.dispatch('increment')">add</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  computed: {
    count() {
      return this.$store.state.count;
    },
  },
};
</script>

Then we can test the code by writing:

example.spec.js

import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import App from '@/App'

const localVue = createLocalVue()

localVue.use(Vuex)

describe('App.vue', () => {
  let actions
  let store

  beforeEach(() => {
    actions = {
      increment: jest.fn(),
    }
    store = new Vuex.Store({
      actions
    })
  })

  it('dispatches "increment" action when button is clicked', async () => {
    const wrapper = shallowMount(App, { store, localVue })
    const button = wrapper.find('button')
    await button.trigger('click')
    expect(actions.increment).toHaveBeenCalled()
  })
})

Once again, we call createLocalVue to create a local Vue instance we use for testing.

Then we have a beforeEach callback to set up the store and inject it into our app.

We inject the mocked store and the localVue object.

Then we get the button and trigger the click event on it.

And finally, we check that the increment action has been triggered after clicking the button.

Mocking Getters

Similarly, we can mock getters in our tests.

Given that we have the following code:

main.js

import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    increment(context) {
      context.commit('increment')
    }
  },
  getters: {
    count(state) {
      return state.count;
    }
  }
})

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <button @click="$store.dispatch('increment')">add</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  name: "App",
  computed: {
    ...mapGetters(['count'])
  },
};
</script>

Then to test our code, we write:

import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import App from '@/App'

const localVue = createLocalVue()

localVue.use(Vuex)

describe('App.vue', () => {
  let actions
  let store
  let getters

  beforeEach(() => {
    getters = {
      count: () => 2,
    }
    actions = {
      increment: jest.fn(),
    }
    store = new Vuex.Store({
      actions,
      getters
    })
  })

  it('dispatches "increment" action when button is clicked', () => {
    const wrapper = shallowMount(App, { store, localVue })
    expect(+wrapper.find('p').text()).toBe(getters.count())
  })
})

We add the mock getter into out mock store object.

Then we get the p element’s text and sees if it matches what’s returned in the mocked getter.

Conclusion

We can mock Vuex and Vue Router in our tests so that our components can be tested in isolation.

Categories
Vue Testing

Unit Test Vue Apps with Vue Test Utils — Mock External Dependencies

With the Vue Test Utils library, we can write and run unit tests for Vue apps easily.

In this article, we’ll look at how to write unit tests with the Vue Test Utils library.

Test Async Behavior Outside of Vue

To test async behavior outside of Vue, we have to mock the async code before we run our test.

For example, if we have a YesNo.vue component in the components folder:

<template>
  <div>
    <button @click="fetchResults">fetch answer</button>
    <p>{{ answer }}</p>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  name: "YesNo",
  data() {
    return {
      answer: undefined
    }
  },
  methods: {
    async fetchResults() {
      const { data: { answer } } = await axios.get('https://yesno.wtf/api')
      this.answer = answer;
    }
  }
};
</script>

We can test it by mocking the axios object and put our own get method in the mocked object:

import { shallowMount } from '@vue/test-utils'
import YesNo from '@/components/YesNo'

jest.mock('axios', () => ({
  get: () => Promise.resolve({ data: { answer: 'yes' } })
}))

describe('YesNo tests', () => {
  it('renders answer after clicking fetch answer', async () => {
    const wrapper = shallowMount(YesNo)
    await wrapper.find('button').trigger('click')
    expect(wrapper.text()).toContain('yes')
  })

})

Since axios.get returns a promise with the response, we do the same thing with our mock get method.

Then when we click the button, we should see the 'yes' answer.

Using with Vue Router

We can test our Vue app with Vue Router.

For example, given that we have the following Vue app code:

components/Bar.vue

<template>
  <div>Bar</div>
</template>

<script>
export default {
  name: "Bar",
};
</script>

components/Foo.vue

<template>
  <div>Foo</div>
</template>

<script>
export default {
  name: "Foo",
};
</script>

main.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Foo from '@/components/Foo';
import Bar from '@/components/Bar';

const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

const router = new VueRouter({
  routes
})

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

We can test the Foo component by writing:

import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import Foo from '@/components/Foo';

const localVue = createLocalVue()
localVue.use(VueRouter)
const router = new VueRouter()

describe('Foo tests', () => {
  it('renders the Foo component', async () => {
    const wrapper = shallowMount(Foo, {
      localVue,
      router
    })
    expect(wrapper.text()).toContain('Foo')
  })

})

We create a local Vue instance with the createLocalVue function.

Then we call use to add the VueRouter plugin.

Also, we create a new VueRouter instance.

Then we pass that all in when we mount our component so that we can test it in isolation.

Testing components that use router-link or router-view

There are a few ways to test components that use the router-link or router-view components.

One way is to stub those components by putting the component names in the stubs array:

import { shallowMount } from '@vue/test-utils'
import App from '@/App';

describe('App tests', () => {
  it('renders the App component', async () => {
    const wrapper = shallowMount(App, {
      stubs: ['router-link', 'router-view']
    })
    expect(wrapper.find('app')).toBeTruthy()
  })

})

We mount our App component from the previous example code with the stub for the router-link and router-view components.

Then we can carry on with our tests.

We can also pass in the localVue object with the local version of the Vue instance that has the VueRouter instance added to it:

import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import App from '@/App';

const localVue = createLocalVue()
localVue.use(VueRouter)

describe('App tests', () => {
  it('renders the App component', async () => {
    const wrapper = shallowMount(App, {
      localVue
    })
    expect(wrapper.find('app')).toBeTruthy()
  })

})

Conclusion

We can test our app with external dependencies by mocking them so that they can run reliably without relying on external resources.

Categories
Vue Testing

Unit Test Vue Apps with Vue Test Utils — Keyboard and Mouse Events

With the Vue Test Utils library, we can write and run unit tests for Vue apps easily.

In this article, we’ll look at how to write unit tests with the Vue Test Utils library.

Keyboard Event Tests

We can test keyboard events in our code.

For example, we can write:

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

const KEY_DOWN = 40
const KEY_UP = 38
const ESCAPE = 27

const QuantityComponent = {
  template: `
    <div>
      <input type="text" [@keydown](http://twitter.com/keydown "Twitter profile for @keydown").prevent="onKeydown" v-model="quantity" />
    </div>
  `,
  data() {
    return {
      quantity: 0
    }
  },
  methods: {
    increment() {
      this.quantity += 1
    },
    decrement() {
      this.quantity -= 1
    },
    clear() {
      this.quantity = 0
    },
    onKeydown(e) {
      if (e.keyCode === ESCAPE) {
        this.clear()
      }
      if (e.keyCode === KEY_DOWN) {
        this.decrement()
      }
      if (e.keyCode === KEY_UP) {
        this.increment()
      }
      if (e.key === 'a') {
        this.quantity = 10
      }
    }
  },
  watch: {
    quantity(newValue) {
      this.$emit('input', newValue)
    }
  }
}

describe('Key event tests', () => {
  it('Quantity is zero by default', () => {
    const wrapper = mount(QuantityComponent)
    expect(wrapper.vm.quantity).toBe(0)
  })

  it('Up arrow key increments quantity by 1', async () => {
    const wrapper = mount(QuantityComponent)
    await wrapper.find('input').trigger('keydown.up')
    expect(wrapper.vm.quantity).toBe(1)
  })

  it('Down arrow key decrements quantity by 1', async () => {
    const wrapper = mount(QuantityComponent)
    wrapper.vm.quantity = 2
    await wrapper.find('input').trigger('keydown.down')
    expect(wrapper.vm.quantity).toBe(1)
  })

  it('Escape sets quantity to 0', async () => {
    const wrapper = mount(QuantityComponent)
    wrapper.vm.quantity = 3
    await wrapper.find('input').trigger('keydown.esc')
    expect(wrapper.vm.quantity).toBe(0)
  })

  it('Magic character "a" sets quantity to 10', async () => {
    const wrapper = mount(QuantityComponent)
    await wrapper.find('input').trigger('keydown', {
      key: 'a'
    })
    expect(wrapper.vm.quantity).toBe(10)
  })
})

to trigger the keyboard events on each test.

The QuantityComponent has an input element that listens to the keydown event and updates the quantity accordingly.

The onKeydown method updates the quantity reactive property to set the value according to the key that’s pressed.

In our tests, we get the input element with the find method.

Then we call trigger to trigger various kinds of keydown events.

keydown.up simulates pressing the up arrow.

keydown.up simulates pressing the down arrow.

keydown.up simulates pressing the esc key.

The last test simulates pressing the 'a' key.

Once we did that, we can check the quantity reactive property to get the final result.

Testing Async Behavior

We can test async behavior by using the same principles as the previous example.

For example, we can write:

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

const Counter = {
  template: `
    <div>
      <button @click='count++'>add</button>
      <p>{{count}}</p>
    </div>
  `,
  data() {
    return {
      count: 0
    }
  },
}

describe('Counter tests', () => {
  it('count is set to 1 after click', async () => {
    const wrapper = mount(Counter)
    expect(wrapper.text()).toContain('0')
    const button = wrapper.find('button')
    await button.trigger('click')
    expect(wrapper.text()).toContain('1')
  })

})

We have the Counter component that updates the count reactive property when we click on the add button.

Then in our test, we check the rendered content with the text method.

And then we click the button and do the check again.

Conclusion

We can simulate clicks and keyboard events in our tests and test the rendered content.

Categories
Vue Testing

Unit Test Vue Apps with Vue Test Utils — Transitions and Plugin Tests

With the Vue Test Utils library, we can write and run unit tests for Vue apps easily.

In this article, we’ll look at how to write unit tests with the Vue Test Utils library.

Mocking Transitions

We can test components with transitions the same way we test other components.

All we have to do is to set the reactive properties to the value we want.

For example, we can write:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

describe('Foo', () => {
  it('renders bar for foo prop', async () => {
    const wrapper = mount(Foo)
    expect(wrapper.text()).toMatch(/Foo/)
    await wrapper.setData({
      show: false
    })
    expect(wrapper.text()).not.toMatch(/Foo/)
  })
})

We call mount to mount the Foo component.

Then we check what’s displayed before we set the show reactive property to false .

Then we call setData to set show to false .

Then we check the pattern of the content displayed with the text method to return the rendered text and the toMatch method to check whether the content matches the given regex pattern.

We can also stub the transitions with the transitionStub helper:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

const transitionStub = () => ({
  render(h) {
    return this.$options._renderChildren
  }
})

describe('Foo', () => {
  it('renders bar for foo prop', async () => {
    const wrapper = mount(Foo, {
      stubs: {
        transition: transitionStub()
      }
    })
    expect(wrapper.text()).toMatch(/Foo/)
    await wrapper.setData({
      show: false
    })
    expect(wrapper.text()).not.toMatch(/Foo/)
  })
})

transitionStub is just a function that returns an object with the render method to simulate rendering the transitions.

We can also avoid using setData if we mount our component and set the reactive properties’ values when we mount it:

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

const Foo = {
  template: `
    <div>
      <transition>
        <p v-if="show">Foo</p>
      </transition>
    </div>
  `,
  data() {
    return {
      show: true
    }
  }
}

test('should render Foo', async () => {
  const wrapper = mount(Foo, {
    data() {
      return {
        show: true
      }
    }
  })

  expect(wrapper.text()).toMatch(/Foo/)
})

test('should not render Foo', async () => {
  const wrapper = mount(Foo, {
    data() {
      return {
        show: false
      }
    }
  })

  expect(wrapper.text()).not.toMatch(/Foo/)
})

Applying Global Plugins and Mixins

If we want to apply global plugins, then we have to use the createLocalVue to return a mocked version of the Vue constructor.

This way, we can control when the global plugin is applied.

For example, we can write:

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

const localVue = createLocalVue()

const MyPlugin = {};
MyPlugin.install = function (Vue, options) {
  Vue.prototype.fooMethod = function () {
    this.foo = 'bar';
  }
}

localVue.use(MyPlugin);
const Foo = {
  template: `
    <div>
      <p>{{foo}}</p>
    </div>
  `,
  data() {
    return {
      foo: ''
    }
  }
}

test('should render bar', async () => {
  const wrapper = mount(Foo, {
    localVue
  })
  await wrapper.vm.fooMethod();
  expect(wrapper.text()).toContain('bar')
})

We call the createLocalVue function to create a mock version of the Vue constructor.

Then we create our plugin by defining the MyPlugin object and adding the fooMethod instance method to our plugin.

Next, we call localVue.use(MyPlugin) so we can add our plugin with we mount the Foo component.

Then in our test, we set the localVue property in the object in the 2nd argument of mount .

And we call our fooMethod to run the test.

Finally, we check if the text is rendered.

Conclusion

We can mock transitions and plugins so that we can do test with plugins.