added tests and css modules for NameContainer components
This commit is contained in:
parent
aa6c03ebcb
commit
469a60871a
@ -1,19 +1,12 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { CSSTransition } from 'react-transition-group';
|
import { CSSTransition } from 'react-transition-group';
|
||||||
import './TimerAnimation.js';
|
import './TimerAnimation.js';
|
||||||
|
|
||||||
const AnimatedOverlay = ({ time }) => {
|
const AnimatedOverlay = ({ time }) => {
|
||||||
const animationDelay = useMemo(() => 15 - Math.ceil((time - Date.now()) / 1000), [time]);
|
const animationDelay = useMemo(() => 15 - Math.ceil((time - Date.now()) / 1000), [time]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CSSTransition
|
<CSSTransition in={true} timeout={0} style={{ animationDelay: `-${animationDelay}s` }} unmountOnExit>
|
||||||
in={true}
|
<div className='overlay' data-testid='animated-overlay'></div>
|
||||||
timeout={0}
|
|
||||||
classNames='overlay'
|
|
||||||
style={{ animationDelay: `-${animationDelay}s` }}
|
|
||||||
unmountOnExit
|
|
||||||
>
|
|
||||||
<div className='overlay'></div>
|
|
||||||
</CSSTransition>
|
</CSSTransition>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
.overlay {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
animation: timerAnimation 15s linear infinite;
|
||||||
|
transition-duration: 15s;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import AnimatedOverlay from './AnimatedOverlay';
|
||||||
|
|
||||||
|
describe('AnimatedOverlay component', () => {
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
render(<AnimatedOverlay time={0} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies animation delay based on time prop', () => {
|
||||||
|
const timeNow = Date.now();
|
||||||
|
const time = timeNow + 5000;
|
||||||
|
render(<AnimatedOverlay time={time} />);
|
||||||
|
const overlay = screen.getByTestId('animated-overlay');
|
||||||
|
const expectedDelay = 15 - Math.ceil((time - timeNow) / 1000);
|
||||||
|
|
||||||
|
expect(overlay).toHaveStyle({ animationDelay: `-${expectedDelay}s` });
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -4,20 +4,20 @@ const steps = 86;
|
|||||||
let count = 0;
|
let count = 0;
|
||||||
let s = 'polygon(50% 50%, 50% 0%, 50% 0%';
|
let s = 'polygon(50% 50%, 50% 0%, 50% 0%';
|
||||||
|
|
||||||
for (let i = 50; i <= 100; i += 5) {
|
for (let i = 50; i < 100; i += 5) {
|
||||||
s += `, ${i}% 0%`;
|
s += `, ${i}% 0%`;
|
||||||
handle();
|
handle();
|
||||||
}
|
}
|
||||||
for (let i = 0; i <= 100; i += 5) {
|
for (let i = 0; i < 100; i += 5) {
|
||||||
s += `, 100% ${i}%`;
|
s += `, 100% ${i}%`;
|
||||||
handle();
|
handle();
|
||||||
}
|
}
|
||||||
for (let i = 100; i >= 0; i -= 5) {
|
for (let i = 100; i > 0; i -= 5) {
|
||||||
s += `, ${i}% 100%`;
|
s += `, ${i}% 100%`;
|
||||||
handle();
|
handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 100; i >= 0; i -= 5) {
|
for (let i = 100; i > 0; i -= 5) {
|
||||||
s += `, 0% ${i}%`;
|
s += `, 0% ${i}%`;
|
||||||
handle();
|
handle();
|
||||||
}
|
}
|
||||||
@ -52,12 +52,13 @@ function handle() {
|
|||||||
keyframes.push(step);
|
keyframes.push(step);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
if (document && document.styleSheets && document.styleSheets[0]) {
|
||||||
document.styleSheets[0].insertRule(
|
document.styleSheets[0].insertRule(
|
||||||
`
|
`
|
||||||
@keyframes timerAnimation {
|
@keyframes timerAnimation {
|
||||||
${keyframes.join('\n')}
|
${keyframes.join('\n')}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
document.styleSheets[0].cssRules.length
|
document.styleSheets[0].cssRules.length
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import AnimatedOverlay from './AnimatedOverlay/AnimatedOverlay';
|
import AnimatedOverlay from './AnimatedOverlay/AnimatedOverlay';
|
||||||
|
import styles from './NameContainer.module.css';
|
||||||
|
|
||||||
const NameContainer = ({ player, time }) => {
|
const NameContainer = ({ player, time }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={styles.container} style={{ backgroundColor: player.ready ? player.color : 'lightgrey' }}>
|
||||||
className='name-container'
|
|
||||||
style={player.ready ? { backgroundColor: player.color } : { backgroundColor: 'lightgrey' }}
|
|
||||||
>
|
|
||||||
<p>{player.name}</p>
|
<p>{player.name}</p>
|
||||||
{player.nowMoving ? <AnimatedOverlay time={time} /> : null}
|
{player.nowMoving ? <AnimatedOverlay time={time} /> : null}
|
||||||
</div>
|
</div>
|
||||||
@ -17,6 +15,7 @@ const NameContainer = ({ player, time }) => {
|
|||||||
NameContainer.propTypes = {
|
NameContainer.propTypes = {
|
||||||
player: PropTypes.object,
|
player: PropTypes.object,
|
||||||
time: PropTypes.number,
|
time: PropTypes.number,
|
||||||
|
testId: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NameContainer;
|
export default NameContainer;
|
||||||
|
|||||||
13
src/components/Navbar/NameContainer/NameContainer.module.css
Normal file
13
src/components/Navbar/NameContainer/NameContainer.module.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
min-width: 100px;
|
||||||
|
min-height: 50px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid white;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
58
src/components/Navbar/NameContainer/NameContainer.test.js
Normal file
58
src/components/Navbar/NameContainer/NameContainer.test.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import NameContainer from './NameContainer';
|
||||||
|
import { NOT_READY_COLOR } from '../../../constants/colors';
|
||||||
|
|
||||||
|
jest.mock('./AnimatedOverlay/AnimatedOverlay.jsx', () => () => {
|
||||||
|
return <mock-animated-overlay data-testid='animated-overlay' />;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('NameContainer component', () => {
|
||||||
|
let player;
|
||||||
|
let time;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
player = {
|
||||||
|
name: 'TestPlayer',
|
||||||
|
ready: false,
|
||||||
|
color: 'blue',
|
||||||
|
nowMoving: false,
|
||||||
|
};
|
||||||
|
time = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
render(<NameContainer player={player} time={time} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders player name', () => {
|
||||||
|
render(<NameContainer player={player} time={time} />);
|
||||||
|
expect(screen.getByText(player.name)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies grey color when player is not ready', () => {
|
||||||
|
player.ready = false;
|
||||||
|
render(<NameContainer player={player} time={time} testId='name-container' />);
|
||||||
|
const container = screen.getByText(player.name).closest('div');
|
||||||
|
expect(container).toHaveStyle({ backgroundColor: NOT_READY_COLOR });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies player colors as background when player is ready', () => {
|
||||||
|
player.ready = true;
|
||||||
|
render(<NameContainer player={player} time={time} testId='name-container' />);
|
||||||
|
const container = screen.getByText(player.name).closest('div');
|
||||||
|
expect(container).toHaveStyle({ backgroundColor: player.color });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders AnimatedOverlay when player is nowMoving', () => {
|
||||||
|
const movingPlayer = { ...player, nowMoving: true };
|
||||||
|
render(<NameContainer player={movingPlayer} time={time} />);
|
||||||
|
expect(screen.getByTestId('animated-overlay')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render AnimatedOverlay when player is not nowMoving', () => {
|
||||||
|
render(<NameContainer player={player} time={time} />);
|
||||||
|
expect(screen.queryByTestId('animated-overlay')).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
2
src/constants/colors.js
Normal file
2
src/constants/colors.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const NOT_READY_COLOR = 'lightgrey';
|
||||||
|
export const PLAYER_COLORS = ['red', 'blue', 'green', 'yellow'];
|
||||||
@ -29,19 +29,6 @@ canvas {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name-container {
|
|
||||||
position: relative;
|
|
||||||
min-width: 100px;
|
|
||||||
min-height: 50px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: 2px solid white;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.timer {
|
.timer {
|
||||||
background-color: darkblue;
|
background-color: darkblue;
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user