context("dependencies") format.html_dependency <- function(x, ...) { sprintf("%s v%s @ %s", x$name, x$version, format(x$src)) } print.html_dependency <- function(x, ...) { cat(format(x), "\n") invisible(x) } expect_resolved_deps <- function(input, output) { expect_identical(resolveDependencies(input), output) } test_that("Dependency resolution works", { a1.1 <- htmlDependency("a", "1.1", c(href="/")) a1.2 <- htmlDependency("a", "1.2", c(href="/")) a1.2.1 <- htmlDependency("a", "1.2.1", c(href="/")) b1.0.0 <- htmlDependency("b", "1.0.0", c(href="/")) b1.0.1 <- htmlDependency("b", "1.0.1", c(href="/")) c1.0 <- htmlDependency("c", "1.0", c(href="/")) expect_resolved_deps( list(a1.1, b1.0.0, b1.0.1, a1.2, a1.2.1, b1.0.0, b1.0.1, c1.0), list(a1.2.1, b1.0.1, c1.0) ) expect_resolved_deps( list(tagFunction(function() { NULL })), list() ) expect_resolved_deps( list(tagFunction(function() { a1.2 })), list(a1.2) ) expect_resolved_deps( list(a1.1, tagFunction(function() { NULL })), list(a1.1) ) expect_resolved_deps( list(a1.1, tagFunction(function() { a1.2 })), list(a1.2) ) expect_resolved_deps( list(a1.1, tagFunction(function() { list(a1.2, a1.2.1) })), list(a1.2.1) ) expect_warning(expect_resolved_deps( list(a1.1, tagFunction(function() { div("foo", a1.2, a1.2.1) })), list(a1.2.1) )) expect_warning(expect_resolved_deps( list(a1.1, tagFunction(function() { tagList(a1.2, a1.2.1) })), list(a1.2.1) )) expect_warning(expect_resolved_deps( list(a1.1, tagFunction(function() { tagList(div("foo", a1.2), div("foo", a1.2.1)) })), list(a1.2.1) )) expect_warning(expect_resolved_deps( list(a1.1, tagFunction(function() { tagList(div("foo", a1.2), div("foo", tagFunction(function() { a1.2.1 }))) } )), list(a1.2.1) )) res <- subtractDependencies(list(a1.2.1, b1.0.1), list(a1.1), warnOnConflict = FALSE) expect_identical(res, list(b1.0.1)) expect_warning(subtractDependencies(list(a1.2.1, b1.0.1), list(a1.1))) }) expect_html_deps <- function(x, html, deps) { expect_identical(as.character(renderTags(x)$html), html) expect_output(print(as.tags(x)), html) expect_identical(findDependencies(x), deps) } test_that("Inline dependencies", { # Test out renderTags and findDependencies when tags are inline a1.1 <- htmlDependency("a", "1.1", c(href="/")) a1.2 <- htmlDependency("a", "1.2", c(href="/")) # tagLists ---------------------------------------------------------- x <- tagList(a1.1, div("foo"), "bar") expect_html_deps(x, "
foo
\nbar", list(a1.1)) x <- tagList(a1.1, div("foo"), a1.2, "bar") expect_html_deps(x, "
foo
\nbar", list(a1.1, a1.2)) x <- tagList(a1.1, div("foo"), "bar", tagFunction(function() { a1.2 })) expect_html_deps(x, "
foo
\nbar", list(a1.1, a1.2)) x <- tagList(a1.1, div("foo"), "bar", tagFunction(function() { div("baz", a1.2) })) expect_html_deps(x, "
foo
\nbar\n
baz
", list(a1.1, a1.2)) # Mixing inline and attribute dependencies x <- attachDependencies( tagList(a1.1, div("foo"), "bar"), a1.2, append = TRUE ) expect_html_deps(x, "
foo
\nbar", list(a1.1, a1.2)) x <- attachDependencies( tagList(a1.1, div("foo"), "bar"), tagFunction(function() { a1.2 }), append = TRUE ) expect_html_deps(x, "
foo
\nbar", list(a1.1, a1.2)) x <- attachDependencies( tagList(div("foo"), "bar", tagFunction(function() { a1.1 })), tagFunction(function() { a1.2 }), append = TRUE ) expect_html_deps(x, "
foo
\nbar", list(a1.1, a1.2)) # tags with children ------------------------------------------------ x <- div(a1.1, div("foo"), "bar") expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1)) x <- div( tagFunction(function() { a1.1 }), tagFunction(function() { div("foo") }), tagFunction(function() { "bar" }) ) expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1)) x <- tagFunction(function() { div(div("foo"), a1.2, tagFunction(function() { "bar"}), a1.1) }) expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.2, a1.1)) x <- attachDependencies(div(a1.1, div("foo"), "bar"), a1.2, append = TRUE) expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1, a1.2)) x <- attachDependencies(div(a1.1, div("foo"), "bar"), tagFunction(function() { a1.2 }), append = TRUE) expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1, a1.2)) # Passing normal lists to tagLists and tag functions --------------- x <- tagList(list(a1.1, div("foo")), "bar") expect_html_deps(x, "
foo
\nbar", list(a1.1)) x <- tagList(list(tagFunction(function() { a1.1 }), div("foo")), "bar") expect_html_deps(x, "
foo
\nbar", list(a1.1)) x <- div(list(a1.1, div("foo")), "bar") expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1)) x <- div(list(tagFunction(function() { a1.1 }), div("foo")), "bar") expect_html_deps(x, "
\n
foo
\n bar\n
", list(a1.1)) # Top-level lists ----------------------------------- x <- list(div("ab"), "cd", a1.1) expect_html_deps(x, "
ab
\ncd", list(a1.1)) x <- structure(list(div("ab"), "cd", a1.1), class = "foo") expect_html_deps(x, "
ab
\ncd", list(a1.1)) x <- tagList(tagFunction(function() { list(div("ab"), "cd", a1.1) }), "bar") expect_html_deps(x, "
ab
\ncd\nbar", list(a1.1)) }) test_that("Modifying children using dependencies", { a1.1 <- htmlDependency("a", "1.1", c(href="/")) a1.2 <- htmlDependency("a", "1.2", c(href="/")) x <- tagAppendChild(div(a1.1), a1.2) expect_identical(findDependencies(x), list(a1.1, a1.2)) x <- tagAppendChild(div(a1.1), tagFunction(function() { a1.2 })) expect_identical(findDependencies(x), list(a1.1, a1.2)) x <- tagAppendChild(div(a1.1), list(a1.2)) expect_identical(findDependencies(x), list(a1.1, a1.2)) x <- tagAppendChildren(div(), a1.1, list(a1.2)) expect_identical(findDependencies(x), list(a1.1, a1.2)) x <- tagAppendChildren(div(), a1.1, tagFunction(function() { list(a1.2) })) expect_identical(findDependencies(x), list(a1.1, a1.2)) x <- tagSetChildren(div("foo", a1.1), a1.2) expect_identical(findDependencies(x), list(a1.2)) x <- tagSetChildren(div("foo", a1.1), tagFunction(function() { a1.2 })) expect_identical(findDependencies(x), list(a1.2)) }) test_that("able to resolve HTML scripts supplied with & without integrity", { src1 <- "https://cdn.com/libs/p1/0.1/" src2 <- "https://cdn/libs/p2/0.2/" deps <- list( htmlDependency( name = "p1", version = "0.1", src = list(href = src1), script = list( src = "p1.min.js", integrity = "longhash", crossorigin = "anonymous", defer = NA ) ), htmlDependency( "p2", version = "0.2", src = list(href = src2), script = "p2.min.js" ) ) expect1 <- paste( '', sep = '' ) expect2 <- paste( '', sep = '' ) expect <- paste(expect1, expect2, sep = '\n') class(expect) <- c("html", "character") actual <- renderDependencies(deps) expect_equal(!!strsplit(actual, "\n"), !!strsplit(expect, "\n")) }) test_that( "can render scripts given as lists of nested lists + scalar strings", { src = "https://cdn.com/libs/p1/0.1" nm <- "p1.js" d1 <- htmlDependency( "p1", "0.1", src = list(href = src), script = list(src = nm) ) deps1 <- list( d1, htmlDependency( "p1", "0.2", src = list(href = src), script = nm ), htmlDependency( "p1", "0.3", src = list(href = src), script = list(list(src = nm)) ) ) out <- renderDependencies(deps1) deps2 <- list( d1, d1, d1 ) expect_length(unique(unlist(strsplit(out, "\n"))), 1) expect_equal(renderDependencies(deps1), renderDependencies(deps2)) nm2 <- "p1-0.1.js" deps3 <- list( htmlDependency( "p1", "0.1", src = list(href = src), script = c(nm, nm2) ) ) out <- renderDependencies(deps3) src_urls <- c( file.path(src, nm), file.path(src, nm2) ) expect <- paste( '\n', '', sep = "") expect_equal(!!as.character(out), !!expect) deps4 <- list( htmlDependency( "p1", "0.1", src = list(href = src), script = list(list(src = nm, integrity = "hash"), nm2) ) ) out <- renderDependencies(deps4) expect <- paste( '\n', '', sep = "") expect_equal(!!as.character(out), !!expect) }) test_that("html escaping is carried out correctly in script rendering", { src = "https://cdn.com/libs/p1/0.1" nm <- "p1.js" funky_hash <- "" deps <- list( htmlDependency( "p1", "0.1", src = list(href = src), script = list(src = nm, integrity = funky_hash) ) ) src_url <- file.path(src, nm) expect <- paste( '', sep = "" ) out <- renderDependencies(deps) expect_equal(!!as.character(out), !!expect) }) test_that("copyDependencyToDir() doesn't create an empty directory", { tmp_dep <- tempfile("dep") dir.create(tmp_dep) on.exit(unlink(tmp_dep)) tmp_rmd <- tempfile("rmd_files") dir.create(tmp_rmd) on.exit(unlink(tmp_rmd), add = TRUE) empty <- htmltools::htmlDependency( name = "empty", version = "9.9.9", src = tmp_dep, head = "", all_files = FALSE ) copied_dep <- copyDependencyToDir(empty, tmp_rmd) # no directory is created for the empty dep expect_equal(dir(tmp_rmd), character()) # copied dependency src points to folder where files should be so that # to keep relativeTo() from throwing an error later in Rmd render process expect_match(copied_dep$src$file, normalizePath(tmp_rmd, "/", TRUE), fixed = TRUE) }) test_that("copyDependencyToDir() creates recursive output directories", { tmp_dep <- tempfile("dep") dir.create(tmp_dep) on.exit(unlink(tmp_dep, recursive = TRUE)) writeLines( c("alert('boo')"), file.path(tmp_dep, "script.js") ) dep <- htmltools::htmlDependency( name = "simple", version = "9.9.9", src = tmp_dep, script = "script.js", all_files = FALSE ) tmp_outputDir <- file.path(tempfile("outputDir"), "subdir") on.exit(unlink(tmp_outputDir, recursive = TRUE), add = TRUE) expect_silent(copyDependencyToDir(dep, tmp_outputDir)) # copyDependencyToDir() creates the nested outputDir expect_true(dir_exists(file.path(tmp_outputDir))) # it moves the dependency into this dir expect_true(dir_exists(file.path(tmp_outputDir, "simple-9.9.9"))) expect_true(file.exists(file.path(tmp_outputDir, "simple-9.9.9", "script.js"))) }) test_that("copyDependencyToDir() handles attributes", { tmp_dep <- tempfile("dep") dir.create(tmp_dep) on.exit(unlink(tmp_dep)) tmp_txt <- "temp.txt" path <- file.path(tmp_dep, tmp_txt) writeLines("Some text in the text/plain dep", path) tmp_js <- "javascript.js" path <- file.path(tmp_dep, tmp_js) writeLines('console.log("log message");', path) tmp_rmd <- tempfile("rmd_files") dir.create(tmp_rmd) on.exit(unlink(tmp_rmd), add = TRUE) dep_with_attributes <- htmltools::htmlDependency( name = "textPlain", version = "9.9.9", src = tmp_dep, script = list(src = tmp_txt, type = "text/plain"), all_files = FALSE ) dep_without <- htmltools::htmlDependency( name = "textPlain", version = "9.9.9", src = tmp_dep, script = tmp_js, all_files = FALSE ) dep_with_both <- htmltools::htmlDependency( name = "textPlain", version = "9.9.9", src = tmp_dep, script = list(tmp_js, list(src = tmp_txt, type = "text/plain")), all_files = FALSE ) dep_with_one_nested <- htmltools::htmlDependency( name = "textPlain", version = "9.9.9", src = tmp_dep, script = list(list(src = tmp_txt, type = "text/plain")), all_files = FALSE ) dep_with_missings <- htmltools::htmlDependency( name = "textPlain", version = "9.9.9", src = tmp_dep, script = list(tmp_js, "foobar1", list(src = "foobar2")), all_files = FALSE ) # None of these except the last should trigger errors as # the first two did in issue #320 copyDependencyToDir(dep_with_attributes, tmp_rmd) expect_equal(dir(tmp_rmd, recursive = TRUE), "textPlain-9.9.9/temp.txt") unlink(dir(tmp_rmd, recursive = TRUE)) copyDependencyToDir(dep_with_both, tmp_rmd) expect_equal(dir(tmp_rmd, recursive = TRUE), c("textPlain-9.9.9/javascript.js", "textPlain-9.9.9/temp.txt")) unlink(dir(tmp_rmd, recursive = TRUE)) copyDependencyToDir(dep_without, tmp_rmd) expect_equal(dir(tmp_rmd, recursive = TRUE), "textPlain-9.9.9/javascript.js") unlink(dir(tmp_rmd, recursive = TRUE)) copyDependencyToDir(dep_with_one_nested, tmp_rmd) expect_equal(dir(tmp_rmd, recursive = TRUE), "textPlain-9.9.9/temp.txt") expect_error(copyDependencyToDir(dep_with_missings, tmp_rmd)) })