Add testing frameworks

This commit is contained in:
Djuri Baars 2023-11-23 02:04:20 +01:00
parent fd492c416c
commit a9c12c2e9f
11 changed files with 1315 additions and 189 deletions

View file

@ -63,6 +63,18 @@ jobs:
run: yarn && yarn postinstall
- name: Run linter
run: yarn lint
- name: Run vitest tests
run: yarn vitest run --reporter=json
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
- name: Build WebUI
run: yarn build

View file

@ -10,19 +10,26 @@
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"postinstall": "patch-package"
"postinstall": "patch-package",
"test": "npm run test:integration && npm run test:unit",
"test:integration": "playwright test",
"test:unit": "vitest"
},
"devDependencies": {
"@rollup/plugin-json": "^6.0.1",
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/adapter-static": "^2.0.3",
"@sveltejs/kit": "^1.27.4",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@testing-library/svelte": "^4.0.5",
"@types/swagger-ui": "^3.52.4",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitest/ui": "^0.34.6",
"eslint": "^8.28.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte": "^2.30.0",
"jsdom": "^22.1.0",
"prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.0.0",
"sass": "^1.69.5",
@ -31,13 +38,16 @@
"svelte-preprocess": "^5.1.1",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
"vite": "^5.0.2",
"vitest": "^0.34.6",
"vitest-dom": "^0.1.1"
},
"type": "module",
"dependencies": {
"@fontsource/antonio": "^5.0.17",
"@fontsource/oswald": "^5.0.17",
"@fontsource/ubuntu": "^5.0.8",
"@playwright/test": "^1.40.0",
"bootstrap": "^5.3.2",
"patch-package": "^8.0.0",
"svelte-i18n": "^4.0.0",

16
playwright.config.ts Normal file
View file

@ -0,0 +1,16 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
use: {
locale: 'en-GB',
timezoneId: 'Europe/Amsterdam'
},
webServer: {
command: 'npm run build && npm run preview',
port: 4173
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
export default config;

View file

@ -12,6 +12,6 @@ init({
initialLocale: browser
? browser && localStorage.getItem('locale')
? localStorage.getItem('locale')
: window.navigator.language
: window.navigator.language.slice(0, 2)
: defaultLocale
});

View file

@ -13,7 +13,7 @@
} from 'sveltestrap';
import { page } from '$app/stores';
import { locale, locales } from 'svelte-i18n';
import { locale, locales, isLoading } from 'svelte-i18n';
export const setLocale = (lang: string) => () => {
locale.set(lang);
@ -39,19 +39,15 @@
}
};
export const getLanguageName = (languageCode: string): string | null => {
const languageNames: { [key: string]: { [key: string]: string } } = {
en: { en: 'English', nl: 'English', es: 'English' },
nl: { en: 'Nederlands', nl: 'Nederlands', es: 'Neerlandés' },
es: { en: 'Español', nl: 'Spaans', es: 'Español' }
};
let languageNames = {};
const lowercaseCode = languageCode.toLowerCase();
locale.subscribe(() => {
let newLanguageNames = new Intl.DisplayNames([$locale], { type: 'language' });
return Object.prototype.hasOwnProperty.call(languageNames, lowercaseCode)
? languageNames[lowercaseCode][lowercaseCode]
: null;
};
for (let l: string of $locales) {
languageNames[l] = newLanguageNames.of(l);
}
});
</script>
<Navbar expand="md">
@ -65,16 +61,18 @@
<NavLink href="/api" active={$page.url.pathname === '/api'}>API</NavLink>
</NavItem>
</Nav>
{#if !$isLoading}
<Dropdown inNavbar>
<DropdownToggle nav caret>{getFlagEmoji($locale)} {getLanguageName($locale)}</DropdownToggle>
<DropdownToggle nav caret>{getFlagEmoji($locale)} {languageNames[$locale]}</DropdownToggle>
<DropdownMenu end>
{#each $locales as locale}
<DropdownItem on:click={setLocale(locale)}
>{getFlagEmoji(locale)} {getLanguageName(locale)}</DropdownItem
>{getFlagEmoji(locale)} {languageNames[locale]}</DropdownItem
>
{/each}
</DropdownMenu>
</Dropdown>
{/if}
</Collapse>
</Navbar>

View file

@ -0,0 +1,30 @@
import { writable } from 'svelte/store';
import Control from './Control.svelte';
import { render } from '@testing-library/svelte';
import { describe, test, expect, beforeEach } from 'vitest';
import { addMessages, init, locale } from 'svelte-i18n';
import '$lib/i18n/index.ts';
import en from '$lib/locales/en.json';
addMessages('en', en);
describe('Control Component', () => {
beforeEach(() => {
init({
fallbackLocale: 'en',
initialLocale: 'en'
});
locale.set('en');
});
test('should render the component', () => {
const host = document.createElement('div');
document.body.appendChild(host);
const instance = render(Control, {
target: host,
props: { status: writable([]), settings: writable([]) }
});
expect(instance).toBeTruthy();
expect(host.innerHTML).toContain('Control');
});
});

View file

@ -0,0 +1,32 @@
import { writable } from 'svelte/store';
import Settings from './Settings.svelte';
import { render } from '@testing-library/svelte';
import { describe, test, expect, beforeEach } from 'vitest';
import { addMessages, init, locale } from 'svelte-i18n';
import '$lib/i18n/index.ts';
import en from '$lib/locales/en.json';
addMessages('en', en);
describe('Settings Component', () => {
beforeEach(() => {
init({
fallbackLocale: 'en',
initialLocale: 'en'
});
locale.set('en');
});
test('should render the component', () => {
locale.set('en');
const host = document.createElement('div');
document.body.appendChild(host);
const instance = render(Settings, {
target: host,
props: { settings: writable([]) }
});
expect(instance).toBeTruthy();
expect(host.innerHTML).toContain('Settings');
});
});

30
src/routes/Status.spec.ts Normal file
View file

@ -0,0 +1,30 @@
import { writable } from 'svelte/store';
import Status from './Status.svelte';
import { render } from '@testing-library/svelte';
import { describe, test, expect, beforeEach } from 'vitest';
import { locale, init, addMessages } from 'svelte-i18n';
import '$lib/i18n/index.ts';
import en from '$lib/locales/en.json';
addMessages('en', en);
describe('Status Component', () => {
beforeEach(() => {
init({
fallbackLocale: 'en',
initialLocale: 'en'
});
locale.set('en');
});
test('should render the component', () => {
const host = document.createElement('div');
document.body.appendChild(host);
const instance = render(Status, {
target: host,
props: { status: writable([]), settings: writable([]) }
});
expect(instance).toBeTruthy();
expect(host.innerHTML).toContain('Status');
});
});

21
tests/test.ts Normal file
View file

@ -0,0 +1,21 @@
import { expect, test } from '@playwright/test';
test('index page has expected status', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Status' })).toBeVisible();
});
test('index page has expected settings', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible();
});
test('index page has expected control', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('heading', { name: 'Control' })).toBeVisible();
});
test('api page has expected load button', async ({ page }) => {
await page.goto('/api');
await expect(page.getByRole('button', { name: 'Load' })).toBeVisible();
});

View file

@ -1,5 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
//import { defineConfig } from 'vite';
import { defineConfig } from 'vitest/config';
import * as fs from 'fs';
import * as path from 'path';
@ -68,5 +69,10 @@ export default defineConfig({
assetFileNames: '[name][extname]'
}
}
},
test: {
include: ['src/**/*.{test,spec}.{js,ts}'],
globals: true,
environment: 'jsdom'
}
});

1313
yarn.lock

File diff suppressed because it is too large Load diff