test(scaffolder): editor toolbar templates menu

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-10-04 14:34:05 +02:00
parent 962ab84e88
commit 01ffa58bce
7 changed files with 178 additions and 24 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Add tests for the `useTemplateDirectory` hook.
@@ -29,7 +29,7 @@ import {
} from '../../../routes';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { scaffolderTranslationRef } from '../../../translation';
import { WebFileSystemStore } from '../../../lib/filesystem/WebFileSystemAccess';
import { WebFileSystemStore } from '../../../lib/filesystem/WebFileSystemStore';
import { createExampleTemplate } from '../../../lib/filesystem/createExampleTemplate';
export function TemplateIntroPage() {
@@ -0,0 +1,133 @@
/*
* Copyright 2024 The Backstage Authors
*
* 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.
*/
import { act, renderHook, waitFor } from '@testing-library/react';
import { useTemplateDirectory } from './useTemplateDirectory';
import {
createExampleTemplate,
TemplateDirectoryAccess,
WebFileSystemStore,
} from '../../../lib/filesystem';
import {
IterableDirectoryHandle,
WebFileSystemAccess,
} from '../../../lib/filesystem/WebFileSystemAccess';
jest.mock('../../../lib/filesystem/createExampleTemplate');
describe('useTemplateDirectory', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should return undefined when there is no existing directory in the file system store', async () => {
jest.spyOn(WebFileSystemStore, 'getDirectory').mockResolvedValue(undefined);
const { result } = renderHook(() => useTemplateDirectory());
expect(result.current.directory).toBeUndefined();
expect(result.current.loading).toBeTruthy();
expect(result.current.error).toBeUndefined();
await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.directory).toBeUndefined();
expect(result.current.error).toBeUndefined();
});
it('should return an access when there is existing directory in the file system store', async () => {
const handle = {} as IterableDirectoryHandle;
jest.spyOn(WebFileSystemStore, 'getDirectory').mockResolvedValue(handle);
const { result } = renderHook(() => useTemplateDirectory());
await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.directory).toMatchObject({ handle });
expect(result.current.error).toBeUndefined();
});
it('should handle opening a directory', async () => {
const handle = {};
jest
.spyOn(WebFileSystemStore, 'getDirectory')
.mockResolvedValue(handle as IterableDirectoryHandle);
const setDirectory = jest
.spyOn(WebFileSystemStore, 'setDirectory')
.mockResolvedValue(undefined);
const requestDirectoryAccess = jest
.spyOn(WebFileSystemAccess, 'requestDirectoryAccess')
.mockResolvedValue(handle as TemplateDirectoryAccess);
const { result } = renderHook(() => useTemplateDirectory());
expect(result.current.directory).toBeUndefined();
await act(async () => {
result.current.handleOpenDirectory();
});
expect(requestDirectoryAccess).toHaveBeenCalled();
expect(setDirectory).toHaveBeenCalledWith(handle);
await waitFor(() => expect(result.current.directory).toBeDefined());
});
it('should handle creating a directory', async () => {
const handle = {};
(createExampleTemplate as jest.Mock).mockResolvedValue(handle);
jest
.spyOn(WebFileSystemStore, 'getDirectory')
.mockResolvedValue(handle as IterableDirectoryHandle);
const setDirectory = jest
.spyOn(WebFileSystemStore, 'setDirectory')
.mockResolvedValue(undefined);
const requestDirectoryAccess = jest
.spyOn(WebFileSystemAccess, 'requestDirectoryAccess')
.mockResolvedValue(handle as TemplateDirectoryAccess);
const { result } = renderHook(() => useTemplateDirectory());
await act(async () => {
result.current.handleCreateDirectory();
});
expect(requestDirectoryAccess).toHaveBeenCalled();
expect(setDirectory).toHaveBeenCalledWith(handle);
expect(createExampleTemplate).toHaveBeenCalledWith(handle);
});
it('should handle closing a directory', async () => {
jest.spyOn(WebFileSystemStore, 'getDirectory').mockResolvedValue(undefined);
const setDirectory = jest
.spyOn(WebFileSystemStore, 'setDirectory')
.mockResolvedValue(undefined);
const { result } = renderHook(() => useTemplateDirectory());
expect(setDirectory).not.toHaveBeenCalled();
expect(result.current.directory).toBeUndefined();
await act(async () => {
result.current.handleCloseDirectory();
});
expect(setDirectory).toHaveBeenCalledWith(undefined);
await waitFor(() => expect(result.current.directory).toBeUndefined());
});
});
@@ -18,11 +18,11 @@ import { useCallback } from 'react';
import useAsyncRetry from 'react-use/esm/useAsyncRetry';
import {
WebFileSystemAccess,
WebFileSystemStore,
WebFileSystemAccess,
WebDirectoryAccess,
createExampleTemplate,
} from '../../../lib/filesystem';
import { createExampleTemplate } from '../../../lib/filesystem/createExampleTemplate';
export function useTemplateDirectory(): {
directory?: WebDirectoryAccess;
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import { get, set } from 'idb-keyval';
import { TemplateDirectoryAccess, TemplateFileAccess } from './types';
type WritableFileHandle = FileSystemFileHandle & {
@@ -25,7 +24,7 @@ type WritableFileHandle = FileSystemFileHandle & {
};
// A nicer type than the one from the TS lib
interface IterableDirectoryHandle extends FileSystemDirectoryHandle {
export interface IterableDirectoryHandle extends FileSystemDirectoryHandle {
values(): AsyncIterable<
| ({ kind: 'file' } & WritableFileHandle)
| ({ kind: 'directory' } & IterableDirectoryHandle)
@@ -124,16 +123,3 @@ export class WebFileSystemAccess {
private constructor() {}
}
export class WebFileSystemStore {
private static readonly key = 'scalfolder-template-editor-directory';
static async getDirectory(): Promise<IterableDirectoryHandle | undefined> {
const directory = await get(WebFileSystemStore.key);
return directory.handle;
}
static async setDirectory(directory: TemplateDirectoryAccess | undefined) {
return set(WebFileSystemStore.key, directory);
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2024 The Backstage Authors
*
* 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.
*/
import { get, set } from 'idb-keyval';
import { TemplateDirectoryAccess } from './types';
import { IterableDirectoryHandle } from './WebFileSystemAccess';
export class WebFileSystemStore {
private static readonly key = 'scalfolder-template-editor-directory';
static async getDirectory(): Promise<IterableDirectoryHandle | undefined> {
const directory = await get(WebFileSystemStore.key);
return directory.handle;
}
static async setDirectory(directory: TemplateDirectoryAccess | undefined) {
return set(WebFileSystemStore.key, directory);
}
}
@@ -14,10 +14,8 @@
* limitations under the License.
*/
export type { TemplateFileAccess, TemplateDirectoryAccess } from './types';
export { blobToBase64 } from './helpers';
export {
WebDirectoryAccess,
WebFileSystemAccess,
WebFileSystemStore,
} from './WebFileSystemAccess';
export { createExampleTemplate } from './createExampleTemplate';
export type { TemplateFileAccess, TemplateDirectoryAccess } from './types';
export { WebFileSystemStore } from './WebFileSystemStore';
export { WebDirectoryAccess, WebFileSystemAccess } from './WebFileSystemAccess';