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