Vue Testing
Pada pengujian aplikasi Vue, terdapat 3 jenis pengujian yang dapat dilakukan, yaitu Unit Testing, Component Testing, dan End-to-End (E2E) Testing.
Unit Testing
Unit testing adalah metode testing yang dilakukan untuk menguji unit kode individual secara terpisah. Tujuan dari pelaksanaan Unit Testing adalah untuk memastikan agar apabila terdapat penambahan fitur baru ataupun terdapat refactoring pada kode, maka bagian kode yang diberikan Unit Testing akan tetap berjalan dan tetap stabil. Terdapat beberapa framework yang dapat digunakan di dalam Unit Testing Vue.
Jest
Jest adalah kerangka unit testing yang berfokus pada mengambil snapshot pengujian sebagai alternatif untuk memverifikasi kode yang telah dibuat.
Jest Setup
Untuk melakukan setup Jest pada aplikasi Vue, jalankan perintah berikut pada command prompt.
npm install --save-dev jest ts-jest
Setelah itu, tambahkan dependency pada package.json
{ "scripts": { "test": "jest" } }
Ketika akan menjalankan testing, jalankan testing dengan perintah berikut ini
npm run test
Jest Testing Example (Docs Example)
Berikut ini adalah contoh kode testing dengan framework Jest
// sum.js function sum(a, b) { return a + b; } module.exports = sum; // sum.test.js const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
Mocha
Mocha adalah kerangka unit testing yang berfokus pada fleksibilitas bagi pengembang untuk menggunakan library yang dibutuhkan, seperti penggunaan Sinon untuk spying dan Chai untuk penambahan assertion.
Mocha Setup
Untuk melakukan setup pada Mocha, jalankan perintah berikut di command prompt
npm install mocha
Lalu setup test script di dalam package.json dengan menuliskan perintah berikut di package.json
"scripts": { "test": "mocha" }
Ketika akan menjalankan testing, jalankan perintah berikut di dalam command prompt
npm test
Mocha Testing Example (Docs)
Berikut ini adalah contoh kode yang ditulis dengan framework Mocha untuk pengujiannya sesuai dengan yang tertera pada dokumentasi
var assert = require('assert'); describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.equal([1, 2, 3].indexOf(4), -1); }); }); });
Component Testing
Component Testing adalah metode pengujian yang dilakukan untuk komponen Vue yang telah dibangun oleh developer sebelumnya. Pada Vue, setiap komponen perlu dijalankan di atas DOM untuk memastikan komponen tersebut benar berjalan. Terdapat beberapa framework yang dapat digunakan di dalam Component Testing aplikasi Vue.
Vue Testing Library (@testing-library/vue)
Vue Testing Library adalah library yang digunakan dalam testing dengan fokus utamanya adalah tes yang dibuat menyerupai cara perangkat lunak digunakan.
Vue Testing Library Setup
Untuk melakukan setup Vue Testing Library pada aplikasi, lakukan instalasi terlebih dahulu dengan memasukkan perintah berikut pada command prompt
npm install --save-dev @testing-library/vue
Vue Testing Library Example (Docs)
Berikut ini adalah contoh penggunaan Vue Testing Library sesuai dengan dokumentasi dengan menggunakan v-model.
<template> <div> <p>Hi, my name is {{ user }}</p> <label for="username">Username:</label> <input v-model="user" id="username" name="username" /> </div> </template> <script> export default { data: () => ({ user: 'Alice', }), } </script>
import { render, fireEvent } from '@testing-library/vue' import Component from './Component.vue' test('properly handles v-model', async () => { const { getByLabelText, getByText } = render(Component) // Asserts initial state. getByText('Hi, my name is Alice') // Get the input DOM node by querying the associated label. const usernameInput = getByLabelText(/username/i) // Updates the <input> value and triggers an `input` event. // fireEvent.input() would make the test fail. await fireEvent.update(usernameInput, 'Bob') getByText('Hi, my name is Bob') })
Vue Test Utils
Vue Test Utils adalah framework testing yang sifatnya lebih low-level ketimbang Vue Testing Library. Untuk pemula, disarankan menggunakan Vue Testing Library.
Vue Test Utils Setup
Untuk menggunakan Vue Test Utils, dapat digunakan bersamaan dengan Jest dan bahkan penggunaan Jest dan Vue Test Utils merupakan kombinasi yang direkomendasikan sesuai dengan dokumentasi resmi Vue Test Utils. Jalankan perintah berikut untuk melakukan instalasi terhadap Jest dan Vue Test Utils secara bersamaan.
npm install --save-dev @vue/test-utils vue-jest ts-jest
Setelah package di-install, lakukan penambahan dependency pada package.json dengan menambahkan hal berikut di dalam file tersebut.
{ "jest": { // lokasi file test ditempatkan "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", "moduleFileExtensions": [ "js", "json", "vue" ], "transform": { ".*\\.(vue)$": "vue-jest", "^.+\\.tsx?$": "ts-jest" } } }
Vue Test Utils Example (Docs)
Berikut ini adalah contoh file testing dengan Vue Test Utils sesuai dengan contoh dokumentasi
// src/components/__tests__/HelloWorld.spec.ts import { shallowMount } from '@vue/test-utils' import HelloWorld from '../HelloWorld.vue' describe('HelloWorld.vue', () => { test('renders props.msg when passed', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) expect(wrapper.text()).toMatch(msg) }) })
End-to-End (E2E) Testing
End-to-End Testing adalah sebuah metode testing yang digunakan untuk pengujian terhadap berbagai lapisan yang ada di dalam aplikasi. Apabila Unit Testing menguji satu bagian jkode sementara Component Testing menguji satu komponen dari aplikasi, maka End-to-End Testing melakukan pengujian pada aplikasi seakan-akan pengguna sedang menggunakan aplikasi. Terdapat beberapa framework yang dapat digunakan di dalam End-to-End (E2E) Testing.
Cypress.io
Cypress.io sendiri adalah sebuah framework yang digunakan untuk E2E Testing dengan fokus utamanya adalah sistem all-in-one. Sistem all-in-one berarti Cypress.io berfokus pada penggunaan berbagai library dalam satu framework
Cypress.io Setup
Untuk melakukan instalasi terhadap Cypress.io, jalankan perintah berikut pada command prompt
npm install cypress --save-dev
Untuk mempermudah, tambahkan potongan kode berikut ke dalam package.json. Tujuan dari penambahan kode ini adalah untuk mempersingkat perintah ketika kita akan menjalankan Cypress.io.
{ "scripts": { "cypress:open": "cypress open" } }
Setelah menambahkan potongan kode di atas ke dalam package.json, Cypress.io dapat dijalankan dengan menjalankan perintah berikut ke dalam command prompt
npm run cypress:open
Cypress.io Examples (Docs)
Berikut ini adalah contoh pengujian dengan menggunakan Cypress.io sesuai dengan dokumentasi. Untuk melihat contoh lainnya yang lebih "advanced", dapat dilihat pada link GitHub ini.
describe('My First Test', () => { it('Gets, types and asserts', () => { cy.visit('https://example.cypress.io') cy.contains('type').click() // Should be on a new URL which includes '/commands/actions' cy.url().should('include', '/commands/actions') // Get an input, type into it and verify that the value has been updated cy.get('.action-email') .type('fake@email.com') .should('have.value', 'fake@email.com') }) })
Nightwatch.js
Nightwatch.js adalah sebuah framework yang digunakan untuk E2E Testing dengan fokus utamanya adalah kecepatan dari proses testing yang dilakukan. Agak kurang worth it karena dari pengalaman orang lain lebih banyak cons daripada pros nya.
Nightwatch.js Setup
Untuk melakukan instalasi pada Nightwatch.js, jalankan perintah berikut pada command prompt
npm install nightwatch
Selain melakukan instalasi terhadap Nightwatch.js itu sendiri, kita juga perlu menginstall Browser Driver untuk menjalankan testing. Terdapat banyak Browser Driver yang dapat dipakai dan hal ini disesuaikan dengan browser yang menjadi target pengujian. Untuk instalasi Browser Driver, dapat dilakukan dengan menjalankan perintah berikut ini.
npm install chromedriver --save-dev
Sebagai catatan, contoh di atas digunakan untuk menginstall chromedriver, Browser Driver yang digunakan pada browser Chrome. Sintaks untuk install Browser Driver pada dasarnya sama (npm install <browser driver> —save-dev), kecuali untuk Safari. Pada Safari, hal ini dapat dilakukan dengan menjalankan perintah di bawah ini.
safaridriver --enable
Selain itu, untuk menggunakan Nightwatch.js juga diperlukan Selenium Server. Untuk melakukan instalasi pada Selenium Server, jalankan perintah di bawah ini pada command prompt.
npm install selenium-server --save-dev
Nightwatch.js Example (Docs)
Berikut ini adalah contoh penggunaan Nightwatch.js sesuai dengan yang tertera pada dokumentasi resmi.
module.exports = { 'step one: navigate to ecosia.org': function(browser) { browser .url('https://www.ecosia.org') .waitForElementVisible('body') .assert.titleContains('Ecosia') .assert.visible('input[type=search]') .setValue('input[type=search]', 'nightwatch') .assert.visible('button[type=submit]'); }, 'step two: click submit' : function (browser) { browser .click('button[type=submit]') .assert.containsText('.mainline-results', 'Nightwatch.js') .end(); } };
Puppeteer
Puppeteer adalah sebuah framework yang digunakan untuk E2E Testing yang fokus utamanya adalah penggunaan prinsip promise dalam pembangunan model testingnya.
Puppeteer Setup
Untuk melakukan instalasi terhadap Puppeteer, jalankan perintah di bawah ini pada command prompt.
npm i puppeteer
Sebagai catatan, versi dari Puppeteer di atas merupakan versi yang lebih "berat". Untuk versi yang lebih ringan, ganti puppeteer dengan puppeteer-core.
Ketika nanti akan menjalankan testing dengan Puppeteer, jalankan perintah berikut untuk menjalankannya.
node <FileName>.js
Puppeteer Example (Docs)
Berikut ini adalah contoh testing yang dibuat dengan Puppeteer sesuai dengan contoh pada dokumentasi.
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); // Get the "viewport" of the page, as reported by the page. const dimensions = await page.evaluate(() => { return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, deviceScaleFactor: window.devicePixelRatio, }; }); console.log('Dimensions:', dimensions); await browser.close(); })();
TestCafe
TestCafe adalah sebuah framework yang digunakan untuk E2E Testing dengan fokus utamanya adalah proses setup yang sederhana agar pengembang dapat berfokus pada pengembangan testing yang baik.
TestCafe Setup
Untuk melakukan instalasi terhadap TestCafe, jalankan perintah berikut di dalam command prompt.
npm install -g testcafe
Untuk menjalankan file testing TestCafe, jalankan perintah berikut ini di dalam command prompt.
testcafe <BrowserName> <FilePath>
TestCafe Example (Docs)
Berikut ini adalah contoh dari testing dengan TestCafe sesuai dengan contoh yang tertera pada dokumentasi resmi.
import { Selector } from 'testcafe'; fixture`HTMLOListElement`.page('https://example.com'); test('Check that the list is reversed', async t => { const olElement = Selector('#ordered-list'); const isListReversed = await t.eval( () => { const list = olElement() as unknown as HTMLOListElement; return list.reversed; }, { dependencies: { olElement } } ); await t.expect(isListReversed).ok(); });
Nuxt Testing
Untuk pengujian terhadap aplikasi Nuxt, terdapat beberapa framework yang dapat digunakan untuk melakukan pengujian.
Jest
Jest, seperti dijelaskan sebelumnya, dapat digunakan pada aplikasi berbasis Nuxt.
Jest Nuxt Setup
Untuk menambahkan Jest pada project Nuxt, jalankan perintah instalasi berikut pada command prompt.
npm install @babel/core @babel/preset-env babel-core@^7.0.0-bridge.0 @vue/test-utils jest babel-jest jest-serializer-vue vue-jest -D
Untuk konfigurasi Jest pada project, buatlah file jest,config.js dan isikan file tersebut dengan kode di bawah ini.
module.exports = { // tell Jest to handle `*.vue` files moduleFileExtensions: ["js", "json", "vue"], watchman: false, moduleNameMapper: { "^~/(.*)$": "<rootDir>/$1", "^~~/(.*)$": "<rootDir>/$1", "^@/(.*)$": "<rootDir>/$1" }, transform: { // process js with `babel-jest` "^.+\\.js$": "<rootDir>/node_modules/babel-jest", // process `*.vue` files with `vue-jest` ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest" }, snapshotSerializers: ["<rootDir>/node_modules/jest-serializer-vue"], collectCoverage: true, collectCoverageFrom: [ "<rootDir>/components/**/*.vue", "<rootDir>/pages/*.vue" ] };
Selain itu, Babel juga perlu dikonfigurasi pada project Nuxt. Untuk mengkonfigurasi Babel, buatlah file babel.config.js dan isikan file tersebut dengan potongan kode di bawah ini.
function isBabelLoader(caller) { return caller && caller.name === "babel-loader"; } module.exports = function(api) { if (api.env("test") && !api.caller(isBabelLoader)) { return { presets: [ [ "@babel/preset-env", { targets: { node: "current" } } ] ] }; } return {}; };
Untuk menambahkan konfigurasi testing dengan Jest, tambahkan kode berikut pada file package.json
... "scripts": { ... "test": "jest" ... } ...
Ketika akan menjalankan testing, jalankan perintah berikut di command prompt untuk memulai proses pengujian
npm run test
Jest Nuxt Example (Docs)
Berikut ini adalah contoh kode testing yang dibuat dengan Jest pada aplikasi berbasis Nuxt berdasarkan dokumentasi resmi
import { shallowMount } from "@vue/test-utils"; import Logo from "../Logo"; const factory = () => { return shallowMount(Logo, {}); }; describe("Logo", () => { test("mounts properly", () => { const wrapper = factory(); expect(wrapper.isVueInstance()).toBeTruthy(); }); test("renders properly", () => { const wrapper = factory(); expect(wrapper.html()).toMatchSnapshot(); }); });
nuxt/test-utils
Tidak seperti Jest atau @testing-library/vue, nuxt/test-utils diciptakan untuk pengujian terhadap aplikasi berbasis Nuxt.
nuxt/test-utils Setup
Untuk melakukan instalasi terhadap nuxt/test-utils, jalankan perintah berikut pada command prompt untuk menginstall library tersebut beserta dengan library lain yang juga digunakan oleh nuxt/test-utils.
npm install --save-dev jest @nuxt/test-utils
Untuk menambah pengaturan pada Jest, tambahkan potongan kode berikut pada jest.config.js.
module.exports = { preset: '@nuxt/test-utils' }
nuxt/test-utils Example (Docs)
Berikut ini adalah contoh file testing yang ditulis dengan nuxt/test-utils sesuai dengan yang tertera pada dokumentasi.
test('should inject plugin', () => { expectModuleToBeCalledWith('addPlugin', { src: expect.stringContaining('templates/plugin.js'), fileName: 'myPlugin.js', options: getNuxt().options.myModule }) })
Vue Testing Library (@testing-library/vue)
Vue testing library, seperti dijelaskan pada bagian sebelumnya, dapat digunakan pada aplikasi berbasis Nuxt.
Vue Testing Library Setup
Untuk melakukan instalasi Vue Testing Library, jalankan perintah berikut ini pada command prompt
npm install -D @testing-library/vue \ vue-jest@^3 \ ts-jest@^26 \ babel-core@7.0.0-bridge.0 \ babel-jest@^26
Untuk menjalankan Jest, tambahkan konfigurasi Jest CLI pada package.json seperti pada di bawah ini.
{ "scripts": { "test": "jest" } }
Karena kita menggunakan Babel dan Jest, tambahkan pula konfigurasi Jest dan Babel seperti yang ada di bawah ini.
// jest.config.js module.exports = { moduleNameMapper: { '^@/(.*)$': '<rootDir>/$1', '^~/(.*)$': '<rootDir>/$1', '^vue$': 'vue/dist/vue.common.js' }, moduleFileExtensions: [ 'ts', // if using TypeScript 'js', 'vue', 'json' ], transform: { "^.+\\.ts$": "ts-jest", // if using TypeScript '^.+\\.js$': 'babel-jest', '.*\\.(vue)$': 'vue-jest' }, collectCoverage: true, collectCoverageFrom: [ '<rootDir>/components/**/*.vue', '<rootDir>/pages/**/*.vue' ] }
// babel.config.js { "env": { "test": { "presets": [ [ "@babel/preset-env", { "targets": { "node": "current" } } ] ] } } }
Untuk menjalankan testing, jalankan perintah di bawah ini di dalam command prompt
npm run test
Vue Testing Library Example (Docs)
Berikut ini adalah contoh penggunaan Vue Testing Library untuk proyek berbasis Nuxt
// <rootDir>/test/Counter.spec.js import {render, screen, fireEvent} from '@testing-library/vue' import Counter from '@/components/Counter.vue' test('increments value on click', async () => { render(Counter) expect(screen.queryByText('Times clicked: 0')).toBeTruthy() const button = screen.getByText('increment') await fireEvent.click(button) await fireEvent.click(button) expect(screen.queryByText('Times clicked: 2')).toBeTruthy() })
Testing with Firebase
Mocking Firebase
Untuk menggunakan Firebase dalam testing, salah satu hal yang perlu dilakukan adalah melakukan mocking terhadap Firebase. Hal ini dapat dilakukan dengan menggunakan library firebase-mock. Untuk melakukan instalasi firebase-mock, jalankan perintah ini di dalam command prompt.
npm install firebase-mock --save-dev
Firebase Mock Example (Docs)
Pada contoh ini, terdapat 2 bagian, yaitu Source dan Test. Source adalah bagian kode yang akan dites, sementara Test adalah bagian kode yang digunakan untuk testing. Berikut ini adalah contoh penggunaan Firebase Mock dalam testing sesuai dengan contoh yang tertera pada dokumentasi resmi.
Source
var collection; var people = { collection: function () { if (!collection) collection = firebase.firestore().collection('people'); return collection; }, greet: function (person) { console.log('hi ' + person.first); }, process: function () { people.collection().get().then(function(snaps) { snaps.forEach(function(doc) { people.greet(doc.data()); }); }); } };
Test
MockFirebase.override(); var greeted = []; people.greet = function (person) { greeted.push(person); }; people.collection().add({ first: 'Michael' }); people.collection().add({ first: 'Ben' }); people.process(); people.collection().flush(); console.assert(greeted.length === 2, '2 people greeted'); console.assert(greeted[0].first === 'Michael', 'Michael greeted'); console.assert(greeted[1].first === 'Ben', 'Ben greeted');
Setup Test Environment in Nuxt
Setup yang akan dipakai adalah setup Jest + Typescript untuk melakukan testing pada Nuxt + Typescript + Vuetify + Firebase.
References
Jest (Berhubungan dengan matcher, expect, mocks, dsb)
Vue Test Utils (Berhubungan dengan wrapper, find component, dsb)
Vuetify unit testing documentation (Berisi cara integrasi vuetify dengan jest atau framework testing lainnya)
Jest snapshot testing
Prerequisites
- Pastikan
Nuxtsudah dikonfigurasi untuk dapat testing menggunakanJestsaat pertama kali inisialisasi project.
- Install dependency
@types/jestagar dapat menggunakanJestdengantypescript. Tambahkantypestersebut padatsconfig.json.
npm i -D @types/jest
// tsconfig.json { "compilerOptions": { ... "types": [ ... "@types/jest" ] }, ... }
Setup Steps
- Pada file
jest.config.js, ubah bagian regex transform ts-jest menjadi'^.+\\\\.(ts|js)(x)?$'dan masukkan fieldsetupFilesAfterEnvyang mengarah ke setup yang akan dijalankan sebelum testing dimulai. Berikut contohjest.config.js(bagian yang ditambahkan adalah yang dipertebal dan memiliki highlight):
// jest.config.js module.exports = { moduleNameMapper: { '^@/(.*)$': '<rootDir>/$1', '^~/(.*)$': '<rootDir>/$1', '^vue$': 'vue/dist/vue.common.js', }, moduleFileExtensions: ['ts', 'js', 'vue', 'json'], transform: { **'^.+\\\\.(ts|js)(x)?$'**: 'ts-jest', '^.+\\\\.js$': 'babel-jest', '.*\\\\.(vue)$': 'vue-jest', }, **transformIgnorePatterns: ['<rootDir>/node_modules/(?!vue-spinner)'],** collectCoverage: true, collectCoverageFrom: [ '<rootDir>/components/**/*.vue', '<rootDir>/pages/**/*.vue', ], **setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],** }
transformIgnorePatterns dapat ditambahkan apabila terdapat library yang tidak mendukung typescript. Apabila lebih dari 1 library dapat menggunakan | seperti berikut:
<rootDir>/node_modules/(?!vue-spinner|another-module|another-module)
- Buat file
jest.setup.jspada root directory yang berisi hal-hal yang perlu di-setup pada testing secara global (contohnyaVuetify).
// jest.setup.js import Vue from 'vue' import Vuetify from 'vuetify' Vue.use(Vuetify)
- Buat file
ts-shim.d.tspada root directory agar filetypescriptyang berisiJestdapat mengenali file.vue
// ts-shim.d.ts declare module '*.vue' { import Vue from 'vue' export default Vue }
- Tambahkan file test yang memiliki nama
.spec.ts(atau bisa juga.test.ts). Agar dapat terintegrasi dengan Vuetify, minimal mengandung boilerplate berikut.
// test/boilerplate.spec.ts import { createLocalVue, mount } from '@vue/test-utils' import Vuetify from 'vuetify' describe('... Page Test', () => { const localVue = createLocalVue() let vuetify: Vuetify beforeEach(() => { vuetify = new Vuetify() // Buat vuetify yang baru setiap awal test sesuai guide }) it('Should ...', () => { const wrapper = mount(..., { localVue, // Agar instansi vue tidak tercampur-campur dengan test lainnya vuetify, // Masukkan vuetify yang baru untuk setiap test ... }) }) })
- Berikut contoh melakukan mock pada Firebase dan dependensi eksternal lainnya. (source: manager-web)
// test/RevisionTest.spec.ts import { createLocalVue, mount } from '@vue/test-utils' import Vuetify from 'vuetify' import RevisionPage from '@/pages/dashboard/revision.vue' // Mock library vue-sweetalert2 (this.$swal) const mockedSwal = { fire: jest.fn(), } // Mock library firestore (this.$fire) const mockedFirebase = { firestore: { collection: () => ({ where: jest.fn(), }), }, } // Reference: <https://github.com/vuejs/vue-test-utils/issues/1809> // TL;DR vue-test-util membuat override method depcrecated sehingga // harus memakai mixins. const mockData = (data: Object[]) => ({ methods: { getDataFromCollection() { return data }, }, }) describe('Revision Page Test', () => { const localVue = createLocalVue() let vuetify: Vuetify // Library yang dimock dan hal-hal yang bersifat statis dapat dimasukkan kesini const mockedDependencies = { localVue, mocks: { $swal: mockedSwal, $fire: mockedFirebase, }, } // Pembuatan wrapper dijadikan fungsi agar kode lebih bersih const makeWrapper = (data: Object[]) => { return mount(RevisionPage, { mixins: [mockData(data)], vuetify, ...mockedDependencies, }) } beforeEach(() => { vuetify = new Vuetify() }) it('Should render empty table with message When no data is found', () => { const wrapper = makeWrapper([]) expect(wrapper.vm).toBeTruthy() expect(wrapper.element).toMatchSnapshot() const dataTable = wrapper.find('td') expect(dataTable.text()).toBe('No data available') }) })
Run Test
# Run test normally npm test # Run test with watcher npm test -- --watch # Run test and update snapshot npm test -- -u # Clear cache and run test npx jest --clearCache && npm test