diff --git a/CHANGELOG.md b/CHANGELOG.md index e4306c59..dc12c4a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # CHANGELOG +## Unreleased + +#### Added + +* *Nothing* + +#### Changed + +* *Nothing* + +#### Deprecated + +* *Nothing* + +#### Removed + +* *Nothing* + +#### Fixed + +* [#56](https://github.com/shlinkio/shlink-web-client/issues/56) Ensured `ColorGenerator` matches keys in a case insensitive way. + + ## 1.1.0 - 2018-09-16 #### Added diff --git a/src/utils/ColorGenerator.js b/src/utils/ColorGenerator.js index 859608a2..673eba3c 100644 --- a/src/utils/ColorGenerator.js +++ b/src/utils/ColorGenerator.js @@ -11,6 +11,7 @@ const buildRandomColor = () => .map(() => letters[floor(random() * letters.length)]) .join('') }`; +const normalizeKey = (key) => key.toLowerCase().trim(); export class ColorGenerator { constructor(storage) { @@ -19,21 +20,24 @@ export class ColorGenerator { } getColorForKey = (key) => { - const color = this.colors[key]; + const normalizedKey = normalizeKey(key); + const color = this.colors[normalizedKey]; // If a color has not been set yet, generate a random one and save it if (!color) { - this.setColorForKey(key, buildRandomColor()); - - return this.getColorForKey(key); + return this.setColorForKey(normalizedKey, buildRandomColor()); } return color; }; setColorForKey = (key, color) => { - this.colors[key] = color; + const normalizedKey = normalizeKey(key); + + this.colors[normalizedKey] = color; this.storage.set('colors', this.colors); + + return color; } } diff --git a/test/utils/ColorGenerator.test.js b/test/utils/ColorGenerator.test.js new file mode 100644 index 00000000..e0a359c6 --- /dev/null +++ b/test/utils/ColorGenerator.test.js @@ -0,0 +1,48 @@ +import * as sinon from 'sinon'; +import { ColorGenerator } from '../../src/utils/ColorGenerator'; + +describe('ColorGenerator', () => { + let colorGenerator; + const storageMock = { + set: sinon.fake(), + get: sinon.fake.returns(undefined), + }; + + beforeEach(() => { + storageMock.set.resetHistory(); + storageMock.get.resetHistory(); + + colorGenerator = new ColorGenerator(storageMock); + }); + + it('sets a color in the storage and makes it available after that', () => { + const color = '#ff0000'; + + colorGenerator.setColorForKey('foo', color); + + expect(colorGenerator.getColorForKey('foo')).toEqual(color); + expect(storageMock.set.callCount).toEqual(1); + expect(storageMock.get.callCount).toEqual(1); + }); + + it('generates a random color when none is available for requested key', () => { + expect(colorGenerator.getColorForKey('bar')).toEqual(expect.stringMatching(/^#(?:[0-9a-fA-F]{6})$/)); + expect(storageMock.set.callCount).toEqual(1); + expect(storageMock.get.callCount).toEqual(1); + }); + + it('trims and lower cases keys before trying to match', () => { + const color = '#ff0000'; + + colorGenerator.setColorForKey('foo', color); + + expect(colorGenerator.getColorForKey(' foo')).toEqual(color); + expect(colorGenerator.getColorForKey('foO')).toEqual(color); + expect(colorGenerator.getColorForKey('FoO')).toEqual(color); + expect(colorGenerator.getColorForKey('FOO')).toEqual(color); + expect(colorGenerator.getColorForKey('FOO ')).toEqual(color); + expect(colorGenerator.getColorForKey(' FoO ')).toEqual(color); + expect(storageMock.set.callCount).toEqual(1); + expect(storageMock.get.callCount).toEqual(1); + }); +});