refactor: Remove hardcoded values
All checks were successful
Queue Release Build / prepare (push) Successful in 2m28s
Deploy Web Apps / deploy (push) Successful in 7m58s
Queue Release Build / build-linux (push) Successful in 46m59s
Queue Release Build / build-windows (push) Successful in 26m2s
Queue Release Build / finalize (push) Successful in 23s

This commit is contained in:
2026-05-17 18:18:14 +02:00
parent a173299ad3
commit ecb1a4b3a0
10 changed files with 201 additions and 65 deletions

View File

@@ -1,4 +1,5 @@
import { Injector } from '@angular/core';
import { environment } from '../../../../../environments/environment';
import type { TojuPluginManifest } from '../../../../shared-kernel';
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
import { PluginStoreService } from './plugin-store.service';
@@ -6,8 +7,11 @@ import { PluginHostService } from './plugin-host.service';
import { PluginDesktopStateService } from './plugin-desktop-state.service';
import { PluginRequirementService } from './plugin-requirement.service';
import { PluginRegistryService } from './plugin-registry.service';
import { PluginCapabilityService } from './plugin-capability.service';
import type { PluginStoreEntry } from '../../domain/models/plugin-store.models';
const OFFICIAL_PLUGIN_SOURCE_URL = environment.pluginStore.defaultSourceUrls[0];
describe('PluginStoreService', () => {
let fetchMock: ReturnType<typeof vi.fn>;
let registerLocalManifest: ReturnType<typeof vi.fn>;
@@ -36,42 +40,79 @@ describe('PluginStoreService', () => {
});
it('loads plugin entries from source manifests and resolves relative links', async () => {
fetchMock.mockResolvedValueOnce(jsonResponse({
plugins: [
{
author: 'Ada Example',
description: 'Adds better channel tools.',
github: 'https://github.com/example/better-channels',
id: 'example.better-channels',
image: './images/better.png',
install: './better/toju-plugin.json',
readme: './better/README.md',
title: 'Better Channels',
version: '1.2.0'
}
],
title: 'Example Plugins'
}));
mockFetchResponses(fetchMock, {
'https://plugins.example.test/index.json': jsonResponse({
plugins: [
{
author: 'Ada Example',
description: 'Adds better channel tools.',
github: 'https://github.com/example/better-channels',
id: 'example.better-channels',
image: './images/better.png',
install: './better/toju-plugin.json',
readme: './better/README.md',
title: 'Better Channels',
version: '1.2.0'
}
],
title: 'Example Plugins'
})
});
const service = createService(registerLocalManifest, unregister);
await service.addSourceUrl('https://plugins.example.test/index.json#latest');
expect(service.sourceUrls()).toEqual(['https://plugins.example.test/index.json']);
expect(service.sources()[0]?.title).toBe('Example Plugins');
expect(service.availablePlugins()).toEqual([
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'https://plugins.example.test/index.json']);
expect(service.sources().some((source) => source.title === 'Example Plugins')).toBe(true);
expect(service.availablePlugins()).toContainEqual(expect.objectContaining({
author: 'Ada Example',
githubUrl: 'https://github.com/example/better-channels',
id: 'example.better-channels',
imageUrl: 'https://plugins.example.test/images/better.png',
installUrl: 'https://plugins.example.test/better/toju-plugin.json',
readmeUrl: 'https://plugins.example.test/better/README.md',
sourceTitle: 'Example Plugins',
title: 'Better Channels',
version: '1.2.0'
}));
});
it('seeds the official plugin repository for new users', () => {
const service = createService(registerLocalManifest, unregister);
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL]);
expect(fetchMock).toHaveBeenCalledWith(
OFFICIAL_PLUGIN_SOURCE_URL,
expect.objectContaining({
author: 'Ada Example',
githubUrl: 'https://github.com/example/better-channels',
id: 'example.better-channels',
imageUrl: 'https://plugins.example.test/images/better.png',
installUrl: 'https://plugins.example.test/better/toju-plugin.json',
readmeUrl: 'https://plugins.example.test/better/README.md',
sourceTitle: 'Example Plugins',
title: 'Better Channels',
version: '1.2.0'
headers: { Accept: 'application/json' }
})
]);
);
});
it('adds the official plugin repository when loading legacy source lists', () => {
storage.setItem('metoyou_plugin_store', JSON.stringify({
installedPlugins: [],
schemaVersion: 1,
sourceUrls: ['https://plugins.example.test/index.json']
}));
const service = createService(registerLocalManifest, unregister);
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'https://plugins.example.test/index.json']);
});
it('keeps user-removed default sources removed after schema migration', () => {
storage.setItem('metoyou_plugin_store', JSON.stringify({
installedPlugins: [],
schemaVersion: 2,
sourceUrls: ['https://plugins.example.test/index.json']
}));
const service = createService(registerLocalManifest, unregister);
expect(service.sourceUrls()).toEqual(['https://plugins.example.test/index.json']);
});
it('accepts local source manifest paths and resolves relative file links', async () => {
@@ -94,9 +135,10 @@ describe('PluginStoreService', () => {
await service.addSourceUrl('/home/ludde/Desktop/TestPlugin/plugin-source.json');
expect(fetchMock).not.toHaveBeenCalled();
expect(fetchMock).not.toHaveBeenCalledWith('/home/ludde/Desktop/TestPlugin/plugin-source.json', expect.anything());
expect(readFile).toHaveBeenCalledWith('/home/ludde/Desktop/TestPlugin/plugin-source.json');
expect(service.sourceUrls()).toEqual(['file:///home/ludde/Desktop/TestPlugin/plugin-source.json']);
expect(service.sourceUrls()).toEqual([OFFICIAL_PLUGIN_SOURCE_URL, 'file:///home/ludde/Desktop/TestPlugin/plugin-source.json']);
expect(service.availablePlugins()).toEqual([
expect.objectContaining({
id: 'example.local-plugin',
@@ -112,7 +154,9 @@ describe('PluginStoreService', () => {
const manifest = createManifest({ version: '1.0.0' });
const plugin = createStoreEntry({ version: '1.0.0' });
fetchMock.mockResolvedValueOnce(jsonResponse(manifest));
mockFetchResponses(fetchMock, {
[plugin.installUrl ?? '']: jsonResponse(manifest)
});
const service = createService(registerLocalManifest, unregister);
@@ -141,9 +185,10 @@ describe('PluginStoreService', () => {
writeFile: vi.fn(async () => true)
};
fetchMock
.mockResolvedValueOnce(jsonResponse(manifest))
.mockResolvedValueOnce(textResponse('export function activate() {}'));
mockFetchResponses(fetchMock, {
[plugin.bundleUrl ?? '']: textResponse('export function activate() {}'),
[plugin.installUrl ?? '']: jsonResponse(manifest)
});
const service = createService(registerLocalManifest, unregister, electronApi);
@@ -171,7 +216,9 @@ describe('PluginStoreService', () => {
it('loads plugin readmes as markdown text', async () => {
const plugin = createStoreEntry({ readmeUrl: 'https://plugins.example.test/better/README.md' });
fetchMock.mockResolvedValueOnce(textResponse('# Better Channels'));
mockFetchResponses(fetchMock, {
[plugin.readmeUrl ?? '']: textResponse('# Better Channels')
});
const service = createService(registerLocalManifest, unregister);
const readme = await service.loadReadme(plugin);
@@ -185,6 +232,21 @@ describe('PluginStoreService', () => {
});
});
function mockFetchResponses(fetchMock: ReturnType<typeof vi.fn>, responses: Record<string, Response>): void {
fetchMock.mockImplementation(async (url: RequestInfo | URL) => {
const requestUrl = typeof url === 'string'
? url
: url instanceof URL
? url.toString()
: url.url;
return responses[requestUrl]
?? (requestUrl === OFFICIAL_PLUGIN_SOURCE_URL
? jsonResponse({ plugins: [], title: 'Official Toju Plugins' })
: textResponse(''));
});
}
function createService(
registerLocalManifest: ReturnType<typeof vi.fn>,
unregister: ReturnType<typeof vi.fn>,
@@ -220,6 +282,12 @@ function createService(
writeJson: vi.fn(async () => undefined)
}
},
{
provide: PluginCapabilityService,
useValue: {
grantAll: vi.fn()
}
},
{
provide: PluginRegistryService,
useValue: { unregister }