1context("Themes")
2
3skip_on_cran() # This test suite is long-running (on cran) and is skipped
4
5test_that("modifying theme element properties with + operator works", {
6
7  # Changing a "leaf node" works
8  t <- theme_grey() + theme(axis.title.x = element_text(colour = 'red', margin = margin()))
9  expect_identical(t$axis.title.x, element_text(colour = 'red', margin = margin(), vjust = 1))
10  # Make sure the theme class didn't change or get dropped
11  expect_true(is.theme(t))
12  # Make sure the element class didn't change or get dropped
13  expect_true(inherits(t$axis.title.x, "element"))
14  expect_true(inherits(t$axis.title.x, "element_text"))
15
16  # Modifying an intermediate node works
17  t <- theme_grey() + theme(axis.title = element_text(colour = 'red'))
18  expect_identical(t$axis.title, element_text(colour = 'red'))
19
20  # Modifying a root node changes only the specified properties
21  t <- theme_grey() + theme(text = element_text(colour = 'red'))
22  expect_identical(t$text$colour, 'red')
23  expect_identical(t$text$family, theme_grey()$text$family)
24  expect_identical(t$text$face,   theme_grey()$text$face)
25  expect_identical(t$text$size,   theme_grey()$text$size)
26  # Descendent is unchanged
27  expect_identical(t$axis.title.x, theme_grey()$axis.title.x)
28
29  # Adding element_blank replaces element
30  t <- theme_grey() + theme(axis.text.y = element_blank())
31  expect_identical(t$axis.text.y, element_blank())
32
33  # Adding a non-blank element to an element_blank() replaces it
34  t <- t + theme(axis.text.y = element_text(colour = 'red'))
35  expect_identical(t$axis.text.y, element_text(colour = 'red'))
36
37  # Adding empty theme() has no effect
38  t <- theme_grey() + theme()
39  expect_identical(t, theme_grey())
40
41  expect_error(theme_grey() + "asdf")
42})
43
44test_that("adding theme object to ggplot object with + operator works", {
45  ## test with complete theme
46  p <- qplot(1:3, 1:3) + theme_grey()
47  p <- p + theme(axis.title = element_text(size = 20))
48  expect_true(p$theme$axis.title$size == 20)
49
50  # Should update specified properties, but not reset other properties
51  p <- p + theme(text = element_text(colour = 'red'))
52  expect_true(p$theme$text$colour == 'red')
53  tt <- theme_grey()$text
54  tt$colour <- 'red'
55  expect_true(tt$inherit.blank)
56  tt$inherit.blank <- FALSE
57  expect_identical(p$theme$text, tt)
58
59  ## test without complete theme
60  p <- qplot(1:3, 1:3)
61  p <- p + theme(axis.title = element_text(size = 20))
62  expect_true(p$theme$axis.title$size == 20)
63
64  # Should update specified properties, but not reset other properties
65  p <- p + theme(text = element_text(colour = 'red'))
66  expect_true(p$theme$text$colour == 'red')
67  expect_null(p$theme$text$family)
68  expect_null(p$theme$text$face)
69  expect_null(p$theme$text$size)
70  expect_null(p$theme$text$hjust)
71  expect_null(p$theme$text$vjust)
72  expect_null(p$theme$text$angle)
73  expect_null(p$theme$text$lineheight)
74  expect_null(p$theme$text$margin)
75  expect_null(p$theme$text$debug)
76
77  ## stepwise addition of partial themes is identical to one-step addition
78  p <- qplot(1:3, 1:3)
79  p1 <- p + theme_light() +
80    theme(axis.line.x = element_line(color = "blue")) +
81    theme(axis.ticks.x = element_line(color = "red"))
82
83  p2 <- p + theme_light() +
84    theme(axis.line.x = element_line(color = "blue"),
85          axis.ticks.x = element_line(color = "red"))
86
87  expect_identical(p1$theme, p2$theme)
88})
89
90test_that("replacing theme elements with %+replace% operator works", {
91  # Changing a "leaf node" works
92  t <- theme_grey() %+replace% theme(axis.title.x = element_text(colour = 'red'))
93  expect_identical(t$axis.title.x, element_text(colour = 'red'))
94  # Make sure the class didn't change or get dropped
95  expect_true(is.theme(t))
96
97  # Changing an intermediate node works
98  t <- theme_grey() %+replace% theme(axis.title = element_text(colour = 'red'))
99  expect_identical(t$axis.title, element_text(colour = 'red'))
100  # Descendent is unchanged
101  expect_identical(t$axis.title.x, theme_grey()$axis.title.x)
102
103  # Adding empty theme() has no effect
104  t <- theme_grey() %+replace% theme()
105  expect_identical(t, theme_grey())
106
107  expect_error(theme_grey() + "asdf")
108})
109
110test_that("calculating theme element inheritance works", {
111  t <- theme_grey() + theme(axis.title = element_text(colour = 'red'))
112
113  # Check that properties are passed along from axis.title to axis.title.x
114  e <- calc_element('axis.title.x', t)
115  expect_identical(e$colour, 'red')
116  expect_false(is.null(e$family))
117  expect_false(is.null(e$face))
118  expect_false(is.null(e$size))
119
120  # Check that rel() works for relative sizing, and is applied at each level
121  t <- theme_grey(base_size = 12) +
122    theme(axis.title   = element_text(size = rel(0.5))) +
123    theme(axis.title.x = element_text(size = rel(0.5)))
124  e <- calc_element('axis.title', t)
125  expect_identical(e$size, 6)
126  ex <- calc_element('axis.title.x', t)
127  expect_identical(ex$size, 3)
128
129  # Check that a theme_blank in a parent node gets passed along to children
130  t <- theme_grey() + theme(text = element_blank())
131  expect_identical(calc_element('axis.title.x', t), element_blank())
132
133  # Check that inheritance from derived class works
134  element_dummyrect <- function(dummy) { # like element_rect but w/ dummy argument
135    structure(list(
136      fill = NULL, colour = NULL, dummy = dummy, size = NULL,
137      linetype = NULL, inherit.blank = FALSE
138    ), class = c("element_dummyrect", "element_rect", "element"))
139  }
140
141  e <- calc_element(
142    "panel.background",
143    theme(
144      rect = element_rect(fill = "white", colour = "black", size = 0.5, linetype = 1),
145      panel.background = element_dummyrect(dummy = 5),
146      complete = TRUE # need to prevent pulling in default theme
147    )
148  )
149
150  expect_identical(
151    e,
152    structure(list(
153      fill = "white", colour = "black", dummy = 5, size = 0.5, linetype = 1,
154      inherit.blank = TRUE # this is true because we're requesting a complete theme
155    ), class = c("element_dummyrect", "element_rect", "element"))
156  )
157
158  # Check that blank elements are skipped in inheritance tree if and only if elements
159  # don't inherit from blank.
160  t <- theme_gray() +
161    theme(
162      strip.text = element_blank(),
163      strip.text.x = element_text() # inherit.blank = FALSE is default
164    )
165  e1 <- calc_element("strip.text.x", t)
166  e2 <- calc_element("text", t)
167  e2$inherit.blank <- FALSE # b/c inherit.blank = TRUE for complete themes
168  expect_identical(e1, e2)
169
170  theme <- theme_gray() +
171    theme(strip.text = element_blank(), strip.text.x = element_text(inherit.blank = TRUE))
172  e1 <- ggplot2:::calc_element("strip.text.x", theme)
173  e2 <- ggplot2:::calc_element("strip.text", theme)
174  expect_identical(e1, e2)
175})
176
177test_that("complete and non-complete themes interact correctly with each other", {
178  # The 'complete' attribute of t1 + t2 is the OR of their 'complete' attributes.
179
180  # But for _element properties_, the one on the right modifies the one on the left.
181  t <- theme_bw() + theme(text = element_text(colour = 'red'))
182  expect_true(attr(t, "complete"))
183  expect_equal(t$text$colour, 'red')
184
185  # A complete theme object (like theme_bw) always trumps a non-complete theme object
186  t <- theme(text = element_text(colour = 'red')) + theme_bw()
187  expect_true(attr(t, "complete"))
188  expect_equal(t$text$colour, theme_bw()$text$colour)
189
190  # Adding two non-complete themes: the one on the right modifies the one on the left.
191  t <- theme(text = element_text(colour = 'blue')) +
192    theme(text = element_text(colour = 'red'))
193  expect_false(attr(t, "complete"))
194  expect_equal(t$text$colour, 'red')
195})
196
197test_that("complete and non-complete themes interact correctly with ggplot objects", {
198  # Check that adding two theme successive theme objects to a ggplot object
199  # works like adding the two theme object to each other
200  p <- ggplot_build(qplot(1:3, 1:3) + theme_bw() + theme(text = element_text(colour = 'red')))
201  expect_true(attr(p$plot$theme, "complete"))
202
203  # Compare the theme objects, after sorting the items, because item order can differ
204  pt <- p$plot$theme
205  tt <- theme_bw() + theme(text = element_text(colour = 'red'))
206  pt <- pt[order(names(pt))]
207  tt <- tt[order(names(tt))]
208  expect_identical(pt, tt)
209
210  p <- ggplot_build(qplot(1:3, 1:3) + theme(text = element_text(colour = 'red')) + theme_bw())
211  expect_true(attr(p$plot$theme, "complete"))
212  # Compare the theme objects, after sorting the items, because item order can differ
213  pt <- p$plot$theme
214  tt <- theme(text = element_text(colour = 'red')) + theme_bw()
215  pt <- pt[order(names(pt))]
216  tt <- tt[order(names(tt))]
217  expect_identical(pt, tt)
218
219  p <- ggplot_build(qplot(1:3, 1:3) + theme(text = element_text(colour = 'red', face = 'italic')))
220  expect_false(attr(p$plot$theme, "complete"))
221  expect_equal(p$plot$theme$text$colour, "red")
222  expect_equal(p$plot$theme$text$face, "italic")
223
224  p <- ggplot_build(qplot(1:3, 1:3) +
225    theme(text = element_text(colour = 'red')) +
226    theme(text = element_text(face = 'italic')))
227  expect_false(attr(p$plot$theme, "complete"))
228  expect_equal(p$plot$theme$text$colour, "red")
229  expect_equal(p$plot$theme$text$face, "italic")
230})
231
232test_that("theme(validate=FALSE) means do not validate_element", {
233  p <- qplot(1:3, 1:3)
234  bw <- p + theme_bw()
235  red.text <- theme(text = element_text(colour = "red"))
236  bw.before <- bw + theme(animint.width = 500, validate = FALSE)
237  expect_equal(bw.before$theme$animint.width, 500)
238
239  bw.after <- p + theme(animint.width = 500, validate = FALSE) + theme_bw()
240  expect_null(bw.after$theme$animint.width)
241
242  red.after <- p + theme(animint.width = 500, validate = FALSE) + red.text
243  expect_equal(red.after$theme$animint.width, 500)
244
245  red.before <- p + red.text + theme(animint.width = 500, validate = FALSE)
246  expect_equal(red.before$theme$animint.width, 500)
247})
248
249test_that("theme validation happens at build stage", {
250  # adding a non-valid theme element to a theme is no problem
251  expect_silent(theme_gray() + theme(text = 0))
252
253  # the error occurs when we try to render the plot
254  p <- ggplot() + theme(text = 0)
255  expect_error(print(p), "must be an object of type `element_text`")
256
257  # without validation, the error occurs when the element is accessed
258  p <- ggplot() + theme(text = 0, validate = FALSE)
259  expect_error(print(p), "text should have class element_text")
260})
261
262test_that("element tree can be modified", {
263  # we cannot add a new theme element without modifying the element tree
264  p <- ggplot() + theme(blablabla = element_text(colour = "red"))
265  expect_error(print(p), "Theme element `blablabla` is not defined in the element hierarchy")
266
267  # things work once we add a new element to the element tree
268  register_theme_elements(
269    element_tree = list(blablabla = el_def("element_text", "text"))
270  )
271  expect_silent(print(p))
272
273  # inheritance and final calculation of novel element works
274  final_theme <- ggplot2:::plot_theme(p, theme_gray())
275  e1 <- calc_element("blablabla", final_theme)
276  e2 <- calc_element("text", final_theme)
277  expect_identical(e1$family, e2$family)
278  expect_identical(e1$face, e2$face)
279  expect_identical(e1$size, e2$size)
280  expect_identical(e1$lineheight, e2$lineheight)
281  expect_identical(e1$colour, "red") # not inherited from element_text
282
283  # existing elements can be overwritten
284  ed <- el_def("element_rect", "rect")
285  register_theme_elements(
286    element_tree = list(axis.title = ed)
287  )
288  expect_identical(get_element_tree()$axis.title, ed)
289
290  reset_theme_settings(reset_current = FALSE) # revert back to defaults
291})
292
293test_that("all elements in complete themes have inherit.blank=TRUE", {
294  inherit_blanks <- function(theme) {
295    all(vapply(theme, function(el) {
296      if (inherits(el, "element") && !inherits(el, "element_blank")) {
297        el$inherit.blank
298      } else {
299        TRUE
300      }
301    }, logical(1)))
302  }
303  expect_true(inherit_blanks(theme_grey()))
304  expect_true(inherit_blanks(theme_bw()))
305  expect_true(inherit_blanks(theme_classic()))
306  expect_true(inherit_blanks(theme_dark()))
307  expect_true(inherit_blanks(theme_light()))
308  expect_true(inherit_blanks(theme_linedraw()))
309  expect_true(inherit_blanks(theme_minimal()))
310  expect_true(inherit_blanks(theme_void()))
311})
312
313test_that("elements can be merged", {
314  text_base <- element_text(colour = "red", size = 10)
315  expect_equal(
316    merge_element(element_text(colour = "blue"), text_base),
317    element_text(colour = "blue", size = 10)
318  )
319  rect_base <- element_rect(colour = "red", size = 10)
320  expect_equal(
321    merge_element(element_rect(colour = "blue"), rect_base),
322    element_rect(colour = "blue", size = 10)
323  )
324  line_base <- element_line(colour = "red", size = 10)
325  expect_equal(
326    merge_element(element_line(colour = "blue"), line_base),
327    element_line(colour = "blue", size = 10)
328  )
329  expect_error(
330    merge_element(text_base, rect_base),
331    "Only elements of the same class can be merged"
332  )
333})
334
335test_that("theme elements that don't inherit from element can be combined", {
336  expect_identical(combine_elements(1, NULL), 1)
337  expect_identical(combine_elements(NULL, 1), 1)
338  expect_identical(combine_elements(1, 0), 1)
339})
340
341test_that("complete plot themes shouldn't inherit from default", {
342  default_theme <- theme_gray() + theme(axis.text.x = element_text(colour = "red"))
343  base <- qplot(1, 1)
344
345  ptheme <- plot_theme(base + theme(axis.text.x = element_text(colour = "blue")), default_theme)
346  expect_equal(ptheme$axis.text.x$colour, "blue")
347
348  ptheme <- plot_theme(base + theme_void(), default_theme)
349  expect_null(ptheme$axis.text.x)
350})
351
352test_that("current theme can be updated with new elements", {
353  old <- theme_set(theme_grey())
354
355  b1 <- ggplot() + theme_grey()
356  b2 <- ggplot()
357
358  # works for root element
359  expect_identical(
360    calc_element("text", plot_theme(b1)),
361    calc_element("text", plot_theme(b2))
362  )
363
364  # works for derived element
365  expect_identical(
366    calc_element("axis.text.x", plot_theme(b1)),
367    calc_element("axis.text.x", plot_theme(b2))
368  )
369
370  # theme calculation for nonexisting element returns NULL
371  expect_identical(calc_element("abcde", plot_theme(b1)), NULL)
372
373  # element tree gets merged properly
374  register_theme_elements(
375    abcde = element_text(color = "blue", hjust = 0, vjust = 1),
376    element_tree = list(abcde = el_def("element_text", "text"))
377  )
378
379  e1 <- calc_element("abcde", plot_theme(b2))
380  e2 <- calc_element("text", plot_theme(b2))
381  e2$colour <- "blue"
382  e2$hjust <- 0
383  e2$vjust <- 1
384  expect_identical(e1, e2)
385
386  reset_theme_settings()
387  theme_set(old)
388})
389
390test_that("titleGrob() and margins() work correctly", {
391  # ascenders and descenders
392  g1 <- titleGrob("aaaa", 0, 0, 0.5, 0.5) # lower-case letters, no ascenders or descenders
393  g2 <- titleGrob("bbbb", 0, 0, 0.5, 0.5) # lower-case letters, no descenders
394  g3 <- titleGrob("gggg", 0, 0, 0.5, 0.5) # lower-case letters, no ascenders
395  g4 <- titleGrob("AAAA", 0, 0, 0.5, 0.5) # upper-case letters, no descenders
396
397  expect_equal(height_cm(g1), height_cm(g2))
398  expect_equal(height_cm(g1), height_cm(g3))
399  expect_equal(height_cm(g1), height_cm(g4))
400
401  # margins
402  g5 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 1, r = 0, b = 0, l = 0, unit = "cm"), margin_x = TRUE, margin_y = TRUE)
403  g6 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 0, r = 1, b = 0, l = 0, unit = "cm"), margin_x = TRUE, margin_y = TRUE)
404  g7 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 0, r = 0, b = 1, l = 0, unit = "cm"), margin_x = TRUE, margin_y = TRUE)
405  g8 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 0, r = 0, b = 0, l = 1, unit = "cm"), margin_x = TRUE, margin_y = TRUE)
406
407  expect_equal(height_cm(g5), height_cm(g1) + 1)
408  expect_equal(width_cm(g5), width_cm(g1))
409  expect_equal(height_cm(g6), height_cm(g1))
410  expect_equal(width_cm(g6), width_cm(g1) + 1)
411  expect_equal(height_cm(g7), height_cm(g1) + 1)
412  expect_equal(width_cm(g7), width_cm(g1))
413  expect_equal(height_cm(g8), height_cm(g1))
414  expect_equal(width_cm(g8), width_cm(g1) + 1)
415
416  # no margins when set to false
417  g9 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 1, r = 1, b = 1, l = 1, unit = "cm"), margin_x = FALSE, margin_y = TRUE)
418  g10 <- titleGrob("aaaa", 0, 0, 0.5, 0.5, margin = margin(t = 1, r = 1, b = 1, l = 1, unit = "cm"), margin_x = TRUE, margin_y = FALSE)
419  expect_equal(height_cm(g9), height_cm(g1) + 2)
420  # when one of margin_x or margin_y is set to FALSE and the other to TRUE, then the dimension for FALSE turns into
421  # length 1null.
422  expect_equal(g9$widths, grid::unit(1, "null"))
423  expect_equal(g10$heights, grid::unit(1, "null"))
424  expect_equal(width_cm(g10), width_cm(g1) + 2)
425})
426
427test_that("provided themes explicitly define all elements", {
428  elements <- names(.element_tree)
429
430  t <- theme_all_null()
431  expect_true(all(names(t) %in% elements))
432  expect_true(all(vapply(t, is.null, logical(1))))
433
434  t <- theme_grey()
435  expect_true(all(names(t) %in% elements))
436
437  t <- theme_bw()
438  expect_true(all(names(t) %in% elements))
439
440  t <- theme_linedraw()
441  expect_true(all(names(t) %in% elements))
442
443  t <- theme_light()
444  expect_true(all(names(t) %in% elements))
445
446  t <- theme_dark()
447  expect_true(all(names(t) %in% elements))
448
449  t <- theme_minimal()
450  expect_true(all(names(t) %in% elements))
451
452  t <- theme_classic()
453  expect_true(all(names(t) %in% elements))
454
455  t <- theme_void()
456  expect_true(all(names(t) %in% elements))
457
458  t <- theme_test()
459  expect_true(all(names(t) %in% elements))
460})
461
462# Visual tests ------------------------------------------------------------
463
464test_that("aspect ratio is honored", {
465  df <- cbind(data_frame(x = 1:8, y = 1:8, f = gl(2,4)), expand.grid(f1 = 1:2, f2 = 1:2, rep = 1:2))
466  p <- ggplot(df, aes(x, y)) +
467    geom_point() +
468    theme_test() +
469    labs(x = NULL, y = NULL)
470
471  p_a <- p + theme(aspect.ratio = 3)
472  p_b <- p + theme(aspect.ratio = 1 / 3)
473
474  expect_doppelganger("height is 3 times width",
475    p_a
476  )
477  expect_doppelganger("width is 3 times height",
478    p_b
479  )
480
481  expect_doppelganger("height is 3 times width, 2 wrap facets",
482    p_a + facet_wrap(~f)
483  )
484  expect_doppelganger("height is 3 times width, 2 column facets",
485    p_a + facet_grid(.~f)
486  )
487  expect_doppelganger("height is 3 times width, 2 row facets",
488    p_a + facet_grid(f~.)
489  )
490  expect_doppelganger("height is 3 times width, 2x2 facets",
491    p_a + facet_grid(f1~f2)
492  )
493
494})
495
496test_that("themes don't change without acknowledgement", {
497  df <- data_frame(x = 1:3, y = 1:3, z = c("a", "b", "a"), a = 1)
498  plot <- ggplot(df, aes(x, y, colour = z)) +
499    geom_point() +
500    facet_wrap(~ a)
501
502  expect_doppelganger("theme_bw", plot + theme_bw())
503  expect_doppelganger("theme_classic", plot + theme_classic())
504  expect_doppelganger("theme_dark", plot + theme_dark())
505  expect_doppelganger("theme_minimal", plot + theme_minimal())
506  expect_doppelganger("theme_gray", plot + theme_gray())
507  expect_doppelganger("theme_light", plot + theme_light())
508  expect_doppelganger("theme_void", plot + theme_void())
509  expect_doppelganger("theme_linedraw", plot + theme_linedraw())
510})
511
512test_that("themes look decent at larger base sizes", {
513  df <- data_frame(x = 1:3, y = 1:3, z = c("a", "b", "a"), a = 1)
514  plot <- ggplot(df, aes(x, y, colour = z)) +
515    geom_point() +
516    facet_wrap(~ a)
517
518  expect_doppelganger("theme_bw_large", plot + theme_bw(base_size = 33))
519  expect_doppelganger("theme_classic_large", plot + theme_classic(base_size = 33))
520  expect_doppelganger("theme_dark_large", plot + theme_dark(base_size = 33))
521  expect_doppelganger("theme_minimal_large", plot + theme_minimal(base_size = 33))
522  expect_doppelganger("theme_gray_large", plot + theme_gray(base_size = 33))
523  expect_doppelganger("theme_light_large", plot + theme_light(base_size = 33))
524  expect_doppelganger("theme_void_large", plot + theme_void(base_size = 33))
525  expect_doppelganger("theme_linedraw_large", plot + theme_linedraw(base_size = 33))
526})
527
528test_that("axes can be styled independently", {
529  plot <- ggplot() +
530    geom_point(aes(1:10, 1:10)) +
531    scale_x_continuous(sec.axis = dup_axis()) +
532    scale_y_continuous(sec.axis = dup_axis()) +
533    theme(
534      axis.title.x.top = element_text(colour = 'red'),
535      axis.title.x.bottom = element_text(colour = 'green'),
536      axis.title.y.left = element_text(colour = 'blue'),
537      axis.title.y.right = element_text(colour = 'yellow'),
538      axis.text.x.top = element_text(colour = 'red'),
539      axis.text.x.bottom = element_text(colour = 'green'),
540      axis.text.y.left = element_text(colour = 'blue'),
541      axis.text.y.right = element_text(colour = 'yellow'),
542      axis.ticks.x.top = element_line(colour = 'red'),
543      axis.ticks.x.bottom = element_line(colour = 'green'),
544      axis.ticks.y.left = element_line(colour = 'blue'),
545      axis.ticks.y.right = element_line(colour = 'yellow'),
546      axis.line.x.top = element_line(colour = 'red'),
547      axis.line.x.bottom = element_line(colour = 'green'),
548      axis.line.y.left = element_line(colour = 'blue'),
549      axis.line.y.right = element_line(colour = 'yellow')
550    )
551  expect_doppelganger("axes_styling", plot)
552})
553
554test_that("axes ticks can have independent lengths", {
555  plot <- ggplot() +
556    theme_test() +
557    geom_point(aes(1:10, 1:10)) +
558    scale_x_continuous(sec.axis = dup_axis()) +
559    scale_y_continuous(sec.axis = dup_axis()) +
560    theme(
561      axis.ticks.length.x.top = unit(-.5, "cm"),
562      axis.ticks.length.x.bottom = unit(-.25, "cm"),
563      axis.ticks.length.y.left = unit(.25, "cm"),
564      axis.ticks.length.y.right = unit(.5, "cm"),
565      axis.text.x.bottom = element_text(margin = margin(t = .25, unit = "cm")),
566      axis.text.x.top = element_text(margin = margin(b = .25, unit = "cm"))
567    )
568  expect_doppelganger("ticks_length", plot)
569})
570
571test_that("strips can be styled independently", {
572  df <- data_frame(x = 1:2, y = 1:2)
573  plot <- ggplot(df, aes(x, y)) +
574    facet_grid(x ~ y) +
575    theme(
576      strip.background.x = element_rect(fill = "red"),
577      strip.background.y = element_rect(fill = "green")
578    )
579  expect_doppelganger("strip_styling", plot)
580})
581
582test_that("rotated axis tick labels work", {
583  df <- data_frame(
584    y = c(1, 2, 3),
585    label = c("short", "medium size", "very long label")
586  )
587
588  plot <- ggplot(df, aes(label, y)) + geom_point() +
589    theme(axis.text.x = element_text(angle = 50, hjust = 1))
590  expect_doppelganger("rotated x axis tick labels", plot)
591})
592
593test_that("plot titles and caption can be aligned to entire plot", {
594  df <- data_frame(
595    x = 1:3,
596    y = 1:3,
597    z = letters[1:3]
598  )
599
600  plot <- ggplot(df, aes(x, y, color = z)) +
601    geom_point() + facet_wrap(~z) +
602    labs(
603      title = "Plot title aligned to entire plot",
604      subtitle = "Subtitle aligned to entire plot",
605      caption = "Caption aligned to panels"
606    ) +
607    theme(plot.title.position = "plot")
608  expect_doppelganger("titles aligned to entire plot", plot)
609
610  plot <- ggplot(df, aes(x, y, color = z)) +
611    geom_point() + facet_wrap(~z) +
612    labs(
613      title = "Plot title aligned to panels",
614      subtitle = "Subtitle aligned to panels",
615      caption = "Caption aligned to entire plot"
616    ) +
617    theme(plot.caption.position = "plot")
618  expect_doppelganger("caption aligned to entire plot", plot)
619
620})
621
622test_that("Strips can render custom elements", {
623  element_test <- function(...) {
624    el <- element_text(...)
625    class(el) <- c('element_test', 'element_text', 'element')
626    el
627  }
628  element_grob.element_test <- function(element, label = "", x = NULL, y = NULL, ...) {
629    rectGrob(width = unit(1, "cm"), height = unit(1, "cm"))
630  }
631  df <- data_frame(x = 1:3, y = 1:3, a = letters[1:3])
632  plot <- ggplot(df, aes(x, y)) +
633    geom_point() +
634    facet_wrap(~a) +
635    theme(strip.text = element_test())
636  expect_doppelganger("custom strip elements can render", plot)
637})
638