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(getWebClient(), baseUrl);
110            Assert.assertNotNull(page);
111            Assert.assertTrue("Clock Page contains Distribute Button", page.asText().contains("Distribute Time Blocks"));
112            this.createTB();
113            updateWebClient();
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(getWebClient(), 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(getWebClient(), 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            updateWebClient();
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 updateWebClient() {
155            WebClient webClient = getWebClient();
156            webClient.setJavaScriptEnabled(true);
157            webClient.setThrowExceptionOnScriptError(false);
158            webClient.setAjaxController(new NicelyResynchronizingAjaxController());
159            webClient.waitForBackgroundJavaScript(10000);
160        }
161    
162        /**
163         * This test is to :
164         * 1) make sure the seconds on clockTimestamp and timestamp are preserved when there is no grace period rule.
165         * 2) the clock in / out button is correctly rendered
166         *
167         * @throws Exception
168         */
169        @Test
170        public void testClockActionWithoutGracePeriodRule() throws Exception {
171            // Make sure there is no active grace period rule
172            GracePeriodRule gpr = TkServiceLocator.getGracePeriodService().getGracePeriodRule(TKUtils.getCurrentDate());
173            if (gpr != null && gpr.isActive()) {
174                gpr.setActive(false);
175                KRADServiceLocator.getBusinessObjectService().save(gpr);
176            }
177    
178            // Clock in
179            clockIn();
180            // Make sure clock out button is rendered
181            ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
182            // Make sure both timestamps preserve seconds
183            Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
184            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
185    
186            // Clock out
187            clockOut();
188            // Make sure both timestamps preserve seconds
189            lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
190            Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
191            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
192        }
193    
194        @Test
195        public void testClockActionWithGracePeriodRule() throws Exception {
196            //clean clock logs
197            KRADServiceLocator.getBusinessObjectService().deleteMatching(ClockLog.class, Collections.singletonMap("principalId", "admin"));
198            GracePeriodRule gpr = new GracePeriodRule();
199            //gpr.setTkGracePeriodRuleId("1");
200            gpr.setEffectiveDate(TKUtils.createDate(1, 1, 2010, 0, 0, 0));
201            gpr.setHourFactor(new BigDecimal(3));
202            gpr.setTimestamp(new Timestamp(System.currentTimeMillis()));
203            
204            gpr.setActive(true);
205            KRADServiceLocator.getBusinessObjectService().save(gpr);
206    
207            // Clock in
208            clockIn();
209            // Make sure clock out button is rendered
210            ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
211            // Make sure both timestamps preserve seconds
212            Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
213            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
214    
215            // Clock out
216            clockOut();
217            // Make sure both timestamps preserve seconds
218            lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
219            Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
220            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
221    
222    
223        }
224    
225        private HtmlPage clockIn() throws Exception {
226    
227            // Clock in
228            HtmlPage page = clockAction(TkConstants.CLOCK_IN);
229    
230            // Make sure clock in button is rendered
231            HtmlUnitUtil.createTempFile(page);
232            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock Out"));
233            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Take Lunch"));
234    
235            return page;
236        }
237    
238        private HtmlPage clockOut() throws Exception {
239            DateTime dateTime = new DateTime();
240            if (dateTime.getSecondOfMinute() >= 58
241                    || dateTime.getSecondOfMinute() == 0) {
242                Thread.sleep(4000);
243            }
244            // Clock out
245            HtmlPage page = clockAction(TkConstants.CLOCK_OUT);
246    
247            // Make sure clock in button is rendered
248            HtmlUnitUtil.createTempFile(page);
249            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock In"));
250    
251            return page;
252        }
253    
254        /**
255         * This method is used for clocking in and out.
256         * For some reason, htmlunit couldn't click the clock action button correctly.
257         * It's probably because we bind a onClick event to the button instead of submitting the form.
258         *
259         * @param clockAction
260         * @return HtmlPage page
261         */
262        private HtmlPage clockAction(String clockAction) throws Exception {
263            DateTime dateTime = new DateTime();
264            if (dateTime.getSecondOfMinute() >= 58
265                    || dateTime.getSecondOfMinute() == 0) {
266                Thread.sleep(4000);
267            }
268            String baseUrl = TkTestConstants.Urls.CLOCK_URL;
269            String actionUrl = baseUrl + "?methodToCall=clockAction&selectedAssignment=30_30_30&currentClockAction=" + clockAction;
270            HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), actionUrl);
271            Assert.assertNotNull("The login page shouldn't be null", page);
272            Thread.sleep(3000);
273            return page;
274        }
275    
276    
277    }