DEV Community

Cover image for NativeScript-Vue unit testing with Vitest
Juan de Dios Martínez Vallejo
Juan de Dios Martínez Vallejo

Posted on • Edited on

NativeScript-Vue unit testing with Vitest

NativeScript (NS) is a framework for building native applications using JS/TS. If we combine NS with Vue we can build native high-performance applications and also, due to the incredible architecture of NS, NS-Vue and Vue, we can use Vue dependencies as if it were a frontend application. In this case we focus on unit testing with Vitest, a testing framework that is gaining more traction every day, created by the Vue team but made to be able to test almost all the frameworks that we use together with its older brother Vite.

Setup

The first thing to do is install the necessary dependencies for the tests.

npm i -D @types/node@22.9.1 @vitejs/plugin-vue @vue/test-utils vitest jsdom
Enter fullscreen mode Exit fullscreen mode

Now that we have the dependencies, we start with the code. Before starting with the configuration of vitest we will create two files that we will use to configure the tests.

To start, for this sample we will create the test folder in the root directory of the project in which we will add our tests and files for the general configuration. Inside this folder we create the file NSMockViews.ts which will contain an array of the views offered by NativeScript. If you have any views of a plugin you can add it to this list. We will use this file in the vitest configuration.

// test/NSMockViews.ts
export const NSMockViews = [
  'AbsoluteLayout',
  'ActionBar',
  'ActionItem',
  'ActivityIndicator',
  'Button',
  'ContentView',
  'DatePicker',
  'DockLayout',
  'FlexboxLayout',
  'FormattedString',
  'Frame',
  'GridLayout',
  'HtmlView',
  'Image',
  'Label',
  'ListPicker',
  'ListView',
  'NavigationButton',
  'Page',
  'Placeholder',
  'Progress',
  'ProxyViewContainer',
  'RootLayout',
  'ScrollView',
  'SearchBar',
  'SegmentedBar',
  'SegmentedBarItem',
  'Slider',
  'Span',
  'StackLayout',
  'Switch',
  'TabView',
  'TabViewItem',
  'TextField',
  'TextView',
  'TimePicker',
  'WebView',
  'WrapLayout',
  'Prop',
  'Template',
];
Enter fullscreen mode Exit fullscreen mode

Now we will create the setup.ts file inside the test folder. In this file we mock nativescript-vue with @vue/test-utils and we will also mock @nativescript/core.

// test/setup.ts
import Vue from '@vue/test-utils';
import { vi } from 'vitest';

/* MOCK Vue & Nativescript */
vi.mock('nativescript-vue', () => Vue);
vi.mock('@nativescript/core', async () => {
  return {
    default: () => ({}),
    TouchManager: {},
  };
});
Enter fullscreen mode Exit fullscreen mode

So that TypeScript doesn't complain in our tests, we'll add the test folder to tsconfig.json in the include section.

// tsconfig.json
"include": [
    "src",
    "types",
+   "test"
],
Enter fullscreen mode Exit fullscreen mode

With all the base configuration for our tests, we create the vitest.config.mts file that vitest will use to launch our tests.

// vitest.config.mts
import Vue from '@vitejs/plugin-vue';
import path from 'path';
import { defineConfig } from 'vitest/config';
import { NSMockViews } from './test/NSMockViews';

export default defineConfig({
  plugins: [
    Vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) =>
            NSMockViews.map((nsView) => nsView.toLowerCase()).includes(
              tag.toLowerCase()
            ),
        },
      },
    }),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '~': path.resolve(__dirname, './src'),
    },
    extensions: ['.mjs', '.js', '.ts', '.json', '.vue'],
  },
  test: {
    globals: true,
    name: 'jsdom',
    environment: 'jsdom',
    setupFiles: ['test/setup.ts'],
  },
});
Enter fullscreen mode Exit fullscreen mode

We briefly explain what we have configured here:

  • We use NSMockViews to tell vue that NativeScript components are customElements.
  • We added the default NativeScript-Vue aliases so that it resolves the components of our application.
  • We indicate the base configuration of the tests.

Build test and run

We now have everything configured. Let's continue creating a basic component that will show an icon to do the tests later on this component.

// src/components/Icon.vue

<script lang="ts" setup>
const props = defineProps({ icon: String });
</script>

<template>
  <Label :text="props.icon" class="m-icon-round"></Label>
</template>
Enter fullscreen mode Exit fullscreen mode

Let's take action, let's do our first test. We create the file test/components/icon.test.ts and add some basic tests, such as checking that the component receives a prop and the NS Label view has the text that we are passing to the component.

// test/components/icon.test.ts
import Icon from '@/components/Icon.vue';
import { mount, VueWrapper } from '@vue/test-utils';
import { beforeEach, describe, expect, test } from 'vitest';

let wrapper: VueWrapper<any, any>;

beforeEach(async () => {
  wrapper = mount(Icon, {
    props: {
      icon: 'my-icon',
    },
  });
});

describe('Icon Component', async () => {
  test('mount component', async () => {
    expect(wrapper.html()).toBeTruthy();
  });

  test('should have icon as text', async () => {
    expect(wrapper.attributes('text')).toContain('my-icon');
  });

  test('should update icon ', async () => {
    expect(wrapper.attributes('text')).toContain('my-icon');
    await wrapper.setProps({ icon: 'updated-icon' });
    expect(wrapper.attributes('text')).toContain('updated-icon');
  });
});
Enter fullscreen mode Exit fullscreen mode

We already have our first test. Let's add the script to launch vitest in our package.json file.

"scripts": {
  "test": "vitest"
},
Enter fullscreen mode Exit fullscreen mode

We are ready to launch the tests, now you just have to launch the tests and you should have 3 tests passing.

npm run test
Enter fullscreen mode Exit fullscreen mode

And that's it! We only had to make a couple of mocks and define the NativeScript views as customElemts.

Here I leave a repository with a base project ready to launch the tests with vitest: https://github.com/vallemar/nativescript-vue-vitest

Happy Testing!

Top comments (1)

Collapse
 
selemondev profile image
Selemondev

This is fantastic! Thank you for sharing this amazing article 🔥.