Skip to content

Commit fcd68e3

Browse files
committed
Fill out getColor tests
1 parent a5d0cdc commit fcd68e3

File tree

3 files changed

+363
-8
lines changed

3 files changed

+363
-8
lines changed

.github/CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ on your system. After you clone this repo, run `npm install` to install
4848
dependencies needed for development. After installation, the following
4949
commands are available:
5050

51-
- `npm start` to launch Storybook with live reload.
51+
- `npm start` to launch Storybook with live reload. Use `PACKAGE=dirname npm start`
52+
(where `dirname` is a package directory name) to limit Storybook launch to the
53+
given Garden package.
5254
- `npm test` to run Jest testing.
5355
- `npm run lint` to enforce consistent JavaScript, CSS, and
5456
markdown code conventions across all component packages. Note this is
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/**
2+
* Copyright Zendesk, Inc.
3+
*
4+
* Use of this source code is governed under the Apache License, Version 2.0
5+
* found at http://www.apache.org/licenses/LICENSE-2.0.
6+
*/
7+
8+
import { getColor } from './getColor';
9+
import DEFAULT_THEME from '../elements/theme';
10+
import PALETTE from '../elements/palette';
11+
import { IGardenTheme } from '../types';
12+
import { darken, lighten, rgba } from 'polished';
13+
import { valid } from 'chroma-js';
14+
15+
const DARK_THEME: IGardenTheme = {
16+
...DEFAULT_THEME,
17+
colors: { ...DEFAULT_THEME.colors, base: 'dark' }
18+
};
19+
20+
describe('getColor', () => {
21+
describe('by variable', () => {
22+
it.each([['light'], ['dark']])('gets the %s mode color specified by string', mode => {
23+
const color = getColor({
24+
theme: mode === 'dark' ? DARK_THEME : DEFAULT_THEME,
25+
variable: 'background.default'
26+
});
27+
const expected = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
28+
29+
expect(color).toBe(expected);
30+
});
31+
32+
it('uses `DEFAULT_THEME` fallback for malformed variables', () => {
33+
const theme: IGardenTheme = {
34+
...DEFAULT_THEME,
35+
colors: { ...DEFAULT_THEME.colors, variables: {} }
36+
} as IGardenTheme;
37+
const color = getColor({ theme, variable: 'background.default' });
38+
39+
expect(color).toBe(PALETTE.white);
40+
});
41+
});
42+
43+
describe('by hue', () => {
44+
it.each([['light'], ['dark']])('gets the %s mode color specified by string', mode => {
45+
const color = getColor({ theme: mode === 'dark' ? DARK_THEME : DEFAULT_THEME, hue: 'red' });
46+
const expected = mode === 'dark' ? PALETTE.red[500] : PALETTE.red[700];
47+
48+
expect(color).toBe(expected);
49+
});
50+
51+
it('applies mode hue as expected', () => {
52+
const color = getColor({ theme: DARK_THEME, hue: 'red', dark: { hue: 'green' } });
53+
const expected = PALETTE.green[500];
54+
55+
expect(color).toBe(expected);
56+
});
57+
58+
it.each([['white'], ['black']])('handles %s theme palette value', hue => {
59+
const color = getColor({ theme: DEFAULT_THEME, hue });
60+
const expected = (PALETTE as any)[hue];
61+
62+
expect(color).toBe(expected);
63+
});
64+
65+
describe('by `theme.color` key', () => {
66+
it.each([
67+
['primaryHue', 'light'],
68+
['primaryHue', 'dark'],
69+
['successHue', 'light'],
70+
['successHue', 'dark'],
71+
['dangerHue', 'light'],
72+
['dangerHue', 'dark'],
73+
['warningHue', 'light'],
74+
['warningHue', 'dark'],
75+
['neutralHue', 'light'],
76+
['neutralHue', 'dark'],
77+
['chromeHue', 'light'],
78+
['chromeHue', 'dark']
79+
])('gets the default %s for %s mode', (hue, mode) => {
80+
const color = getColor({ theme: mode === 'dark' ? DARK_THEME : DEFAULT_THEME, hue });
81+
const shade = mode === 'dark' ? 500 : 700;
82+
const expected = (PALETTE as any)[(DEFAULT_THEME as any).colors[hue]][shade];
83+
84+
expect(color).toBe(expected);
85+
});
86+
});
87+
88+
it('uses `DEFAULT_THEME` fallback for malformed palette', () => {
89+
const theme: IGardenTheme = {
90+
...DEFAULT_THEME,
91+
palette: {}
92+
} as IGardenTheme;
93+
const color = getColor({ theme, hue: 'fuschia' });
94+
const expected = PALETTE.fuschia[700];
95+
96+
expect(color).toBe(expected);
97+
});
98+
99+
it('uses `DEFAULT_THEME` fallback for malformed colors', () => {
100+
const theme: IGardenTheme = {
101+
...DEFAULT_THEME,
102+
colors: {}
103+
} as IGardenTheme;
104+
const hue = 'successHue';
105+
const color = getColor({ theme, hue });
106+
const expected = (PALETTE as any)[(DEFAULT_THEME as any).colors[hue]][700];
107+
108+
expect(color).toBe(expected);
109+
});
110+
});
111+
112+
describe('by shade', () => {
113+
it('gets the specified shade of hue', () => {
114+
const color = getColor({ theme: DEFAULT_THEME, hue: 'red', shade: 100 });
115+
const expected = PALETTE.red[100];
116+
117+
expect(color).toBe(expected);
118+
});
119+
120+
it('applies mode shade as expected', () => {
121+
const color = getColor({ theme: DARK_THEME, hue: 'red', shade: 100, dark: { shade: 200 } });
122+
const expected = PALETTE.red[200];
123+
124+
expect(color).toBe(expected);
125+
});
126+
127+
it('handles inbetween shades as expected', () => {
128+
const color = getColor({ theme: DEFAULT_THEME, hue: 'red', shade: 150 });
129+
const expected = darken(0.025, PALETTE.red[100]);
130+
131+
expect(color).toBe(expected);
132+
});
133+
134+
it('darkens the color if shade is greater than what exists within the hue', () => {
135+
const color = getColor({ theme: DEFAULT_THEME, hue: 'blue', shade: 1300 });
136+
const expected = darken(0.05, PALETTE.blue[1200]);
137+
138+
expect(color).toBe(expected);
139+
});
140+
141+
it('lightens the color if shade is lesser than what what exists within the hue', () => {
142+
const color = getColor({ theme: DEFAULT_THEME, hue: 'blue', shade: 0 });
143+
const expected = lighten(0.05, PALETTE.blue[100]);
144+
145+
expect(color).toBe(expected);
146+
});
147+
148+
it('generates color for a custom hex palette hue with unspecified shade', () => {
149+
const theme = { ...DEFAULT_THEME, palette: { custom: '#fd5a1e' } };
150+
const adjustedColor = getColor({ theme, hue: 'custom', shade: 600 });
151+
152+
expect(valid(adjustedColor)).toBe(true);
153+
154+
theme.palette.custom = adjustedColor;
155+
156+
const unadjustedColor = getColor({ theme, hue: 'custom' });
157+
158+
expect(unadjustedColor).toBe(adjustedColor);
159+
});
160+
});
161+
162+
describe('by offset', () => {
163+
it('applies offset as expected', () => {
164+
const color = getColor({ theme: DEFAULT_THEME, hue: 'blue', offset: 100 });
165+
const expected = PALETTE.blue[800];
166+
167+
expect(color).toBe(expected);
168+
});
169+
170+
it('applies mode offset as expected', () => {
171+
const color = getColor({
172+
theme: DARK_THEME,
173+
hue: 'blue',
174+
offset: 100,
175+
dark: { offset: -100 }
176+
});
177+
const expected = PALETTE.blue[400];
178+
179+
expect(color).toBe(expected);
180+
});
181+
182+
it('handles inbetween offset as expected', () => {
183+
const color = getColor({ theme: DEFAULT_THEME, hue: 'blue', offset: 150 });
184+
const expected = darken(0.025, PALETTE.blue[800]);
185+
186+
expect(color).toBe(expected);
187+
});
188+
});
189+
190+
describe('by transparency', () => {
191+
it('applies transparency as expected', () => {
192+
const hue = 'blue';
193+
const transparency = 0.5;
194+
const color = getColor({ theme: DEFAULT_THEME, hue, transparency });
195+
const expected = rgba(PALETTE[hue][700], transparency);
196+
197+
expect(color).toBe(expected);
198+
});
199+
200+
it('applies mode transparency as expected', () => {
201+
const hue = 'blue';
202+
const transparency = 0.5;
203+
const color = getColor({
204+
theme: DARK_THEME,
205+
hue,
206+
transparency,
207+
dark: { transparency: 0.25 }
208+
});
209+
const expected = rgba(PALETTE[hue][500], 0.25);
210+
211+
expect(color).toBe(expected);
212+
});
213+
});
214+
215+
describe('by theme', () => {
216+
let theme: IGardenTheme;
217+
218+
beforeEach(() => {
219+
theme = {
220+
...DEFAULT_THEME,
221+
colors: {
222+
...DEFAULT_THEME.colors,
223+
primaryHue: 'test'
224+
},
225+
palette: {
226+
test: {
227+
400: '#400',
228+
600: '#600'
229+
}
230+
}
231+
};
232+
});
233+
234+
it('gets the specified color from the theme', () => {
235+
const color = getColor({ theme, hue: 'test', shade: 400 });
236+
const expected = theme.palette.test[400];
237+
238+
expect(color).toBe(expected);
239+
});
240+
});
241+
242+
describe('precedence', () => {
243+
const ARGUMENTS = {
244+
hue: 'blue',
245+
shade: 600,
246+
offset: 100,
247+
transparency: 0.5
248+
};
249+
250+
it('overrides arguments based on mode', () => {
251+
const color = getColor({
252+
theme: DEFAULT_THEME,
253+
...ARGUMENTS,
254+
light: { hue: 'red', shade: 500, offset: -100, transparency: 0.25 }
255+
});
256+
const expected = rgba(PALETTE.red[400], 0.25);
257+
258+
expect(color).toBe(expected);
259+
});
260+
261+
it('falls back to default arguments if not provided by mode', () => {
262+
const color = getColor({
263+
theme: DARK_THEME,
264+
...ARGUMENTS,
265+
dark: { hue: 'kale', offset: -100 }
266+
});
267+
const expected = rgba(PALETTE.kale[500], ARGUMENTS.transparency);
268+
269+
expect(color).toBe(expected);
270+
});
271+
272+
it.each([['light'], ['dark']])(
273+
'ensures %s mode variable lookup takes precedence over other arguments',
274+
mode => {
275+
const theme = mode === 'dark' ? DARK_THEME : DEFAULT_THEME;
276+
const { hue, shade } = ARGUMENTS;
277+
const color = getColor({ theme, hue, shade, variable: 'foreground.default' });
278+
const expected = mode === 'dark' ? PALETTE.grey[300] : PALETTE.grey[900];
279+
280+
expect(color).toBe(expected);
281+
}
282+
);
283+
284+
it.each([['light'], ['dark']])(
285+
'ensures variable lookup uses `offset` and `transparency` arguments in %s mode',
286+
mode => {
287+
const theme = mode === 'dark' ? DARK_THEME : DEFAULT_THEME;
288+
const color = getColor({ theme, ...ARGUMENTS, variable: 'foreground.default' });
289+
const expected = rgba(
290+
mode === 'dark' ? PALETTE.grey[400] : PALETTE.grey[1000],
291+
ARGUMENTS.transparency
292+
);
293+
294+
expect(color).toBe(expected);
295+
}
296+
);
297+
298+
it.each([['light'], ['dark']])(
299+
'ensures variable lookup prefers mode fallback arguments in %s mode',
300+
mode => {
301+
const theme = mode === 'dark' ? DARK_THEME : DEFAULT_THEME;
302+
const color = getColor({
303+
theme,
304+
...ARGUMENTS,
305+
variable: 'border.default',
306+
light: { offset: 0, transparency: 0 },
307+
dark: { offset: -100, transparency: 0 }
308+
});
309+
const expected = mode === 'dark' ? PALETTE.grey[600] : PALETTE.grey[400];
310+
311+
expect(color).toBe(expected);
312+
}
313+
);
314+
});
315+
316+
describe('errors', () => {
317+
const consoleError = console.error;
318+
319+
beforeEach(() => {
320+
console.error = jest.fn();
321+
});
322+
323+
afterEach(() => {
324+
console.error = consoleError;
325+
});
326+
327+
it('throws an error if color arguments are missing', () => {
328+
expect(() => getColor({ theme: DEFAULT_THEME })).toThrow(Error);
329+
});
330+
331+
it('throws an error when variable reference is invalid', () => {
332+
expect(() => getColor({ theme: DEFAULT_THEME, variable: 'invalid.key' })).toThrow(
333+
ReferenceError
334+
);
335+
});
336+
337+
it('throws an error when variable reference does not resolve to a string', () => {
338+
expect(() => getColor({ theme: DEFAULT_THEME, variable: 'background' })).toThrow(Error);
339+
});
340+
341+
it('throws an error when hue is off palette', () => {
342+
expect(() => getColor({ theme: DEFAULT_THEME, hue: 'missing' })).toThrow(Error);
343+
});
344+
345+
it('throws an error if shade is invalid', () => {
346+
expect(() => getColor({ theme: DEFAULT_THEME, hue: 'blue', shade: NaN })).toThrow(TypeError);
347+
});
348+
});
349+
});

0 commit comments

Comments
 (0)