001 /**
002 * Copyright 2004-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.hr.time.clock.web;
017
018 import java.math.BigDecimal;
019 import java.sql.Timestamp;
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.Collections;
023 import java.util.Iterator;
024 import java.util.List;
025
026 import org.joda.time.DateTime;
027 import org.junit.Assert;
028 import org.junit.Ignore;
029 import org.junit.Test;
030 import org.kuali.hr.test.KPMETestCase;
031 import org.kuali.hr.time.clocklog.ClockLog;
032 import org.kuali.hr.time.graceperiod.rule.GracePeriodRule;
033 import org.kuali.hr.time.service.base.TkServiceLocator;
034 import org.kuali.hr.time.test.HtmlUnitUtil;
035 import org.kuali.hr.time.test.TkTestConstants;
036 import org.kuali.hr.time.timeblock.TimeBlock;
037 import org.kuali.hr.time.timeblock.TimeHourDetail;
038 import org.kuali.hr.time.timesheet.TimesheetDocument;
039 import org.kuali.hr.time.util.TKUtils;
040 import org.kuali.hr.time.util.TkConstants;
041 import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
042 import org.kuali.rice.krad.service.KRADServiceLocator;
043
044 import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
045 import com.gargoylesoftware.htmlunit.WebClient;
046 import com.gargoylesoftware.htmlunit.html.HtmlElement;
047 import com.gargoylesoftware.htmlunit.html.HtmlPage;
048
049
050 public class ClockWebTest extends KPMETestCase {
051
052 private String tbId;
053
054 public Long maxDocumentId() {
055 Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimesheetDocumentHeader.class);
056 Long maxId = new Long(-1);
057 Iterator<TimesheetDocumentHeader> itr = aCol.iterator();
058 while (itr.hasNext()) {
059 TimesheetDocumentHeader tdh = itr.next();
060 Long temp = new Long(tdh.getDocumentId());
061 if (temp > maxId) {
062 maxId = temp;
063 }
064 }
065 return maxId;
066 }
067
068 public Long maxTimeBlockId() {
069 Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimeBlock.class);
070 Long maxId = new Long(-1);
071 Iterator<TimeBlock> itr = aCol.iterator();
072 while (itr.hasNext()) {
073 TimeBlock tb = itr.next();
074 Long temp = new Long(tb.getTkTimeBlockId());
075 if (temp > maxId) {
076 maxId = temp;
077 }
078 }
079 return maxId;
080 }
081
082 public void createTB() {
083 TimeBlock timeBlock = new TimeBlock();
084 timeBlock.setUserPrincipalId("admin");
085 timeBlock.setJobNumber(2L);
086 timeBlock.setWorkArea(1234L);
087 timeBlock.setTask(1L);
088 timeBlock.setEarnCode("RGN");
089 Timestamp beginTimestamp = new Timestamp(System.currentTimeMillis());
090 timeBlock.setBeginTimestamp(beginTimestamp);
091 Timestamp endTimestamp = new Timestamp(System.currentTimeMillis());
092 timeBlock.setEndTimestamp(endTimestamp);
093 TimeHourDetail timeHourDetail = new TimeHourDetail();
094 timeHourDetail.setEarnCode("RGN");
095 timeHourDetail.setHours(new BigDecimal(2.0));
096 timeBlock.getTimeHourDetails().add(timeHourDetail);
097 timeBlock.setHours(new BigDecimal(2.0));
098 List<TimeBlock> tbList = new ArrayList<TimeBlock>();
099 String documentId = this.maxDocumentId().toString();
100 timeBlock.setDocumentId(documentId);
101 tbList.add(timeBlock);
102 TkServiceLocator.getTimeBlockService().saveTimeBlocks(tbList);
103
104 tbId = timeBlock.getTkTimeBlockId();
105 TimesheetDocument td = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId);
106 td.setTimeBlocks(tbList);
107
108 }
109
110 @Ignore
111 public void testDistributeTB() throws Exception {
112 String baseUrl = TkTestConstants.Urls.CLOCK_URL;
113 HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(baseUrl);
114 Assert.assertNotNull(page);
115 Assert.assertTrue("Clock Page contains Distribute Button", page.asText().contains("Distribute Time Blocks"));
116 this.createTB();
117 this.setWebClient(page.getWebClient());
118 HtmlElement element = page.getElementByName("distributeTime");
119 Assert.assertNotNull(element);
120 // HtmlPage testPage1 = element.click();
121 // assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Close"));
122 // assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Edit"));
123
124 // timeDistribute.jsp
125 String distributeUrl = baseUrl + "?methodToCall=distributeTimeBlocks";
126 HtmlPage page1 = HtmlUnitUtil.gotoPageAndLogin(distributeUrl);
127 Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Close"));
128 Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Edit"));
129
130 element = page1.getElementByName("editTimeBlock");
131 Assert.assertNotNull(element);
132 Assert.assertTrue("Onclick attribute of Edit button contains", element.getAttribute("onclick").contains("Clock.do?methodToCall=editTimeBlock&editTimeBlockId="));
133
134 if (tbId == null) {
135 tbId = this.maxTimeBlockId().toString();
136 }
137
138 //editTimeBlock.jsp
139 String editUrl = baseUrl + "?methodToCall=editTimeBlock&editTimeBlockId=" + tbId;
140 HtmlPage page3 = HtmlUnitUtil.gotoPageAndLogin(editUrl);
141
142 // editTimeBlock.jsp
143 Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Add"));
144 Assert.assertTrue("Edit Time Blocks Page contains Save button", page3.asText().contains("Save"));
145 Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Cancel"));
146
147 element = page3.getElementByName("addTimeBlock");
148 Assert.assertNotNull(element);
149 Assert.assertTrue("Onclick attribute of Add button contains", element.getAttribute("onclick").contains("javascript: addTimeBlockRow(this.form);"));
150
151 this.setWebClient(page3.getWebClient());
152
153 // HtmlPage page4 = element.click();
154 // assertTrue("Edit Time Blocks Page contains Cancel button", page4.asText().contains("Add"));
155
156 }
157
158 public void setWebClient(WebClient webClient) {
159 webClient.setJavaScriptEnabled(true);
160 webClient.setThrowExceptionOnScriptError(false);
161 webClient.setAjaxController(new NicelyResynchronizingAjaxController());
162 webClient.waitForBackgroundJavaScript(10000);
163 }
164
165 /**
166 * This test is to :
167 * 1) make sure the seconds on clockTimestamp and timestamp are preserved when there is no grace period rule.
168 * 2) the clock in / out button is correctly rendered
169 *
170 * @throws Exception
171 */
172 @Test
173 public void testClockActionWithoutGracePeriodRule() throws Exception {
174 // Make sure there is no active grace period rule
175 GracePeriodRule gpr = TkServiceLocator.getGracePeriodService().getGracePeriodRule(TKUtils.getCurrentDate());
176 if (gpr != null && gpr.isActive()) {
177 gpr.setActive(false);
178 KRADServiceLocator.getBusinessObjectService().save(gpr);
179 }
180
181 // Clock in
182 clockIn();
183 // Make sure clock out button is rendered
184 ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
185 // Make sure both timestamps preserve seconds
186 Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
187 Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
188
189 // Clock out
190 clockOut();
191 // Make sure both timestamps preserve seconds
192 lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
193 Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
194 Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
195 }
196
197 @Test
198 public void testClockActionWithGracePeriodRule() throws Exception {
199 //clean clock logs
200 KRADServiceLocator.getBusinessObjectService().deleteMatching(ClockLog.class, Collections.singletonMap("principalId", "admin"));
201 GracePeriodRule gpr = new GracePeriodRule();
202 //gpr.setTkGracePeriodRuleId("1");
203 gpr.setEffectiveDate(TKUtils.createDate(1, 1, 2010, 0, 0, 0));
204 gpr.setHourFactor(new BigDecimal(3));
205 gpr.setTimestamp(new Timestamp(System.currentTimeMillis()));
206
207 gpr.setActive(true);
208 KRADServiceLocator.getBusinessObjectService().save(gpr);
209
210 // Clock in
211 clockIn();
212 // Make sure clock out button is rendered
213 ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
214 // Make sure both timestamps preserve seconds
215 Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
216 Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
217
218 // Clock out
219 clockOut();
220 // Make sure both timestamps preserve seconds
221 lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
222 Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
223 Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
224
225
226 }
227
228 private HtmlPage clockIn() throws Exception {
229
230 // Clock in
231 HtmlPage page = clockAction(TkConstants.CLOCK_IN);
232
233 // Make sure clock in button is rendered
234 HtmlUnitUtil.createTempFile(page);
235 Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock Out"));
236 Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Take Lunch"));
237
238 return page;
239 }
240
241 private HtmlPage clockOut() throws Exception {
242 DateTime dateTime = new DateTime();
243 if (dateTime.getSecondOfMinute() == 0) {
244 Thread.sleep(2000);
245 }
246 // Clock out
247 HtmlPage page = clockAction(TkConstants.CLOCK_OUT);
248
249 // Make sure clock in button is rendered
250 HtmlUnitUtil.createTempFile(page);
251 Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock In"));
252
253 return page;
254 }
255
256 /**
257 * This method is used for clocking in and out.
258 * For some reason, htmlunit couldn't click the clock action button correctly.
259 * It's probably because we bind a onClick event to the button instead of submitting the form.
260 *
261 * @param clockAction
262 * @return HtmlPage page
263 */
264 private HtmlPage clockAction(String clockAction) throws Exception {
265 DateTime dateTime = new DateTime();
266 if (dateTime.getSecondOfMinute() == 0) {
267 Thread.sleep(2000);
268 }
269 String baseUrl = TkTestConstants.Urls.CLOCK_URL;
270 String actionUrl = baseUrl + "?methodToCall=clockAction&selectedAssignment=30_30_30¤tClockAction=" + clockAction;
271 HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(actionUrl);
272 Assert.assertNotNull("The login page shouldn't be null", page);
273 Thread.sleep(3000);
274 return page;
275 }
276
277
278 }