Use screen terminology instead of page as documented by vite-browser-react

This commit is contained in:
Alejandro Celaya
2026-08-16 21:08:53 +02:00
parent c5c994a603
commit 31531c1f87
18 changed files with 213 additions and 210 deletions

View File

@@ -49,8 +49,8 @@ describe('<App />', () => {
['/server/def456/bar', 'ShlinkWebComponentContainer'], ['/server/def456/bar', 'ShlinkWebComponentContainer'],
['/other', 'Oops! We could not find requested route.'], ['/other', 'Oops! We could not find requested route.'],
])('renders expected route', async (activeRoute, expectedComponent) => { ])('renders expected route', async (activeRoute, expectedComponent) => {
const page = await setUp(activeRoute); const screen = await setUp(activeRoute);
await expect.element(page.getByText(expectedComponent)).toBeInTheDocument(); await expect.element(screen.getByText(expectedComponent)).toBeInTheDocument();
}); });
it.each([ it.each([
@@ -58,8 +58,8 @@ describe('<App />', () => {
['/bar', false], ['/bar', false],
['/', true], ['/', true],
])('renders expected classes on shlink-wrapper based on current pathname', async (pathname, isFlex) => { ])('renders expected classes on shlink-wrapper based on current pathname', async (pathname, isFlex) => {
const page = await setUp(pathname); const screen = await setUp(pathname);
const shlinkWrapper = page.getByTestId('shlink-wrapper'); const shlinkWrapper = screen.getByTestId('shlink-wrapper');
if (isFlex) { if (isFlex) {
await expect.element(shlinkWrapper).toHaveClass('flex'); await expect.element(shlinkWrapper).toHaveClass('flex');

View File

@@ -10,28 +10,28 @@ describe('<AppUpdateBanner />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders initial state', async () => { it('renders initial state', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('heading')).toHaveTextContent('This app has just been updated!'); await expect.element(screen.getByRole('heading')).toHaveTextContent('This app has just been updated!');
await expect.element(page.getByText('Restarting...')).not.toBeInTheDocument(); await expect.element(screen.getByText('Restarting...')).not.toBeInTheDocument();
await expect.element(page.getByText('Restart now')).not.toHaveAttribute('disabled'); await expect.element(screen.getByText('Restart now')).not.toHaveAttribute('disabled');
}); });
it('invokes toggle when alert is closed', async () => { it('invokes toggle when alert is closed', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(onClose).not.toHaveBeenCalled(); expect(onClose).not.toHaveBeenCalled();
await user.click(page.getByLabelText('Close')); await user.click(screen.getByLabelText('Close'));
expect(onClose).toHaveBeenCalled(); expect(onClose).toHaveBeenCalled();
}); });
it('triggers the update when clicking the button', async () => { it('triggers the update when clicking the button', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(forceUpdate).not.toHaveBeenCalled(); expect(forceUpdate).not.toHaveBeenCalled();
await user.click(page.getByText(/^Restart now/)); await user.click(screen.getByText(/^Restart now/));
expect(forceUpdate).toHaveBeenCalled(); expect(forceUpdate).toHaveBeenCalled();
await expect.element(page.getByText('Restarting...')).toBeInTheDocument(); await expect.element(screen.getByText('Restarting...')).toBeInTheDocument();
await expect.element(page.getByText(/^Restart now/)).not.toBeInTheDocument(); await expect.element(screen.getByText(/^Restart now/)).not.toBeInTheDocument();
}); });
}); });

View File

@@ -26,25 +26,25 @@ describe('<ErrorHandler />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders children when no error has occurred', async () => { it('renders children when no error has occurred', async () => {
const page = await setUp(<span>Foo</span>); const screen = await setUp(<span>Foo</span>);
await expect.element(page.getByText('Foo')).toBeInTheDocument(); await expect.element(screen.getByText('Foo')).toBeInTheDocument();
await expect.element(page.getByText('Oops! This is awkward :S')).not.toBeInTheDocument(); await expect.element(screen.getByText('Oops! This is awkward :S')).not.toBeInTheDocument();
await expect.element(page.getByRole('button')).not.toBeInTheDocument(); await expect.element(screen.getByRole('button')).not.toBeInTheDocument();
}); });
it('renders error page when error has occurred', async () => { it('renders error page when error has occurred', async () => {
const page = await setUp(<ComponentWithError />); const screen = await setUp(<ComponentWithError />);
await expect.element(page.getByText('Oops! This is awkward :S')).toBeInTheDocument(); await expect.element(screen.getByText('Oops! This is awkward :S')).toBeInTheDocument();
await expect.element(page.getByRole('button')).toBeInTheDocument(); await expect.element(screen.getByRole('button')).toBeInTheDocument();
}); });
it('reloads page on button click', async () => { it('reloads page on button click', async () => {
const { user, ...page } = await setUp(<ComponentWithError />); const { user, ...screen } = await setUp(<ComponentWithError />);
expect(reload).not.toHaveBeenCalled(); expect(reload).not.toHaveBeenCalled();
await user.click(page.getByRole('button')); await user.click(screen.getByRole('button'));
expect(reload).toHaveBeenCalled(); expect(reload).toHaveBeenCalled();
}); });
}); });

View File

@@ -20,8 +20,8 @@ describe('<Home />', () => {
checkAccessibility(setUp({ '1a': fromPartial<ServerWithId>({ name: 'foo', id: '1' }) }))); checkAccessibility(setUp({ '1a': fromPartial<ServerWithId>({ name: 'foo', id: '1' }) })));
it('renders title', async () => { it('renders title', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('heading', { name: 'Welcome!' })).toBeInTheDocument(); await expect.element(screen.getByRole('heading', { name: 'Welcome!' })).toBeInTheDocument();
}); });
it.each([ it.each([
@@ -35,16 +35,16 @@ describe('<Home />', () => {
], ],
[{}, 2], [{}, 2],
])('shows link to create or set-up server only when no servers exist', async (servers, expectedServers) => { ])('shows link to create or set-up server only when no servers exist', async (servers, expectedServers) => {
const page = await setUp(servers); const screen = await setUp(servers);
const links = page.getByRole('link').elements(); const links = screen.getByRole('link').elements();
expect(links).toHaveLength(expectedServers); expect(links).toHaveLength(expectedServers);
if (Object.keys(servers).length === 0) { if (Object.keys(servers).length === 0) {
await expect await expect
.element(page.getByText('This application will help you manage your Shlink servers.')) .element(screen.getByText('This application will help you manage your Shlink servers.'))
.toBeInTheDocument(); .toBeInTheDocument();
await expect.element(page.getByText('Learn more about Shlink')).toBeInTheDocument(); await expect.element(screen.getByText('Learn more about Shlink')).toBeInTheDocument();
} }
}); });
}); });

View File

@@ -19,8 +19,8 @@ describe('<MainHeader />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders ServersDropdown', async () => { it('renders ServersDropdown', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('button', { name: 'Servers' })).toBeInTheDocument(); await expect.element(screen.getByRole('button', { name: 'Servers' })).toBeInTheDocument();
}); });
it.each([ it.each([
@@ -30,9 +30,9 @@ describe('<MainHeader />', () => {
['/settings/foo', true], ['/settings/foo', true],
['/settings/bar', true], ['/settings/bar', true],
])('sets link to settings as active only when current path is settings', async (currentPath, isActive) => { ])('sets link to settings as active only when current path is settings', async (currentPath, isActive) => {
const page = await setUp(currentPath); const screen = await setUp(currentPath);
await expect await expect
.element(page.getByRole('menuitem', { name: /Settings$/ })) .element(screen.getByRole('menuitem', { name: /Settings$/ }))
.toHaveAttribute('data-active', isActive ? 'true' : 'false'); .toHaveAttribute('data-active', isActive ? 'true' : 'false');
}); });
}); });

View File

@@ -14,15 +14,15 @@ describe('<NotFound />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('shows expected error title', async () => { it('shows expected error title', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByText('Oops! We could not find requested route.')).toBeInTheDocument(); await expect.element(screen.getByText('Oops! We could not find requested route.')).toBeInTheDocument();
}); });
it('shows expected error message', async () => { it('shows expected error message', async () => {
const page = await setUp(); const screen = await setUp();
await expect await expect
.element( .element(
page.getByText( screen.getByText(
"Use your browser's back button to navigate to the page you have previously come from, or just press this button.", "Use your browser's back button to navigate to the page you have previously come from, or just press this button.",
), ),
) )
@@ -34,8 +34,8 @@ describe('<NotFound />', () => {
[{ to: '/foo/bar', children: 'Hello' }, '/foo/bar', 'Hello'], [{ to: '/foo/bar', children: 'Hello' }, '/foo/bar', 'Hello'],
[{ to: '/baz-bar', children: <>Foo</> }, '/baz-bar', 'Foo'], [{ to: '/baz-bar', children: <>Foo</> }, '/baz-bar', 'Foo'],
])('shows expected link and text', async (props, expectedLink, expectedText) => { ])('shows expected link and text', async (props, expectedLink, expectedText) => {
const page = await setUp(props); const screen = await setUp(props);
const link = page.getByRole('link'); const link = screen.getByRole('link');
await expect.element(link).toHaveAttribute('href', expectedLink); await expect.element(link).toHaveAttribute('href', expectedLink);
await expect.element(link).toHaveTextContent(expectedText); await expect.element(link).toHaveTextContent(expectedText);

View File

@@ -25,10 +25,10 @@ describe('<ShlinkWebComponentContainer />', () => {
it('passes a11y checks', () => checkAccessibility(setUp(fromPartial({ version: '3.0.0' })))); it('passes a11y checks', () => checkAccessibility(setUp(fromPartial({ version: '3.0.0' }))));
it('shows loading indicator while loading server', async () => { it('shows loading indicator while loading server', async () => {
const page = await setUp(null); const screen = await setUp(null);
await expect.element(page.getByText('Loading...')).toBeInTheDocument(); await expect.element(screen.getByText('Loading...')).toBeInTheDocument();
await expect.element(page.getByText('ShlinkWebComponent')).not.toBeInTheDocument(); await expect.element(screen.getByText('ShlinkWebComponent')).not.toBeInTheDocument();
}); });
it.each([ it.each([
@@ -38,17 +38,17 @@ describe('<ShlinkWebComponentContainer />', () => {
/Could not connect to this Shlink server/, /Could not connect to this Shlink server/,
], ],
])('shows error for non reachable servers', async (selectedServer, expectedError) => { ])('shows error for non reachable servers', async (selectedServer, expectedError) => {
const page = await setUp(selectedServer); const screen = await setUp(selectedServer);
await expect.element(page.getByText('Loading...')).not.toBeInTheDocument(); await expect.element(screen.getByText('Loading...')).not.toBeInTheDocument();
await expect.element(page.getByText(expectedError)).toBeInTheDocument(); await expect.element(screen.getByText(expectedError)).toBeInTheDocument();
await expect.element(page.getByText('ShlinkWebComponent')).not.toBeInTheDocument(); await expect.element(screen.getByText('ShlinkWebComponent')).not.toBeInTheDocument();
}); });
it('renders ShlinkWebComponent for reachable servers', async () => { it('renders ShlinkWebComponent for reachable servers', async () => {
const page = await setUp(fromPartial({ version: '3.0.0' })); const screen = await setUp(fromPartial({ version: '3.0.0' }));
await expect.element(page.getByText('Loading...')).not.toBeInTheDocument(); await expect.element(screen.getByText('Loading...')).not.toBeInTheDocument();
await expect.element(page.getByText('ShlinkWebComponent')).toBeInTheDocument(); await expect.element(screen.getByText('ShlinkWebComponent')).toBeInTheDocument();
}); });
}); });

View File

@@ -45,38 +45,38 @@ describe('<CreateServer />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('shows success message when imported is true', async () => { it('shows success message when imported is true', async () => {
const page = await setUp({ serversImported: true }); const screen = await setUp({ serversImported: true });
await expect await expect
.element(page.getByText('Servers properly imported. You can now select one from the list :)')) .element(screen.getByText('Servers properly imported. You can now select one from the list :)'))
.toBeInTheDocument(); .toBeInTheDocument();
await expect await expect
.element(page.getByText('The servers could not be imported. Make sure the format is correct.')) .element(screen.getByText('The servers could not be imported. Make sure the format is correct.'))
.not.toBeInTheDocument(); .not.toBeInTheDocument();
await expect.element(page.getByText('ImportServersBtn')).not.toBeInTheDocument(); await expect.element(screen.getByText('ImportServersBtn')).not.toBeInTheDocument();
}); });
it('shows error message when import failed', async () => { it('shows error message when import failed', async () => {
const page = await setUp({ importFailed: true }); const screen = await setUp({ importFailed: true });
await expect await expect
.element(page.getByText('Servers properly imported. You can now select one from the list :)')) .element(screen.getByText('Servers properly imported. You can now select one from the list :)'))
.not.toBeInTheDocument(); .not.toBeInTheDocument();
await expect await expect
.element(page.getByText('The servers could not be imported. Make sure the format is correct.')) .element(screen.getByText('The servers could not be imported. Make sure the format is correct.'))
.toBeInTheDocument(); .toBeInTheDocument();
}); });
it('creates server data when form is submitted', async () => { it('creates server data when form is submitted', async () => {
const { user, history, store, ...page } = await setUp(); const { user, history, store, ...screen } = await setUp();
const expectedServerId = 'the_name-the_url.com'; const expectedServerId = 'the_name-the_url.com';
await user.type(page.getByLabelText(/^Name/), 'the_name'); await user.type(screen.getByLabelText(/^Name/), 'the_name');
await user.type(page.getByLabelText(/^URL/), 'https://the_url.com'); await user.type(screen.getByLabelText(/^URL/), 'https://the_url.com');
await user.type(page.getByLabelText(/^API key/), 'the_api_key'); await user.type(screen.getByLabelText(/^API key/), 'the_api_key');
expect(store.getState().servers[expectedServerId]).not.toBeDefined(); expect(store.getState().servers[expectedServerId]).not.toBeDefined();
await user.click(page.getByRole('button', { name: 'Create server' })); await user.click(screen.getByRole('button', { name: 'Create server' }));
expect(store.getState().servers[expectedServerId]).toEqual( expect(store.getState().servers[expectedServerId]).toEqual(
expect.objectContaining({ expect.objectContaining({
id: expectedServerId, id: expectedServerId,
@@ -87,20 +87,20 @@ describe('<CreateServer />', () => {
); );
expect(history.location.pathname).toEqual(`/server/${expectedServerId}`); expect(history.location.pathname).toEqual(`/server/${expectedServerId}`);
await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).not.toBeInTheDocument();
}); });
it('displays dialog when trying to create a duplicated server', async () => { it('displays dialog when trying to create a duplicated server', async () => {
const { user, history, ...page } = await setUp(); const { user, history, ...screen } = await setUp();
await user.type(page.getByLabelText(/^Name/), 'the_name'); await user.type(screen.getByLabelText(/^Name/), 'the_name');
await user.type(page.getByLabelText(/^URL/), 'https://existing_url.com'); await user.type(screen.getByLabelText(/^URL/), 'https://existing_url.com');
await user.type(page.getByLabelText(/^API key/), 'existing_api_key'); await user.type(screen.getByLabelText(/^API key/), 'existing_api_key');
await user.click(page.getByRole('button', { name: 'Create server' })); await user.click(screen.getByRole('button', { name: 'Create server' }));
await expect.element(page.getByRole('dialog')).toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).toBeInTheDocument();
await user.click(page.getByRole('button', { name: 'Discard' })); await user.click(screen.getByRole('button', { name: 'Discard' }));
expect(history.location.pathname).toEqual('/foo'); // Goes back to first route from history's initialEntries expect(history.location.pathname).toEqual('/foo'); // Goes back to first route from history's initialEntries
}); });

View File

@@ -28,21 +28,21 @@ describe('<DeleteServerButton />', () => {
}); });
it('displays modal when button is clicked', async () => { it('displays modal when button is clicked', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await expect.element(page.getByText(/Are you sure you want to remove/)).not.toBeInTheDocument(); await expect.element(screen.getByText(/Are you sure you want to remove/)).not.toBeInTheDocument();
await user.click(page.getByText('Remove this server')); await user.click(screen.getByText('Remove this server'));
await expect.element(page.getByText(/Are you sure you want to remove/)).toBeInTheDocument(); await expect.element(screen.getByText(/Are you sure you want to remove/)).toBeInTheDocument();
}); });
it('navigates to home when deletion is confirmed', async () => { it('navigates to home when deletion is confirmed', async () => {
const { user, history, ...page } = await setUp(); const { user, history, ...screen } = await setUp();
// Open modal // Open modal
await user.click(page.getByText('Remove this server')); await user.click(screen.getByText('Remove this server'));
expect(history.location.pathname).toEqual('/foo'); expect(history.location.pathname).toEqual('/foo');
await user.click(page.getByRole('button', { name: 'Delete' })); await user.click(screen.getByRole('button', { name: 'Delete' }));
expect(history.location.pathname).toEqual('/'); expect(history.location.pathname).toEqual('/');
}); });
}); });

View File

@@ -19,38 +19,38 @@ describe('<DeleteServerModal />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders a modal window', async () => { it('renders a modal window', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('dialog')).toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).toBeInTheDocument();
await expect.element(page.getByRole('heading')).toHaveTextContent('Remove server'); await expect.element(screen.getByRole('heading')).toHaveTextContent('Remove server');
}); });
it('displays the name of the server as part of the content', async () => { it('displays the name of the server as part of the content', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByText(/^Are you sure you want to remove/)).toBeInTheDocument(); await expect.element(screen.getByText(/^Are you sure you want to remove/)).toBeInTheDocument();
await expect.element(page.getByText(serverName)).toBeInTheDocument(); await expect.element(screen.getByText(serverName)).toBeInTheDocument();
}); });
it.each([ it.each([
[(page: RenderResult) => page.getByRole('button', { name: 'Cancel' })], [(screen: RenderResult) => screen.getByRole('button', { name: 'Cancel' })],
[(page: RenderResult) => page.getByLabelText('Close dialog')], [(screen: RenderResult) => screen.getByLabelText('Close dialog')],
])('closes dialog when clicking cancel button', async (getButton) => { ])('closes dialog when clicking cancel button', async (getButton) => {
const { user, store, ...page } = await setUp(); const { user, store, ...screen } = await setUp();
await expect.element(page.getByRole('dialog')).toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).toBeInTheDocument();
await user.click(getButton(page)); await user.click(getButton(screen));
await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).not.toBeInTheDocument();
// No server has been deleted // No server has been deleted
expect(Object.keys(store.getState().servers)).toHaveLength(1); expect(Object.keys(store.getState().servers)).toHaveLength(1);
}); });
it('deletes server when clicking accept button', async () => { it('deletes server when clicking accept button', async () => {
const { user, store, ...page } = await setUp(); const { user, store, ...screen } = await setUp();
expect(Object.keys(store.getState().servers)).toHaveLength(1); expect(Object.keys(store.getState().servers)).toHaveLength(1);
await user.click(page.getByRole('button', { name: 'Delete' })); await user.click(screen.getByRole('button', { name: 'Delete' }));
expect(Object.keys(store.getState().servers)).toHaveLength(0); expect(Object.keys(store.getState().servers)).toHaveLength(0);
}); });
}); });

View File

@@ -35,31 +35,31 @@ describe('<EditServer />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders nothing if selected server is not reachable', async () => { it('renders nothing if selected server is not reachable', async () => {
const page = await setUp(fromPartial<SelectedServer>({})); const screen = await setUp(fromPartial<SelectedServer>({}));
await expect.element(page.getByText('Edit')).not.toBeInTheDocument(); await expect.element(screen.getByText('Edit')).not.toBeInTheDocument();
await expect.element(page.getByText('Cancel')).not.toBeInTheDocument(); await expect.element(screen.getByText('Cancel')).not.toBeInTheDocument();
await expect.element(page.getByText('Save')).not.toBeInTheDocument(); await expect.element(screen.getByText('Save')).not.toBeInTheDocument();
}); });
it('renders server title', async () => { it('renders server title', async () => {
const page = await setUp(); const screen = await setUp();
expect(page.getByText(`Edit "${defaultSelectedServer.name}"`)).toBeInTheDocument(); expect(screen.getByText(`Edit "${defaultSelectedServer.name}"`)).toBeInTheDocument();
}); });
it('display the server info in the form components', async () => { it('display the server info in the form components', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByLabelText(/^Name/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^Name/)).toBeInTheDocument();
await expect.element(page.getByLabelText(/^URL/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^URL/)).toBeInTheDocument();
await expect.element(page.getByLabelText(/^API key/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^API key/)).toBeInTheDocument();
}); });
it('edits server and redirects to it when form is submitted', async () => { it('edits server and redirects to it when form is submitted', async () => {
const { user, history, store, ...page } = await setUp(); const { user, history, store, ...screen } = await setUp();
await user.type(page.getByLabelText(/^Name/), ' edited'); await user.type(screen.getByLabelText(/^Name/), ' edited');
await user.click(page.getByRole('button', { name: 'Save' })); await user.click(screen.getByRole('button', { name: 'Save' }));
expect(store.getState().servers[defaultSelectedServer.id]).toEqual( expect(store.getState().servers[defaultSelectedServer.id]).toEqual(
expect.objectContaining({ expect.objectContaining({
@@ -74,11 +74,11 @@ describe('<EditServer />', () => {
it.each([{ forwardCredentials: true }, { forwardCredentials: false }])( it.each([{ forwardCredentials: true }, { forwardCredentials: false }])(
'edits advanced options - forward credentials', 'edits advanced options - forward credentials',
async ({ forwardCredentials }) => { async ({ forwardCredentials }) => {
const { user, store, ...page } = await setUp({ ...defaultSelectedServer, forwardCredentials }); const { user, store, ...screen } = await setUp({ ...defaultSelectedServer, forwardCredentials });
await user.click(page.getByText('Advanced options')); await user.click(screen.getByText('Advanced options'));
await user.click(page.getByLabelText('Forward credentials to this server on every request.')); await user.click(screen.getByLabelText('Forward credentials to this server on every request.'));
await user.click(page.getByRole('button', { name: 'Save' })); await user.click(screen.getByRole('button', { name: 'Save' }));
expect(store.getState().servers[defaultSelectedServer.id]).toEqual( expect(store.getState().servers[defaultSelectedServer.id]).toEqual(
expect.objectContaining({ expect.objectContaining({

View File

@@ -32,43 +32,44 @@ describe('<ManageServers />', () => {
)); ));
it('shows search field which allows searching servers, affecting te amount of rendered rows', async () => { it('shows search field which allows searching servers, affecting te amount of rendered rows', async () => {
const { user, ...page } = await setUp({ const { user, ...screen } = await setUp({
foo: createServerMock('foo'), foo: createServerMock('foo'),
bar: createServerMock('bar'), bar: createServerMock('bar'),
baz: createServerMock('baz'), baz: createServerMock('baz'),
}); });
const search = async (searchTerm: string) => { const search = async (searchTerm: string) => {
await user.clear(page.getByPlaceholder('Search...')); await user.clear(screen.getByPlaceholder('Search...'));
await user.type(page.getByPlaceholder('Search...'), searchTerm); await user.type(screen.getByPlaceholder('Search...'), searchTerm);
}; };
// Add one for the header row // Add one for the header row
const expectRows = (amount: number) => expect.poll(() => page.getByRole('row').elements()).toHaveLength(amount + 1); const expectRows = (amount: number) =>
expect.poll(() => screen.getByRole('row').elements()).toHaveLength(amount + 1);
await expectRows(3); await expectRows(3);
await expect.element(page.getByText('No servers found.')).not.toBeInTheDocument(); await expect.element(screen.getByText('No servers found.')).not.toBeInTheDocument();
await search('foo'); await search('foo');
await expectRows(1); await expectRows(1);
await expect.element(page.getByText('No servers found.')).not.toBeInTheDocument(); await expect.element(screen.getByText('No servers found.')).not.toBeInTheDocument();
await search('Ba'); await search('Ba');
await expectRows(2); await expectRows(2);
await expect.element(page.getByText('No servers found.')).not.toBeInTheDocument(); await expect.element(screen.getByText('No servers found.')).not.toBeInTheDocument();
await search('invalid'); await search('invalid');
await expectRows(1); await expectRows(1);
await expect.element(page.getByText('No servers found.')).toBeInTheDocument(); await expect.element(screen.getByText('No servers found.')).toBeInTheDocument();
}); });
it.each([[createServerMock('foo')], [createServerMock('foo', true)]])( it.each([[createServerMock('foo')], [createServerMock('foo', true)]])(
'shows different amount of columns if there are at least one auto-connect server', 'shows different amount of columns if there are at least one auto-connect server',
async (server) => { async (server) => {
const page = await setUp({ server }); const screen = await setUp({ server });
if (server.autoConnect) { if (server.autoConnect) {
await expect.element(page.getByTestId('auto-connect')).toBeInTheDocument(); await expect.element(screen.getByTestId('auto-connect')).toBeInTheDocument();
} else { } else {
await expect.element(page.getByTestId('auto-connect')).not.toBeInTheDocument(); await expect.element(screen.getByTestId('auto-connect')).not.toBeInTheDocument();
} }
}, },
); );
@@ -77,30 +78,30 @@ describe('<ManageServers />', () => {
[{}, 0], [{}, 0],
[{ foo: createServerMock('foo') }, 1], [{ foo: createServerMock('foo') }, 1],
])('shows export button if the list of servers is not empty', async (servers, expectedButtons) => { ])('shows export button if the list of servers is not empty', async (servers, expectedButtons) => {
const page = await setUp(servers); const screen = await setUp(servers);
expect(page.getByRole('button', { name: 'Export servers' }).elements()).toHaveLength(expectedButtons); expect(screen.getByRole('button', { name: 'Export servers' }).elements()).toHaveLength(expectedButtons);
}); });
it('allows exporting servers when clicking on button', async () => { it('allows exporting servers when clicking on button', async () => {
const { user, ...page } = await setUp({ foo: createServerMock('foo') }); const { user, ...screen } = await setUp({ foo: createServerMock('foo') });
expect(exportServers).not.toHaveBeenCalled(); expect(exportServers).not.toHaveBeenCalled();
await user.click(page.getByRole('button', { name: 'Export servers' })); await user.click(screen.getByRole('button', { name: 'Export servers' }));
expect(exportServers).toHaveBeenCalled(); expect(exportServers).toHaveBeenCalled();
}); });
it.each([[true], [false]])('shows an error message if an error occurs while importing servers', async (hasError) => { it.each([[true], [false]])('shows an error message if an error occurs while importing servers', async (hasError) => {
useTimeoutToggle.mockReturnValue([hasError, vi.fn()]); useTimeoutToggle.mockReturnValue([hasError, vi.fn()]);
const page = await setUp({ foo: createServerMock('foo') }); const screen = await setUp({ foo: createServerMock('foo') });
if (hasError) { if (hasError) {
await expect await expect
.element(page.getByText('The servers could not be imported. Make sure the format is correct.')) .element(screen.getByText('The servers could not be imported. Make sure the format is correct.'))
.toBeInTheDocument(); .toBeInTheDocument();
} else { } else {
await expect await expect
.element(page.getByText('The servers could not be imported. Make sure the format is correct.')) .element(screen.getByText('The servers could not be imported. Make sure the format is correct.'))
.not.toBeInTheDocument(); .not.toBeInTheDocument();
} }
}); });

View File

@@ -27,13 +27,13 @@ describe('<ManageServersRow />', () => {
[true, 4], [true, 4],
[false, 3], [false, 3],
])('renders expected amount of columns', async (hasAutoConnect, expectedCols) => { ])('renders expected amount of columns', async (hasAutoConnect, expectedCols) => {
const page = await setUp(hasAutoConnect); const screen = await setUp(hasAutoConnect);
expect(page.getByRole('cell').elements()).toHaveLength(expectedCols); expect(screen.getByRole('cell').elements()).toHaveLength(expectedCols);
}); });
it('renders an options dropdown', async () => { it('renders an options dropdown', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('button', { name: 'Options' })).toBeInTheDocument(); await expect.element(screen.getByRole('button', { name: 'Options' })).toBeInTheDocument();
}); });
it.each([[true], [false]])('renders auto-connect icon only if server is autoConnect', async (autoConnect) => { it.each([[true], [false]])('renders auto-connect icon only if server is autoConnect', async (autoConnect) => {
@@ -42,11 +42,11 @@ describe('<ManageServersRow />', () => {
}); });
it('renders server props where appropriate', async () => { it('renders server props where appropriate', async () => {
const page = await setUp(); const screen = await setUp();
const link = page.getByRole('link'); const link = screen.getByRole('link');
await expect.element(link).toHaveAttribute('href', `/server/${server.id}`); await expect.element(link).toHaveAttribute('href', `/server/${server.id}`);
await expect.element(link).toHaveTextContent(server.name); await expect.element(link).toHaveTextContent(server.name);
await expect.element(page.getByText(server.url)).toBeInTheDocument(); await expect.element(screen.getByText(server.url)).toBeInTheDocument();
}); });
}); });

View File

@@ -21,50 +21,50 @@ describe('<ManageServersRowDropdown />', () => {
}, },
); );
}; };
const toggleDropdown = (user: UserEvent, page: RenderResult) => user.click(page.getByRole('button')); const toggleDropdown = (user: UserEvent, screen: RenderResult) => user.click(screen.getByRole('button'));
it('passes a11y checks', async () => { it('passes a11y checks', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
// Open menu // Open menu
await toggleDropdown(user, page); await toggleDropdown(user, screen);
return checkAccessibility(page); return checkAccessibility(screen);
}); });
it('renders expected amount of dropdown items', async () => { it('renders expected amount of dropdown items', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await expect.element(page.getByRole('menu')).not.toBeInTheDocument(); await expect.element(screen.getByRole('menu')).not.toBeInTheDocument();
await toggleDropdown(user, page); await toggleDropdown(user, screen);
await expect.element(page.getByRole('menu')).toBeInTheDocument(); await expect.element(screen.getByRole('menu')).toBeInTheDocument();
expect(page.getByRole('menuitem').elements()).toHaveLength(4); expect(screen.getByRole('menuitem').elements()).toHaveLength(4);
await expect await expect
.element(page.getByRole('menuitem', { name: 'Connect', exact: true })) .element(screen.getByRole('menuitem', { name: 'Connect', exact: true }))
.toHaveAttribute('href', '/server/abc123'); .toHaveAttribute('href', '/server/abc123');
await expect await expect
.element(page.getByRole('menuitem', { name: 'Edit server' })) .element(screen.getByRole('menuitem', { name: 'Edit server' }))
.toHaveAttribute('href', '/server/abc123/edit'); .toHaveAttribute('href', '/server/abc123/edit');
}); });
it.each([true, false])('allows toggling auto-connect', async (autoConnect) => { it.each([true, false])('allows toggling auto-connect', async (autoConnect) => {
const { user, store, ...page } = await setUp(autoConnect); const { user, store, ...screen } = await setUp(autoConnect);
await toggleDropdown(user, page); await toggleDropdown(user, screen);
await user.click(page.getByRole('menuitem', { name: autoConnect ? 'Do not auto-connect' : 'Auto-connect' })); await user.click(screen.getByRole('menuitem', { name: autoConnect ? 'Do not auto-connect' : 'Auto-connect' }));
expect(Object.values(store.getState().servers)[0].autoConnect).toEqual(!autoConnect); expect(Object.values(store.getState().servers)[0].autoConnect).toEqual(!autoConnect);
}); });
it('renders deletion modal', async () => { it('renders deletion modal', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(page.getByRole('dialog')).not.toBeInTheDocument(); expect(screen.getByRole('dialog')).not.toBeInTheDocument();
await toggleDropdown(user, page); await toggleDropdown(user, screen);
await user.click(page.getByRole('menuitem', { name: 'Remove server' })); await user.click(screen.getByRole('menuitem', { name: 'Remove server' }));
await expect.element(page.getByRole('dialog')).toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).toBeInTheDocument();
}); });
it.each([[true], [false]])('renders expected size and icon', async (autoConnect) => { it.each([[true], [false]])('renders expected size and icon', async (autoConnect) => {

View File

@@ -24,18 +24,18 @@ describe('<ServersDropdown />', () => {
); );
it('passes a11y checks', async () => { it('passes a11y checks', async () => {
const { user, container, ...page } = await setUp(); const { user, container, ...screen } = await setUp();
// Open menu // Open menu
await user.click(page.getByText('Servers')); await user.click(screen.getByText('Servers'));
return checkAccessibility({ container }); return checkAccessibility({ container });
}); });
it('contains the list of servers and the "mange servers" button', async () => { it('contains the list of servers and the "mange servers" button', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await user.click(page.getByText('Servers')); await user.click(screen.getByText('Servers'));
const items = page.getByRole('menuitem').elements(); const items = screen.getByRole('menuitem').elements();
// We have to add two for the "Manage servers" and the "Settings" menu items // We have to add two for the "Manage servers" and the "Settings" menu items
expect(items).toHaveLength(Object.values(fallbackServers).length + 2); expect(items).toHaveLength(Object.values(fallbackServers).length + 2);
@@ -46,23 +46,23 @@ describe('<ServersDropdown />', () => {
}); });
it('contains a toggle with proper text', async () => { it('contains a toggle with proper text', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByRole('button')).toHaveTextContent('Servers'); await expect.element(screen.getByRole('button')).toHaveTextContent('Servers');
}); });
it('contains a button to manage servers', async () => { it('contains a button to manage servers', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await user.click(page.getByText('Servers')); await user.click(screen.getByText('Servers'));
await expect await expect
.element(page.getByRole('menuitem', { name: 'Manage servers' })) .element(screen.getByRole('menuitem', { name: 'Manage servers' }))
.toHaveAttribute('href', '/manage-servers'); .toHaveAttribute('href', '/manage-servers');
}); });
it('shows only create link when no servers exist yet', async () => { it('shows only create link when no servers exist yet', async () => {
const { user, ...page } = await setUp({}); const { user, ...screen } = await setUp({});
await user.click(page.getByText('Servers')); await user.click(screen.getByText('Servers'));
await expect.element(page.getByRole('menuitem', { name: 'Add a server' })).toBeInTheDocument(); await expect.element(screen.getByRole('menuitem', { name: 'Add a server' })).toBeInTheDocument();
}); });
}); });

View File

@@ -22,8 +22,8 @@ describe('<DuplicatedServersModal />', () => {
[[mockServer(), mockServer(), mockServer()], 3], [[mockServer(), mockServer(), mockServer()], 3],
[[mockServer(), mockServer(), mockServer(), mockServer()], 4], [[mockServer(), mockServer(), mockServer(), mockServer()], 4],
])('renders expected amount of items', async (duplicatedServers, expectedItems) => { ])('renders expected amount of items', async (duplicatedServers, expectedItems) => {
const page = await setUp(duplicatedServers); const screen = await setUp(duplicatedServers);
expect(page.getByRole('listitem')).toHaveLength(expectedItems); expect(screen.getByRole('listitem')).toHaveLength(expectedItems);
}); });
it.each([ it.each([
@@ -48,13 +48,13 @@ describe('<DuplicatedServersModal />', () => {
}, },
], ],
])('renders expected texts based on amount of servers', async (duplicatedServers, assertions) => { ])('renders expected texts based on amount of servers', async (duplicatedServers, assertions) => {
const page = await setUp(duplicatedServers); const screen = await setUp(duplicatedServers);
await expect.element(page.getByRole('heading')).toHaveTextContent(assertions.header); await expect.element(screen.getByRole('heading')).toHaveTextContent(assertions.header);
await expect.element(page.getByText(assertions.firstParagraph)).toBeInTheDocument(); await expect.element(screen.getByText(assertions.firstParagraph)).toBeInTheDocument();
await expect.element(page.getByText(assertions.lastParagraph)).toBeInTheDocument(); await expect.element(screen.getByText(assertions.lastParagraph)).toBeInTheDocument();
await expect.element(page.getByRole('button', { name: assertions.discardBtn })).toBeInTheDocument(); await expect.element(screen.getByRole('button', { name: assertions.discardBtn })).toBeInTheDocument();
await expect.element(page.getByRole('button', { name: assertions.confirmButton })).toBeInTheDocument(); await expect.element(screen.getByRole('button', { name: assertions.confirmButton })).toBeInTheDocument();
}); });
it.each([ it.each([
@@ -62,19 +62,19 @@ describe('<DuplicatedServersModal />', () => {
[[mockServer({ url: 'url', apiKey: 'apiKey' })]], [[mockServer({ url: 'url', apiKey: 'apiKey' })]],
[[mockServer({ url: 'url_1', apiKey: 'apiKey_1' }), mockServer({ url: 'url_2', apiKey: 'apiKey_2' })]], [[mockServer({ url: 'url_1', apiKey: 'apiKey_1' }), mockServer({ url: 'url_2', apiKey: 'apiKey_2' })]],
])('displays provided server data', async (duplicatedServers) => { ])('displays provided server data', async (duplicatedServers) => {
const page = await setUp(duplicatedServers); const screen = await setUp(duplicatedServers);
if (duplicatedServers.length === 0) { if (duplicatedServers.length === 0) {
await expect.element(page.getByRole('listitem')).not.toBeInTheDocument(); await expect.element(screen.getByRole('listitem')).not.toBeInTheDocument();
} else if (duplicatedServers.length === 1) { } else if (duplicatedServers.length === 1) {
const [firstItem, secondItem] = page.getByRole('listitem').elements(); const [firstItem, secondItem] = screen.getByRole('listitem').elements();
await expect.element(firstItem).toHaveTextContent(`URL: ${duplicatedServers[0].url}`); await expect.element(firstItem).toHaveTextContent(`URL: ${duplicatedServers[0].url}`);
await expect.element(secondItem).toHaveTextContent(`API key: ${duplicatedServers[0].apiKey}`); await expect.element(secondItem).toHaveTextContent(`API key: ${duplicatedServers[0].apiKey}`);
} else { } else {
expect.assertions(duplicatedServers.length); expect.assertions(duplicatedServers.length);
await Promise.all( await Promise.all(
page screen
.getByRole('listitem') .getByRole('listitem')
.elements() .elements()
.map((item, index) => { .map((item, index) => {
@@ -86,18 +86,18 @@ describe('<DuplicatedServersModal />', () => {
}); });
it('invokes onClose when appropriate button is clicked', async () => { it('invokes onClose when appropriate button is clicked', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(onClose).not.toHaveBeenCalled(); expect(onClose).not.toHaveBeenCalled();
await user.click(page.getByRole('button', { name: 'Discard' })); await user.click(screen.getByRole('button', { name: 'Discard' }));
expect(onClose).toHaveBeenCalled(); expect(onClose).toHaveBeenCalled();
}); });
it('invokes onConfirm when appropriate button is clicked', async () => { it('invokes onConfirm when appropriate button is clicked', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(onConfirm).not.toHaveBeenCalled(); expect(onConfirm).not.toHaveBeenCalled();
await user.click(page.getByRole('button', { name: 'Save duplicate' })); await user.click(screen.getByRole('button', { name: 'Save duplicate' }));
expect(onConfirm).toHaveBeenCalled(); expect(onConfirm).toHaveBeenCalled();
}); });
}); });

View File

@@ -19,11 +19,11 @@ describe('<ImportServersBtn />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('shows tooltip on button hover', async () => { it('shows tooltip on button hover', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await expect.element(page.getByText('You can create servers by importing a CSV file')).not.toBeInTheDocument(); await expect.element(screen.getByText('You can create servers by importing a CSV file')).not.toBeInTheDocument();
await user.hover(page.getByRole('button')); await user.hover(screen.getByRole('button'));
await expect.element(page.getByText('You can create servers by importing a CSV file')).toBeInTheDocument(); await expect.element(screen.getByText('You can create servers by importing a CSV file')).toBeInTheDocument();
}); });
it.each([ it.each([
@@ -31,8 +31,10 @@ describe('<ImportServersBtn />', () => {
['foo', 'foo'], ['foo', 'foo'],
['bar', 'bar'], ['bar', 'bar'],
])('allows a class name to be provided', async (providedClassName, expectedClassName) => { ])('allows a class name to be provided', async (providedClassName, expectedClassName) => {
const page = await setUp({ className: providedClassName }); const screen = await setUp({ className: providedClassName });
await expect.element(page.getByRole('button')).toHaveAttribute('class', expect.stringContaining(expectedClassName)); await expect
.element(screen.getByRole('button'))
.toHaveAttribute('class', expect.stringContaining(expectedClassName));
}); });
it.each([ it.each([
@@ -40,14 +42,14 @@ describe('<ImportServersBtn />', () => {
['foo', 'foo'], ['foo', 'foo'],
['bar', 'bar'], ['bar', 'bar'],
])('has expected text', async (children, expectedText) => { ])('has expected text', async (children, expectedText) => {
const page = await setUp({ children }); const screen = await setUp({ children });
await expect.element(page.getByRole('button')).toHaveTextContent(expectedText); await expect.element(screen.getByRole('button')).toHaveTextContent(expectedText);
}); });
it('imports servers when file input changes', async () => { it('imports servers when file input changes', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
await user.upload(page.getByTestId('csv-file-input'), csvFile); await user.upload(screen.getByTestId('csv-file-input'), csvFile);
expect(importServersFromFile).toHaveBeenCalledTimes(1); expect(importServersFromFile).toHaveBeenCalledTimes(1);
}); });
@@ -67,19 +69,19 @@ describe('<ImportServersBtn />', () => {
id: 'existingserver-s.test', id: 'existingserver-s.test',
}; };
const newServer: ServerData = { name: 'newServer', url: 'http://s.test/newUrl', apiKey: 'newApiKey' }; const newServer: ServerData = { name: 'newServer', url: 'http://s.test/newUrl', apiKey: 'newApiKey' };
const { user, store, ...page } = await setUp({}, { [existingServer.id]: existingServer }); const { user, store, ...screen } = await setUp({}, { [existingServer.id]: existingServer });
importServersFromFile.mockResolvedValue([existingServerData, newServer]); importServersFromFile.mockResolvedValue([existingServerData, newServer]);
await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).not.toBeInTheDocument();
await user.upload(page.getByTestId('csv-file-input'), csvFile); await user.upload(screen.getByTestId('csv-file-input'), csvFile);
// Once the file is uploaded, non-duplicated servers are immediately created // Once the file is uploaded, non-duplicated servers are immediately created
const { servers } = store.getState(); const { servers } = store.getState();
expect(Object.keys(servers)).toHaveLength(2); expect(Object.keys(servers)).toHaveLength(2);
await expect.element(page.getByRole('dialog')).toBeInTheDocument(); await expect.element(screen.getByRole('dialog')).toBeInTheDocument();
await user.click(page.getByRole('button', { name: btnName })); await user.click(screen.getByRole('button', { name: btnName }));
// If duplicated servers are saved, there's one extra server creation // If duplicated servers are saved, there's one extra server creation
if (savesDuplicatedServers) { if (savesDuplicatedServers) {

View File

@@ -15,36 +15,36 @@ describe('<ServerForm />', () => {
it('passes a11y checks', () => checkAccessibility(setUp())); it('passes a11y checks', () => checkAccessibility(setUp()));
it('renders inputs', async () => { it('renders inputs', async () => {
const page = await setUp(); const screen = await setUp();
await expect.element(page.getByLabelText(/^Name/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^Name/)).toBeInTheDocument();
await expect.element(page.getByLabelText(/^URL/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^URL/)).toBeInTheDocument();
await expect.element(page.getByLabelText(/^API key/)).toBeInTheDocument(); await expect.element(screen.getByLabelText(/^API key/)).toBeInTheDocument();
await expect.element(page.getByText('Something')).toBeInTheDocument(); await expect.element(screen.getByText('Something')).toBeInTheDocument();
await expect.element(page.getByText('Advanced options')).toBeInTheDocument(); await expect.element(screen.getByText('Advanced options')).toBeInTheDocument();
}); });
it('invokes submit callback when submit event is triggered', async () => { it('invokes submit callback when submit event is triggered', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
expect(onSubmit).not.toHaveBeenCalled(); expect(onSubmit).not.toHaveBeenCalled();
// Fill required elements so the form can be submitted // Fill required elements so the form can be submitted
await user.type(page.getByLabelText(/^Name/), 'The server'); await user.type(screen.getByLabelText(/^Name/), 'The server');
await user.type(page.getByLabelText(/^URL/), 'https://example.com'); await user.type(screen.getByLabelText(/^URL/), 'https://example.com');
await user.type(page.getByLabelText(/^API key/), '123456'); await user.type(screen.getByLabelText(/^API key/), '123456');
await user.click(page.getByRole('button', { name: 'Submit' })); await user.click(screen.getByRole('button', { name: 'Submit' }));
expect(onSubmit).toHaveBeenCalled(); expect(onSubmit).toHaveBeenCalled();
}); });
it('shows advanced options', async () => { it('shows advanced options', async () => {
const { user, ...page } = await setUp(); const { user, ...screen } = await setUp();
const forwardCredentialsLabel = 'Forward credentials to this server on every request.'; const forwardCredentialsLabel = 'Forward credentials to this server on every request.';
await expect.element(page.getByLabelText(forwardCredentialsLabel)).not.toBeInTheDocument(); await expect.element(screen.getByLabelText(forwardCredentialsLabel)).not.toBeInTheDocument();
await user.click(page.getByText('Advanced options')); await user.click(screen.getByText('Advanced options'));
await expect.element(page.getByLabelText(forwardCredentialsLabel)).toBeInTheDocument(); await expect.element(screen.getByLabelText(forwardCredentialsLabel)).toBeInTheDocument();
}); });
}); });