Skip to content

Commit

Permalink
renaming MapModal comp and adding error message to modal
Browse files Browse the repository at this point in the history
  • Loading branch information
Taylor Grafft authored and Taylor Grafft committed Jan 25, 2024
1 parent a857ea6 commit a1492b0
Show file tree
Hide file tree
Showing 14 changed files with 531 additions and 328 deletions.
19 changes: 0 additions & 19 deletions react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"@testing-library/react": "^13.4.0",
"@types/leaflet.markercluster": "^1.5.1",
"axios": "^1.6.2",
"bootstrap": "^5.3.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1",
Expand Down
2 changes: 1 addition & 1 deletion react/src/__fixtures__/authStateFixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AuthState } from '../types';

export const authenticatedUser: AuthState = {
user: {
name: 'user',
username: 'user',
email: '[email protected]',
},
token: {
Expand Down
27 changes: 27 additions & 0 deletions react/src/components/CreateMapModal/CreateMapModal.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
:global(.btn-close) {
background: transparent;
border: none;
font-size: 1.5rem;
cursor: pointer;
}

:global(.btn-close::after) {
content: '\00D7'; /* Unicode character for 'X' */
}

.custom-error-message {
margin-top: 0.25rem;
font-size: 0.8em;
color: #dc3545;
}

.form-check-label {
font-style: italic;
}

.btn-close-custom {
background: transparent;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
250 changes: 250 additions & 0 deletions react/src/components/CreateMapModal/CreateMapModal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
import React from 'react';
import {
render,
cleanup,
fireEvent,
screen,
waitFor,
} from '@testing-library/react';
import CreateMapModal from './CreateMapModal';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import authReducer from '../../redux/authSlice';
import { geoapi } from '../../redux/api/geoapi';
import { BrowserRouter as Router } from 'react-router-dom';

describe('CreateMapModal', () => {
const dummyOnSubmit = jest.fn();

const mockUsername = 'mockUser';
const mockEmail = '[email protected]';

const mockToken = {
token: 'mockTokenValue',
expires: Date.now() + 1000 * 60 * 60,
};

const mockStore = configureStore({
reducer: {
auth: authReducer,
[geoapi.reducerPath]: geoapi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(geoapi.middleware),
preloadedState: {
auth: {
user: { username: mockUsername, email: mockEmail },
token: mockToken,
},
},
});
const renderComponent = () => {
return render(
<Provider store={mockStore}>
<Router>
<CreateMapModal
isOpen={true}
toggle={() => {
//no op
}}
onSubmit={dummyOnSubmit}
isCreating={false}
/>
</Router>
</Provider>
);
};

afterEach(() => {
cleanup();
});

test('renders the modal when open', () => {
renderComponent();
expect(screen.getByText(/Create a New Map/)).toBeTruthy();
});

test('allows form field interaction and submission', async () => {
renderComponent();
// Interact with name field
const nameInput = screen.getByTestId('name-input') as HTMLInputElement;
fireEvent.change(nameInput, { target: { value: 'Test Map' } });
expect(nameInput.value).toBe('Test Map');

// Interact with description field
const descriptionInput = screen.getByLabelText(
/Description/
) as HTMLInputElement;
fireEvent.change(descriptionInput, {
target: { value: 'Test Description' },
});
expect(descriptionInput.value).toBe('Test Description');

// Interact with custom file name field
const customFileNameInput = screen.getByLabelText(
/Custom File Name/
) as HTMLInputElement;
fireEvent.change(customFileNameInput, { target: { value: 'test-file' } });
expect(customFileNameInput.value).toBe('test-file');

// Prepare expected data based on the form structure
const expectedData = {
observable: false,
watch_content: false,
project: {
name: 'Test Map',
description: 'Test Description',
system_file: 'test-file',
system_id: 'designsafe.storage.default',
system_path: `/${mockUsername}`,
},
};

// Submit form
fireEvent.click(screen.getByRole('button', { name: /Create/ }));
await waitFor(() => {
expect(dummyOnSubmit).toHaveBeenCalledWith(
expectedData,
expect.anything(),
expect.anything()
);
});
});
test('specific 409 error message is displayed', async () => {
const mockOnSubmitWith409Error = jest
.fn()
.mockImplementation((projectData, actions, setError) => {
const error = { response: { status: 409 } };
console.error('Error creating project:', error);
setError('That folder is already syncing with a different map.');
actions.setSubmitting(false);
});

render(
<Provider store={mockStore}>
<Router>
<CreateMapModal
isOpen={true}
toggle={() => {
//no op
}}
onSubmit={mockOnSubmitWith409Error}
isCreating={false}
/>
</Router>
</Provider>
);

// Interact with the form fields
fireEvent.change(screen.getByTestId('name-input'), {
target: { value: 'Test Map' },
});
fireEvent.change(screen.getByLabelText('Description'), {
target: { value: 'Test Description' },
});
fireEvent.change(screen.getByLabelText('Custom File Name'), {
target: { value: 'test-file' },
});

// Submit form
fireEvent.click(screen.getByRole('button', { name: /Create/ }));

// Wait for the error message to appear
await waitFor(() => {
expect(
screen.getByText('That folder is already syncing with a different map.')
).toBeTruthy();
});
});

test('specific 500 error message is displayed', async () => {
const mockOnSubmitWith500Error = jest
.fn()
.mockImplementation((projectData, actions, setError) => {
const error = { response: { status: 500 } };
console.error('Error creating project:', error);
setError('Internal server error. Please contact support.');
actions.setSubmitting(false);
});

render(
<Provider store={mockStore}>
<Router>
<CreateMapModal
isOpen={true}
toggle={() => {
//no op
}}
onSubmit={mockOnSubmitWith500Error}
isCreating={false}
/>
</Router>
</Provider>
);

// Interact with the form fields
fireEvent.change(screen.getByTestId('name-input'), {
target: { value: 'Test Map' },
});
fireEvent.change(screen.getByLabelText('Description'), {
target: { value: 'Test Description' },
});
fireEvent.change(screen.getByLabelText('Custom File Name'), {
target: { value: 'test-file' },
});

// Submit form
fireEvent.click(screen.getByRole('button', { name: /Create/ }));

// Wait for the error message to appear
await waitFor(() => {
expect(
screen.getByText('Internal server error. Please contact support.')
).toBeTruthy();
});
});

test('generic error message is displayed on other submission errors', async () => {
const mockOnSubmitWithGenericError = jest
.fn()
.mockImplementation((projectData, actions, setError) => {
setError('Something went wrong. Please contact support.');
actions.setSubmitting(false);
});

render(
<Provider store={mockStore}>
<Router>
<CreateMapModal
isOpen={true}
toggle={() => {
//no op
}}
onSubmit={mockOnSubmitWithGenericError}
isCreating={false}
/>
</Router>
</Provider>
);

// Interact with the form fields
fireEvent.change(screen.getByTestId('name-input'), {
target: { value: 'Test Map' },
});
fireEvent.change(screen.getByLabelText('Description'), {
target: { value: 'Test Description' },
});
fireEvent.change(screen.getByLabelText('Custom File Name'), {
target: { value: 'test-file' },
});

// Submit form
fireEvent.click(screen.getByRole('button', { name: /Create/ }));

await waitFor(() => {
expect(
screen.getByText('Something went wrong. Please contact support.')
).toBeTruthy();
});
});
});
Loading

0 comments on commit a1492b0

Please sign in to comment.