diff --git a/src/virtual-drive.ts b/src/virtual-drive.ts index 57d2dcb3..3b881b24 100644 --- a/src/virtual-drive.ts +++ b/src/virtual-drive.ts @@ -34,8 +34,8 @@ class VirtualDrive { this.logger = createLogger(loggerPath); } - addLoggerPath(logPath: string) { - addon.addLogger({ logPath }); + convertToWindowsTime(jsTime: number) { + return BigInt(jsTime) * 10000n + 116444736000000000n; } convertToWindowsPath(path: string) { @@ -51,11 +51,15 @@ class VirtualDrive { } } + addLoggerPath(logPath: string) { + addon.addLogger({ logPath }); + } + getPlaceholderState(path: string) { return addon.getPlaceholderState({ path: this.fixPath(path) }); } - getPlaceholderWithStatePending(): any { + getPlaceholderWithStatePending() { return addon.getPlaceholderWithStatePending(); } @@ -65,19 +69,15 @@ class VirtualDrive { } } - convertToWindowsTime(jsTime: number): bigint { - return BigInt(jsTime) * 10000n + 116444736000000000n; - } - getFileIdentity(relativePath: string) { return addon.getFileIdentity({ path: this.fixPath(relativePath) }); } - async deleteFileSyncRoot(relativePath: string): Promise { + async deleteFileSyncRoot(relativePath: string) { return addon.deleteFileSyncRoot({ path: this.fixPath(relativePath) }); } - async connectSyncRoot() { + connectSyncRoot() { if (this.callbacks === undefined) { throw new Error("Callbacks are not defined"); } @@ -139,14 +139,6 @@ class VirtualDrive { }); } - private isValidFolderPath(path: string) { - return path.startsWith("/") && path.endsWith("/") && !path.includes("."); - } - - private isValidFilePath(path: string) { - return path.includes("."); - } - async registerSyncRoot( providerName: string, providerVersion: string, @@ -163,9 +155,8 @@ class VirtualDrive { }); } - static unregisterSyncRoot(syncRootPath: string): any { - const result = addon.unregisterSyncRoot({ syncRootPath }); - return result; + static unregisterSyncRoot(syncRootPath: string) { + return addon.unregisterSyncRoot({ syncRootPath }); } watchAndWait( @@ -173,15 +164,10 @@ class VirtualDrive { queueManager: IQueueManager, loggerPath: string ): void { - if (this.callbacks === undefined) { - throw new Error("Callbacks are not defined"); - } - + this.watcher.addon = addon; this.watcher.queueManager = queueManager; - this.watcher.logger = this.logger; - - this.watcher.syncRootPath = path; + this.watcher.syncRootPath = this.syncRootPath; this.watcher.options = { ignored: /(^|[\/\\])\../, persistent: true, @@ -195,8 +181,6 @@ class VirtualDrive { usePolling: true, }; - this.watcher.addon = addon; - this.watcher.watchAndWait(); } @@ -206,7 +190,7 @@ class VirtualDrive { size: number = 0, creationTime: number = Date.now(), lastWriteTime: number = Date.now() - ): void { + ) { const fullPath = path.join(this.syncRootPath, relativePath); const splitPath = relativePath.split("/").filter((p) => p); const directoryPath = path.resolve(this.syncRootPath); @@ -241,7 +225,7 @@ class VirtualDrive { size: number = 0, creationTime: number = Date.now(), lastWriteTime: number = Date.now() - ): void { + ) { const splitPath = relativePath.split("/").filter((p) => p); const directoryPath = path.resolve(this.syncRootPath); let currentPath = directoryPath; @@ -268,107 +252,30 @@ class VirtualDrive { } } - createItemByPath( - relativePath: string, - itemId: string, - size: number = 0, - creationTime: number = Date.now(), - lastWriteTime: number = Date.now() - ): void { - const fullPath = path.join(this.syncRootPath, relativePath); - const splitPath = relativePath.split("/").filter((p) => p); - const directoryPath = path.resolve(this.syncRootPath); - let currentPath = directoryPath; - if (this.isValidFolderPath(relativePath)) { - // Es un directorio - - for (const dir of splitPath) { - if (fs.existsSync(currentPath)) { - try { - this.createPlaceholderDirectory( - dir, - itemId, - true, - size, - PLACEHOLDER_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, - creationTime, - lastWriteTime, - Date.now(), - currentPath - ); - } catch (error) { - //@ts-ignore - console.error(`Error while creating directory: ${error.message}`); - } - } - currentPath = path.join(currentPath, dir); - } - } else if (this.isValidFilePath(relativePath)) { - // Es un archivo - - try { - for (let i = 0; i < splitPath.length - 1; i++) { - // everything except last element - const dir = splitPath[i]; - if (fs.existsSync(currentPath)) { - this.createPlaceholderDirectory( - dir, - itemId, - true, - 0, - PLACEHOLDER_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, - Date.now(), - Date.now(), - Date.now(), - currentPath - ); - } - currentPath = path.join(currentPath, dir); - } - // last element is the file - this.createPlaceholderFile( - path.basename(fullPath), - itemId, - size, - PLACEHOLDER_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, - creationTime, - lastWriteTime, - Date.now(), - currentPath - ); - } catch (error) { - //@ts-ignore - console.error(`Error al crear placeholder: ${error.message}`); - } - } else { - console.error("Invalid path"); - } - } - disconnectSyncRoot() { return addon.disconnectSyncRoot(); } - async updateSyncStatus( + updateSyncStatus( itemPath: string, isDirectory: boolean, sync: boolean = true ) { - return await addon.updateSyncStatus({ path: this.fixPath(itemPath), isDirectory, sync }); + return addon.updateSyncStatus({ path: this.fixPath(itemPath), isDirectory, sync }); } - convertToPlaceholder(itemPath: string, id: string): boolean { + convertToPlaceholder(itemPath: string, id: string) { return addon.convertToPlaceholder({ path: this.fixPath(itemPath), id }); } - updateFileIdentity(itemPath: string, id: string, isDirectory: boolean): void { - addon.updateFileIdentity({ path: this.fixPath(itemPath), id, isDirectory }); + updateFileIdentity(itemPath: string, id: string, isDirectory: boolean) { + return addon.updateFileIdentity({ path: this.fixPath(itemPath), id, isDirectory }); } - async dehydrateFile(itemPath: string) { + dehydrateFile(itemPath: string) { return addon.dehydrateFile({ path: this.fixPath(itemPath) }); } - async hydrateFile(itemPath: string): Promise { + hydrateFile(itemPath: string) { return addon.hydrateFile({ path: this.fixPath(itemPath) }); } } diff --git a/src/watcher/events/on-add.service.ts b/src/watcher/events/on-add.service.ts index 25e50fec..3dde04fd 100644 --- a/src/watcher/events/on-add.service.ts +++ b/src/watcher/events/on-add.service.ts @@ -6,36 +6,29 @@ import { PinState, SyncState } from "@/types/placeholder.type"; import { Watcher } from "../watcher"; export class OnAddService { - execute({ self, path, stats }: TProps) { + execute({ self, path, stats }: { self: Watcher; path: string; stats: Stats }) { try { - const ext = path.split(".").pop(); const { size, birthtime, mtime } = stats; - const itemId = self.addon.getFileIdentity({ path }); - - self.logger.info({ fn: "onAdd", path, ext, size, birthtime, mtime, itemId }); - if (!ext || size === 0 || size > 20 * 1024 * 1024 * 1024) return; + if (size === 0 || size > 20 * 1024 * 1024 * 1024) return; + const itemId = self.addon.getFileIdentity({ path }); const status = self.addon.getPlaceholderState({ path }); - self.logger.info({ fn: "onAdd", path, status }); - // Verificar tiempos de creación y modificación + self.logger.info({ fn: "onAdd", path, size, birthtime, mtime, itemId, status }); + const creationTime = new Date(birthtime).getTime(); const modificationTime = new Date(mtime).getTime(); - const currentTime = Date.now(); let isNewFile = false; let isMovedFile = false; if (!itemId) { - // El archivo fue creado recientemente (dentro de los últimos 60 segundos) isNewFile = true; } else if (creationTime !== modificationTime) { - // El archivo fue movido (o modificado) isMovedFile = true; } - // Procesar el archivo según su estado if (status.pinState === PinState.AlwaysLocal || status.pinState === PinState.OnlineOnly || status.syncState === SyncState.InSync) { return; } @@ -45,16 +38,9 @@ export class OnAddService { self.queueManager.enqueue({ path, type: typeQueue.add, isFolder: false }); } else if (isMovedFile) { self.logger.info({ fn: "onAdd", msg: "File moved", path }); - // Procesar archivo movido según sea necesario } } catch (error) { self.logger.error("onAddService", error); } } } - -type TProps = { - self: Watcher; - path: string; - stats: Stats; -}; diff --git a/src/watcher/events/on-all.service.ts b/src/watcher/events/on-all.service.ts deleted file mode 100644 index acfa0b80..00000000 --- a/src/watcher/events/on-all.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Stats } from "fs"; - -import { Watcher } from "../watcher"; - -export class OnAllService { - execute({ self, event, path, stats }: TProps) {} -} - -type TProps = { - self: Watcher; - event: string; - path: string; - stats?: Stats; -}; diff --git a/src/watcher/watcher.ts b/src/watcher/watcher.ts index 1e3f364b..2695b968 100644 --- a/src/watcher/watcher.ts +++ b/src/watcher/watcher.ts @@ -1,18 +1,17 @@ -import * as chokidar from "chokidar"; +import { watch, WatchOptions, FSWatcher } from "chokidar"; import { Stats } from "fs"; import { Logger } from "winston"; +import { Addon } from "@/addon-wrapper"; import { QueueManager } from "@/queue/queue-manager"; import { IQueueManager } from "@/queue/queueManager"; import { OnAddDirService } from "./events/on-add-dir.service"; import { OnAddService } from "./events/on-add.service"; -import { OnAllService } from "./events/on-all.service"; import { OnRawService } from "./events/on-raw.service"; -import { Addon } from "@/addon-wrapper"; export namespace Watcher { - export type TOptions = chokidar.WatchOptions; + export type TOptions = WatchOptions; } export class Watcher { @@ -22,21 +21,15 @@ export class Watcher { queueManager!: IQueueManager; logger!: Logger; fileInDevice = new Set(); + chokidar?: FSWatcher; constructor( - private readonly onAll: OnAllService = new OnAllService(), private readonly onAdd: OnAddService = new OnAddService(), private readonly onAddDir: OnAddDirService = new OnAddDirService(), private readonly onRaw: OnRawService = new OnRawService(), ) {} - init( - queueManager: QueueManager, - syncRootPath: string, - options: chokidar.WatchOptions, - logger: Logger, - addon: Addon, - ) { + init(queueManager: QueueManager, syncRootPath: string, options: WatchOptions, logger: Logger, addon: Addon) { this.queueManager = queueManager; this.syncRootPath = syncRootPath; this.options = options; @@ -58,10 +51,8 @@ export class Watcher { public watchAndWait() { try { - const watcher = chokidar.watch(this.syncRootPath, this.options); - - watcher - .on("all", (event, path, stats) => this.onAll.execute({ self: this, event, path, stats })) + this.chokidar = watch(this.syncRootPath, this.options); + this.chokidar .on("add", (path, stats) => this.onAdd.execute({ self: this, path, stats: stats! })) .on("change", this.onChange) .on("addDir", (path, stats) => this.onAddDir.execute({ self: this, path, stats: stats! })) diff --git a/src/watcher/watcher.unit.test.ts b/src/watcher/watcher.unit.test.ts index 5a08c5de..c3a59b59 100644 --- a/src/watcher/watcher.unit.test.ts +++ b/src/watcher/watcher.unit.test.ts @@ -14,17 +14,18 @@ import { sleep } from "@/utils"; import { OnAddDirService } from "./events/on-add-dir.service"; import { OnAddService } from "./events/on-add.service"; -import { OnAllService } from "./events/on-all.service"; import { OnRawService } from "./events/on-raw.service"; import { Watcher } from "./watcher"; describe("Watcher", () => { + let watcher: Watcher | undefined; + const addon = mockDeep(); const queueManager = mockDeep(); const logger = mockDeep(); const options = {}; - const onAll = mockDeep(); + const onAll = vi.fn(); const onAdd = mockDeep(); const onAddDir = mockDeep(); const onRaw = mockDeep(); @@ -34,19 +35,24 @@ describe("Watcher", () => { await mkdir(syncRootPath); } - const watcher = new Watcher(onAll, onAdd, onAddDir, onRaw); + watcher = new Watcher(onAdd, onAddDir, onRaw); watcher.init(queueManager, syncRootPath, options, logger, addon); watcher.watchAndWait(); + watcher.chokidar?.on("all", (event, path) => onAll({ event, path })); }; const getEvents = () => { - return onAll.execute.mock.calls.map((call) => call[0].event); + return onAll.mock.calls.map((call) => ({ event: call[0].event, path: call[0].path })); }; - beforeEach(async () => { + beforeEach(() => { vi.clearAllMocks(); }); + afterEach(() => { + watcher?.chokidar?.close(); + }); + describe("[Watcher] When call watchAndWait", () => { it("When folder is empty, then emit one addDir event", async () => { // Arrange @@ -54,29 +60,33 @@ describe("Watcher", () => { await mkdir(syncRootPath); // Act + await sleep(50); await setupWatcher(syncRootPath); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir"]); - expect(onAddDir.execute).toHaveBeenCalledWith(expect.objectContaining({ path: syncRootPath })); + expect(getEvents()).toStrictEqual([{ event: "addDir", path: syncRootPath }]); }); it("When folder has one file, then emit one addDir and one add event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const file = join(syncRootPath, `${v4()}.txt`); + const file = join(syncRootPath, v4()); await mkdir(syncRootPath); await writeFile(file, Buffer.alloc(1000)); // Act + await sleep(50); await setupWatcher(syncRootPath); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add"]); - expect(onAdd.execute).toHaveBeenCalledWith(expect.objectContaining({ path: file })); - expect(onAddDir.execute).toHaveBeenCalledWith(expect.objectContaining({ path: syncRootPath })); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + ]), + ); }); }); @@ -88,60 +98,80 @@ describe("Watcher", () => { await setupWatcher(syncRootPath); // Act + await sleep(50); await mkdir(folder); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir"]); - expect(onAddDir.execute).toHaveBeenCalledWith(expect.objectContaining({ path: folder })); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + ]), + ); }); it("When add a file, then emit one add event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const file = join(syncRootPath, `${v4()}.txt`); + const file = join(syncRootPath, v4()); await setupWatcher(syncRootPath); // Act + await sleep(50); await writeFile(file, Buffer.alloc(1000)); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add"]); - expect(onAdd.execute).toHaveBeenCalledWith(expect.objectContaining({ path: file })); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + ]), + ); }); it("When add a file of zero size, then emit one add event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const file = join(syncRootPath, `${v4()}.txt`); + const file = join(syncRootPath, v4()); await setupWatcher(syncRootPath); // Act + await sleep(50); await writeFile(file, Buffer.alloc(0)); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add"]); - expect(onAdd.execute).toHaveBeenCalledWith(expect.objectContaining({ path: file })); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + ]), + ); }); it("When add a folder and a file inside, then emit one addDir and one add event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); const folder = join(syncRootPath, v4()); - const file = join(folder, `${v4()}.txt`); + const file = join(folder, v4()); await setupWatcher(syncRootPath); // Act + await sleep(50); await mkdir(folder); await writeFile(file, Buffer.alloc(1000)); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir", "add"]); - expect(onAdd.execute).toHaveBeenCalledWith(expect.objectContaining({ path: file })); - expect(onAddDir.execute).toHaveBeenCalledWith(expect.objectContaining({ path: folder })); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + { event: "add", path: file }, + ]), + ); }); }); @@ -149,27 +179,23 @@ describe("Watcher", () => { it("When modify a file, then emit one change event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const fileName = `${v4()}.txt`; + const fileName = v4(); const file = join(syncRootPath, fileName); await setupWatcher(syncRootPath); await writeFile(file, Buffer.alloc(1000)); - + // Act await sleep(50); await appendFile(file, Buffer.alloc(1000)); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add", "change"]); - expect(onRaw.execute).toHaveBeenCalledWith( - expect.objectContaining({ - event: "change", - path: fileName, - details: { - watchedPath: file, - // TODO: why does not include prev and curr stats - }, - }), + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "change", path: file }, + ]), ); }); }); @@ -178,19 +204,26 @@ describe("Watcher", () => { it("When rename a file, then do not emit any event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const fileName1 = `${v4()}.txt`; - const fileName2 = `${v4()}.txt`; + const fileName1 = v4(); + const fileName2 = v4(); const file1 = join(syncRootPath, fileName1); const file2 = join(syncRootPath, fileName2); await setupWatcher(syncRootPath); await writeFile(file1, Buffer.alloc(1000)); // Act + await sleep(50); await rename(file1, file2); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file1 }, + { event: "add", path: file2 }, + ]), + ); }); it("When rename a folder, then do not emit any event", async () => { @@ -202,11 +235,19 @@ describe("Watcher", () => { await mkdir(folder1); // Act + await sleep(50); await rename(folder1, folder2); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder1 }, + { event: "unlinkDir", path: folder1 }, + { event: "addDir", path: folder2 }, + ]), + ); }); }); @@ -215,21 +256,30 @@ describe("Watcher", () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); const folder = join(syncRootPath, v4()); - const fileName = `${v4()}.txt`; + const fileName = v4(); const file = join(syncRootPath, fileName); + const movedFile = join(folder, fileName); await setupWatcher(syncRootPath); await mkdir(folder); await writeFile(file, Buffer.alloc(1000)); // Act - await rename(file, join(folder, fileName)); + await sleep(50); + await rename(file, movedFile); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir", "add"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "addDir", path: folder }, + { event: "add", path: movedFile }, + ]), + ); }); - it("When move a folder to a folder, then do not emit any event", async () => { + it("When move a folder to a folder, then emit one unlinkDir and one addDir event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); const folder = join(syncRootPath, v4()); @@ -237,15 +287,24 @@ describe("Watcher", () => { const folder1 = join(syncRootPath, folderName); const folder2 = join(folder, folderName); await setupWatcher(syncRootPath); - - // Act await mkdir(folder); await mkdir(folder1); + + // Act + await sleep(50); await rename(folder1, folder2); await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir", "addDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + { event: "addDir", path: folder1 }, + { event: "unlinkDir", path: folder1 }, + { event: "addDir", path: folder2 }, + ]), + ); }); }); @@ -253,7 +312,7 @@ describe("Watcher", () => { it("When delete a file, then emit one unlink event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const file = join(syncRootPath, `${v4()}.txt`); + const file = join(syncRootPath, v4()); await setupWatcher(syncRootPath); await writeFile(file, Buffer.alloc(1000)); @@ -263,7 +322,13 @@ describe("Watcher", () => { await sleep(150); // Assert - expect(getEvents()).toEqual(["addDir", "add", "unlink"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "unlink", path: file }, + ]), + ); }); it("When delete a folder, then emit one unlinkDir event", async () => { @@ -279,7 +344,13 @@ describe("Watcher", () => { await sleep(150); // Assert - expect(getEvents()).toEqual(["addDir", "addDir", "unlinkDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + { event: "unlinkDir", path: folder }, + ]), + ); }); }); @@ -287,7 +358,7 @@ describe("Watcher", () => { it("When pin a file, then emit one change event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const fileName = `${v4()}.txt`; + const fileName = v4(); const file = join(syncRootPath, fileName); await setupWatcher(syncRootPath); await writeFile(file, Buffer.alloc(1000)); @@ -298,16 +369,12 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add", "change"]); - expect(onRaw.execute).toHaveBeenCalledWith( - expect.objectContaining({ - event: "change", - path: fileName, - details: { - watchedPath: file, - // TODO: why does not include prev and curr stats - }, - }), + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "change", path: file }, + ]), ); }); @@ -324,7 +391,12 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + ]), + ); }); }); @@ -332,7 +404,7 @@ describe("Watcher", () => { it("When unpin a file, then emit one change event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const fileName = `${v4()}.txt`; + const fileName = v4(); const file = join(syncRootPath, fileName); await setupWatcher(syncRootPath); await writeFile(file, Buffer.alloc(1000)); @@ -345,16 +417,13 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add", "change", "change"]); - expect(onRaw.execute).toHaveBeenCalledWith( - expect.objectContaining({ - event: "change", - path: fileName, - details: { - watchedPath: file, - // TODO: why does not include prev and curr stats - }, - }), + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "change", path: file }, + { event: "change", path: file }, + ]), ); }); @@ -373,7 +442,12 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + ]), + ); }); }); @@ -381,7 +455,7 @@ describe("Watcher", () => { it("When set a file to online only, then emit one change event", async () => { // Arrange const syncRootPath = join(TEST_FILES, v4()); - const fileName = `${v4()}.txt`; + const fileName = v4(); const file = join(syncRootPath, fileName); await setupWatcher(syncRootPath); await writeFile(file, Buffer.alloc(1000)); @@ -392,16 +466,12 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "add", "change"]); - expect(onRaw.execute).toHaveBeenCalledWith( - expect.objectContaining({ - event: "change", - path: fileName, - details: { - watchedPath: file, - // TODO: why does not include prev and curr stats - }, - }), + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "add", path: file }, + { event: "change", path: file }, + ]), ); }); @@ -418,7 +488,12 @@ describe("Watcher", () => { await sleep(50); // Assert - expect(getEvents()).toEqual(["addDir", "addDir"]); + expect(getEvents()).toStrictEqual( + expect.arrayContaining([ + { event: "addDir", path: syncRootPath }, + { event: "addDir", path: folder }, + ]), + ); }); }); });