Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cb 5277 test components #2721

Merged
merged 4 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions webapp/packages/core-blocks/src/Cell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { waitFor } from '@testing-library/react';

import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { Cell } from './Cell';

const app = createApp();

describe('Cell', () => {
it('should render children correctly', async () => {
const { getByText } = renderInApp(<Cell>Test Children</Cell>, app);
const text = await waitFor(() => getByText('Test Children'));

expect(text).toBeInTheDocument();
});

it('should render before element correctly', async () => {
const { getByText } = renderInApp(<Cell before={<span>Before Element</span>}>Test Children</Cell>, app);

const beforeText = await waitFor(() => getByText('Before Element'));
expect(beforeText).toBeInTheDocument();
});

it('should render after element correctly', async () => {
const { getByText } = renderInApp(<Cell after={<span>After Element</span>}>Test Children</Cell>, app);

const afterText = await waitFor(() => getByText('After Element'));
expect(afterText).toBeInTheDocument();
});

it('should render after and before elements correctly', async () => {
const { getByText } = renderInApp(
<Cell before={<span>Before Element</span>} after={<span>After Element</span>}>
Test Children
</Cell>,
app,
);

const afterText = await waitFor(() => getByText('After Element'));
const beforeText = await waitFor(() => getByText('Before Element'));

expect(beforeText).toBeInTheDocument();
expect(afterText).toBeInTheDocument();
});

it('should render description element correctly', async () => {
const { getByText } = renderInApp(<Cell description={<span>Description Element</span>}>Test Children</Cell>, app);

const description = await waitFor(() => getByText('Description Element'));
expect(description).toBeInTheDocument();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also check in new test case that ripple, big classnames are present here

});
63 changes: 63 additions & 0 deletions webapp/packages/core-blocks/src/Link.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { fireEvent, queryByAttribute, waitFor } from '@testing-library/react';

import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { Link } from './Link';

const app = createApp();

describe('Link', () => {
it('should render link and children correctly', async () => {
const { getByText } = renderInApp(<Link href="#">Test Link</Link>, app);
const linkElement = await waitFor(() => getByText('Test Link'));

expect(linkElement.tagName).toBe('A');
expect(linkElement).toBeInTheDocument();
});

it('should display the indicator icon when indicator is true', async () => {
const { container } = renderInApp(
<Link href="#" indicator>
Test Link
</Link>,
app,
);

const icon = await waitFor(() => queryByAttribute('href', container, /external-link/i));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

searching by className here seems a bit easier than by attribute

expect(icon).toBeInTheDocument();
});

it('should apply the className correctly', async () => {
const { getByText } = renderInApp(
<Link href="#" className="custom-class">
Test Link
</Link>,
app,
);

const linkContainer = await waitFor(() => getByText('Test Link').closest('div'));
expect(linkContainer).toHaveClass('custom-class');
});

it('should handle onClick event', async () => {
const handleClick = jest.fn();
const { getByText } = renderInApp(
<Link href="#" onClick={handleClick}>
Test Link
</Link>,
app,
);

const linkElement = await waitFor(() => getByText('Test Link'));
fireEvent.click(linkElement);

expect(handleClick).toHaveBeenCalled();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the case where there is only a href and if you click on it - it leads you with this link

});
64 changes: 64 additions & 0 deletions webapp/packages/core-blocks/src/StatusMessage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { fireEvent, queryByAttribute, waitFor } from '@testing-library/react';

import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { ENotificationType } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { StatusMessage } from './StatusMessage';

const app = createApp(coreLocalizationManifest, coreDialogsManifest);

describe('StatusMessage', () => {
it('should display an error icon and message when type is error', async () => {
const message = 'test_error';
const { container, getByTitle } = renderInApp(<StatusMessage message={message} type={ENotificationType.Error} />, app);
const title = await waitFor(() => getByTitle(message));
const icon = await waitFor(() => queryByAttribute('src', container, /error/i));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not by className?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if possible please change it everywhere


expect(title).toBeInTheDocument();
expect(icon).toBeInTheDocument();
});

it('should display a success icon and message when type is success', async () => {
const message = 'test_success';
const { container, getByTitle } = renderInApp(<StatusMessage message={message} type={ENotificationType.Success} />, app);
const title = await waitFor(() => getByTitle(message));
const icon = await waitFor(() => queryByAttribute('src', container, /success/i));

expect(title).toBeInTheDocument();
expect(icon).toBeInTheDocument();
});

it('should display an error message when no message is provided', async () => {
const { getByText } = renderInApp(<StatusMessage exception={new Error('Test error')} />, app);
const message = await waitFor(() => getByText('Test error'));

expect(message).toBeInTheDocument();
});

it('should call onShowDetails when link is clicked', async () => {
const onShowDetails = jest.fn();
const message = 'test_message_with_details';
const { getByText } = renderInApp(<StatusMessage message={message} onShowDetails={onShowDetails} />, app);
const link = await waitFor(() => getByText(message));

fireEvent.click(link);
expect(onShowDetails).toHaveBeenCalled();
});

it('should display multiple messages joined by comma', async () => {
const messages = ['message_one', 'message_two'];
const { getByText } = renderInApp(<StatusMessage message={messages} />, app);
const message = await waitFor(() => getByText('message_one, message_two'));

expect(message).toBeInTheDocument();
});
});
40 changes: 40 additions & 0 deletions webapp/packages/core-blocks/src/Text.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { waitFor } from '@testing-library/react';

import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { Text } from './Text';

const app = createApp();

describe('Text Component', () => {
it('renders children correctly', async () => {
const { getByText } = renderInApp(<Text>Hello World</Text>, app);
const text = await waitFor(() => getByText('Hello World'));
expect(text).toBeInTheDocument();
});

it('applies custom className', () => {
const { container } = renderInApp(<Text className="custom-class">Hello World</Text>, app);
expect(container.getElementsByClassName('custom-class')).toHaveLength(1);
});

it('passes HTML attributes correctly', () => {
const { container } = renderInApp(
<Text id="custom-id" data-testid="custom-testid">
Hello World
</Text>,
app,
);

const div = container.firstChild;
expect(div).toHaveAttribute('id', 'custom-id');
expect(div).toHaveAttribute('data-testid', 'custom-testid');
});
});
4 changes: 1 addition & 3 deletions webapp/packages/core-blocks/src/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
*/
import { observer } from 'mobx-react-lite';

interface Props extends React.HTMLAttributes<HTMLDivElement> {}

export const Text: React.FC<Props> = observer(function Text({ children, ...rest }) {
export const Text: React.FC<React.HTMLAttributes<HTMLDivElement>> = observer(function Text({ children, ...rest }) {
return <div {...rest}>{children}</div>;
});
27 changes: 27 additions & 0 deletions webapp/packages/core-blocks/src/TextPlaceholder.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { waitFor } from '@testing-library/react';

import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { TextPlaceholder } from './TextPlaceholder';

const app = createApp();

describe('TextPlaceholder Component', () => {
it('renders children correctly', async () => {
const { getByText } = renderInApp(<TextPlaceholder>Hello World</TextPlaceholder>, app);
const text = await waitFor(() => getByText('Hello World'));
expect(text).toBeInTheDocument();
});

it('applies custom className', () => {
const { container } = renderInApp(<TextPlaceholder className="custom-class">Hello World</TextPlaceholder>, app);
expect(container.getElementsByClassName('custom-class')).toHaveLength(1);
});
});
42 changes: 42 additions & 0 deletions webapp/packages/core-blocks/src/TimerIcon.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { queryByAttribute, waitFor } from '@testing-library/react';

import { createApp, renderInApp } from '@cloudbeaver/tests-runner';

import { TimerIcon } from './TimerIcon';

const app = createApp();

describe('TimerIcon', () => {
it('renders correctly with state "play" and interval 30', async () => {
const { getByText, container } = renderInApp(<TimerIcon state="play" interval={30} />, app);
const text = await waitFor(() => getByText('30'));
const name = await waitFor(() => queryByAttribute('href', container, '/icons/timer-play_m.svg#root'));

expect(name).toBeInTheDocument();
expect(text).toBeInTheDocument();
});

it('renders correctly with state "stop" and interval 60', async () => {
const { getByText, container } = renderInApp(<TimerIcon state="stop" interval={60} />, app);
const text = await waitFor(() => getByText('60'));
const name = await waitFor(() => queryByAttribute('href', container, '/icons/timer-stop_m.svg#root'));

expect(name).toBeInTheDocument();
expect(text).toBeInTheDocument();
});

it('passes HTML attributes correctly', () => {
const { container } = renderInApp(<TimerIcon state="play" interval={30} id="custom-id" data-testid="custom-testid" />, app);

const div = container.firstChild;
expect(div).toHaveAttribute('id', 'custom-id');
expect(div).toHaveAttribute('data-testid', 'custom-testid');
});
});
4 changes: 2 additions & 2 deletions webapp/packages/core-blocks/src/TimerIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type React from 'react';

import { Icon } from './Icon';
import { s } from './s';
import style from './TimerIcon.module.css';
import classes from './TimerIcon.module.css';
import { useS } from './useS';

interface Props {
Expand All @@ -19,7 +19,7 @@ interface Props {
}

export const TimerIcon = observer<Props & React.ButtonHTMLAttributes<HTMLDivElement>>(function TimerIcon({ state, interval, ...rest }) {
const styles = useS(style);
const styles = useS(classes);

return (
<div className={s(styles, { timer: true })} {...rest}>
Expand Down
Loading