From 7cd8f704f0f09157f3b5fbde6a2d1cca956c3c1b Mon Sep 17 00:00:00 2001 From: axel7083 <42176370+axel7083@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:27:02 +0100 Subject: [PATCH] test: ensuring added classes work as expected Signed-off-by: axel7083 <42176370+axel7083@users.noreply.github.com> --- .../backend/src/utils/JsonWatcher.spec.ts | 146 ++++++++++++++++++ packages/backend/src/utils/JsonWatcher.ts | 22 ++- packages/backend/src/utils/Publisher.spec.ts | 41 +++++ 3 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 packages/backend/src/utils/JsonWatcher.spec.ts create mode 100644 packages/backend/src/utils/Publisher.spec.ts diff --git a/packages/backend/src/utils/JsonWatcher.spec.ts b/packages/backend/src/utils/JsonWatcher.spec.ts new file mode 100644 index 000000000..bca24e88a --- /dev/null +++ b/packages/backend/src/utils/JsonWatcher.spec.ts @@ -0,0 +1,146 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ +import { beforeEach, describe, expect, test, vi } from 'vitest'; +import { promises, existsSync } from 'node:fs'; +import type { FileSystemWatcher } from '@podman-desktop/api'; +import { EventEmitter, fs } from '@podman-desktop/api'; +import { JsonWatcher } from './JsonWatcher'; + +vi.mock('@podman-desktop/api', () => { + return { + EventEmitter: vi.fn(), + fs: { + createFileSystemWatcher: () => ({ + onDidCreate: vi.fn(), + onDidDelete: vi.fn(), + onDidChange: vi.fn(), + }), + }, + }; +}); + +vi.mock('node:fs', () => { + return { + existsSync: vi.fn(), + promises: { + readFile: vi.fn(), + }, + }; +}); + +beforeEach(() => { + vi.resetAllMocks(); + // Mock event emitters + const listeners: ((value: unknown) => void)[] = []; + vi.mocked(EventEmitter).mockReturnValue({ + event: vi.fn().mockImplementation(callback => { + listeners.push(callback); + }), + fire: vi.fn().mockImplementation((content: unknown) => { + listeners.forEach(listener => listener(content)); + }), + } as unknown as EventEmitter); +}); + +test('should provide default value', async () => { + vi.mocked(existsSync).mockReturnValue(false); + const watcher = new JsonWatcher('dummyPath', 'dummyDefaultvalue'); + const listener = vi.fn(); + watcher.onContentUpdated(listener); + + watcher.init(); + + await vi.waitFor(() => { + expect(listener).toHaveBeenCalledWith('dummyDefaultvalue'); + }); + expect(existsSync).toHaveBeenCalledWith('dummyPath'); + expect(promises.readFile).not.toHaveBeenCalled(); +}); + +test('should read file content', async () => { + vi.mocked(existsSync).mockReturnValue(true); + vi.spyOn(promises, 'readFile').mockResolvedValue('["hello"]'); + const watcher = new JsonWatcher('dummyPath', []); + const listener = vi.fn(); + watcher.onContentUpdated(listener); + + watcher.init(); + + await vi.waitFor(() => { + expect(listener).toHaveBeenCalledWith(['hello']); + }); + expect(promises.readFile).toHaveBeenCalledWith('dummyPath', 'utf-8'); +}); + +describe('file system watcher events should fire onContentUpdated', () => { + let onDidCreateListener: () => void; + let onDidDeleteListener: () => void; + let onDidChangeListener: () => void; + beforeEach(() => { + vi.spyOn(fs, 'createFileSystemWatcher').mockReturnValue({ + onDidCreate: vi.fn().mockImplementation(listener => (onDidCreateListener = listener)), + onDidDelete: vi.fn().mockImplementation(listener => (onDidDeleteListener = listener)), + onDidChange: vi.fn().mockImplementation(listener => (onDidChangeListener = listener)), + } as unknown as FileSystemWatcher); + }); + + test('onDidCreate', async () => { + vi.mocked(existsSync).mockReturnValue(false); + const watcher = new JsonWatcher('dummyPath', 'dummyDefaultValue'); + const listener = vi.fn(); + watcher.onContentUpdated(listener); + watcher.init(); + + expect(onDidCreateListener).toBeDefined(); + onDidCreateListener(); + + await vi.waitFor(() => { + expect(listener).toHaveBeenNthCalledWith(2, 'dummyDefaultValue'); + }); + }); + + test('onDidDeleteListener', async () => { + vi.mocked(existsSync).mockReturnValue(false); + const watcher = new JsonWatcher('dummyPath', 'dummyDefaultValue'); + const listener = vi.fn(); + watcher.onContentUpdated(listener); + watcher.init(); + + expect(onDidDeleteListener).toBeDefined(); + onDidDeleteListener(); + + await vi.waitFor(() => { + expect(listener).toHaveBeenNthCalledWith(2, 'dummyDefaultValue'); + }); + }); + + test('onDidChangeListener', async () => { + vi.mocked(existsSync).mockReturnValue(false); + const watcher = new JsonWatcher('dummyPath', 'dummyDefaultValue'); + const listener = vi.fn(); + watcher.onContentUpdated(listener); + watcher.init(); + + expect(onDidChangeListener).toBeDefined(); + onDidChangeListener(); + + await vi.waitFor(() => { + expect(listener).toHaveBeenNthCalledWith(2, 'dummyDefaultValue'); + }); + }); +}); diff --git a/packages/backend/src/utils/JsonWatcher.ts b/packages/backend/src/utils/JsonWatcher.ts index 57391161f..95dacbcf8 100644 --- a/packages/backend/src/utils/JsonWatcher.ts +++ b/packages/backend/src/utils/JsonWatcher.ts @@ -1,6 +1,22 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ import { type Disposable, type FileSystemWatcher, fs, EventEmitter, type Event } from '@podman-desktop/api'; -import * as nodeFs from 'fs'; -import { promises } from 'node:fs'; +import { promises, existsSync } from 'node:fs'; export class JsonWatcher implements Disposable { #fileSystemWatcher: FileSystemWatcher | undefined; @@ -45,7 +61,7 @@ export class JsonWatcher implements Disposable { } private async updateContent(): Promise { - if (!nodeFs.existsSync(this.path)) { + if (!existsSync(this.path)) { this._onEvent.fire(this.defaultValue); return; } diff --git a/packages/backend/src/utils/Publisher.spec.ts b/packages/backend/src/utils/Publisher.spec.ts new file mode 100644 index 000000000..11021ceff --- /dev/null +++ b/packages/backend/src/utils/Publisher.spec.ts @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ +import { expect, test, vi } from 'vitest'; +import { Publisher } from './Publisher'; +import type { Webview } from '@podman-desktop/api'; + +test('ensure publisher properly use getter', async () => { + const postMessageMock = vi.fn().mockResolvedValue(undefined); + const getterMock = vi.fn().mockReturnValue('dummyValue'); + const publisher = new Publisher( + { + postMessage: postMessageMock, + } as unknown as Webview, + 'dummyChannel', + getterMock, + ); + publisher.notify(); + + await vi.waitFor(() => { + expect(postMessageMock).toHaveBeenCalledWith({ + id: 'dummyChannel', + body: 'dummyValue', + }); + }); + expect(getterMock).toHaveBeenCalled(); +});