| package org.apache.tapestry5.internal.services; |
| |
| import org.apache.tapestry5.dom.Document |
| import org.apache.tapestry5.dom.Element |
| import org.apache.tapestry5.dom.XMLMarkupModel |
| import org.apache.tapestry5.internal.test.InternalBaseTestCase |
| import org.apache.tapestry5.json.JSONArray |
| import org.apache.tapestry5.services.javascript.InitializationPriority |
| import org.apache.tapestry5.services.javascript.ModuleManager |
| import org.apache.tapestry5.services.javascript.StylesheetLink |
| import org.apache.tapestry5.services.javascript.StylesheetOptions |
| import org.easymock.EasyMock |
| import org.easymock.IAnswer |
| import org.testng.annotations.Test |
| |
| import static org.easymock.EasyMock.eq |
| import static org.easymock.EasyMock.isA |
| |
| class DocumentLinkerImplTest extends InternalBaseTestCase { |
| |
| def check(Document document, String expectedContent) throws Exception { |
| |
| // TestNG's assertEquals() is actually more useful here than Groovy's assert. Normally, |
| // it's the other way around. |
| |
| assertEquals document.toString(), expectedContent.trim() |
| } |
| |
| @Test |
| void exception_if_missing_html_root_element_and_javascript() { |
| Document document = new Document() |
| |
| document.newRootElement("not-html").text("not an HTML document") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| // Only checked if there's something to link. |
| |
| linker.addLibrary("foo.js") |
| linker.addScript(InitializationPriority.NORMAL, "doSomething();") |
| |
| try { |
| linker.updateDocument(document) |
| unreachable() |
| } catch (RuntimeException ex) { |
| |
| assert ex.message == |
| "The root element of the rendered document was <not-html>, not <html>. A root element of <html> is needed when linking JavaScript and stylesheet resources." |
| } |
| } |
| |
| @Test |
| void logged_error_if_missing_html_element_and_css() { |
| Document document = new Document() |
| |
| document.newRootElement("not-html").text("not an HTML document") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| // Only checked if there's something to link. |
| |
| linker.addStylesheetLink(new StylesheetLink("style.css")) |
| |
| replay() |
| |
| linker.updateDocument(document) |
| |
| // Check that document is unchanged. |
| |
| check document, "<not-html>not an HTML document</not-html>" |
| |
| verify() |
| } |
| |
| @Test |
| void missing_root_element_is_a_noop() { |
| Document document = new Document() |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| linker.addLibrary("foo.js") |
| linker.addScript(InitializationPriority.NORMAL, "doSomething();") |
| |
| // No root element is not an error, even though there's work to do. |
| // The failure to render is reported elsewhere. |
| linker.updateDocument(document) |
| } |
| |
| @Test |
| void add_script_links() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.") |
| |
| def manager = mockModuleManager(["core.js", "foo.js", "bar/baz.js"], [new JSONArray("t5/core/pageinit:evalJavaScript", "pageINIT();")]) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, false, "1.2.3") |
| |
| replay() |
| |
| linker.addLibrary("core.js") |
| linker.addLibrary("foo.js") |
| linker.addLibrary("bar/baz.js") |
| linker.addScript(InitializationPriority.NORMAL, "pageINIT();") |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <html><body data-page-initialized="false"><p>Ready to be updated with scripts.</p><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| /** |
| * TAP5-446 |
| */ |
| @Test |
| void include_generator_meta() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("html").element("body").element("p").text("Ready to be marked with generator meta.") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, false, false, "1.2.3") |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <html><head><meta content="Apache Tapestry Framework (version 1.2.3)" name="generator"/></head><body data-page-initialized="true"><p>Ready to be marked with generator meta.</p></body></html> |
| ''' |
| } |
| |
| /** |
| * TAP5-584 |
| */ |
| @Test |
| void omit_generator_meta_on_no_html_root() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("no_html").text("Generator meta only added if root is html tag.") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, false, false, "1.2.3") |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <no_html>Generator meta only added if root is html tag.</no_html> |
| ''' |
| } |
| |
| |
| @Test |
| void add_style_links() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("html").element("body").element("p").text("Ready to be updated with styles.") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| linker.addStylesheetLink(new StylesheetLink("foo.css")) |
| linker.addStylesheetLink(new StylesheetLink("bar/baz.css", new StylesheetOptions("print"))) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <html><head><link type="text/css" rel="stylesheet" href="foo.css"/><link media="print" type="text/css" rel="stylesheet" href="bar/baz.css"/></head><body data-page-initialized="true"><p>Ready to be updated with styles.</p></body></html> |
| ''' |
| } |
| |
| @Test |
| void existing_head_used_if_present() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("html").element("head").comment(" existing head ").container.element("body").text( |
| "body content") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| linker.addStylesheetLink(new StylesheetLink("foo.css")) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <html><head><!-- existing head --><link type="text/css" rel="stylesheet" href="foo.css"/></head><body data-page-initialized="true">body content</body></html> |
| ''' |
| } |
| |
| @Test |
| void add_script() throws Exception { |
| Document document = new Document() |
| |
| document.newRootElement("html").element("body").element("p").text("Ready to be updated with scripts.") |
| |
| def manager = mockModuleManager([], [new JSONArray("t5/core/pageinit:evalJavaScript", "doSomething();")]) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, true, "1.2.3") |
| |
| replay() |
| |
| linker.addScript(InitializationPriority.IMMEDIATE, "doSomething();") |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><body data-page-initialized="false"><script type="text/javascript">document.write("<div class=\\"pageloading-mask\\"><div></div></div>");</script><p>Ready to be updated with scripts.</p><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| /** |
| * Perhaps the linker should create the <body> element in this case? In the meantime, |
| */ |
| @Test |
| void no_body_element() throws Exception { |
| Document document = new Document(new XMLMarkupModel()) |
| |
| document.newRootElement("html").element("notbody").element("p").text("Ready to be updated with scripts.") |
| |
| def manager = mockModuleManager(["foo.js"], []) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, false, "1.2.3") |
| |
| replay() |
| |
| linker.addLibrary("foo.js") |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <?xml version="1.0"?> |
| <html><notbody><p>Ready to be updated with scripts.</p></notbody><body data-page-initialized="false"><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| @Test |
| void immediate_initialization() throws Exception { |
| Document document = new Document() |
| |
| Element head = document.newRootElement("html").element("head") |
| |
| head.element("meta") |
| head.element("script") |
| |
| def manager = mockModuleManager([], [new JSONArray("['immediate/module:myfunc', {'fred':'barney'}]")]) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, false, "1.2.3") |
| |
| replay() |
| |
| linker.addInitialization(InitializationPriority.IMMEDIATE, "immediate/module", "myfunc", new JSONArray("[{ 'fred' : 'barney' }]")) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><head><meta/><script></script></head><body data-page-initialized="false"><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| |
| @Test |
| void ie_conditional_stylesheet() throws Exception { |
| Document document = new Document() |
| |
| document.newRootElement("html") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| linker.addStylesheetLink(new StylesheetLink("everybody.css")) |
| linker.addStylesheetLink(new StylesheetLink("just_ie.css", new StylesheetOptions().withCondition("IE"))) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><head><link type="text/css" rel="stylesheet" href="everybody.css"/> |
| <!--[if IE]> |
| <link type="text/css" rel="stylesheet" href="just_ie.css"/> |
| <![endif]--> |
| </head><body data-page-initialized="true"></body></html> |
| ''' |
| } |
| |
| @Test |
| void stylesheet_insertion_point() throws Exception { |
| Document document = new Document() |
| |
| document.newRootElement("html") |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(null, true, false, "1.2.3") |
| |
| linker.addStylesheetLink(new StylesheetLink("whatever.css")) |
| linker.addStylesheetLink(new StylesheetLink("insertion-point.css", new StylesheetOptions().asAjaxInsertionPoint())) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><head><link type="text/css" rel="stylesheet" href="whatever.css"/><link type="text/css" rel="stylesheet t-ajax-insertion-point" href="insertion-point.css"/></head><body data-page-initialized="true"></body></html> |
| ''' |
| } |
| |
| @Test |
| void module_based_INIT() throws Exception { |
| Document document = new Document() |
| |
| Element head = document.newRootElement("html").element("head") |
| |
| head.element("meta") |
| |
| def manager = mockModuleManager([], ["my/module", |
| new JSONArray("my/other/module:normal", 111, 222), |
| new JSONArray("my/other/module:late", 333, 444)]) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, false, "1.2.3") |
| |
| replay() |
| |
| linker.addInitialization(InitializationPriority.NORMAL, "my/module", null, null) |
| linker.addInitialization(InitializationPriority.NORMAL, "my/other/module", "normal", new JSONArray(111, 222)) |
| linker.addInitialization(InitializationPriority.LATE, "my/other/module", "late", new JSONArray(333, 444)) |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><head><meta/></head><body data-page-initialized="false"><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| @Test |
| void module_INIT_with_no_parameters_coalesce() throws Exception { |
| Document document = new Document() |
| |
| Element head = document.newRootElement("html").element("head") |
| |
| head.element("meta") |
| |
| def manager = mockModuleManager([], ["my/module", |
| new JSONArray("my/other/module:normal", 111, 222)]) |
| |
| DocumentLinkerImpl linker = new DocumentLinkerImpl(manager, true, false, "1.2.3") |
| |
| replay() |
| |
| linker.addInitialization(InitializationPriority.NORMAL, "my/module", null, null) |
| linker.addInitialization(InitializationPriority.NORMAL, "my/other/module", "normal", new JSONArray(111, 222)) |
| linker.addInitialization(InitializationPriority.NORMAL, "my/module", null, new JSONArray()); |
| |
| linker.updateDocument(document) |
| |
| check document, ''' |
| <html><head><meta/></head><body data-page-initialized="false"><!--MM-CONFIG--><!--MM-INIT--></body></html> |
| ''' |
| |
| verify() |
| } |
| |
| private ModuleManager mockModuleManager(def libraryURLs, def inits) { |
| |
| ModuleManager mock = newMock(ModuleManager); |
| |
| expect(mock.writeConfiguration(isA(Element), |
| eq([]))).andAnswer({ |
| def body = EasyMock.currentArguments[0] |
| |
| body.comment("MM-CONFIG") |
| } as IAnswer).once() |
| |
| expect(mock.writeInitialization(isA(Element), |
| eq(libraryURLs), |
| eq(inits))).andAnswer({ |
| def body = EasyMock.currentArguments[0]; |
| |
| body.comment("MM-INIT"); |
| } as IAnswer).once() |
| |
| |
| return mock; |
| } |
| } |