diff --git a/simon-says/debug.log b/simon-says/debug.log index 4b248a12166ac7de06ebb85d279b1fd4001287a4..73ba570d685c9c0d9902df2f41965596ad007b8f 100644 --- a/simon-says/debug.log +++ b/simon-says/debug.log @@ -233,3 +233,47 @@ [0903/165534.614:ERROR:crash_report_database_win.cc(469)] failed to stat report [0903/165534.614:ERROR:crash_report_database_win.cc(469)] failed to stat report [0903/165534.614:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.239:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.240:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/184126.241:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.337:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report +[0903/202655.338:ERROR:crash_report_database_win.cc(469)] failed to stat report diff --git a/simon-says/src/app.js b/simon-says/src/app.js index b1f7ffabcd43ad7e219a9f30c074b7fbe5cf3a1b..9134e2f2f1cf5e313d7b642116c6f906cba38d5c 100644 --- a/simon-says/src/app.js +++ b/simon-says/src/app.js @@ -7,7 +7,6 @@ export function App() { return ( <> <Route exact path={'/'}> - <Pattern label={'Taps'} /> </Route> </> ); diff --git a/simon-says/src/features/patternGen/patternGeneration.js b/simon-says/src/features/patternGen/patternGeneration.js index 6c33ac4f819c7f93be01cd19b7e47254191d85ef..5410e737bbaa32bd4e6651af5691ddb73ea6b3ad 100644 --- a/simon-says/src/features/patternGen/patternGeneration.js +++ b/simon-says/src/features/patternGen/patternGeneration.js @@ -3,7 +3,9 @@ import { useSelector, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import styles from './buttonLayout.css'; +import styles from './patternGeneration.module.css'; + +import { Title } from './patternTitle.js'; import { selectColorOne, @@ -15,51 +17,56 @@ import { showColorThree, showColorFour, hideColorOne, + hideColorTwo, + hideColorThree, + hideColorFour, } from './patternSlice'; -export function Pattern() { +export function Pattern(props) { const colorOne = useSelector(selectColorOne); const colorTwo = useSelector(selectColorTwo); const colorThree = useSelector(selectColorThree); const colorFour = useSelector(selectColorFour); const dispatch = useDispatch(); - - const onRedClick = () => { + const onRedEnter = () => { dispatch(showColorOne()); - } - + }; const onRedLeave = () => { dispatch(hideColorOne()); - } - - const onBlueClick = () => { + }; + const onBlueEnter = () => { dispatch(showColorTwo()); - } - - const onYellowClick = () => { + }; + const onBlueLeave = () => { + dispatch(hideColorTwo()); + }; + const onYellowEnter = () => { dispatch(showColorThree()); - } - - const onGreenClick = () => { + }; + const onYellowLeave = () => { + dispatch(hideColorThree()); + }; + const onGreenEnter = () => { dispatch(showColorFour()); - } + }; + const onGreenLeave = () => { + dispatch(hideColorFour()); + }; return ( - <main> - <div> - <blockquote className={'title'}> - Color Learner - </blockquote> - <button title='red' class={'redbutton'} onPointerEnter={onRedClick} onPointerLeave={onRedLeave}> + <main className={styles.flexbox}> + <Title title={'Color Learner'} /> + <div className={styles.buttonGrid}> + <button title='red' className={styles.redbutton} onPointerEnter={onRedEnter} onPointerLeave={onRedLeave}> {colorOne} </button> - <button title='blue' class={'bluebutton'} onClick={onBlueClick}> + <button title='blue' className={styles.bluebutton} onPointerEnter={onBlueEnter} onPointerLeave={onBlueLeave}> {colorTwo} </button> - <button title='yellow' class={'yellowbutton'} onClick={onYellowClick}> + <button title='yellow' className={styles.yellowbutton} onPointerEnter={onYellowEnter} onPointerLeave={onYellowLeave}> {colorThree} </button> - <button title='green' class={'greenbutton'} onClick={onGreenClick}> + <button title='green' className={styles.greenbutton} onPointerEnter={onGreenEnter} onPointerLeave={onGreenLeave}> {colorFour} </button> </div> diff --git a/simon-says/src/features/patternGen/buttonLayout.css b/simon-says/src/features/patternGen/patternGeneration.module.css similarity index 68% rename from simon-says/src/features/patternGen/buttonLayout.css rename to simon-says/src/features/patternGen/patternGeneration.module.css index ae4958fc44f2f3638262998bdad94e84b0eb9785..120d0263c4a117bcc83340e89ed9700ce6311524 100644 --- a/simon-says/src/features/patternGen/buttonLayout.css +++ b/simon-says/src/features/patternGen/patternGeneration.module.css @@ -1,38 +1,42 @@ .title{ + flex: 0 1 auto; font-size: 1.5em; width: 50%; left: 10em; right: 10em; } +.buttonGrid { + flex: 0 1 auto; +} .redbutton{ + vertical-align: top; background-color: #f44336; border: none; width: 50%; height: 15em; - padding: 0; - margin: 0; } .bluebutton{ + vertical-align: top; background-color: #008CBA; border: none; width: 50%; height: 15em; - padding: 0; - margin: 0; } .yellowbutton{ + vertical-align: top; background-color: #ffff00; border: none; width: 50%; height: 15em; - padding: 0; - margin: 0; } .greenbutton{ + vertical-align: top; background-color: #4CAF50; border: none; width: 50%; height: 15em; - padding: 0; - margin: 0; +} +.flexbox{ + display: flex; + flex-flow: column nowrap; } diff --git a/simon-says/src/features/patternGen/patternGeneration.test.js b/simon-says/src/features/patternGen/patternGeneration.test.js index 81050b7cb2e67493bc3105e8dddd589b7b1fc0c4..9847e00a277784f7e012abf02a568615d73e8cdd 100644 --- a/simon-says/src/features/patternGen/patternGeneration.test.js +++ b/simon-says/src/features/patternGen/patternGeneration.test.js @@ -8,34 +8,116 @@ import '../../testing/mockRedux.js'; import { Pattern } from './patternGeneration.js'; import { - selectBorderState, - selectPatternList, - selectScore, + selectColorOne, + selectColorTwo, + selectColorThree, + selectColorFour, + showColorOne, + showColorTwo, + showColorThree, + showColorFour, + hideColorOne, + hideColorTwo, + hideColorThree, + hideColorFour, } from './patternSlice.js' jest.mock('./patternSlice.js', () =>({ - selectBorderState: jest.fn().mockName('selectBorderState'), - selectPatternList: jest.fn().mockName('selectPatternList'), - selectScore: jest.fn().mockName('selectScore'), + selectColorOne: jest.fn().mockName('selectColorOne'), + showColorOne: jest.fn().mockName('showColorOne'), + hideColorOne: jest.fn().mockName('hideColorOne'), + selectColorTwo: jest.fn().mockName('selectColorTwo'), + showColorTwo: jest.fn().mockName('showColorTwo'), + hideColorTwo: jest.fn().mockName('hideColorTwo'), + selectColorThree: jest.fn().mockName('selectColorThree'), + showColorThree: jest.fn().mockName('showColorThree'), + hideColorThree: jest.fn().mockName('hideColorThree'), + selectColorFour: jest.fn().mockName('selectColorFour'), + showColorFour: jest.fn().mockName('showColorFour'), + hideColorFour: jest.fn().mockName('hideColorFour'), })); describe('red button', () => { - test('has a white border if borderState is true', () => { - selectBorderState.mockReturnValue(true); - render(<Pattern button={'Foo'}/>); - expect(screen.getByTitle('red')).toHaveClass('redlit'); + test('displays nothing when no pointer is present', () => { + selectColorOne.mockReturnValue(''); + render(<Pattern></Pattern>); + expect(screen.getByTitle('red')).toHaveTextContent(''); + }); + test('changes to red when pointer is present', () => { + selectColorOne.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('red')); + expect(showColorOne).toHaveBeenCalledTimes(1); + }); + test('changes back to nothing when pointer leaves', () => { + selectColorOne.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('red')); + expect(showColorOne).toHaveBeenCalledTimes(1); + userEvent.unhover(screen.getByTitle('red')); + expect(hideColorOne).toHaveBeenCalledTimes(1); + }); +}); +describe('blue button', () => { + test('displays nothing when no pointer is present', () => { + selectColorTwo.mockReturnValue(''); + render(<Pattern></Pattern>); + expect(screen.getByTitle('blue')).toHaveTextContent(''); + }); + test('changes to blue when pointer is present', () => { + selectColorTwo.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('blue')); + expect(showColorTwo).toHaveBeenCalledTimes(1); + }); + test('changes back to nothing when pointer leaves', () => { + selectColorTwo.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('blue')); + expect(showColorTwo).toHaveBeenCalledTimes(1); + userEvent.unhover(screen.getByTitle('blue')); + expect(hideColorTwo).toHaveBeenCalledTimes(1); }); }); -describe('the score counter', () => { - test('displays the correct score', () => { - selectScore.mockReturnValue(100); +describe('yellow button', () => { + test('displays nothing when no pointer is present', () => { + selectColorThree.mockReturnValue(''); + render(<Pattern></Pattern>); + expect(screen.getByTitle('yellow')).toHaveTextContent(''); + }); + test('changes to yellow when pointer is present', () => { + selectColorThree.mockReturnValue(''); render(<Pattern></Pattern>); - expect(screen.getByTitle('score')).toHaveTextContent('Score: 100'); + userEvent.hover(screen.getByTitle('yellow')); + expect(showColorThree).toHaveBeenCalledTimes(1); + }); + test('changes back to nothing when pointer leaves', () => { + selectColorThree.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('yellow')); + expect(showColorThree).toHaveBeenCalledTimes(1); + userEvent.unhover(screen.getByTitle('yellow')); + expect(hideColorThree).toHaveBeenCalledTimes(1); }); }); -describe('the pattern list', () => { - test('works', () => { - const list = selectPatternList.mockReturnValue([0, 1, 3]); +describe('green button', () => { + test('displays nothing when no pointer is present', () => { + selectColorFour.mockReturnValue(''); render(<Pattern></Pattern>); - expect( list === [0,1,3]); + expect(screen.getByTitle('green')).toHaveTextContent(''); }); -}); \ No newline at end of file + test('changes to green when pointer is present', () => { + selectColorFour.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('green')); + expect(showColorFour).toHaveBeenCalledTimes(1); + }); + test('changes back to nothing when pointer leaves', () => { + selectColorFour.mockReturnValue(''); + render(<Pattern></Pattern>); + userEvent.hover(screen.getByTitle('green')); + expect(showColorFour).toHaveBeenCalledTimes(1); + userEvent.unhover(screen.getByTitle('green')); + expect(hideColorFour).toHaveBeenCalledTimes(1); + }); +}); + diff --git a/simon-says/src/features/patternGen/patternSlice.js b/simon-says/src/features/patternGen/patternSlice.js index 62c164b5aa6f2806da61b2358965f0b2d409e046..fa13d35d4d8e828d24111a89e5b6bd3fe76d89ad 100644 --- a/simon-says/src/features/patternGen/patternSlice.js +++ b/simon-says/src/features/patternGen/patternSlice.js @@ -25,6 +25,15 @@ const patternSlice = createSlice({ hideColorOne: (pattern, action) => { pattern.colorOne = ''; }, + hideColorTwo: (pattern, action) => { + pattern.colorTwo = ''; + }, + hideColorThree: (pattern, action) => { + pattern.colorThree = ''; + }, + hideColorFour: (pattern, action) => { + pattern.colorFour = ''; + }, }, }); export default patternSlice; @@ -35,21 +44,24 @@ export const { showColorThree, showColorFour, hideColorOne, + hideColorTwo, + hideColorThree, + hideColorFour, } = patternSlice.actions; -export function selectColorOne(state){ +export function selectColorOne(state) { return state.pattern.colorOne; } -export function selectColorTwo(state){ +export function selectColorTwo(state) { return state.pattern.colorTwo; } -export function selectColorThree(state){ +export function selectColorThree(state) { return state.pattern.colorThree; } -export function selectColorFour(state){ +export function selectColorFour(state) { return state.pattern.colorFour; -} \ No newline at end of file +} diff --git a/simon-says/src/features/patternGen/patternSlice.test.js b/simon-says/src/features/patternGen/patternSlice.test.js new file mode 100644 index 0000000000000000000000000000000000000000..be01607b3d44e906c5972ffdd6f5a90a3b6a0d32 --- /dev/null +++ b/simon-says/src/features/patternGen/patternSlice.test.js @@ -0,0 +1,160 @@ +/* eslint-disable no-magic-numbers */ + +import patternSlice, { + selectColorOne, + selectColorTwo, + selectColorThree, + selectColorFour, + showColorOne, + showColorTwo, + showColorThree, + showColorFour, + hideColorOne, + hideColorTwo, + hideColorThree, + hideColorFour, +} from './patternslice.js'; + +describe('the initial state', () => { + test('has no text', () => { + const state = patternSlice.reducer(undefined, {}); + expect(state).toEqual({ + colorOne: '', + colorTwo: '', + colorThree: '', + colorFour: '', + }); + }); +}); + +describe('selectColorOne', () => { + test('reads the stored value', () => { + const state = { + colorOne: 'red', + colorTwo:'', + colorThree: '', + colorFour: '', + }; + const result = selectColorOne({ [patternSlice.name] : state }); + expect(result).toBe('red'); + }); +}); + +describe('showColorOne', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorOne: '', + }, showColorOne()); + expect(state).toEqual({ + colorOne: 'red', + }); + }); +}); + +describe('hideColorOne', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorOne: 'red', + }, hideColorOne()); + expect(state).toEqual({ + colorOne: '', + }); + }); +}); +describe('selectColorTwo', () => { + test('reads the stored value', () => { + const state = { + colorOne: '', + colorTwo:'blue', + colorThree: '', + colorFour: '', + }; + const result = selectColorTwo({ [patternSlice.name] : state }); + expect(result).toBe('blue'); + }); +}); + +describe('showColorTwo', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorTwo: '', + }, showColorTwo()); + expect(state).toEqual({ + colorTwo: 'blue', + }); + }); +}); +describe('hideColorTwo', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorTwo: 'blue', + }, hideColorTwo()); + expect(state).toEqual({ + colorTwo: '', + }); + }); +}); +describe('selectColorThree', () => { + test('reads the stored value', () => { + const state = { + colorOne: '', + colorTwo:'', + colorThree: 'yellow', + colorFour: '', + }; + const result = selectColorThree({ [patternSlice.name] : state }); + expect(result).toBe('yellow'); + }); +}); +describe('showColorThree', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorThree: '', + }, showColorThree()); + expect(state).toEqual({ + colorThree: 'yellow', + }); + }); +}); +describe('hideColorThree', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorThree: 'yellow', + }, hideColorThree()); + expect(state).toEqual({ + colorThree: '', + }); + }); +}); +describe('selectColorFour', () => { + test('reads the stored value', () => { + const state = { + colorOne: '', + colorTwo:'', + colorThree: '', + colorFour: 'green', + }; + const result = selectColorFour({ [patternSlice.name] : state }); + expect(result).toBe('green'); + }); +}); +describe('showColorFour', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorFour: '', + }, showColorFour()); + expect(state).toEqual({ + colorFour: 'green', + }); + }); +}); +describe('hideColorFour', () => { + test('overwrites the stored value', () => { + const state = patternSlice.reducer({ + colorFour: 'green', + }, hideColorFour()); + expect(state).toEqual({ + colorFour: '', + }); + }); +}); \ No newline at end of file diff --git a/simon-says/src/features/patternGen/patternTitle.js b/simon-says/src/features/patternGen/patternTitle.js new file mode 100644 index 0000000000000000000000000000000000000000..769e674b89b4efebe4727989927b0a7070f60950 --- /dev/null +++ b/simon-says/src/features/patternGen/patternTitle.js @@ -0,0 +1,13 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export function Title(props) { + return ( + <h1> + {props.title}: + </h1> + ) +} +Title.propTypes = { + title: PropTypes.string.isRequired, + }; \ No newline at end of file