Skip to content

Commit

Permalink
test: add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mtdvlpr committed Dec 27, 2024
1 parent 58b4676 commit 3885381
Show file tree
Hide file tree
Showing 23 changed files with 1,721 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
yarn quasar prepare
yarn lint
yarn type-check
- name: Run tests
run: yarn test:unit:ci
- name: Install Apple certificate
if: runner.os == 'macOS'
env:
Expand Down
7 changes: 5 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ yarn lint
# Check for type errors
yarn type-check

# Run tests
yarn test
# Run unit tests with a listener
yarn test:unit

# Run unit tests with UI
yarn test:unit:ui
```

### Build Tools
Expand Down
3 changes: 3 additions & 0 deletions __mocks__/fs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { fs } = require('memfs');
module.exports = fs;
3 changes: 3 additions & 0 deletions __mocks__/fs/promises.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { fs } = require('memfs');
module.exports = fs.promises;
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"format": "prettier \"**/*\" --ignore-unknown --write",
"lint": "eslint -c ./eslint.config.js './**/*.{js,ts,cjs,mjs,mts,vue}'",
"type-check": "vue-tsc --noEmit -p tsconfig.json",
"test": "echo \"No test specified\" && exit 0"
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"test:unit:ui": "vitest --ui",
"test:unit": "vitest",
"test:unit:ci": "vitest run"
},
"dependencies": {
"@formkit/drag-and-drop": "^0.1.6",
Expand Down Expand Up @@ -75,6 +78,8 @@
"@intlify/unplugin-vue-i18n": "^6.0.2",
"@quasar/app-vite": "^2.0.4",
"@quasar/icongenie": "^4.0.0",
"@quasar/quasar-app-extension-testing-unit-vitest": "^1.1.0",
"@quasar/vite-plugin": "^1.8.1",
"@rollup/plugin-inject": "^5.0.5",
"@sentry/esbuild-plugin": "^2.22.7",
"@sentry/vite-plugin": "^2.22.7",
Expand All @@ -87,8 +92,10 @@
"@types/node": "^20.17.10",
"@types/pretty-bytes": "^5.2.0",
"@types/sanitize-html": "^2.13.0",
"@vitest/ui": "^2.0.5",
"@vue/eslint-config-prettier": "^10.1.0",
"@vue/eslint-config-typescript": "^14.2.0",
"@vue/test-utils": "^2.4.4",
"autoprefixer": "^10.4.20",
"electron": "^33.2.1",
"electron-builder": "^25.1.8",
Expand All @@ -98,10 +105,13 @@
"globals": "^15.14.0",
"husky": "^9.1.7",
"lint-staged": "^15.2.11",
"memfs": "^4.15.1",
"msw": "^2.7.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"typescript": "~5.6.3",
"vitepress": "^1.5.0",
"vitest": "^2.0.5",
"vue-tsc": "^2.2.0"
},
"browserslist": [
Expand Down
5 changes: 5 additions & 0 deletions quasar.extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"@quasar/testing-unit-vitest": {
"options": ["ui"]
}
}
47 changes: 47 additions & 0 deletions src/components/demo-vitest/ExampleComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div>
<p>{{ title }}</p>
<q-list>
<q-item v-for="todo in todos" :key="todo.id" clickable @click="increment">
{{ todo.id }} - {{ todo.content }}
</q-item>
</q-list>

<p>Count: {{ todoCount }} / {{ meta.totalCount }}</p>
<p>Active: {{ active ? 'yes' : 'no' }}</p>
<p>Clicks on todos: {{ clickCount }}</p>
</div>
</template>

<script lang="ts" setup>
import { computed, ref } from 'vue';
interface Meta {
totalCount: number;
}
interface Todo {
content: string;
id: number;
}
const props = withDefaults(
defineProps<{
active?: boolean;
meta: Meta;
title: string;
todos?: Todo[];
}>(),
{
todos: () => [],
},
);
const clickCount = ref(0);
function increment() {
clickCount.value += 1;
return clickCount.value;
}
const todoCount = computed(() => props.todos.length);
</script>
12 changes: 12 additions & 0 deletions src/components/demo-vitest/LayoutComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<template>
<q-header>
<q-toolbar>
<q-toolbar-title>Header</q-toolbar-title>
</q-toolbar>
</q-header>
<q-footer>
<q-toolbar>
<q-toolbar-title>Footer</q-toolbar-title>
</q-toolbar>
</q-footer>
</template>
11 changes: 11 additions & 0 deletions src/components/demo-vitest/NotifyComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<q-btn @click="onClick"> Click me! </q-btn>
</template>

<script lang="ts" setup>
import { Notify } from 'quasar';
function onClick() {
Notify.create('Hello there!');
}
</script>
39 changes: 39 additions & 0 deletions src/components/demo-vitest/__tests__/ExampleComponent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { mount } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';

import ExampleComponent from './../ExampleComponent.vue';

installQuasarPlugin();

describe('example Component', () => {
it('should mount component with todos', async () => {
const wrapper = mount(ExampleComponent, {
props: {
meta: {
totalCount: 4,
},
title: 'Hello',
todos: [
{ content: 'Hallo', id: 1 },
{ content: 'Hoi', id: 2 },
],
},
});
expect(wrapper.vm.clickCount).toBe(0);

Check failure on line 23 in src/components/demo-vitest/__tests__/ExampleComponent.test.ts

View workflow job for this annotation

GitHub Actions / build / build (ubuntu-latest)

Property 'clickCount' does not exist on type 'ComponentPublicInstance<NonNullable<{ readonly active?: boolean | undefined; readonly meta: Meta; readonly title: string; readonly todos?: Todo[] | undefined; } & VNodeProps & AllowedComponentProps & ComponentCustomProps>, { ...; } & ... 6 more ... & Omit<...>>'.
await wrapper.find('.q-item').trigger('click');
expect(wrapper.vm.clickCount).toBe(1);

Check failure on line 25 in src/components/demo-vitest/__tests__/ExampleComponent.test.ts

View workflow job for this annotation

GitHub Actions / build / build (ubuntu-latest)

Property 'clickCount' does not exist on type 'ComponentPublicInstance<NonNullable<{ readonly active?: boolean | undefined; readonly meta: Meta; readonly title: string; readonly todos?: Todo[] | undefined; } & VNodeProps & AllowedComponentProps & ComponentCustomProps>, { ...; } & ... 6 more ... & Omit<...>>'.
});

it('should mount component without todos', () => {
const wrapper = mount(ExampleComponent, {
props: {
meta: {
totalCount: 4,
},
title: 'Hello',
},
});
expect(wrapper.findAll('.q-item')).toHaveLength(0);
});
});
15 changes: 15 additions & 0 deletions src/components/demo-vitest/__tests__/LayoutComponent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { mount } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';

import LayoutComponent from './../LayoutComponent.vue';

installQuasarPlugin();

describe('layout example', () => {
it('should mount component properly', () => {
const wrapper = mount(LayoutComponent);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
expect(wrapper.exists()).to.be.true;
});
});
20 changes: 20 additions & 0 deletions src/components/demo-vitest/__tests__/NotifyComponent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-vitest';
import { mount } from '@vue/test-utils';
import { Notify } from 'quasar';
import { describe, expect, it, vi } from 'vitest';

import NotifyComponent from './../NotifyComponent.vue';

installQuasarPlugin({ plugins: { Notify } });

describe('notify example', () => {
it('should call notify on click', async () => {
expect(NotifyComponent).toBeTruthy();

const wrapper = mount(NotifyComponent);
const spy = vi.spyOn(Notify, 'create');
expect(spy).not.toHaveBeenCalled();
await wrapper.trigger('click');
expect(spy).toHaveBeenCalled();
});
});
35 changes: 19 additions & 16 deletions src/types/github.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,28 @@ export interface Author {
subscriptions_url: string;
type: string;
url: string;
user_view_type: string;
}

export interface Release {
assets: Asset[];
assets_url: string;
author: Author;
body: null | string;
created_at: string;
discussion_url: string;
draft: boolean;
html_url: string;
id: number;
name: null | string;
node_id: string;
assets?: Asset[];
assets_url?: string;
author?: Author;
body?: null | string;
created_at?: string;
discussion_url?: string;
draft?: boolean;
html_url?: string;
id?: number;
mentions_count?: number;
name?: null | string;
node_id?: string;
prerelease: boolean;
published_at: string;
published_at?: string;
tag_name: string;
tarball_url: null | string;
upload_url: string;
url: string;
zipball_url: null | string;
tarball_url?: null | string;
target_commitish?: string;
upload_url?: string;
url?: string;
zipball_url?: null | string;
}
38 changes: 38 additions & 0 deletions src/utils/__tests__/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { jwYeartext } from 'app/test/vitest/mocks/jw';
import { describe, expect, it } from 'vitest';

import {
fetchAnnouncements,
fetchJwLanguages,
fetchLatestVersion,
fetchYeartext,
} from '../api';

describe('fetchJwLanguages', () => {
it('should fetch the jw languages', async () => {
const languages = await fetchJwLanguages('jw.org');
expect(languages?.length).toBe(2);
});
});

describe('fetchYeartext', () => {
it('should fetch the yeartext', async () => {
const yeartext = await fetchYeartext('E', 'jw.org');
expect(yeartext.wtlocale).toBe('E');
expect(yeartext.yeartext).toBe(jwYeartext.content);
});
});

describe('fetchAnnouncements', () => {
it('should fetch the announcements', async () => {
const announcements = await fetchAnnouncements();
expect(announcements.length).toBe(3);
});
});

describe('fetchLatestVersion', () => {
it('should fetch the latest version', async () => {
const version = await fetchLatestVersion();
expect(version).toBe('1.2.3');
});
});
Loading

0 comments on commit 3885381

Please sign in to comment.