org.bonitasoft.web.designer.controller.PageResourceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.bonitasoft.web.designer.controller.PageResourceTest.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.controller;

import static com.jayway.jsonassert.impl.matcher.IsCollectionWithSize.hasSize;
import static java.nio.file.Files.readAllBytes;
import static org.assertj.core.api.Assertions.assertThat;
import static org.bonitasoft.web.designer.builder.AssetBuilder.anAsset;
import static org.bonitasoft.web.designer.builder.PageBuilder.aFilledPage;
import static org.bonitasoft.web.designer.builder.PageBuilder.aPage;
import static org.bonitasoft.web.designer.controller.asset.AssetService.OrderType.DECREMENT;
import static org.bonitasoft.web.designer.controller.asset.AssetService.OrderType.INCREMENT;
import static org.bonitasoft.web.designer.model.asset.AssetScope.PAGE;
import static org.bonitasoft.web.designer.model.asset.AssetType.JAVASCRIPT;
import static org.bonitasoft.web.designer.model.contract.builders.ContractBuilder.aSimpleContract;
import static org.bonitasoft.web.designer.utils.RestControllerUtil.convertObjectToJsonBytes;
import static org.bonitasoft.web.designer.utils.UIDesignerMockMvcBuilder.mockServer;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.fasterxml.jackson.core.FakeJsonProcessingException;
import org.bonitasoft.web.designer.controller.asset.AssetService;
import org.bonitasoft.web.designer.controller.asset.MalformedJsonException;
import org.bonitasoft.web.designer.experimental.mapping.ContractToPageMapper;
import org.bonitasoft.web.designer.experimental.mapping.FormScope;
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.contract.Contract;
import org.bonitasoft.web.designer.model.page.Element;
import org.bonitasoft.web.designer.model.page.Page;
import org.bonitasoft.web.designer.repository.PageRepository;
import org.bonitasoft.web.designer.repository.exception.NotFoundException;
import org.bonitasoft.web.designer.repository.exception.RepositoryException;
import org.bonitasoft.web.designer.visitor.AssetVisitor;
import org.hamcrest.Matchers;
import org.joda.time.Instant;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.MediaType;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import com.google.common.collect.Sets;

/**
 * Test de {@link org.bonitasoft.web.designer.controller.PageResource}
 */
@RunWith(MockitoJUnitRunner.class)
public class PageResourceTest {

    private MockMvc mockMvc;

    @Mock
    private PageRepository pageRepository;

    @Mock
    private SimpMessagingTemplate messagingTemplate;

    @Mock
    private ContractToPageMapper contractToPageMapper;

    @Mock
    private AssetService<Page> pageAssetService;

    @Mock
    private AssetVisitor assetVisitor;

    @InjectMocks
    private PageResource pageResource;

    private Path widgetRepositoryPath;

    @Before
    public void setUp() throws URISyntaxException {
        mockMvc = mockServer(pageResource).build();
        widgetRepositoryPath = Paths.get(getClass().getResource("/workspace/widgets").toURI());
    }

    private Page mockPageOfId(String id) {
        Page page = aPage().withId(id).build();
        when(pageRepository.get(id)).thenReturn(page);
        return page;
    }

    @Test
    public void should_list_pages() throws Exception {
        Page page = new Page();
        page.setId("id");
        page.setName("name");
        page.setLastUpdate(Instant.parse("2015-02-02"));
        when(pageRepository.getAll()).thenReturn(Arrays.asList(page));

        mockMvc.perform(get("/rest/pages")).andExpect(status().isOk()).andExpect(jsonPath("$", hasSize(1)))
                .andExpect(jsonPath("$[*].id").value("id")).andExpect(jsonPath("$[*].name").value("name"))
                .andExpect(jsonPath("$[*].lastUpdate").value(Instant.parse("2015-02-02").getMillis()));
    }

    @Test
    public void should_create_a_page_from_a_Page() throws Exception {
        Page pageToBeSaved = aPage().withId("my-page").build();
        List<Element> emptyRow = Collections.emptyList();
        List<List<Element>> rows = Collections.singletonList(emptyRow);
        pageToBeSaved.setRows(rows);
        pageToBeSaved.setName("test");

        mockMvc.perform(post("/rest/pages").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(pageToBeSaved))).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", notNullValue()));

        verify(pageRepository).updateLastUpdateAndSave(notNull(Page.class));
        verify(pageAssetService).loadDefaultAssets(any(Page.class));
    }

    @Test
    public void should_duplicate_a_page_from_a_Page() throws Exception {
        Asset pageAsset = aPageAsset();
        Asset widgetAsset = aWidgetAsset();
        Page pageToBeSaved = aPage().withId("my-page").withName("test").withAsset(pageAsset, widgetAsset).build();
        when(pageRepository.get("my-page-source")).thenReturn(
                aPage().withId("my-page-source").withName("test").withAsset(pageAsset, widgetAsset).build());

        mockMvc.perform(post("/rest/pages?duplicata=my-page-source").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(pageToBeSaved))).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", notNullValue()));

        ArgumentCaptor<Page> argument = ArgumentCaptor.forClass(Page.class);
        verify(pageRepository).updateLastUpdateAndSave(argument.capture());
        assertThat(argument.getValue().getName()).isEqualTo(pageToBeSaved.getName());
        assertThat(argument.getValue().getAssets()).containsOnly(pageAsset);
        verify(pageAssetService).duplicateAsset(any(Path.class), any(Path.class), eq("my-page-source"),
                anyString());
    }

    @Test
    public void should_create_a_page_from_a_Contract_at_task_scope() throws Exception {
        Contract contract = aSimpleContract();
        Page newPage = aPage().withName("myPage").build();
        when(contractToPageMapper.createFormPage(eq("myPage"), notNull(Contract.class), eq(FormScope.TASK)))
                .thenReturn(newPage);

        mockMvc.perform(post("/rest/pages/contract/task/myPage").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(contract))).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", notNullValue()));

        verify(pageRepository).updateLastUpdateAndSave(newPage);
    }

    @Test
    public void should_create_a_page_from_a_Contract_at_process_scope() throws Exception {
        Contract contract = aSimpleContract();
        Page newPage = aPage().withName("myPage").build();
        when(contractToPageMapper.createFormPage(eq("myPage"), notNull(Contract.class), eq(FormScope.PROCESS)))
                .thenReturn(newPage);

        mockMvc.perform(post("/rest/pages/contract/process/myPage").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(contract))).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", notNullValue()));

        verify(pageRepository).updateLastUpdateAndSave(newPage);
    }

    @Test
    public void should_create_a_page_from_a_Contract_at_overview_scope() throws Exception {
        Contract contract = aSimpleContract();
        Page newPage = aPage().withName("myPage").build();
        when(contractToPageMapper.createFormPage(eq("myPage"), notNull(Contract.class), eq(FormScope.OVERVIEW)))
                .thenReturn(newPage);

        mockMvc.perform(post("/rest/pages/contract/overview/myPage").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(contract))).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", notNullValue()));

        verify(pageRepository).updateLastUpdateAndSave(newPage);
    }

    @Test
    public void should_save_a_page() throws Exception {
        Page pageToBeSaved = aFilledPage("my-page");

        mockMvc.perform(put("/rest/pages/my-page").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(pageToBeSaved))).andExpect(status().isOk());

        verify(pageRepository).updateLastUpdateAndSave(pageToBeSaved);
        verify(messagingTemplate).convertAndSend("/previewableUpdates", "my-page");
    }

    @Test
    public void should_not_save_widget_assets_while_saving_a_page() throws Exception {
        Page pageToBeSaved = aPage().withId("my-page").withAsset(aWidgetAsset(), aPageAsset()).build();
        Page expectedPage = aPage().withId("my-page").withAsset(aPageAsset()).build();

        mockMvc.perform(put("/rest/pages/my-page").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(pageToBeSaved))).andExpect(status().isOk());

        verify(pageRepository).updateLastUpdateAndSave(expectedPage);
    }

    private Asset aPageAsset() {
        return anAsset().withName("myJs.js").withType(AssetType.JAVASCRIPT).build();
    }

    private Asset aWidgetAsset() {
        return anAsset().withName("myCss.css").withType(AssetType.CSS).withScope(AssetScope.WIDGET)
                .withComponentId("widget-id").build();
    }

    @Test
    public void should_respond_415_unsupported_media_type_when_trying_to_save_non_json_content() throws Exception {

        mockMvc.perform(put("/rest/pages/my-page").content("this is not json")).andExpect(status().is(415));
    }

    @Test
    public void should_respond_500_internal_error_if_error_occurs_while_saving_a_page() throws Exception {
        Page page = aPage().withId("my-page").build();
        Mockito.doThrow(new RepositoryException("exception occurs", new Exception())).when(pageRepository)
                .updateLastUpdateAndSave(page);

        mockMvc.perform(put("/rest/pages/my-page").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(page))).andExpect(status().isInternalServerError());
    }

    @Test
    public void should_retrieve_a_page_representation_by_its_id() throws Exception {
        Page expectedPage = aFilledPage("my-page");
        when(pageRepository.get("my-page")).thenReturn(expectedPage);

        mockMvc.perform(get("/rest/pages/my-page")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$", notNullValue()));
    }

    @Test
    public void should_respond_404_not_found_if_page_is_not_existing() throws Exception {
        when(pageRepository.get("my-page")).thenThrow(new NotFoundException("page not found"));

        mockMvc.perform(get("/rest/pages/my-page")).andExpect(status().isNotFound());
    }

    @Test
    public void should_respond_404_not_found_when_delete_inexisting_page() throws Exception {
        doThrow(new NotFoundException("page not found")).when(pageRepository).delete("my-page");

        mockMvc.perform(delete("/rest/pages/my-page")).andExpect(status().isNotFound());
    }

    @Test
    public void should_respond_500_internal_error_when_error_on_deletion_page() throws Exception {
        doThrow(new RepositoryException("error occurs", new RuntimeException())).when(pageRepository)
                .delete("my-page");

        mockMvc.perform(delete("/rest/pages/my-page")).andExpect(status().isInternalServerError());
    }

    @Test
    public void should_delete_a_page() throws Exception {
        mockMvc.perform(delete("/rest/pages/my-page")).andExpect(status().isOk());
    }

    @Test
    public void should_rename_a_page() throws Exception {
        String newName = "my-page-new-name";
        mockPageOfId("my-page");

        mockMvc.perform(
                put("/rest/pages/my-page/name").contentType(MediaType.APPLICATION_JSON_VALUE).content(newName))
                .andExpect(status().isOk());

        ArgumentCaptor<Page> pageArgumentCaptor = ArgumentCaptor.forClass(Page.class);
        verify(pageRepository).updateLastUpdateAndSave(pageArgumentCaptor.capture());

        assertThat(pageArgumentCaptor.getValue().getName()).isEqualTo(newName);
    }

    @Test
    public void should_respond_404_not_found_if_page_is_not_existing_when_renaming() throws Exception {
        when(pageRepository.get("my-page")).thenThrow(new NotFoundException("page not found"));

        mockMvc.perform(put("/rest/pages/my-page/name").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes("hello"))).andExpect(status().isNotFound());
    }

    @Test
    public void should_respond_500_internal_error_if_error_occurs_while_renaming_a_page() throws Exception {
        doThrow(new RepositoryException("exception occurs", new Exception())).when(pageRepository)
                .updateLastUpdateAndSave(any(Page.class));
        mockPageOfId("my-page");

        mockMvc.perform(put("/rest/pages/my-page/name").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes("hello"))).andExpect(status().isInternalServerError());
    }

    @Test
    public void should_upload_a_local_asset() throws Exception {
        //We construct a mockfile (the first arg is the name of the property expected in the controller
        MockMultipartFile file = new MockMultipartFile("file", "myfile.js", "application/javascript",
                "foo".getBytes());
        Page page = mockPageOfId("my-page");
        Asset expectedAsset = anAsset().withId("assetId").active().withName("myfile.js").withOrder(2)
                .withScope(PAGE).withType(AssetType.JAVASCRIPT).build();
        when(pageAssetService.upload(file, page, "js")).thenReturn(expectedAsset);

        mockMvc.perform(fileUpload("/rest/pages/my-page/assets/js").file(file)).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id").value("assetId")).andExpect(jsonPath("$.name").value("myfile.js"))
                .andExpect(jsonPath("$.scope").value(PAGE.toString())).andExpect(jsonPath("$.type").value("js"))
                .andExpect(jsonPath("$.order").value(2));

        verify(pageAssetService).upload(file, page, "js");
    }

    @Test
    public void should_respond_202_with_error_when_uploading_a_json_asset_with_malformed_json_file()
            throws Exception {
        byte[] content = "notvalidjson".getBytes();
        MockMultipartFile file = aJsonFileWithContent(content);
        int expectedLine = 4, expectedColumn = 2;
        when(pageAssetService.upload(file, mockPageOfId("my-page"), "json"))
                .thenThrow(aMalformedJsonException(content, expectedLine, expectedColumn));

        mockMvc.perform(fileUpload("/rest/pages/my-page/assets/json").file(file)).andExpect(status().isAccepted())
                .andExpect(jsonPath("$.type").value("MalformedJsonException"))
                .andExpect(jsonPath("$.infos.location.line").value(expectedLine))
                .andExpect(jsonPath("$.infos.location.column").value(expectedColumn));
    }

    private MockMultipartFile aJsonFileWithContent(byte[] content) {
        return new MockMultipartFile("file", "myfile.js", "application/json", content);
    }

    private MalformedJsonException aMalformedJsonException(byte[] bytes, int errorLine, int errorColumn) {
        return new MalformedJsonException(
                new FakeJsonProcessingException("Error while checking json", bytes, errorLine, errorColumn));
    }

    @Test
    public void should_not_upload_an_asset_when_upload_send_an_error() throws Exception {
        //We construct a mockfile (the first arg is the name of the property expected in the controller
        MockMultipartFile file = new MockMultipartFile("file", "myfile.js", "application/javascript",
                "foo".getBytes());
        Page page = mockPageOfId("my-page");
        doThrow(IllegalArgumentException.class).when(pageAssetService).upload(file, page, "js");

        mockMvc.perform(fileUpload("/rest/pages/my-page/assets/js").file(file)).andExpect(status().isBadRequest());

        verify(pageAssetService).upload(file, page, "js");
    }

    @Test
    public void should_save_an_external_asset() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset expectedAsset = anAsset().withId("assetId").active().withName("myfile.js").withOrder(2)
                .withScope(PAGE).withType(AssetType.JAVASCRIPT).build();
        when(pageAssetService.save(page, expectedAsset)).thenReturn(expectedAsset);

        mockMvc.perform(post("/rest/pages/my-page/assets").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(expectedAsset))).andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value("assetId")).andExpect(jsonPath("$.name").value("myfile.js"))
                .andExpect(jsonPath("$.scope").value(PAGE.toString())).andExpect(jsonPath("$.type").value("js"))
                .andExpect(jsonPath("$.order").value(2));

        verify(pageAssetService).save(page, expectedAsset);
    }

    @Test
    public void should_not_save_an_external_asset_when_upload_send_an_error() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset asset = anAsset().build();
        doThrow(IllegalArgumentException.class).when(pageAssetService).save(page, asset);

        mockMvc.perform(post("/rest/pages/my-page/assets").contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(convertObjectToJsonBytes(asset))).andExpect(status().isBadRequest());
    }

    @Test
    public void should_list_page_assets() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset[] assets = new Asset[] {
                anAsset().withName("myCss.css").withType(AssetType.CSS).withScope(AssetScope.WIDGET)
                        .withComponentId("widget-id").build(),
                anAsset().withName("myJs.js").withType(JAVASCRIPT).withScope(AssetScope.PAGE).build(),
                anAsset().withName("https://mycdn.com/myExternalJs.js").withScope(AssetScope.PAGE)
                        .withType(JAVASCRIPT).build() };
        when(assetVisitor.visit(page)).thenReturn(Sets.newHashSet(assets));

        mockMvc.perform(get("/rest/pages/my-page/assets")).andExpect(status().isOk())
                .andExpect(jsonPath("$", hasSize(3)))
                .andExpect(jsonPath("$[*].name",
                        Matchers.containsInAnyOrder("https://mycdn.com/myExternalJs.js", "myJs.js", "myCss.css")))
                .andExpect(jsonPath("$[*].type", Matchers.containsInAnyOrder("js", "js", "css")))
                .andExpect(jsonPath("$[*].scope", Matchers.containsInAnyOrder("page", "page", "widget")))
                .andExpect(jsonPath("$[*].componentId", Matchers.containsInAnyOrder("widget-id")));

    }

    @Test
    public void should_list_page_assets_while_getting_a_page() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset[] assets = new Asset[] {
                anAsset().withName("myCss.css").withType(AssetType.CSS).withScope(AssetScope.WIDGET)
                        .withComponentId("widget-id").build(),
                anAsset().withName("myJs.js").withType(AssetType.JAVASCRIPT).withScope(AssetScope.PAGE).build(),
                anAsset().withName("https://mycdn.com/myExternalJs.js").withType(AssetType.JAVASCRIPT)
                        .withScope(AssetScope.PAGE).build() };
        when(assetVisitor.visit(page)).thenReturn(Sets.newHashSet(assets));

        mockMvc.perform(get("/rest/pages/my-page")).andExpect(status().isOk())
                .andExpect(jsonPath("$.assets", hasSize(3)))
                .andExpect(jsonPath("$.assets[*].name",
                        Matchers.containsInAnyOrder("https://mycdn.com/myExternalJs.js", "myJs.js", "myCss.css")))
                .andExpect(jsonPath("$.assets[*].type", Matchers.containsInAnyOrder("js", "js", "css")))
                .andExpect(jsonPath("$.assets[*].scope", Matchers.containsInAnyOrder("page", "page", "widget")))
                .andExpect(jsonPath("$.assets[*].componentId", Matchers.containsInAnyOrder("widget-id")));
    }

    @Test
    public void should_increment_an_asset() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset asset = anAsset().withComponentId("my-page").withOrder(3).build();

        mockMvc.perform(put("/rest/pages/my-page/assets/UIID?increment=true")
                .contentType(MediaType.APPLICATION_JSON_VALUE).content(convertObjectToJsonBytes(asset)))
                .andExpect(status().isOk());

        verify(pageAssetService).changeAssetOrderInComponent(page, "UIID", INCREMENT);
    }

    @Test
    public void should_decrement_an_asset() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset asset = anAsset().withComponentId("my-page").withOrder(3).build();

        mockMvc.perform(put("/rest/pages/my-page/assets/UIID?decrement=true")
                .contentType(MediaType.APPLICATION_JSON_VALUE).content(convertObjectToJsonBytes(asset)))
                .andExpect(status().isOk());

        verify(pageAssetService).changeAssetOrderInComponent(page, "UIID", DECREMENT);
    }

    @Test
    public void should_delete_an_asset() throws Exception {
        Page page = mockPageOfId("my-page");

        mockMvc.perform(delete("/rest/pages/my-page/assets/UIID").contentType(MediaType.APPLICATION_JSON_VALUE))
                .andExpect(status().isOk());

        verify(pageAssetService).delete(page, "UIID");
    }

    @Test
    public void should_inactive_an_asset() throws Exception {
        Page page = mockPageOfId("my-page");
        Asset asset = anAsset().withComponentId(page.getId()).withOrder(3).build();

        mockMvc.perform(put("/rest/pages/my-page/assets/UIID?active=false")
                .contentType(MediaType.APPLICATION_JSON_VALUE).content(convertObjectToJsonBytes(asset)))
                .andExpect(status().isOk());

        verify(pageAssetService).changeAssetStateInPreviewable(page, "UIID", false);
    }

    @Test
    public void should_mark_a_page_as_favorite() throws Exception {

        mockMvc.perform(
                put("/rest/pages/my-page/favorite").contentType(MediaType.APPLICATION_JSON_VALUE).content("true"))
                .andExpect(status().isOk());

        verify(pageRepository).markAsFavorite("my-page");
    }

    @Test
    public void should_unmark_a_page_as_favorite() throws Exception {

        mockMvc.perform(
                put("/rest/pages/my-page/favorite").contentType(MediaType.APPLICATION_JSON_VALUE).content("false"))
                .andExpect(status().isOk());

        verify(pageRepository).unmarkAsFavorite("my-page");
    }

    @Test
    public void should_load_page_asset_on_disk_with_content_type_text() throws Exception {
        Path expectedFile = widgetRepositoryPath.resolve("pbLabel/pbLabel.js");
        when(pageAssetService.findAssetPath("page-id", "asset.js", AssetType.JAVASCRIPT.getPrefix()))
                .thenReturn(expectedFile);

        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js?format=text")).andExpect(status().isOk())
                .andExpect(content().bytes(readAllBytes(expectedFile)))
                .andExpect(content().contentType(MediaType.TEXT_PLAIN))
                .andExpect(header().string("Content-Length", String.valueOf(expectedFile.toFile().length())))
                .andExpect(header().string("Content-Disposition", "inline; filename=\"pbLabel.js\""))
                .andExpect(content().encoding("UTF-8"));
    }

    @Test
    public void should_download_page_asset() throws Exception {
        Path expectedFile = widgetRepositoryPath.resolve("pbLabel/pbLabel.js");
        when(pageAssetService.findAssetPath("page-id", "asset.js", AssetType.JAVASCRIPT.getPrefix()))
                .thenReturn(expectedFile);

        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js")).andExpect(status().isOk())
                .andExpect(content().bytes(readAllBytes(expectedFile)))
                .andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
                .andExpect(header().string("Content-Length", String.valueOf(expectedFile.toFile().length())))
                .andExpect(header().string("Content-Disposition", "attachment; filename=\"pbLabel.js\""))
                .andExpect(content().encoding("UTF-8"));
    }

    @Test
    public void should_respond_404_when_widget_asset_included_in_page_is_not_found() throws Exception {
        when(pageAssetService.findAssetPath("page-id", "asset.js", AssetType.JAVASCRIPT.getPrefix()))
                .thenReturn(null);

        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js?format=text")).andExpect(status().isNotFound());
        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js")).andExpect(status().isNotFound());
    }

    @Test
    public void should_respond_500_when_widget_asset_included_in_page_produce_IOException() throws Exception {
        when(pageAssetService.findAssetPath("page-id", "asset.js", AssetType.JAVASCRIPT.getPrefix()))
                .thenThrow(new IOException("can't read file"));

        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js?format=text"))
                .andExpect(status().isInternalServerError());
        mockMvc.perform(get("/rest/pages/page-id/assets/js/asset.js")).andExpect(status().isInternalServerError());
    }

}