Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0abd910
added test folder structure and implemented some tests for the utils …
uiysg Feb 22, 2026
49aaff9
Merge pull request #215 from vitruv-tools/utils-and-hooks-test
TsotneMikadze Feb 24, 2026
8d11a0a
Refactor and enhance utility and hook tests
TsotneMikadze Feb 24, 2026
c09922f
Refactor OtpVerificationPage tests to use mock functions
TsotneMikadze Feb 24, 2026
460a103
Update OtpVerificationPage tests for improved validation checks
TsotneMikadze Feb 24, 2026
9c2ed2a
Fix test assertion in OtpVerificationPage for mock function usage
TsotneMikadze Feb 24, 2026
5876286
Merge pull request #218 from vitruv-tools/tests-for-pages
TsotneMikadze Feb 24, 2026
ebf0454
Enhance OtpVerificationPage tests with additional scenarios
TsotneMikadze Feb 24, 2026
d7eb524
Merge pull request #220 from vitruv-tools/test-for-components
TsotneMikadze Feb 26, 2026
d4ebc6f
Refactor UML relationship rendering and merge point logic
TsotneMikadze Mar 3, 2026
5750466
create reaction file immediately on edge creation
uiysg Mar 4, 2026
6ac1c56
after changing the closing behaviour of the codeEditor the one test n…
uiysg Mar 4, 2026
9f9e3cb
refactored code to solve build warning
uiysg Mar 4, 2026
426912b
added tests to cover new code
uiysg Mar 5, 2026
1a6b9ee
added some mor etetss to cover more code in the flowcanvas
uiysg Mar 5, 2026
8493c2b
corrected the mocking in flowcanvas test
uiysg Mar 5, 2026
d16342b
added more tests to raise test coverage
uiysg Mar 5, 2026
b70bdb6
Merge pull request #226 from vitruv-tools/UML-issue
TsotneMikadze Mar 6, 2026
6ea319b
solve sonar issues
uiysg Mar 6, 2026
4084070
resolved sonar issue 'unexpected negation'
uiysg Mar 6, 2026
ff83f6e
resolved build error
uiysg Mar 6, 2026
16b6e86
Merge pull request #227 from vitruv-tools/fix-code-editor-window
uiysg Mar 6, 2026
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
18 changes: 18 additions & 0 deletions src/__mocks__/reactflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const useNodesState = (initial: any[]) => {
const [nodes, setNodes] = React.useState<any[]>(initial);
return [nodes, setNodes, jest.fn()] as const;
};

const useEdgesState = (initial: any[]) => {
const [edges, setEdges] = React.useState<any[]>(initial);
return [edges, setEdges, jest.fn()] as const;
};

module.exports = {
__esModule: true,
useNodesState,
useEdgesState,
default: {},
};
21 changes: 21 additions & 0 deletions src/__tests__/components/auth/AuthPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

const mockAuthPage = jest.fn(() => <div>AuthPage mock</div>);

jest.mock('../../../components/auth/AuthPage', () => ({
__esModule: true,
AuthPage: (props: any) => mockAuthPage(props),
}));

import { AuthPage } from '../../../components/auth/AuthPage';

describe('AuthPage', () => {
it('renders AuthPage with default props', async () => {
render(<AuthPage />);

expect(mockAuthPage).toHaveBeenCalled();
});
});

17 changes: 17 additions & 0 deletions src/__tests__/components/auth/KeycloakRedirect.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { KeycloakRedirect } from '../../../components/auth/KeycloakRedirect';

describe('KeycloakRedirect', () => {
it('renders redirect message', () => {
render(<KeycloakRedirect />);

expect(
screen.getByText(/Redirecting to Keycloak authentication/i),
).toBeInTheDocument();
expect(
screen.getByText(/If you are not redirected automatically/i),
).toBeInTheDocument();
});
});

148 changes: 148 additions & 0 deletions src/__tests__/components/auth/SignIn.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SignIn } from '../../../components/auth/SignIn';

jest.mock('../../../contexts/AuthContext', () => ({
useAuth: () => ({
signIn: mockSignIn,
}),
}));

jest.mock('../../../services/api', () => ({
apiService: {
forgotPassword: jest.fn(),
},
}));

const mockSignIn = jest.fn();
const mockOnSignInSuccess = jest.fn();
const mockOnSwitchToSignUp = jest.fn();

describe('SignIn component', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('renders username, password fields and sign in button', () => {
render(
<SignIn
onSignInSuccess={mockOnSignInSuccess}
onSwitchToSignUp={mockOnSwitchToSignUp}
/>,
);

expect(screen.getByLabelText(/Username or Email/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Password/i)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Sign In/i })).toBeInTheDocument();
});

it('shows validation error when submitting with empty fields', async () => {
render(
<SignIn
onSignInSuccess={mockOnSignInSuccess}
onSwitchToSignUp={mockOnSwitchToSignUp}
/>,
);

await userEvent.click(screen.getByRole('button', { name: /Sign In/i }));

expect(
await screen.findByText(/Please fill in all fields/i),
).toBeInTheDocument();
expect(mockSignIn).not.toHaveBeenCalled();
});

it('calls signIn and onSignInSuccess on successful submit', async () => {
const fakeUser = { id: '1', emailVerified: true };
mockSignIn.mockResolvedValueOnce(fakeUser);

render(
<SignIn
onSignInSuccess={mockOnSignInSuccess}
onSwitchToSignUp={mockOnSwitchToSignUp}
/>,
);

await userEvent.type(
screen.getByLabelText(/Username or Email/i),
'john@example.com',
);
await userEvent.type(screen.getByLabelText(/Password/i), 'password123!');
await userEvent.click(screen.getByRole('button', { name: /Sign In/i }));

await waitFor(() => {
expect(mockSignIn).toHaveBeenCalledWith(
'john@example.com',
'password123!',
);
});
expect(mockOnSignInSuccess).toHaveBeenCalledWith(fakeUser);
});

it('shows error when signIn throws', async () => {
mockSignIn.mockRejectedValueOnce(new Error('Invalid credentials'));

render(
<SignIn
onSignInSuccess={mockOnSignInSuccess}
onSwitchToSignUp={mockOnSwitchToSignUp}
/>,
);

await userEvent.type(
screen.getByLabelText(/Username or Email/i),
'john@example.com',
);
await userEvent.type(screen.getByLabelText(/Password/i), 'wrong');
await userEvent.click(screen.getByRole('button', { name: /Sign In/i }));

expect(
await screen.findByText(/Invalid credentials/i),
).toBeInTheDocument();
});

it('opens forgot password modal and validates email', async () => {
const { apiService } = jest.requireMock('../../../services/api') as {
apiService: { forgotPassword: jest.Mock };
};

render(
<SignIn
onSignInSuccess={mockOnSignInSuccess}
onSwitchToSignUp={mockOnSwitchToSignUp}
/>,
);

await userEvent.click(
screen.getByRole('button', { name: /Forgot your password\?/i }),
);

const emailInput = await screen.findByLabelText(/Registered Email Address/i);
const submitButton = screen.getByRole('button', {
name: /Submit Request/i,
});

// Invalid email
await userEvent.type(emailInput, 'not-an-email');
await userEvent.click(submitButton);
expect(
await screen.findByText(/Please enter a valid email address/i),
).toBeInTheDocument();

// Valid email -> API is called
apiService.forgotPassword.mockResolvedValueOnce({
message: 'Reset email sent',
data: {},
});

await userEvent.clear(emailInput);
await userEvent.type(emailInput, 'user@example.com');
await userEvent.click(submitButton);

await waitFor(() => {
expect(apiService.forgotPassword).toHaveBeenCalledWith('user@example.com');
});
});
});

118 changes: 118 additions & 0 deletions src/__tests__/components/auth/SignUp.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from 'react';
import { render, screen, waitFor, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { SignUp } from '../../../components/auth/SignUp';

const mockSignUp = jest.fn();

jest.mock('../../../contexts/AuthContext', () => ({
useAuth: () => ({
signUp: mockSignUp,
}),
}));

describe('SignUp component', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.useRealTimers();
});

it('renders all required fields and submit button', () => {
render(
<SignUp
onSignUpSuccess={jest.fn()}
onSwitchToSignIn={jest.fn()}
/>,
);

expect(screen.getByLabelText(/First Name \*/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Last Name \*/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Username \*/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Email \*/i)).toBeInTheDocument();
expect(
screen.getByPlaceholderText(/Create a strong password/i),
).toBeInTheDocument();
expect(
screen.getByPlaceholderText(/Confirm your password/i),
).toBeInTheDocument();
expect(
screen.getByRole('button', { name: /Create Account/i }),
).toBeInTheDocument();
});

it('shows validation error for too short first name', async () => {
render(
<SignUp
onSignUpSuccess={jest.fn()}
onSwitchToSignIn={jest.fn()}
/>,
);

await userEvent.type(screen.getByLabelText(/First Name \*/i), 'A');
await userEvent.type(screen.getByLabelText(/Last Name \*/i), 'Doe');
await userEvent.type(screen.getByLabelText(/Username \*/i), 'john');
await userEvent.type(screen.getByLabelText(/Email \*/i), 'john@example.com');
await userEvent.type(
screen.getByPlaceholderText(/Create a strong password/i),
'Password1!',
);
await userEvent.type(
screen.getByPlaceholderText(/Confirm your password/i),
'Password1!',
);

await userEvent.click(
screen.getByRole('button', { name: /Create Account/i }),
);

expect(
await screen.findByText(/First name is required \(at least 2 characters\)/i),
).toBeInTheDocument();
expect(mockSignUp).not.toHaveBeenCalled();
});

it('calls signUp and onSignUpSuccess on valid submit', async () => {
jest.useFakeTimers();
const onSignUpSuccess = jest.fn();
mockSignUp.mockResolvedValueOnce(undefined);

render(
<SignUp
onSignUpSuccess={onSignUpSuccess}
onSwitchToSignIn={jest.fn()}
/>,
);

await userEvent.type(screen.getByLabelText(/First Name \*/i), 'John');
await userEvent.type(screen.getByLabelText(/Last Name \*/i), 'Doe');
await userEvent.type(screen.getByLabelText(/Username \*/i), 'johndoe');
await userEvent.type(screen.getByLabelText(/Email \*/i), 'john@example.com');
await userEvent.type(
screen.getByPlaceholderText(/Create a strong password/i),
'Password1!',
);
await userEvent.type(
screen.getByPlaceholderText(/Confirm your password/i),
'Password1!',
);

await userEvent.click(
screen.getByRole('button', { name: /Create Account/i }),
);

await waitFor(() => {
expect(mockSignUp).toHaveBeenCalled();
});

expect(
await screen.findByText(/Account Created Successfully!/i),
).toBeInTheDocument();

await act(async () => {
jest.advanceTimersByTime(2000);
});

expect(onSignUpSuccess).toHaveBeenCalled();
});
});

Loading
Loading