mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-05 18:20:39 -08:00
test: unit cover adaptor subwiki routing
This commit is contained in:
parent
a90ccdf44e
commit
8dfdfeb412
3 changed files with 425 additions and 5 deletions
|
|
@ -857,7 +857,6 @@ ${tiddler.content}
|
|||
fileSystemPathFilterEnable: Boolean(options.fileSystemPathFilter),
|
||||
fileSystemPathFilter: options.fileSystemPathFilter ?? null,
|
||||
tagNames: [tagName],
|
||||
tagName: tagName,
|
||||
userName: '',
|
||||
order: 1,
|
||||
port: 5213,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const workspacesSubject = new BehaviorSubject([
|
|||
mainWikiID: 'workspace-1',
|
||||
mainWikiToLink: '/path/to/wiki1',
|
||||
port: 5213,
|
||||
tagName: 'WorkNotes',
|
||||
tagNames: ['WorkNotes'],
|
||||
metadata: { badgeCount: 5 },
|
||||
},
|
||||
// Built-in page workspaces generated from pageTypes
|
||||
|
|
|
|||
|
|
@ -37,6 +37,13 @@ global.$tw = {
|
|||
files: {} as Record<string, IFileInfo>,
|
||||
},
|
||||
utils: mockUtils,
|
||||
wiki: {
|
||||
filterTiddlers: vi.fn(() => []),
|
||||
makeTiddlerIterator: vi.fn((titles) => titles),
|
||||
},
|
||||
rootWidget: {
|
||||
makeFakeWidgetWithVariables: vi.fn(() => ({})),
|
||||
},
|
||||
};
|
||||
|
||||
describe('FileSystemAdaptor - Routing Logic', () => {
|
||||
|
|
@ -275,7 +282,7 @@ describe('FileSystemAdaptor - Routing Logic', () => {
|
|||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['SubWikiTag', 'OtherTag'] },
|
||||
} as Tiddler;
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
|
|
@ -319,7 +326,7 @@ describe('FileSystemAdaptor - Routing Logic', () => {
|
|||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['Tag1', 'Tag2'] },
|
||||
} as Tiddler;
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
|
|
@ -378,7 +385,7 @@ describe('FileSystemAdaptor - Routing Logic', () => {
|
|||
// Tiddler with unmatched tags
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['UnmatchedTag'] },
|
||||
} as Tiddler;
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
|
|
@ -509,4 +516,418 @@ describe('FileSystemAdaptor - Routing Logic', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTiddlerFileInfo - Tag Tree Routing (includeTagTree)', () => {
|
||||
beforeEach(async () => {
|
||||
vi.mocked(workspace.get).mockResolvedValue(
|
||||
{
|
||||
id: 'test-workspace',
|
||||
name: 'Test Workspace',
|
||||
wikiFolderLocation: '/test/wiki',
|
||||
} as Parameters<typeof workspace.get>[0] extends Promise<infer T> ? T : never,
|
||||
);
|
||||
|
||||
// Setup mock wiki with workspace ID
|
||||
mockWiki = {
|
||||
getTiddlerText: vi.fn((title) => {
|
||||
if (title === '$:/info/tidgi/workspaceID') return 'test-workspace';
|
||||
return '';
|
||||
}),
|
||||
tiddlerExists: vi.fn(() => false),
|
||||
addTiddler: vi.fn(),
|
||||
} as unknown as Wiki;
|
||||
});
|
||||
|
||||
it('should route to sub-wiki when tiddler matches tag tree', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-tagtree',
|
||||
name: 'Sub Wiki TagTree',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: ['RootTag'],
|
||||
includeTagTree: true,
|
||||
wikiFolderLocation: '/test/wiki/subwiki/tagtree',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as IWikiWorkspace[]);
|
||||
|
||||
// Mock filterTiddlers to return the tiddler when using in-tagtree-of filter
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn(() => ['ChildTiddler']);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'ChildTiddler', tags: ['ParentTag'] }, // Not directly tagged with RootTag
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use sub-wiki directory because tag tree matching found a match
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/tagtree',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not match tag tree when includeTagTree is disabled', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-notree',
|
||||
name: 'Sub Wiki NoTree',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: ['RootTag'],
|
||||
includeTagTree: false, // Disabled
|
||||
wikiFolderLocation: '/test/wiki/subwiki/notree',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as IWikiWorkspace[]);
|
||||
|
||||
// Even if filterTiddlers would return a match, it shouldn't be called
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn(() => ['ChildTiddler']);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'ChildTiddler', tags: ['ParentTag'] }, // Not directly tagged with RootTag
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use default directory because includeTagTree is disabled
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/tiddlers',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTiddlerFileInfo - Custom Filter Routing (fileSystemPathFilter)', () => {
|
||||
beforeEach(async () => {
|
||||
vi.mocked(workspace.get).mockResolvedValue(
|
||||
{
|
||||
id: 'test-workspace',
|
||||
name: 'Test Workspace',
|
||||
wikiFolderLocation: '/test/wiki',
|
||||
} as Parameters<typeof workspace.get>[0] extends Promise<infer T> ? T : never,
|
||||
);
|
||||
|
||||
mockWiki = {
|
||||
getTiddlerText: vi.fn((title) => {
|
||||
if (title === '$:/info/tidgi/workspaceID') return 'test-workspace';
|
||||
return '';
|
||||
}),
|
||||
tiddlerExists: vi.fn(() => false),
|
||||
addTiddler: vi.fn(),
|
||||
} as unknown as Wiki;
|
||||
});
|
||||
|
||||
it('should route to sub-wiki when tiddler matches custom filter', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-filter',
|
||||
name: 'Sub Wiki Filter',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: ['SomeTag'],
|
||||
fileSystemPathFilterEnable: true,
|
||||
fileSystemPathFilter: '[has[customfield]]',
|
||||
wikiFolderLocation: '/test/wiki/subwiki/filter',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as IWikiWorkspace[]);
|
||||
|
||||
// Mock filterTiddlers to return the tiddler for custom filter
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn((filter) => {
|
||||
if (filter === '[has[customfield]]') {
|
||||
return ['FilterMatchTiddler'];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'FilterMatchTiddler', tags: [] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use sub-wiki directory because custom filter matched
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/filter',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not match custom filter when fileSystemPathFilterEnable is disabled', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-filter-disabled',
|
||||
name: 'Sub Wiki Filter Disabled',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: ['SomeTag'],
|
||||
fileSystemPathFilterEnable: false, // Disabled
|
||||
fileSystemPathFilter: '[has[customfield]]',
|
||||
wikiFolderLocation: '/test/wiki/subwiki/filter-disabled',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as IWikiWorkspace[]);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'FilterMatchTiddler', tags: [] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use default directory because filter is disabled
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/tiddlers',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should support multiple filter lines (any match wins)', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-multifilter',
|
||||
name: 'Sub Wiki MultiFilter',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: [],
|
||||
fileSystemPathFilterEnable: true,
|
||||
fileSystemPathFilter: '[has[field1]]\n[has[field2]]',
|
||||
wikiFolderLocation: '/test/wiki/subwiki/multifilter',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as unknown as IWikiWorkspace[]);
|
||||
|
||||
// Mock filterTiddlers to return match on second filter
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn((filter) => {
|
||||
if (filter === '[has[field2]]') {
|
||||
return ['TiddlerWithField2'];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TiddlerWithField2', tags: [] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use sub-wiki directory because second filter line matched
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/multifilter',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTiddlerFileInfo - Routing Priority', () => {
|
||||
beforeEach(async () => {
|
||||
vi.mocked(workspace.get).mockResolvedValue(
|
||||
{
|
||||
id: 'test-workspace',
|
||||
name: 'Test Workspace',
|
||||
wikiFolderLocation: '/test/wiki',
|
||||
} as Parameters<typeof workspace.get>[0] extends Promise<infer T> ? T : never,
|
||||
);
|
||||
|
||||
mockWiki = {
|
||||
getTiddlerText: vi.fn((title) => {
|
||||
if (title === '$:/info/tidgi/workspaceID') return 'test-workspace';
|
||||
return '';
|
||||
}),
|
||||
tiddlerExists: vi.fn(() => false),
|
||||
addTiddler: vi.fn(),
|
||||
} as unknown as Wiki;
|
||||
});
|
||||
|
||||
it('should prioritize direct tag match over tag tree match', async () => {
|
||||
const subWiki1 = {
|
||||
id: 'sub-wiki-direct',
|
||||
name: 'Sub Wiki Direct Tag',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
order: 0,
|
||||
tagNames: ['DirectTag'],
|
||||
includeTagTree: false,
|
||||
wikiFolderLocation: '/test/wiki/subwiki/direct',
|
||||
};
|
||||
|
||||
const subWiki2 = {
|
||||
id: 'sub-wiki-tagtree',
|
||||
name: 'Sub Wiki TagTree',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
order: 1,
|
||||
tagNames: ['RootTag'],
|
||||
includeTagTree: true,
|
||||
wikiFolderLocation: '/test/wiki/subwiki/tagtree',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki1, subWiki2] as IWikiWorkspace[]);
|
||||
|
||||
// Mock tag tree matching to return the tiddler
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn(() => ['TestTiddler']);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
// Tiddler has both DirectTag (direct match) and would match RootTag via tag tree
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['DirectTag'] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use direct tag sub-wiki (first match wins, and direct tag check happens before tag tree)
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/direct',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should prioritize tag match over custom filter match within same workspace', async () => {
|
||||
const subWiki = {
|
||||
id: 'sub-wiki-both',
|
||||
name: 'Sub Wiki Both',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
tagNames: ['MatchTag'],
|
||||
fileSystemPathFilterEnable: true,
|
||||
fileSystemPathFilter: '[has[customfield]]',
|
||||
wikiFolderLocation: '/test/wiki/subwiki/both',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki] as IWikiWorkspace[]);
|
||||
|
||||
// Reset filterTiddlers mock
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
global.$tw.wiki.filterTiddlers = vi.fn(() => []);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
// Tiddler has the matching tag
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['MatchTag'] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should match via tag (filter shouldn't even be checked for this tiddler)
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/both',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should check workspaces in order and use first match', async () => {
|
||||
const subWiki1 = {
|
||||
id: 'sub-wiki-first',
|
||||
name: 'Sub Wiki First',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
order: 0,
|
||||
tagNames: ['SharedTag'],
|
||||
wikiFolderLocation: '/test/wiki/subwiki/first',
|
||||
};
|
||||
|
||||
const subWiki2 = {
|
||||
id: 'sub-wiki-second',
|
||||
name: 'Sub Wiki Second',
|
||||
isSubWiki: true,
|
||||
mainWikiID: 'test-workspace',
|
||||
order: 1,
|
||||
tagNames: ['SharedTag'], // Same tag
|
||||
wikiFolderLocation: '/test/wiki/subwiki/second',
|
||||
};
|
||||
|
||||
vi.mocked(workspace.getWorkspacesAsList).mockResolvedValue([subWiki1, subWiki2] as IWikiWorkspace[]);
|
||||
|
||||
adaptor = new FileSystemAdaptor({
|
||||
wiki: mockWiki,
|
||||
// @ts-expect-error - TiddlyWiki global
|
||||
boot: global.$tw.boot,
|
||||
});
|
||||
|
||||
await adaptor['updateSubWikisCache']();
|
||||
|
||||
const tiddler: Tiddler = {
|
||||
fields: { title: 'TestTiddler', tags: ['SharedTag'] },
|
||||
} as unknown as Tiddler;
|
||||
|
||||
await adaptor.getTiddlerFileInfo(tiddler);
|
||||
|
||||
// Should use first sub-wiki (order 0)
|
||||
expect(mockUtils.generateTiddlerFileInfo).toHaveBeenCalledWith(
|
||||
tiddler,
|
||||
expect.objectContaining({
|
||||
directory: '/test/wiki/subwiki/first',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue