org.bonitasoft.web.designer.visitors.HtmlBuilderVisitorTest.java Source code

Java tutorial

Introduction

Here is the source code for org.bonitasoft.web.designer.visitors.HtmlBuilderVisitorTest.java

Source

/**
 * Copyright (C) 2015 Bonitasoft S.A.
 * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2.0 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.bonitasoft.web.designer.visitors;

import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.bonitasoft.web.designer.builder.AssetBuilder.anAsset;
import static org.bonitasoft.web.designer.builder.ComponentBuilder.aComponent;
import static org.bonitasoft.web.designer.builder.ComponentBuilder.aParagraph;
import static org.bonitasoft.web.designer.builder.ComponentBuilder.anInput;
import static org.bonitasoft.web.designer.builder.ContainerBuilder.aContainer;
import static org.bonitasoft.web.designer.builder.FormContainerBuilder.aFormContainer;
import static org.bonitasoft.web.designer.builder.PageBuilder.aPage;
import static org.bonitasoft.web.designer.builder.RowBuilder.aRow;
import static org.bonitasoft.web.designer.builder.TabBuilder.aTab;
import static org.bonitasoft.web.designer.builder.TabsContainerBuilder.aTabsContainer;
import static org.bonitasoft.web.designer.utils.assertions.CustomAssertions.assertThatHtmlBody;
import static org.bonitasoft.web.designer.utils.assertions.CustomAssertions.assertThatHtmlHead;
import static org.bonitasoft.web.designer.utils.assertions.CustomAssertions.toBody;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

import java.util.Arrays;
import java.util.Collections;

import org.apache.commons.codec.digest.DigestUtils;
import org.bonitasoft.web.designer.model.asset.Asset;
import org.bonitasoft.web.designer.model.asset.AssetScope;
import org.bonitasoft.web.designer.model.asset.AssetType;
import org.bonitasoft.web.designer.model.page.FormContainer;
import org.bonitasoft.web.designer.model.page.Page;
import org.bonitasoft.web.designer.model.widget.Widget;
import org.bonitasoft.web.designer.rendering.DirectivesCollector;
import org.bonitasoft.web.designer.rendering.GenerationException;
import org.bonitasoft.web.designer.rendering.HtmlGenerator;
import org.bonitasoft.web.designer.repository.AssetRepository;
import org.bonitasoft.web.designer.utils.assertions.CustomAssertions;
import org.bonitasoft.web.designer.utils.rule.TestResource;
import org.bonitasoft.web.designer.visitor.AssetVisitor;
import org.bonitasoft.web.designer.visitor.HtmlBuilderVisitor;
import org.bonitasoft.web.designer.visitor.PageFactory;
import org.bonitasoft.web.designer.visitor.RequiredModulesVisitor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.google.common.collect.Sets;

@RunWith(MockitoJUnitRunner.class)
public class HtmlBuilderVisitorTest {

    @Mock
    private PageFactory pageFactory;

    @Mock
    private RequiredModulesVisitor requiredModulesVisitor;

    @Mock
    private AssetVisitor assetVisitor;

    @Mock
    private AssetRepository<Page> pageAssetRepository;

    @Mock
    private AssetRepository<Widget> widgetAssetRepository;

    private HtmlBuilderVisitor visitor;

    private static final byte[] assetsContent = new byte[0];

    private String assetSHA1;

    @Mock
    private DirectivesCollector directivesCollector;

    @Rule
    public TestResource testResource = new TestResource(HtmlGenerator.class);

    @Before
    public void setUp() throws Exception {
        initMocks(this);
        visitor = new HtmlBuilderVisitor(asList(pageFactory), requiredModulesVisitor, assetVisitor,
                directivesCollector, pageAssetRepository, widgetAssetRepository);
        when(requiredModulesVisitor.visit(any(Page.class))).thenReturn(Collections.<String>emptySet());
        when(pageAssetRepository.readAllBytes(anyString(), any(Asset.class))).thenReturn(assetsContent);
        when(widgetAssetRepository.readAllBytes(any(Asset.class))).thenReturn(assetsContent);
        assetSHA1 = DigestUtils.sha1Hex(assetsContent);
    }

    @Test
    public void should_build_a_component_html_when_visiting_a_component() throws Exception {
        assertThatHtmlBody(visitor.visit(aComponent("pbWidget").withReference("component-reference")
                .withPropertyValue("property", "value").build()))
                        .isEqualToBody(testResource.load("component.html"));
    }

    @Test
    public void should_add_dimension_to_component() throws Exception {
        Element element = CustomAssertions.toBody(visitor.visit(aComponent("pbWidget").withDimension(3).build()));

        assertThatHtmlBody(element.childNode(1).outerHtml()).hasClass("col-xs-3");
    }

    @Test
    public void should_build_a_container() throws GenerationException {

        assertThatHtmlBody(visitor.visit(
                aContainer().withReference("container-reference").withPropertyValue("property", "value").build()))
                        .isEqualToBody(testResource.load("simplecontainer.html"));
    }

    @Test
    public void should_add_rows_to_the_container() throws Exception {

        assertThatHtmlBody(visitor.visit(aContainer().with(aRow()).withReference("container-reference").build()))
                .isEqualToBody(testResource.load("containerWithRow.html"));
    }

    @Test
    public void should_build_a_repeatable_container() throws GenerationException {

        assertThatHtmlBody(visitor.visit(aContainer().withReference("container-reference")
                .withPropertyValue("repeatedCollection", "json", "[\"foo\",\"bar\"]").build()))
                        .isEqualToBody(testResource.load("repeatedContainer.html"));
    }

    @Test
    public void should_not_build_a_repeatable_container_if_repeated_collection_is_an_empty_string()
            throws GenerationException {

        assertThatHtmlBody(visitor.visit(aContainer().withReference("container-reference")
                .withPropertyValue("repeatedCollection", "json", "").build()))
                        .isEqualToBody(testResource.load("notRepeatedContainer.html"));
    }

    @Test
    public void should_add_dimension_to_the_container() throws GenerationException {

        assertThatHtmlBody(
                visitor.visit(aContainer().withDimension(7).withReference("container-reference").build()))
                        .isEqualToBody(testResource.load("containerWithDimension.html"));
    }

    @Test
    public void should_add_elements_to_the_container_rows() throws Exception {

        // we should have two div.col-xs-12 with two div.row containing added components
        Elements rows = toBody(
                visitor.visit(aContainer().with(aRow().with(aComponent().withWidgetId("pbLabel").build()),
                        aRow().with(aComponent().withWidgetId("customLabel").build())).build())).select(".row");

        assertThat(rows.size()).isEqualTo(2);
        assertThat(rows.first().select("pb-label").outerHtml()).isEqualTo("<pb-label></pb-label>");
        assertThat(rows.last().select("custom-label").outerHtml()).isEqualTo("<custom-label></custom-label>");
    }

    @Test
    public void should_build_a_tabsContainer_html_when_visiting_a_tabsContainer() throws Exception {

        assertThatHtmlBody(visitor.visit(aTabsContainer()
                .with(aTab().withId("1").withTitle("First").with(aContainer().withReference("first-container")),
                        aTab().withId("2").withTitle("Last").with(aContainer().withReference("last-container")))
                .withReference("tabs-container-reference").build()))
                        .isEqualToBody(testResource.load("tabsContainerWithTwoTabs.html"));
    }

    @Test
    public void should_build_a_tab_container_bootstrap_like() throws Exception {

        assertThatHtmlBody(visitor.visit(aTabsContainer().withReference("tabs-container-reference").withDimension(4)
                .withPropertyValue("property", "value").build()))
                        .isEqualToBody(testResource.load("simpleTabContainer.html"));
    }

    @Test
    public void should_add_elements_to_the_tab_container_tabs() throws Exception {

        assertThatHtmlBody(visitor.visit(aTabsContainer()
                .with(aTab().withId("1")
                        .with(aContainer().with(aRow().with(aParagraph().withReference("paragraph-reference")))
                                .withReference("container-reference")))
                .withReference("tabs-container-reference").build()))
                        .isEqualToBody(testResource.load("tabsContainerWithContent.html"));
    }

    @Test
    public void should_build_a_container_fluid_for_a_previewable() throws Exception {
        Page page = aPage().build();
        when(pageFactory.generate(page)).thenReturn("var foo = \"bar\";");

        assertThatHtmlBody(visitor.build(page, "mycontext/")).hasElement("div.container-fluid");
    }

    @Test
    public void should_generate_an_html_with_the_list_of_widgets() throws Exception {
        Page page = aPage().withId("page-id").build();
        when(pageFactory.generate(page)).thenReturn("var foo = \"bar\";");
        when(directivesCollector.buildUniqueDirectivesFiles(page, page.getId()))
                .thenReturn(Arrays.asList("assets/widgets.js"));

        // when we generate the html
        String generatedHtml = visitor.build(page, "mycontext/");

        // then we should have the directive scripts included
        assertThat(generatedHtml).contains("<script src=\"assets/widgets.js\"></script>");

        // and an empty object as constant
        assertThat(generatedHtml).contains("pb-model='page-id'");
    }

    @Test
    public void should_generate_html_for_a_page() throws Exception {
        Asset assetLocal = anAsset().withOrder(1).withName("bonita.vendors.js").withExternal(false).build();
        Asset assetJquery = anAsset().withOrder(2).withName("//code.jquery.com/jquery-2.1.4.min.js")
                .withExternal(true).build();
        Asset assetRelative = anAsset().withOrder(3).withName("bonita.min.js").withExternal(true).build();
        Page page = aPage().withId("page-id").withAsset(assetRelative, assetJquery)
                .with(aContainer()
                        .with(aRow().with(anInput().withReference("input-reference"),
                                aParagraph().withReference("paragraph-reference")))
                        .withReference("container-reference"))
                .build();
        when(pageFactory.generate(page)).thenReturn("var baz = \"qux\";");
        when(directivesCollector.buildUniqueDirectivesFiles(page, page.getId()))
                .thenReturn(Arrays.asList("assets/widgets-f8b2ef17808cccb95dbf0973e7745cd53c29c684.js"));
        when(assetVisitor.visit(page)).thenReturn(Sets.newHashSet(assetRelative, assetJquery, assetLocal));

        String html = visitor.build(page, "mycontext/");

        assertThatHtmlBody(html).isEqualToBody(testResource.load("page.html"));
        assertThatHtmlHead(html).isEqualToHead(testResource.load("page.html"));
    }

    @Test
    public void should_generate_html_for_a_formcontainer() throws GenerationException {
        assertThatHtmlBody(
                visitor.visit(aFormContainer().with(aContainer().withReference("container-reference").build())
                        .withReference("formcontainer-reference").build()))
                                .isEqualToBody(testResource.load("formContainerSimple.html"));
    }

    @Test
    public void should_add_dimension_to_the_formcontainer() throws GenerationException {
        FormContainer formContainer = aFormContainer()
                .with(aContainer().withReference("container-reference").build()).withDimension(5).build();

        String html = visitor.visit(formContainer);

        assertThatHtmlBody(html).isEqualToBody(testResource.load("formContainerWithDimension.html"));
    }

    @Test
    public void should_add_container_to_the_formcontainer() throws Exception {
        FormContainer formContainer = aFormContainer()
                .with(aContainer()
                        .with(aRow().with(
                                aComponent().withWidgetId("pbLabel").withReference("component-reference").build()))
                        .withReference("container-reference").build())
                .withReference("formcontainer-reference").build();

        assertThatHtmlBody(visitor.visit(formContainer))
                .isEqualToBody(testResource.load("formContainerWithContainer.html"));
    }

    @Test
    public void should_add_extra_modules_when_widgets_needs_them() throws Exception {
        Page page = aPage().build();
        when(requiredModulesVisitor.visit(page)).thenReturn(newHashSet("needed.module"));

        String html = visitor.build(page, "");

        Element head = Jsoup.parse(html).head();
        assertThat(head.html()).contains("angular.module('bonitasoft.ui').requires.push('needed.module');");
    }

    @Test
    public void should_not_add_extra_modules_when_no_widgets_needs_them() throws Exception {
        Page page = aPage().build();
        when(requiredModulesVisitor.visit(page)).thenReturn(Collections.<String>emptySet());

        String html = visitor.build(page, "");

        Element head = Jsoup.parse(html).head();
        assertThat(head.html()).doesNotContain("angular.module('bonitasoft.ui').requires.push");
    }

    @Test
    public void should_add_asset_import_in_header() throws Exception {
        Page page = aPage().build();

        when(assetVisitor.visit(page)).thenReturn(Sets.newHashSet(
                //A css file in the page
                new Asset().setName("myfile.css").setType(AssetType.CSS),
                new Asset().setName("http://moncdn/myfile.css").setExternal(true).setType(AssetType.CSS),
                //An external css file in the page
                //A js file in a widget
                new Asset().setName("myfile.js").setType(AssetType.JAVASCRIPT).setScope(AssetScope.WIDGET)
                        .setComponentId("widget-id")));

        String html = visitor.build(page, "mycontext/");

        String head = Jsoup.parse(html).head().html();
        assertThat(head)
                .contains("<link rel=\"stylesheet\" href=\"assets/css/myfile.css?hash=" + assetSHA1 + "\">");
        assertThat(head).contains("<link rel=\"stylesheet\" href=\"http://moncdn/myfile.css\">");
        assertThat(head)
                .contains("<script src=\"widgets/widget-id/assets/js/myfile.js?hash=" + assetSHA1 + "\"></script>");
    }

    @Test
    public void should_build_rows() throws Exception {

        String html = visitor.build(asList(aRow().with(aParagraph().withReference("1")).build(),
                aRow().with(anInput().withReference("2"), aParagraph().withReference("3")).build()));

        assertThatHtmlBody(html).isEqualToBody(testResource.load("rowsWithComponents.html"));
    }

    @Test
    public void should_add_active_and_ordered_asset_import_in_header() throws Exception {
        Page page = aPage().build();

        when(assetVisitor.visit(page)).thenReturn(Sets.newHashSet(
                //Widgets assets
                new Asset().setName("myfile3.js").setOrder(3).setType(AssetType.JAVASCRIPT)
                        .setScope(AssetScope.WIDGET).setComponentId("widget-id"),
                new Asset().setName("myfile2.js").setOrder(2).setType(AssetType.JAVASCRIPT)
                        .setScope(AssetScope.WIDGET).setComponentId("widget-id"),
                new Asset().setName("myfile99.js").setOrder(99).setActive(false).setType(AssetType.JAVASCRIPT)
                        .setScope(AssetScope.WIDGET).setComponentId("widget-id"),
                //Another widget but with a name starting with z
                new Asset().setName("myfile4.js").setOrder(1).setType(AssetType.JAVASCRIPT)
                        .setScope(AssetScope.WIDGET).setComponentId("zidget-id"),
                //Page asset
                new Asset().setName("myfile1.js").setOrder(0).setType(AssetType.JAVASCRIPT)));

        String html = visitor.build(page, "mycontext/");

        String head = Jsoup.parse(html).head().html();

        //The header not contain inactive asset
        assertThat(head).doesNotContain("myfile99.js");
        //Page asset should be the last one, after widget assets identified by [widget-id] and widget assets identified by [zidget-id]
        assertThat(head).contains("<script src=\"widgets/widget-id/assets/js/myfile2.js?hash=" + assetSHA1
                + "\"></script> \n" + "<script src=\"widgets/widget-id/assets/js/myfile3.js?hash=" + assetSHA1
                + "\"></script> \n" + "<script src=\"widgets/zidget-id/assets/js/myfile4.js?hash=" + assetSHA1
                + "\"></script> \n" + "<script src=\"assets/js/myfile1.js?hash=" + assetSHA1 + "\"></script>");
    }
}