@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { AddShortcut } from './AddShortcut';
|
||||
import { LocalStoredShortcuts } from './api';
|
||||
import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { AlertDisplay } from '@backstage/core';
|
||||
|
||||
describe('AddShortcut', () => {
|
||||
const api = new LocalStoredShortcuts(MockStorageApi.create());
|
||||
|
||||
const props = {
|
||||
onClose: jest.fn(),
|
||||
anchorEl: document.createElement('div'),
|
||||
api,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
document.title = 'some document title';
|
||||
});
|
||||
|
||||
it('displays the title', async () => {
|
||||
render(wrapInTestApp(<AddShortcut {...props} />));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Add Shortcut')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('closes the popup', async () => {
|
||||
render(wrapInTestApp(<AddShortcut {...props} />));
|
||||
|
||||
fireEvent.click(screen.getByText('Cancel'));
|
||||
await waitFor(() => {
|
||||
expect(props.onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('saves the input', async () => {
|
||||
const spy = jest.spyOn(api, 'add');
|
||||
|
||||
render(wrapInTestApp(<AddShortcut {...props} />));
|
||||
|
||||
const urlInput = screen.getByPlaceholderText('Enter a URL');
|
||||
const titleInput = screen.getByPlaceholderText('Enter a display name');
|
||||
fireEvent.change(urlInput, { target: { value: '/some-url' } });
|
||||
fireEvent.change(titleInput, { target: { value: 'some title' } });
|
||||
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(spy).toBeCalledWith({
|
||||
title: 'some title',
|
||||
url: '/some-url',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('pastes the values', async () => {
|
||||
const spy = jest.spyOn(api, 'add');
|
||||
|
||||
render(
|
||||
wrapInTestApp(<AddShortcut {...props} />, {
|
||||
routeEntries: ['/some-initial-url'],
|
||||
}),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Paste Current Url'));
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(spy).toBeCalledWith({
|
||||
title: 'some document title',
|
||||
url: '/some-initial-url',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('displays errors', async () => {
|
||||
jest.spyOn(api, 'add').mockRejectedValueOnce(new Error('some add error'));
|
||||
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<>
|
||||
<AlertDisplay />
|
||||
<AddShortcut {...props} />
|
||||
</>,
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Paste Current Url'));
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Could not add shortcut: some add error'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { EditShortcut } from './EditShortcut';
|
||||
import { Shortcut } from './types';
|
||||
import { LocalStoredShortcuts } from './api';
|
||||
import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { AlertDisplay } from '@backstage/core';
|
||||
|
||||
describe('EditShortcut', () => {
|
||||
const shortcut: Shortcut = {
|
||||
id: 'id',
|
||||
url: '/some-url',
|
||||
title: 'some title',
|
||||
};
|
||||
const api = new LocalStoredShortcuts(MockStorageApi.create());
|
||||
|
||||
const props = {
|
||||
onClose: jest.fn(),
|
||||
anchorEl: document.createElement('div'),
|
||||
shortcut,
|
||||
api,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('displays the title', async () => {
|
||||
render(wrapInTestApp(<EditShortcut {...props} />));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Edit Shortcut')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('closes the popup', async () => {
|
||||
render(wrapInTestApp(<EditShortcut {...props} />));
|
||||
|
||||
fireEvent.click(screen.getByText('Cancel'));
|
||||
await waitFor(() => {
|
||||
expect(props.onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the shortcut', async () => {
|
||||
const spy = jest.spyOn(api, 'update');
|
||||
|
||||
render(wrapInTestApp(<EditShortcut {...props} />));
|
||||
|
||||
const urlInput = screen.getByPlaceholderText('Enter a URL');
|
||||
const titleInput = screen.getByPlaceholderText('Enter a display name');
|
||||
fireEvent.change(urlInput, { target: { value: '/some-new-url' } });
|
||||
fireEvent.change(titleInput, { target: { value: 'some new title' } });
|
||||
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(spy).toBeCalledWith({
|
||||
id: 'id',
|
||||
title: 'some new title',
|
||||
url: '/some-new-url',
|
||||
});
|
||||
expect(props.onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('removes the shortcut', async () => {
|
||||
const spy = jest.spyOn(api, 'remove');
|
||||
|
||||
render(wrapInTestApp(<EditShortcut {...props} />));
|
||||
|
||||
fireEvent.click(screen.getByText('Remove'));
|
||||
await waitFor(() => {
|
||||
expect(spy).toBeCalledWith({
|
||||
id: 'id',
|
||||
title: 'some title',
|
||||
url: '/some-url',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('displays errors', async () => {
|
||||
jest
|
||||
.spyOn(api, 'update')
|
||||
.mockRejectedValueOnce(new Error('some update error'));
|
||||
|
||||
jest
|
||||
.spyOn(api, 'remove')
|
||||
.mockRejectedValueOnce(new Error('some remove error'));
|
||||
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<>
|
||||
<AlertDisplay />
|
||||
<EditShortcut {...props} />
|
||||
</>,
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Could not update shortcut: some update error'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('error-button-close'));
|
||||
|
||||
fireEvent.click(screen.getByText('Remove'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Could not delete shortcut: some remove error'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { ShortcutForm } from './ShortcutForm';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('ShortcutForm', () => {
|
||||
const props = {
|
||||
onSave: jest.fn(),
|
||||
onClose: jest.fn(),
|
||||
};
|
||||
|
||||
it('displays validation messages', async () => {
|
||||
render(wrapInTestApp(<ShortcutForm {...props} />));
|
||||
|
||||
const urlInput = screen.getByPlaceholderText('Enter a URL');
|
||||
const titleInput = screen.getByPlaceholderText('Enter a display name');
|
||||
fireEvent.change(urlInput, { target: { value: 'url' } });
|
||||
fireEvent.change(titleInput, { target: { value: 't' } });
|
||||
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Must be a relative URL (starts with a /)'),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Must be at least 2 characters'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the save handler', async () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<ShortcutForm
|
||||
{...props}
|
||||
formValues={{ url: '/some-url', title: 'some title' }}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Save'));
|
||||
await waitFor(() => {
|
||||
expect(props.onSave).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ title: 'some title', url: '/some-url' }),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the close handler', async () => {
|
||||
render(wrapInTestApp(<ShortcutForm {...props} />));
|
||||
|
||||
fireEvent.click(screen.getByText('Cancel'));
|
||||
await waitFor(() => {
|
||||
expect(props.onClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { ShortcutItem } from './ShortcutItem';
|
||||
import { Shortcut } from './types';
|
||||
import { SidebarContext } from '@backstage/core';
|
||||
import { LocalStoredShortcuts } from './api';
|
||||
import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { pageTheme } from '@backstage/theme';
|
||||
|
||||
describe('ShortcutItem', () => {
|
||||
const shortcut: Shortcut = {
|
||||
id: 'id',
|
||||
url: '/some-url',
|
||||
title: 'some title',
|
||||
};
|
||||
const api = new LocalStoredShortcuts(MockStorageApi.create());
|
||||
|
||||
it('displays the shortcut', async () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<SidebarContext.Provider value={{ isOpen: true }}>
|
||||
<ShortcutItem api={api} shortcut={shortcut} />
|
||||
</SidebarContext.Provider>,
|
||||
),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('ST')).toBeInTheDocument();
|
||||
expect(screen.getByText('some title')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('calculates the shortcut text correctly', async () => {
|
||||
const shortcut1: Shortcut = {
|
||||
id: 'id1',
|
||||
url: '/some-url',
|
||||
title: 'onetitle',
|
||||
};
|
||||
const shortcut2: Shortcut = {
|
||||
id: 'id2',
|
||||
url: '/some-url',
|
||||
title: 'two title',
|
||||
};
|
||||
const shortcut3: Shortcut = {
|
||||
id: 'id3',
|
||||
url: '/some-url',
|
||||
title: 'more | title words',
|
||||
};
|
||||
|
||||
const { rerender } = render(
|
||||
wrapInTestApp(<ShortcutItem api={api} shortcut={shortcut1} />),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('On')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
rerender(wrapInTestApp(<ShortcutItem api={api} shortcut={shortcut2} />));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('TT')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
rerender(wrapInTestApp(<ShortcutItem api={api} shortcut={shortcut3} />));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('MT')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the edit icon on hover', async () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<SidebarContext.Provider value={{ isOpen: true }}>
|
||||
<ShortcutItem api={api} shortcut={shortcut} />
|
||||
</SidebarContext.Provider>,
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.mouseOver(screen.getByText('ST'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('edit')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.mouseOut(screen.getByText('ST'));
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('edit')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('gets the color based on the theme', async () => {
|
||||
const { rerender } = render(
|
||||
wrapInTestApp(<ShortcutItem api={api} shortcut={shortcut} />),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(document.querySelector('circle')?.getAttribute('fill')).toEqual(
|
||||
pageTheme.tool.colors[0],
|
||||
);
|
||||
});
|
||||
|
||||
const newShortcut: Shortcut = {
|
||||
id: 'id',
|
||||
url: '/catalog',
|
||||
title: 'some title',
|
||||
};
|
||||
rerender(wrapInTestApp(<ShortcutItem api={api} shortcut={newShortcut} />));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(document.querySelector('circle')?.getAttribute('fill')).toEqual(
|
||||
pageTheme.home.colors[0],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 React from 'react';
|
||||
import { SidebarContext, ApiProvider, ApiRegistry } from '@backstage/core';
|
||||
import { wrapInTestApp, MockStorageApi } from '@backstage/test-utils';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { Shortcuts } from './Shortcuts';
|
||||
import { LocalStoredShortcuts, shortcutsApiRef } from './api';
|
||||
|
||||
const apis = ApiRegistry.from([
|
||||
[shortcutsApiRef, new LocalStoredShortcuts(MockStorageApi.create())],
|
||||
]);
|
||||
|
||||
describe('Shortcuts', () => {
|
||||
it('displays an add button', async () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<SidebarContext.Provider value={{ isOpen: true }}>
|
||||
<ApiProvider apis={apis}>
|
||||
<Shortcuts />
|
||||
</ApiProvider>
|
||||
</SidebarContext.Provider>,
|
||||
),
|
||||
);
|
||||
await waitFor(() => !screen.queryByTestId('progress'));
|
||||
expect(screen.getByText('Add Shortcuts')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 { MockStorageApi } from '@backstage/test-utils';
|
||||
import { pageTheme } from '@backstage/theme';
|
||||
import { Shortcut } from '../types';
|
||||
import { LocalStoredShortcuts } from './LocalStoredShortcuts';
|
||||
import { ShortcutApi } from './ShortcutApi';
|
||||
|
||||
describe('LocalStoredShortcuts', () => {
|
||||
// eslint-disable-next-line jest/no-done-callback
|
||||
it('should observe shortcuts', async done => {
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(
|
||||
MockStorageApi.create(),
|
||||
);
|
||||
const shortcut: Shortcut = { id: 'id', title: 'title', url: '/url' };
|
||||
|
||||
await shortcutApi.add(shortcut);
|
||||
shortcutApi.observe().subscribe(data => {
|
||||
expect(data).toEqual(
|
||||
expect.arrayContaining([{ ...shortcut, id: expect.anything() }]),
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should add shortcuts with ids', async () => {
|
||||
const storageApi = MockStorageApi.create();
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(storageApi);
|
||||
const shortcut: Omit<Shortcut, 'id'> = { title: 'title', url: '/url' };
|
||||
const spy = jest.spyOn(storageApi, 'set');
|
||||
|
||||
await shortcutApi.add(shortcut);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
'items',
|
||||
expect.objectContaining([{ ...shortcut, id: expect.anything() }]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should update shortcuts', async () => {
|
||||
const storageApi = MockStorageApi.create();
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(storageApi);
|
||||
const shortcut: Shortcut = { id: 'someid', title: 'title', url: '/url' };
|
||||
const spy = jest.spyOn(storageApi, 'set');
|
||||
|
||||
await shortcutApi.update(shortcut);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
'items',
|
||||
expect.objectContaining([shortcut]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should remove shortcuts', async () => {
|
||||
const storageApi = MockStorageApi.create();
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(storageApi);
|
||||
const shortcut: Shortcut = { id: 'someid', title: 'title', url: '/url' };
|
||||
const spy = jest.spyOn(storageApi, 'set');
|
||||
|
||||
await shortcutApi.remove(shortcut);
|
||||
expect(spy).toHaveBeenCalledWith('items', []);
|
||||
});
|
||||
|
||||
it('should get a color', () => {
|
||||
const storageApi = MockStorageApi.create();
|
||||
const shortcutApi: ShortcutApi = new LocalStoredShortcuts(storageApi);
|
||||
|
||||
expect(shortcutApi.getColor('/catalog')).toEqual(pageTheme.home.colors[0]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user