110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { contextualLaunchUrl, loadCatalogue } from './catalogue';
|
|
import { catalogue, catalogueFetch } from './test/fixtures';
|
|
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
describe('catalogue loading', () => {
|
|
it('loads and resolves internal apps using the shared contract', async () => {
|
|
vi.stubGlobal('fetch', vi.fn(catalogueFetch()));
|
|
const loaded = await loadCatalogue('/toolbox.catalog.json');
|
|
expect(loaded.catalogue.name).toBe('add·ideas Toolbox');
|
|
expect(loaded.homeUrl).toBe('http://localhost:3000/');
|
|
expect(loaded.apps).toHaveLength(8);
|
|
expect(loaded.apps[0]).toMatchObject({
|
|
id: 'de.add-ideas.pdf-tools',
|
|
name: 'PDF Workbench',
|
|
entryUrl: 'http://localhost:3000/apps/pdf/',
|
|
sourceUrl: 'https://git.add-ideas.de/lotobo/pdf-tools',
|
|
});
|
|
});
|
|
|
|
it('keeps valid apps available when another manifest fails', async () => {
|
|
const twoApps = {
|
|
...catalogue,
|
|
apps: [
|
|
...catalogue.apps,
|
|
{ manifest: './apps/missing/toolbox-app.json', enabled: true },
|
|
],
|
|
};
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn(
|
|
catalogueFetch({
|
|
'/toolbox.catalog.json': Response.json(twoApps),
|
|
})
|
|
)
|
|
);
|
|
const loaded = await loadCatalogue('/toolbox.catalog.json');
|
|
expect(loaded.apps.map((app) => app.id)).toEqual([
|
|
'de.add-ideas.pdf-tools',
|
|
'de.add-ideas.xslt-tools',
|
|
'de.add-ideas.onenote-tools',
|
|
'de.add-ideas.svg-tools',
|
|
'de.add-ideas.auth-tools',
|
|
'de.add-ideas.sudoku-tools',
|
|
'de.add-ideas.colour-tools',
|
|
'de.add-ideas.office-tools',
|
|
]);
|
|
expect(loaded.unavailable).toHaveLength(1);
|
|
expect(loaded.unavailable[0]?.reason).toMatch(/HTTP 404/);
|
|
});
|
|
|
|
it('rejects cross-origin manifest references', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn(
|
|
catalogueFetch({
|
|
'/toolbox.catalog.json': Response.json({
|
|
...catalogue,
|
|
apps: [
|
|
{
|
|
manifest: 'https://example.invalid/toolbox-app.json',
|
|
enabled: true,
|
|
},
|
|
],
|
|
}),
|
|
})
|
|
)
|
|
);
|
|
await expect(loadCatalogue('/toolbox.catalog.json')).rejects.toThrow(
|
|
/share the page origin/i
|
|
);
|
|
});
|
|
|
|
it('rejects a cross-origin catalogue home', async () => {
|
|
vi.stubGlobal(
|
|
'fetch',
|
|
vi.fn(
|
|
catalogueFetch({
|
|
'/toolbox.catalog.json': Response.json({
|
|
...catalogue,
|
|
home: 'https://example.invalid/',
|
|
}),
|
|
})
|
|
)
|
|
);
|
|
await expect(loadCatalogue('/toolbox.catalog.json')).rejects.toThrow(
|
|
/share the page origin/i
|
|
);
|
|
});
|
|
|
|
it('adds catalogue context only to same-origin launch links', () => {
|
|
const contextual = new URL(
|
|
contextualLaunchUrl(
|
|
'http://localhost:3000/apps/pdf/',
|
|
'http://localhost:3000/toolbox.catalog.json'
|
|
)
|
|
);
|
|
expect(contextual.searchParams.get('toolbox')).toBe(
|
|
'http://localhost:3000/toolbox.catalog.json'
|
|
);
|
|
expect(
|
|
contextualLaunchUrl(
|
|
'https://example.com/tool',
|
|
'http://localhost:3000/toolbox.catalog.json'
|
|
)
|
|
).toBe('https://example.com/tool');
|
|
});
|
|
});
|