Hoppa till innehåll

@soleil-se/vitest-sitevision

Paket för att ge stöd för automatisk enhetstestning både vanilla javascript, Svelte komponenter och server side kod som använder Sitevisions API.

Terminal window
npm install @soleil-se/vitest-sitevision --save-dev --include=dev

Plus att alla underavsnitt här genomförs manuellt.

Alternativt använd följande kommando som sätter upp allt åt dig:

Terminal window
npx @soleil-se/run create-test-config

Se mer här om create-test-config

Lägg till följande i .gitignore för att ignorera genererade coverage-rapporter.

# Test #
########
coverage/

Skapa upp konfigurationsfiler för vitest i form av:

  • vitest-setup.js
  • vitest.config.js
vitest-setup.js
import '@testing-library/jest-dom/vitest';
vitest.config.js
import { defineConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { svelteTesting } from '@testing-library/svelte/vite';
export default defineConfig({
plugins: [svelte(), svelteTesting()],
test: {
globals: true,
coverage: {
reporter: ['text', 'html'],
exclude: ['**/vitest-setup.js'],
},
environment: 'jsdom',
setupFiles: ['./vitest-setup.js'],
},
});

Lägg till följande i package.json för att kunna starta skriptet.

package.json
{
"scripts": {
"test": "vitest --coverage"
}
}

För att kunna köra tester för kod som inkluderar anrop till Sitevision API behöver API:et mockas, dvs vi skapar upp funktionerna i Sitevision API som tomma skal så att koden tror den finns tillgänglig på importerna.

För att detta ska bli tillgängligt behöver man i testfiler som använder Sitevision API inkludera följande kodsnutt:

import { vi } from 'vitest';
await vi.hoisted(async () => {
const { initSitevisionMock } = await import('@soleil-se/vitest-sitevision');
initSitevisionMock();
});

vi.hoisted ser till koden körs innan allt annat så att det importerade finns med innan några andra importer görs, dvs innan Sitevision API

importeras, så att dessa kommer dirigeras till de mockade funktionerna.

Skapa testfiler bredvid de filer som du ska testa, med filändelsen .test.js.

Lite dum kod för att exemplifiera i form av en funktion som helt enkelt dubblerar sitt indata:

Double.js
export function double(num) {
return num * 2;
}

Som testas med följande:

Double.test.js
import { describe, expect, test } from 'vitest';
import { double } from './Double';
describe('double', () => {
test('gives correct doubling', () => {
const result = double(2);
expect(result).toBe(4);
});
});

En svelte-komponent/app som visa ett meddelande som ändras till ‘Tryckt’ när knappen klickas på.

App.svelte
<script>
let { message } = $props();
let shownMessage = $state(message);
</script>
<div data-testid="test-text">
<span>{shownMessage}</span>
</div>
<button onclick={() => (shownMessage = 'Tryckt')}>Klicka här</button>

Och dess test

import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import { beforeEach, describe, expect, test } from 'vitest';
import App from './App.svelte';
describe('App.svelte', async () => {
beforeEach(() => {
render(App, { message: 'World' });
});
test('show correct given initial message', () => {
const text = screen.getByTestId('test-text');
expect(text).toHaveTextContent('World');
});
test('include expected button with correct text', () => {
const button = screen.getByRole('button');
expect(button).toHaveTextContent('Klicka här');
});
test('that message is updated when button is clicked', async () => {
const text = screen.getByTestId('test-text');
const button = screen.getByRole('button');
const user = userEvent.setup();
await user.click(button);
expect(text).toHaveTextContent('Tryckt');
});
});

Exempelkod som hämtar ut namnet på konfigurerat metadata som innehåller rubriken för en sida som sedan hämtas ut från aktuell sida tillsamans med konfigurerad rubriknivå.

import portletContextUtil from '@sitevision/api/server/PortletContextUtil';
import properties from '@sitevision/api/server/Properties';
import appData from '@sitevision/api/server/appData';
export function getConfiguration() {
const currPage = portletContextUtil.getCurrentPage();
const headingMetadataName = appData.get('headingMetadata', 'name');
const heading = properties.get(currPage, headingMetadataName);
return {
headingLevel: appData.get('headingLevel'),
heading,
};
}

Testkod

import { vi, expect, describe, test, beforeAll } from 'vitest';
import portletContextUtil from '@sitevision/api/server/PortletContextUtil';
import { getConfiguration } from './Configuration';
const data = {
headingMetadata: { name: 'headingMeta' },
headingLevel: 'h3',
};
await vi.hoisted(async () => {
const { initSitevisionMock } = await import('@soleil-se/vitest-sitevision');
initSitevisionMock();
});
beforeAll(() => {
// Set which data appData will return in the mock
mockData.setData('appData', data);
});
describe('getConfiguration', () => {
test('should return correct configuration', () => {
// Tell what getCurrentPage() should return. Is what Properties.get() will access
portletContextUtil.getCurrentPage.mockReturnValue({ headingMetadata: 'TestHeading' });
const config = getConfiguration();
expect(config).toEqual({
heading: 'TestHeading',
headingLevel: 'h3',
});
});
});

Kör bara följande kommando i repots eller appens root.

Terminal window
npm run test

Om du bara vill köra tester för en viss app eller mapp i kod kan du lägga till sökvägen för den delmängd av test du vill köra.

Terminal window
# Kör bara för appen Breadcrumbs
npm run test -- server_src/webapps/apps/Breadcrumbs

När testkörningen startas kör den först alla test och lägger sig sedan i observationsläge där den kör om test som uppdateras.

Det genereras också en kodtäckningsrapport för vilka delar av koden som testades av enhetstesterna. Denna rapporten genereras i mappen /coverage. Öppna filen index.html i den i en webbläsare för en interaktiv webbsida där man kan se täckningen för respektive källkodsfiler.