mirror of
https://github.com/firstsun-dev/git-files-sync.git
synced 2026-07-22 17:20:30 +00:00
fix(build): resolve dependencies, fix Vitest 4 mocking, and handle file existence
This commit is contained in:
parent
8ea6edf51e
commit
6161bd75cd
5 changed files with 1440 additions and 1327 deletions
2710
package-lock.json
generated
2710
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,8 +17,8 @@
|
|||
"license": "0-BSD",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.30.1",
|
||||
"@eslint/json": "^1.2.0",
|
||||
"@types/node": "^16.11.6",
|
||||
"@eslint/json": "0.14.0",
|
||||
"@types/node": "^24.0.0",
|
||||
"@vitest/ui": "^4.1.2",
|
||||
"esbuild": "0.25.5",
|
||||
"eslint-plugin-obsidianmd": "0.1.9",
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
"tslib": "2.4.0",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "8.35.1",
|
||||
"vitest": "^1.6.1"
|
||||
"vitest": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"obsidian": "latest"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ export class SyncManager {
|
|||
}
|
||||
|
||||
async pushFile(file: TFile) {
|
||||
if (!this.app.vault.getFileByPath(file.path)) {
|
||||
new Notice(`File ${file.name} no longer exists in vault.`);
|
||||
return;
|
||||
}
|
||||
const content = await this.app.vault.read(file);
|
||||
try {
|
||||
// Conflict detection
|
||||
|
|
@ -62,6 +66,10 @@ export class SyncManager {
|
|||
}
|
||||
|
||||
async pullFile(file: TFile) {
|
||||
if (!this.app.vault.getFileByPath(file.path)) {
|
||||
new Notice(`File ${file.name} no longer exists in vault.`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const remote = await this.gitlab.getFile(file.path, this.settings.branch);
|
||||
const localContent = await this.app.vault.read(file);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const mockApp = {
|
|||
vault: {
|
||||
read: vi.fn(),
|
||||
modify: vi.fn(),
|
||||
getFileByPath: vi.fn(),
|
||||
}
|
||||
} as unknown as App;
|
||||
|
||||
|
|
@ -36,6 +37,8 @@ describe('SyncManager', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Default: file exists in vault
|
||||
vi.spyOn(mockApp.vault, 'getFileByPath').mockReturnValue(new TFile());
|
||||
manager = new SyncManager(mockApp, mockGitLab, mockSettings);
|
||||
});
|
||||
|
||||
|
|
@ -90,7 +93,7 @@ describe('SyncManager', () => {
|
|||
|
||||
// Capture the callback passed to the modal
|
||||
let callback: (choice: 'local' | 'remote') => void = () => {};
|
||||
modalMock.mockImplementation((app, file, local, remote, onChoose) => {
|
||||
modalMock.mockImplementation(function(app, file, local, remote, onChoose) {
|
||||
callback = onChoose;
|
||||
return {
|
||||
open: vi.fn(),
|
||||
|
|
@ -130,7 +133,7 @@ describe('SyncManager', () => {
|
|||
const modalMock = vi.mocked(SyncConflictModal);
|
||||
|
||||
let callback: (choice: 'local' | 'remote') => void = () => {};
|
||||
modalMock.mockImplementation((app, file, local, remote, onChoose) => {
|
||||
modalMock.mockImplementation(function(app, file, local, remote, onChoose) {
|
||||
callback = onChoose;
|
||||
return {
|
||||
open: vi.fn(),
|
||||
|
|
@ -190,4 +193,35 @@ describe('SyncManager', () => {
|
|||
expect(getSpy).toHaveBeenCalled();
|
||||
expect(mockSettings.syncMetadata['test.md']?.lastSyncedSha).toBe('sha');
|
||||
});
|
||||
|
||||
it('should handle file not existing in vault', async () => {
|
||||
const mockFile = Object.assign(new TFile(), { path: 'non-existent.md', name: 'non-existent.md' });
|
||||
vi.spyOn(mockApp.vault, 'getFileByPath').mockReturnValue(null);
|
||||
|
||||
await manager.pushFile(mockFile);
|
||||
|
||||
expect(mockGitLab.getFile).not.toHaveBeenCalled();
|
||||
expect(mockGitLab.pushFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add new file to repo when it exists locally but not on remote', async () => {
|
||||
const mockFile = Object.assign(new TFile(), { path: 'new.md', name: 'new.md' });
|
||||
mockSettings.syncMetadata = {};
|
||||
|
||||
vi.spyOn(mockApp.vault, 'read').mockResolvedValue('new local content');
|
||||
// Remote returns 404/empty
|
||||
vi.spyOn(mockGitLab, 'getFile').mockResolvedValueOnce({ content: '', sha: '' });
|
||||
vi.spyOn(mockGitLab, 'pushFile').mockResolvedValue('new.md');
|
||||
vi.spyOn(mockGitLab, 'getFile').mockResolvedValue({ content: 'new local content', sha: 'new-sha' });
|
||||
|
||||
await manager.pushFile(mockFile);
|
||||
|
||||
expect(mockGitLab.pushFile).toHaveBeenCalledWith(
|
||||
'new.md',
|
||||
'new local content',
|
||||
'main',
|
||||
expect.stringContaining('Update new.md')
|
||||
);
|
||||
expect(mockSettings.syncMetadata['new.md']?.lastSyncedSha).toBe('new-sha');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ export const Setting = class {
|
|||
addToggle(_cb: unknown) { return this; }
|
||||
addButton(_cb: unknown) { return this; }
|
||||
};
|
||||
export const Notice = vi.fn().mockImplementation((message: string) => ({}));
|
||||
export const Notice = class {
|
||||
constructor(message: string) {}
|
||||
};
|
||||
export const Modal = class {
|
||||
constructor(_app: unknown) {}
|
||||
open() {}
|
||||
|
|
@ -43,6 +45,7 @@ export const App = class {
|
|||
vault = {
|
||||
read: vi.fn(),
|
||||
modify: vi.fn(),
|
||||
getFileByPath: vi.fn(),
|
||||
on: vi.fn(),
|
||||
adapter: {
|
||||
getBasePath: vi.fn().mockReturnValue('/mock/path'),
|
||||
|
|
|
|||
Loading…
Reference in a new issue