package com.metservice.kanban.jwebunit;
import static com.metservice.kanban.KanbanService.KANBAN_HOME_PROPERTY_NAME;
import static com.metservice.kanban.jwebunit.BoardPage.openProject;
import static org.junit.Assert.assertEquals;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.joda.time.LocalDate;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import com.metservice.kanban.KanbanService;
import com.metservice.kanban.model.EstimatesProject;
import com.metservice.kanban.model.KanbanProject;
import com.metservice.kanban.model.WorkItem;
import com.metservice.kanban.tests.util.TestUtils;
import com.metservice.kanban.web.KanbanBoardController;
public class EndToEndTest {
private static Server server;
private static TemporaryFolder kanbanHome = new TemporaryFolder();
@BeforeClass
public static void beforeClass() throws Exception {
kanbanHome.create();
System.setProperty(KANBAN_HOME_PROPERTY_NAME, kanbanHome.getRoot().getAbsolutePath());
server = new Server(8008);
server.setHandler(new WebAppContext("src/main/webapp", "/kanban"));
server.start();
}
@AfterClass
public static void afterClass() throws Exception {
server.stop();
kanbanHome.delete();
}
@Test
public void userCanDeleteAWorkItem() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton();
page.clickAddFeatureButton().enterName("feature name").clickSaveButton();
// page.clickBacklogButton();
page.clickEditFeatureButton("feature name").clickDeleteButtonAndConfirm();
page.assertFeatureNotPresent("feature name");
}
@Test
public void petPageShowsPlannedFeatures() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickAddFeatureButton().enterName("feature name").clickSaveButton();
page.clickPETButton().checkFeatureDescription("feature name");
}
@Test
public void petPageShowsPlannedStoriesForProjectsWithOnlyStories() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project 2", "/Test Project 2/");
page.clickAddStoryButton().enterName("feature name").clickSaveButton();
page.clickPETButton().checkFeatureDescription("feature name");
}
@Test
public void projectListAppearsSorted() throws IOException {
File root = kanbanHome.getRoot();
BoardPage.cleanProject(kanbanHome);
TestUtils.createTestProject(root, "123", "/Test Project 2/");
TestUtils.createTestProject(root, "ABC", "/Test Project 2/");
TestUtils.createTestProject(root, "XYZ", "/Test Project 2/");
TestUtils.createTestProject(root, "acb", "/Test Project 2/");
TestUtils.createTestProject(root, "xzy", "/Test Project 2/");
TestUtils.createTestProject(root, "A1z", "/Test Project 2/");
BoardPage.createBoardPage("123").assertProjectListIsSorted();
}
@Test
public void userCanAddSizeToAWorkItem() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton();
page.clickAddFeatureButton().enterName("feature name").enterAverageCase("5").enterWorstCase("10")
.clickSaveButton();
//Check that the size on the feature or story matches the Average Case value in P.E.T
page.clickPETButton().checkPetAverageCaseValue("5").checkPetWorstCaseValue("10");
}
@Test
public void userCanRenameAWorkItem() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton();
page.clickAddFeatureButton().enterName("feature name").clickSaveButton();
page.clickEditFeatureButton("feature name").enterName("new feature name").clickSaveButton();
page.assertFeatureNotPresent("feature name");
page.assertFeatureIsPresent("new feature name");
}
@Test
public void userCanAddDatedEntriesInTheJournal() throws Exception {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
JournalPage journalPage = page.clickJournalButton();
page.setCurrentUser("Project Champion");
journalPage.clickAddEntry().enterJournalDate("2012-01-12").enterJournalText("test journal text").clickOkButton();
journalPage.assertJournalTextIsPresent("Project Champion wrote on 2012-01-12", "test journal text");
ChartPage cumulativeChartPage = page.clickCumulativeFlowChartButton();
cumulativeChartPage.assertJournalTextIsPresent("Project Champion wrote on 2012-01-12", "test journal text");
ChartPage featureCycleTimeChartPage = page.clickFeatureCycleTimeChartButton();
featureCycleTimeChartPage.assertJournalTextIsPresent("Project Champion wrote on 2012-01-12", "test journal text");
ChartPage burnUpChartPage = page.clickBurnUpChartButton();
burnUpChartPage.assertJournalTextIsPresent("Project Champion wrote on 2012-01-12", "test journal text");
}
@Test
public void userGetsValidationErrorWhenAddingIncompleteEntriesInTheJournal() throws Exception {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
JournalPage journalPage = page.clickJournalButton();
journalPage.clickAddEntry().clickOkButton();
journalPage.assertValidationErrorShows("Entry date cannot be empty");
journalPage.clickAddEntry().enterJournalDate("2012-01-12").clickOkButton();
journalPage.assertValidationErrorShows("Journal text cannot be empty");
journalPage.clearEntryDate();
journalPage.clickAddEntry().enterJournalText("test journal text").clickOkButton();
journalPage.assertValidationErrorShows("Entry date cannot be empty");
journalPage.clickCancelButton();
journalPage.assertJournalTextIsNotPresent("test journal text");
}
@Test
public void userCanExcludeAWorkItemFromReports() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton();
page.clickAddFeatureButton().enterName("feature name").clickSaveButton();
page.clickEditFeatureButton("feature name").assertExcludeBoxIs(false);
page.clickBacklogButton();
page.clickEditFeatureButton("feature name").tickExcludeBox().clickSaveButton();
page.clickEditFeatureButton("feature name").assertExcludeBoxIs(true);
}
@Test
public void userCanChangeTheParentOfAWorkItem() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton();
page.clickAddFeatureButton().enterName("feature 1").clickSaveButton();
page.clickAddFeatureButton().enterName("feature 2").clickSaveButton();
page.clickAdvance("feature 1");
page.clickAdvance("feature 2");
WallPage wall = page.clickWallButton();
//
// wall.clickAddStoryButton("feature 1").enterName("story").clickSaveButton();
//
// wall.clickEditStoryButton("story").setParent("feature 2").clickSaveButton();
//27/09/11 - feature 2 never gets to the wall.
// TODO: Ask Ben!
//wall.clickEditStoryButton("story").assertParentIs("feature 2");
}
@Test
public void userCanViewAChart() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
ChartPage chartPage = page.clickFeatureCycleTimeChartButton();
chartPage.assertImageIsValidPng(
String.format("cycle-time-chart.png?level=feature&startDate=%s&endDate=%s&workStream=",
getDefaultStartDate(),
getDefaultEndDate()
));
}
String getDefaultEndDate() {
return LocalDate.fromCalendarFields(Calendar.getInstance()).toString("yyyy-MM-dd");
}
String getDefaultStartDate() {
return LocalDate.fromCalendarFields(Calendar.getInstance()).minusMonths(4).toString("yyyy-MM-dd");
}
@Test
public void userCanViewABurnUpChart() throws IOException {
BoardPage wallPage = openProject(kanbanHome, "Test project", "/end-to-end-test/");
ChartPage chartPage = wallPage.clickBurnUpChartButton();
chartPage.assertImageIsValidPng(
String.format(
"burn-up-chart.png?level=feature&startDate=%s&endDate=%s&workStream=",
getDefaultStartDate(),
getDefaultEndDate()
));
}
@Test
public void mustHaveItemShouldBeIndicatedInBacklog() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickAddFeatureButton().enterName("feature name must have").clickSaveButton();
page.clickAddFeatureButton().enterName("feature name nice to have").clickSaveButton();
BoardPage backlog = page.clickPETButton().clickMustHave(1).clickBacklogButton();
backlog.assertItemNameIsIndicatedMustHave(1);
backlog.assertItemNameIsIndicatedNiceToHave(2);
}
@Test
@Ignore
public void mustHaveItemShouldBeIndicatedInComplete() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickAddFeatureButton().enterName("feature name must have").clickSaveButton();
page.clickAddFeatureButton().enterName("feature name nice to have").clickSaveButton();
BoardPage complete = page.clickPETButton().clickMustHave(1).clickCompleteButton();
complete.assertItemNameIsIndicatedMustHave(1);
complete.assertItemNameIsIndicatedNiceToHave(2);
}
@Test
public void userCanGoFromEditPageToPrintPage() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
PrintPage printPage = page.clickAddFeatureButton().enterName("feature name to print")
.clickSaveAndPrintButton();
printPage.assertIsPrintPage();
printPage.assertItemHasName(1, "feature name to print");
}
@Test
@Ignore("this requirement is not longer valid - displaying comments instead of notes")
public void quotesAreEscapedOnWall() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page
.clickAddFeatureButton()
.enterName("feature name to print")
.enterNotes("This is \"note\" with.")
.clickSaveButton()
.clickAdvance("feature name to print");
WallPage wallPage = page.clickWallButton();
String notes = wallPage.getNotesForItem(1);
assertEquals("Notes: This is \"note\" with.", notes);
}
@Test
@Ignore("this requirement is not longer valid - displaying comments instead of notes")
public void htmlEntitiesAreEscapedOnWall() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
WallPage wallPage = page.clickAddFeatureButton().enterName("feature name to print")
.enterNotes("This is note with <div>HTMLtags</div>.").clickSaveButton()
.clickAdvance("feature name to print")
.clickWallButton();
// if HTML entities are not escaped, this method throws an exception
String notes = wallPage.getNotesForItem(1);
assertEquals("Notes: This is note with <div>HTMLtags</div>.", notes);
}
@Test
@Ignore("not possible to test with jWebUnit 3.0 - cannot simulate pressing enter")
public void userCanCreateAStoryWithHashInQuickEditor() throws IOException {
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickBacklogButton().enterQuickName("abc");
}
@Test
public void columnsWithBrokenWIPLimitShouldGoRed() throws IOException {
// end-to-end project has WIP limit for second phase set to 2
BoardPage page = openProject(kanbanHome, "Test project", "/end-to-end-test/");
page.clickAddFeatureButton().enterName("feature 1").clickSaveButton();
page.clickAddFeatureButton().enterName("feature 2").clickSaveButton();
page.clickAddFeatureButton().enterName("feature 3").clickSaveButton();
page.clickBacklogButton().clickAdvance("feature 1").clickAdvance("feature 2");
WallPage wall = page.clickWallButton();
wall.assertWipNotBroken("feature wall");
wall = wall.clickBacklogButton().clickAdvance("feature 3").clickWallButton();
wall.assertWipBroken("feature wall");
}
@Test
public void userCanRenameAProject() throws IOException {
BoardPage wallPage = openProject(kanbanHome, "Test project", "/end-to-end-test/");
AdminPage adminPage = wallPage.clickAdminButton();
adminPage.clickEditProject().enterName("Renamed Test Project").clickSubmitQueryButton();
wallPage.assertProjectNotPresent("Test project");
wallPage.assertProjectIsPresent("Renamed Test Project");
}
@Test
public void cycleTimeChartsVisibleWhenNewPhaseIsAddedToAProject() throws IOException {
BoardPage wallPage = openProject(kanbanHome, "Test project", "/test-project/");
AdminPage adminPage = wallPage.clickAdminButton();
ProjectPropertiesPage projectPropertiesPage = adminPage.clickEditProject();
String currentProjectProperties = projectPropertiesPage.getProjectProperties();
currentProjectProperties
.replace(
"workItemTypes.feature.phases=Backlog,Design,Implement,Accept,ReadyToDeploy,Deployed,Bugs,Blocks,Done",
"workItemTypes.feature.phases=Backlog,Design,Implement,Test,Accept,ReadyToDeploy,Deployed,Bugs,Blocks,Done");
projectPropertiesPage.enterProjectProperties(currentProjectProperties).clickSubmitQueryButton();
wallPage.clickFeatureCycleTimeChartButton().assertImageIsValidPng(
String.format(
"cycle-time-chart.png?level=feature&startDate=%s&endDate=%s&workStream=",
getDefaultStartDate(),
getDefaultEndDate()
));
}
@Test
public void verifyCompBoardPhaseWidth() throws IOException {
BoardPage wallPage = openProject(kanbanHome, "Test project", "/test-project/");
KanbanService service = new KanbanService();
String name = "CompTest";
KanbanProject project = service.getKanbanProject("Test project");
int item = project.addWorkItem(WorkItem.ROOT_WORK_ITEM_ID, project.getWorkItemTypes().getByName("feature"), name, 0, 0, 0, "", "555555", false, "", new LocalDate(2010, 05, 1));
WorkItem workItem = project.getWorkItemById(item);
workItem.setDate("Backlog", new LocalDate(2011, 05, 2));
workItem.setDate("Design", new LocalDate(2011, 05, 5));
workItem.setDate("Implement", new LocalDate(2011, 05, 8));
workItem.setDate("Accept", new LocalDate(2011, 05, 10));
workItem.setDate("Deployed", new LocalDate(2011, 05, 13));
workItem.setDate("Bugs", new LocalDate(2011, 05, 18));
workItem.setDate("Blocks", new LocalDate(2011, 05, 22));
workItem.setDate("Done", new LocalDate(2011, 05, 30));
project.save();
BoardPage completePage = wallPage.clickCompleteButton();
completePage.assertFeatureIsPresent(name);
completePage.assertCompleteItemWidthIsCorrect(item, 5, 0);
}
@Test
public void defaultStartDateWhenCumulativeFlowChartOpened() throws IOException {
BoardPage wallPage = openProject(kanbanHome, "Test project", "/test-project/");
ChartPage chartPage = wallPage.clickCumulativeFlowChartButton();
LocalDate endDateParsed = LocalDate.fromCalendarFields(Calendar.getInstance());
String startDate = endDateParsed.minusMonths(KanbanBoardController.DEFAULT_MONTHS_DISPLAY).toString(
"yyyy-MM-dd");
chartPage.assertStartDateEquals(startDate);
}
// @Test
// public void userCanDownloadStories() throws IOException {
// BoardPage wallPage = openProject("Test project");
// String responseContent = wallPage.clickDownloadFeaturesButton();
// File expectedFile = new File(SystemUtils.getUserDir(), "/src/test/resources/end-to-end-test/feature.csv");
// String expectedContent = FileUtils.readFileToString(expectedFile);
// assertThat(responseContent, is(expectedContent));
// }
// @Test
// public void columnRedWhenWIPExceeded() throws IOException {
// BoardPage wallPage = openProject("Test project");
// //assert that th id"phase_2" background-color = #f00
// //TODO Get help from someone at MetService for writing tests
// }
}