Skip to content

Commit

Permalink
Merge pull request #137 from bluewave-labs/116-implement-github-actio…
Browse files Browse the repository at this point in the history
…ns-integrate-tests-check-and-pages-on-github-

New tests, Create account page refactoring.
  • Loading branch information
uparkalau authored Aug 9, 2024
2 parents 566a3d7 + 6ff60de commit 7749ea2
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 180 deletions.
10 changes: 5 additions & 5 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import HintDefaultPage from "./scenes/hints/HintDefaultPage";
import CreatePopupPage from "./scenes/popup/CreatePopupPage";

function App() {
// const { isLoggedIn } = useAuth(); //commented out for testing
const isLoggedIn = true;
const { isLoggedIn } = useAuth(); //commented out for testing
// const isLoggedIn = true;
return (
<>
<Routes>

{/* <Route path="/" element={isLoggedIn ? <Private Component={Home} /> : <LoginPage />} /> commented out for testing */}
{/* <Route path="/home" element={<Private Component={Home} />} /> */}
<Route path="/" element={isLoggedIn ? <Private Component={Home} /> : <LoginPage />} />
<Route path="/home" element={<Private Component={Home} />} />
<Route path="/" element={isLoggedIn ? <Home/> : <LoginPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<CreateAccountPage />} />
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
<Route path="/reset-password" element={<PasswordResetPage />} />
Expand Down
54 changes: 0 additions & 54 deletions frontend/src/components/ButtonGroup.jsx

This file was deleted.

105 changes: 59 additions & 46 deletions frontend/src/scenes/login/CreateAccountPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function CreateAccountPage() {
const [formData, setFormData] = useState({ username: '', email: '', password: '' });
const [validation, setValidation] = useState({ isUsernameValid: false, isEmailValid: false, isPasswordValid: false });
const [passwordChecks, setPasswordChecks] = useState({ hasSpecialCharacter: false, atLeastEightCharacters: false });
const [error, setError] = useState('');
const navigate = useNavigate();

const handleInputChange = (e) => {
Expand Down Expand Up @@ -45,80 +46,92 @@ function CreateAccountPage() {
return;
}

const userData = { username: formData.username, email: formData.email, password: formData.password };

try {
const response = await signUp(formData);
console.log('Sign up successful:', response);
navigate('/');
} catch (error) {
console.error('Sign up failed:', error);
if (error.response && error.response.data) {
if (error.response.data.error === 'User already exists') {
setError('User already exists');
} else {
setError('An error occurred. Please try again.');
}
} else {
setError('An error occurred. Please check your network connection and try again.');
}
}
};

const formFields = [
{
label: 'Username*:',
name: 'username',
type: 'name',
placeholder: 'Enter your username',
isValid: validation.isUsernameValid
},
{
label: 'Email*:',
name: 'email',
type: 'email',
placeholder: 'Enter your email',
isValid: validation.isEmailValid
},
{
label: 'Password*:',
name: 'password',
type: 'password',
placeholder: 'Create your password',
isValid: validation.isPasswordValid
}
];

return (
<div className="login-container">
<h2>Create an account</h2>

{formFields.map(({ label, name, type, placeholder, isValid }) => (
<div className="form-group" key={name}>
<div className='check-div'>
{isValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label>{label}</label>
</div>
<input
type={type}
name={name}
value={formData[name]}
onChange={handleInputChange}
placeholder={placeholder}
/>
<div className="form-group">
<div className='check-div'>
{validation.isUsernameValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="username">Username*:</label>
</div>
))}
<input
id="username"
type="name"
name="username"
value={formData.username}
onChange={handleInputChange}
placeholder="Enter your username"
/>
{error && <div className="error-message">{error}</div>}
</div>

<div className="form-group">
<div className='check-div'>
{validation.isEmailValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="email">Email*:</label>
</div>
<input
id="email"
type="email"
name="email"
value={formData.email}
onChange={handleInputChange}
placeholder="Enter your email"
/>
</div>

<div className="form-group">
<div className='check-div'>
{validation.isPasswordValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="password">Password*:</label>
</div>
<input
id="password"
type="password"
name="password"
value={formData.password}
onChange={handleInputChange}
placeholder="Create your password"
/>
</div>

<div className="password-constraints">
<CheckCircleIcon style={{ color: passwordChecks.atLeastEightCharacters ? 'green' : '#D0D5DD', fontSize: '20px', marginRight: "5px" }} />
<CheckCircleIcon style={{ color: passwordChecks.atLeastEightCharacters ? 'green' : '#D0D5DD', fontSize: '20px', marginRight: '5px' }} />
Must be at least 8 characters
</div>

<div className="password-constraints">
<CheckCircleIcon style={{ color: passwordChecks.hasSpecialCharacter ? 'green' : '#D0D5DD', fontSize: '20px', marginRight: "5px" }} />
<CheckCircleIcon style={{ color: passwordChecks.hasSpecialCharacter ? 'green' : '#D0D5DD', fontSize: '20px', marginRight: '5px' }} />
Must contain one special character
</div>

<button className="create-account-button" onClick={handleSignUp}>
Get started
</button>

<GoogleSignInButton />

<div className="sign-up-link">
Already have an account? <a href="/">Log in</a>
</div>
</div>
);
}

export default CreateAccountPage;
export default CreateAccountPage;
Original file line number Diff line number Diff line change
@@ -1,62 +1,86 @@
import { describe, it, expect } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import CustomTextField from "../../../components/TextFieldComponents/CustomTextField";
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import CustomTextField from '../../../components/TextFieldComponents/CustomTextField/CustomTextField';

describe("CustomTextField", () => {
it("should render the text field with the provided label", () => {
render(<CustomTextField label="Test Label" />);
const textField = screen.getByLabelText(/test label/i);
expect(textField).toBeDefined();
describe('CustomTextField', () => {
it('renders the CustomTextField with default props', () => {
render(<CustomTextField labelText="Test Label" />);

expect(screen.getByText('Test Label')).not.toBeNull();
expect(screen.getByRole('textbox')).not.toBeNull();
});

it("should render the helper text when provided", () => {
render(<CustomTextField label="Test Label" helperText="Help text" />);
const helperText = screen.getByText(/help text/i);
expect(helperText).toBeDefined();
it('displays the correct value', () => {
render(<CustomTextField labelText="Test Label" value="Test Value" />);

expect(screen.getByDisplayValue('Test Value')).not.toBeNull();
});

it("should show an error message when error prop is true", () => {
render(
<CustomTextField
label="Test Label"
error
helperText="This is an error message"
/>
);
const errorMessage = screen.getByText(/This is an error message/i);
expect(errorMessage).toBeDefined();
const styles = getComputedStyle(errorMessage);
expect(styles.color).toBe("rgb(211, 47, 47)");
it('calls onChange when the input value changes', () => {
const handleChange = vi.fn();
render(<CustomTextField labelText="Test Label" onChange={handleChange} />);

fireEvent.change(screen.getByRole('textbox'), { target: { value: 'New Value' } });
expect(handleChange).toHaveBeenCalledWith(expect.any(Object));
});

it('displays helper text when provided', () => {
render(<CustomTextField labelText="Test Label" helperText="Helper Text" />);

expect(screen.getByText('Helper Text')).not.toBeNull();
});

it("should render start adornment when provided", () => {
render(<CustomTextField label="Test Label" startAdornment="http://" />);
const startAdornment = screen.getByText(/http:\/\//i);
expect(startAdornment).toBeDefined();
it('renders with multiline and rows props', () => {
render(<CustomTextField labelText="Test Label" multiline={true} rows={4} />);

expect(screen.getByRole('textbox').getAttribute('rows')).toBe('4');
});

it("should render end adornment when provided", () => {
it('renders with startAdornment and endAdornment', () => {
render(
<CustomTextField
label="Test Label"
endAdornment={<button>Copy</button>}
labelText="Test Label"
startAdornment={<div>Start</div>}
endAdornment={<div>End</div>}
/>
);
const endAdornment = screen.getByText(/copy/i);
expect(endAdornment).toBeDefined();

expect(screen.getByText('Start')).not.toBeNull();
expect(screen.getByText('End')).not.toBeNull();
});

it("should render chips when provided", () => {
const chips = [{ label: "Design", onDelete: () => {} }];
render(<CustomTextField label="Test Label" chips={chips} />);
const chip = screen.getByText(/design/i);
expect(chip).toBeDefined();
it('renders with chips', () => {
const chips = [{ label: 'Chip 1' }, { label: 'Chip 2' }];
render(<CustomTextField labelText="Test Label" chips={chips} />);

expect(screen.getByText('Chip 1')).not.toBeNull();
expect(screen.getByText('Chip 2')).not.toBeNull();
});

// Additional tests
it('renders with a placeholder', () => {
render(<CustomTextField labelText="Test Label" placeholder="Enter text here" />);

expect(screen.getByPlaceholderText('Enter text here')).not.toBeNull();
});

it("should allow the user to enter text", () => {
render(<CustomTextField label="Test Label" />);
const textField = screen.getByLabelText(/test label/i);
fireEvent.change(textField, { target: { value: "User input" } });
expect(textField.value).toBe("User input");
it('renders with custom input height', () => {
render(<CustomTextField labelText="Test Label" inputHeight="50px" />);

expect(screen.getByRole('textbox').style.height).toBe('50px');
});

it('renders with custom label font weight', () => {
render(<CustomTextField labelText="Test Label" labelFontWeight={700} />);

const label = screen.getByText('Test Label');
expect(window.getComputedStyle(label).fontWeight).toBe('700');
});

it('renders with no chips when chips prop is empty', () => {
render(<CustomTextField labelText="Test Label" chips={[]} />);

expect(screen.queryByText('Chip 1')).toBeNull();
expect(screen.queryByText('Chip 2')).toBeNull();
});
});
Loading

0 comments on commit 7749ea2

Please sign in to comment.