mirror of
https://github.com/koloml/furbooru-tagging-assistant.git
synced 2025-12-23 23:02:58 +00:00
Merge pull request #96 from koloml/feature/vitest
Added Vitest for testing the codebase
This commit is contained in:
32
.github/workflows/build-and-tests.yml
vendored
Normal file
32
.github/workflows/build-and-tests.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Testing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- 'release/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- 'release/**'
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
name: 'Run Unit Tests'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Building the extension
|
||||
run: npm run build
|
||||
|
||||
- name: Running unit tests
|
||||
run: npm run test
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,10 +2,11 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/coverage
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
1853
package-lock.json
generated
1853
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,9 @@
|
||||
"build:popup": "vite build",
|
||||
"build:extension": "node build-extension.js",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"test": "vitest run --coverage",
|
||||
"test:watch": "vitest watch --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^4.0.0",
|
||||
@@ -15,12 +17,15 @@
|
||||
"@sveltejs/kit": "^2.17.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@types/chrome": "^0.0.304",
|
||||
"@vitest/coverage-v8": "^3.0.6",
|
||||
"cheerio": "^1.0.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"sass": "^1.85.0",
|
||||
"svelte": "^5.20.1",
|
||||
"svelte-check": "^4.1.4",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.1.0"
|
||||
"vite": "^6.1.0",
|
||||
"vitest": "^3.0.6"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -19,6 +19,7 @@ const config = {
|
||||
"$styles": "./src/styles",
|
||||
"$stores": "./src/stores",
|
||||
"$entities": "./src/lib/extension/entities",
|
||||
"$tests": "./tests"
|
||||
},
|
||||
typescript: {
|
||||
config: config => {
|
||||
|
||||
40
tests/lib/browser/StorageHelper.spec.ts
Normal file
40
tests/lib/browser/StorageHelper.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import ChromeStorageArea from "$tests/mocks/ChromeStorageArea";
|
||||
import StorageHelper from "$lib/browser/StorageHelper";
|
||||
import { expect } from "vitest";
|
||||
|
||||
describe('StorageHelper', () => {
|
||||
let storageAreaMock: ChromeStorageArea;
|
||||
let storageHelper: StorageHelper;
|
||||
|
||||
beforeEach(() => {
|
||||
storageAreaMock = new ChromeStorageArea();
|
||||
storageHelper = new StorageHelper(storageAreaMock);
|
||||
});
|
||||
|
||||
it("should return value when data exists", async () => {
|
||||
const key = 'existingKey';
|
||||
const value = 'test value';
|
||||
|
||||
storageAreaMock.insertMockedData({[key]: value});
|
||||
|
||||
expect(await storageHelper.read(key)).toBe(value);
|
||||
});
|
||||
|
||||
it('should return default when data is not present', async () => {
|
||||
const fallbackValue = 'fallback';
|
||||
|
||||
expect(await storageHelper.read('nonexistent', fallbackValue)).toBe(fallbackValue);
|
||||
});
|
||||
|
||||
it('should treat falsy values as existing values', async () => {
|
||||
const falsyValues = [false, '', 0];
|
||||
const key = 'testedKey';
|
||||
const fallbackValue = 'fallback';
|
||||
|
||||
for (let testedValue of falsyValues) {
|
||||
storageAreaMock.insertMockedData({[key]: testedValue});
|
||||
|
||||
expect(await storageHelper.read(key, fallbackValue)).toBe(testedValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
9
tests/mocks/ChromeEvent.ts
Normal file
9
tests/mocks/ChromeEvent.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export default class ChromeEvent<T extends Function> implements chrome.events.Event<T> {
|
||||
addListener = vi.fn();
|
||||
getRules = vi.fn();
|
||||
hasListener = vi.fn();
|
||||
removeRules = vi.fn();
|
||||
addRules = vi.fn();
|
||||
removeListener = vi.fn();
|
||||
hasListeners = vi.fn();
|
||||
}
|
||||
5
tests/mocks/ChromeLocalStorageArea.ts
Normal file
5
tests/mocks/ChromeLocalStorageArea.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import ChromeStorageArea from "$tests/mocks/ChromeStorageArea";
|
||||
|
||||
export class ChromeLocalStorageArea extends ChromeStorageArea implements chrome.storage.LocalStorageArea {
|
||||
QUOTA_BYTES = 100000;
|
||||
}
|
||||
71
tests/mocks/ChromeStorageArea.ts
Normal file
71
tests/mocks/ChromeStorageArea.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import ChromeEvent from "./ChromeEvent";
|
||||
|
||||
type ChangedEventCallback = (changes: chrome.storage.StorageChange) => void
|
||||
|
||||
export default class ChromeStorageArea implements chrome.storage.StorageArea {
|
||||
#mockedData: Record<string, any> = {};
|
||||
|
||||
getBytesInUse = vi.fn();
|
||||
clear = vi.fn((): Promise<void> => {
|
||||
return new Promise(resolve => {
|
||||
this.#mockedData = {};
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
set = vi.fn((...args: any[]): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.#mockedData = Object.assign(this.#mockedData, args[0]);
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
remove = vi.fn((...args: any[]): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const key = args[0];
|
||||
|
||||
if (typeof key === 'string') {
|
||||
delete this.#mockedData[key];
|
||||
resolve();
|
||||
}
|
||||
|
||||
reject(new Error('This behavior is not mocked!'));
|
||||
});
|
||||
});
|
||||
get = vi.fn((...args: any[]) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const key = args[0];
|
||||
|
||||
if (!key) {
|
||||
resolve(this.#mockedData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof key === 'string') {
|
||||
resolve({[key]: this.#mockedData[key]});
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(key)) {
|
||||
resolve(
|
||||
(key as string[]).reduce((entries, key) => {
|
||||
entries[key] = this.#mockedData[key];
|
||||
return entries;
|
||||
}, {} as Record<string, any>)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
reject(new Error('This behavior is not implemented by the mock.'));
|
||||
});
|
||||
});
|
||||
setAccessLevel = vi.fn();
|
||||
onChanged = new ChromeEvent<ChangedEventCallback>();
|
||||
getKeys = vi.fn();
|
||||
|
||||
insertMockedData(data: Record<string, any>) {
|
||||
this.#mockedData = data;
|
||||
}
|
||||
|
||||
get mockedData(): Record<string, any> {
|
||||
return this.#mockedData;
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,9 @@
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": false,
|
||||
"types": [
|
||||
"vitest/globals",
|
||||
"@types/chrome",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {sveltekit} from '@sveltejs/kit/vite';
|
||||
import {defineConfig} from 'vite';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
@@ -9,4 +9,13 @@ export default defineConfig({
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
exclude: ['**/node_modules/**', '.*\\.d\\.ts$', '.*\\.spec\\.ts$'],
|
||||
coverage: {
|
||||
reporter: ['text', 'html'],
|
||||
include: ['src/lib/**/*.{js,ts}'],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user