diff --git a/js/Marquee.jsx b/js/Marquee.jsx index 92727062..2176e742 100644 --- a/js/Marquee.jsx +++ b/js/Marquee.jsx @@ -28,17 +28,22 @@ const getDoubleSizeModeText = (enabled) => { return `${enabled ? 'Disable' : 'Enable'} doublesize mode`; }; -const wrapForMarquee = (text, step) => { - if (text.length <= 30) { - return text; +const isLong = (text) => text.length > 30; + +// Given text and step, how many pixels should it be shifted? +const stepOffset = (text, step) => { + if (!isLong(text)) { + return 0; } - step = step % (text.length + 1); - const chars = text.split(''); - const start = chars.slice(step); - const end = chars.slice(0, step); - return [...start, ' ', ...end].slice(0, 30).join(''); + return (step % text.length) * 5; }; +// Format an int as negative pixels +const negativePixels = (pixels) => `-${pixels}px`; + +// If text is wider than the marquee, it needs to loop +const loopText = (text) => isLong(text) ? text + text : text; + import CharacterString from './CharacterString.jsx'; class Marquee extends React.Component { @@ -91,10 +96,13 @@ class Marquee extends React.Component { } render() { - const text = wrapForMarquee(this.getText(), this.props.display.marqueeStep); - return - {text} - ; + const text = this.getText(); + const offset = stepOffset(text, this.props.display.marqueeStep); + return
+ + {loopText(text)} + +
; } } @@ -104,7 +112,9 @@ export { getPositionText, getMediaText, getDoubleSizeModeText, - wrapForMarquee, + negativePixels, + stepOffset, + loopText, Marquee }; export default connect(state => state)(Marquee); diff --git a/js/__tests__/Marquee-test.jsx b/js/__tests__/Marquee-test.js similarity index 59% rename from js/__tests__/Marquee-test.jsx rename to js/__tests__/Marquee-test.js index a00139a6..c1f28f85 100644 --- a/js/__tests__/Marquee-test.jsx +++ b/js/__tests__/Marquee-test.js @@ -1,3 +1,4 @@ +jest.unmock('../Marquee.jsx'); jest.unmock('../utils'); import { @@ -6,7 +7,9 @@ import { getPositionText, getMediaText, getDoubleSizeModeText, - wrapForMarquee + stepOffset, + negativePixels, + loopText } from '../Marquee.jsx'; describe('getBalanceText', () => { @@ -55,35 +58,62 @@ describe('getMediaText', () => { }); }); -describe('wrapForMarquee', () => { +describe('stepOffset', () => { const long = 'This is a long string. Longer than 30 characters!'; - it('truncates to 30 characters', () => { - const actual = wrapForMarquee(long, 0); - const expected = 'This is a long string. Longer '; + it('starts at 0', () => { + const actual = stepOffset(long, 0); + const expected = 0; expect(actual).toEqual(expected); }); - it('offsets by the number of steps', () => { - const actual = wrapForMarquee(long, 8); - const expected = 'a long string. Longer than 30 '; + it('first step offsets by one character', () => { + const actual = stepOffset(long, 1); + const expected = 5; expect(actual).toEqual(expected); }); - it('wraps around when step > text length', () => { - const actual = wrapForMarquee(long, 51); - const expected = 'his is a long string. Longer t'; + it('resets to 0 when step === string.length', () => { + const actual = stepOffset(long, long.length); + const expected = 0; expect(actual).toEqual(expected); }); - it('wraps text when it gets to the end', () => { - const actual = wrapForMarquee(long, 30); - const expected = 'than 30 characters! This is a '; + it('offsets by one char when step = string.length + 1', () => { + const actual = stepOffset(long, long.length + 1); + const expected = 5; expect(actual).toEqual(expected); }); - it('does not step through short strings', () => { - const actual = wrapForMarquee('Short string', 30); - const expected = 'Short string'; + xit('does not try to offset strings shorter than 30 characters', () => { + const actual = stepOffset('hello', 15); + const expected = 0; expect(actual).toEqual(expected); }); }); +describe('negativePixels', () => { + it('converts an integer into a CSS offset', () => { + const actual = negativePixels(1); + const expected = '-1px'; + expect(actual).toEqual(expected); + }); + it('handles 0', () => { + const actual = negativePixels(0); + const expected = '-0px'; + expect(actual).toEqual(expected); + }); +}); + +describe('loopText', () => { + const long = 'This is a long string. Longer than 30 characters!'; + const short = 'This is a short string.'; + it('loops long string', () => { + const actual = loopText(long); + const expected = long + long; + expect(actual).toEqual(expected); + }); + it('does not loop sort strings', () => { + const actual = loopText(short); + const expected = short; + expect(actual).toEqual(expected); + }); +}); describe('getDoubleSizeModeText', () => { it('prompts to enable when disabled', () => { const actual = getDoubleSizeModeText(true); diff --git a/package.json b/package.json index 50b391fe..7ec7aa15 100644 --- a/package.json +++ b/package.json @@ -56,5 +56,11 @@ "react-redux": "^4.4.5", "redux": "^3.5.2", "redux-thunk": "^2.1.0" + }, + "jest": { + "unmockedModulePathPatterns": [ + "/node_modules/react/", + "/node_modules/react-redux/" + ] } }