login('test@leantime.io', 'Test123456!'); } /** * Create timesheet on my page. */ #[Group('timesheet')] #[Depends('Acceptance\TicketsCest:createTicket')] public function createMyTimesheet(AcceptanceTester $I): void { $I->wantTo('Add hours to tickets on my timesheet'); $I->amOnPage('/timesheets/showMy'); // Select project. $I->waitForElementNotVisible('.project-select', 120); $I->clickWithRetry('#projectSelect .chosen-single'); $I->waitForElementVisible('.chosen-drop', 120); $I->clickWithRetry('#projectSelect .chosen-results .active-result'); // Select ticket. $I->waitForElementNotVisible('.ticket-select', 120); $I->clickWithRetry('#ticketSelect .chosen-single'); $I->waitForElementVisible('.chosen-drop', 120); $I->clickWithRetry('#ticketSelect .chosen-results .active-result'); // Select type. $I->waitForElementVisible('.kind-select', 120); $I->selectOption('.kind-select', 'General, billable'); // Set hours in active $I->fillField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', 1); $I->fillField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', 2); $I->clickWithRetry('.saveTimesheetBtn'); $I->waitForElement('.growl', 60); $I->seeInField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', '1'); $I->seeInField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', '2'); $I->wait(3); $I->seeInSource('3'); $I->seeInDatabase('zp_timesheets', [ 'id' => 1, 'hours' => 1, 'kind' => 'GENERAL_BILLABLE', ]); $I->seeInDatabase('zp_timesheets', [ 'id' => 2, 'hours' => 2, 'kind' => 'GENERAL_BILLABLE', ]); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function checkForEmptyTimesheet(AcceptanceTester $I): void { $I->wantTo('I do not what to see empty ("zero") time registrations'); $I->amOnPage('/timesheets/showMy'); // Do not what to see empty time regs. $I->dontSeeInDatabase('zp_timesheets', [ 'hours' => 0, ]); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function notShiftingTimesheet(AcceptanceTester $I): void { $I->wantTo('Try registering time on the same ticket on another day. Should not remove existing registrations.'); $I->amOnPage('/timesheets/showMy'); // Since we assume "Create Timesheet was created we just add values to day 3 and 4. // Set hours. $I->fillField('//*[contains(@class, "rowday3")]//input[@class="hourCell"]', 1); $I->fillField('//*[contains(@class, "rowday4")]//input[@class="hourCell"]', 2); $I->clickWithRetry('.saveTimesheetBtn'); $I->waitForElement('.growl', 60); $I->wait(10); $I->seeInField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', '1'); $I->seeInField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', '2'); $I->seeInField('//*[contains(@class, "rowday3")]//input[@class="hourCell"]', '1'); $I->seeInField('//*[contains(@class, "rowday4")]//input[@class="hourCell"]', '2'); $I->seeInSource('6'); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function sameTicketTimesheet(AcceptanceTester $I): void { $I->wantTo('Test timesheet updated with data one same ticket'); $I->amOnPage('/timesheets/showMy'); // Set hours in active $I->fillField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', 1); $I->fillField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', 2); $I->clickWithRetry('.saveTimesheetBtn'); $I->waitForElement('.growl', 60); $I->seeInSource('6'); } /** * Save the timesheet once more to ensure number do not change. * * If the cell IDs are not correct, this will break the registrations. */ #[Group('timesheet')] #[Depends('createMyTimesheet')] public function saveOnceMoreTimezone(AcceptanceTester $I): void { $I->wantTo('Save the timesheet once more to ensure number do not change'); $I->amOnPage('/timesheets/showMy'); $I->clickWithRetry('.saveTimesheetBtn'); $I->waitForElement('.growl', 120); $I->seeInSource('Timesheet saved successfully'); // An page reload will trigger an "resend submission popup". $I->amOnPage('/timesheets/showMy'); $I->waitForElementVisible('//*[contains(@class, "rowday1")]//input[@class="hourCell"]'); $I->seeInField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', '1'); $I->seeInField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', '2'); $I->seeInSource('6'); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function changeTimezone(AcceptanceTester $I): void { $I->wantTo('Change timezone and see the correct timesheet'); // Change timezone and see the correct timesheet. $this->changeUsersTimeZone($I, 'Europe/Copenhagen'); // Check timesheet $I->amOnPage('/timesheets/showMy'); $I->waitForElementVisible('//*[contains(@class, "rowday1")]//input[@class="hourCell"]'); $I->seeInField('//*[contains(@class, "rowday1")]//input[@class="hourCell"]', '1'); $I->seeInField('//*[contains(@class, "rowday2")]//input[@class="hourCell"]', '2'); $I->seeInSource('6'); // Switch back. $this->changeUsersTimeZone($I); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function editTimesheet(AcceptanceTester $I): void { $I->wantTo('Edit timesheet'); $I->amOnPage('/timesheets/showMyList'); $I->waitForElementVisible('#allTimesheetsTable'); $I->see('#1 - Edit'); $I->clickWithRetry('#editTimesheet-1'); $I->waitForElementVisible('#hours'); $I->fillField('#hours', 2); $I->clickWithRetry('.stdformbutton input[type=submit]'); $I->waitForElement('.growl', 120); $I->seeInDatabase('zp_timesheets', [ 'id' => '1', 'hours' => 2, ]); // Close modal. $I->waitForElementVisible('.nyroModalClose'); $I->clickWithRetry('.nyroModalClose'); // Check that data have been updated. $I->wait(5); $I->waitForElementVisible('#allTimesheetsTable'); $I->see('2', '//*//tr[@class="odd"]//td', '2'); $I->see('2', '//*//tr[@class="odd"]//td', '-2'); } #[Group('timesheet')] #[Depends('createMyTimesheet', 'editTimesheet')] public function logTimeOnTicketTimesheet(AcceptanceTester $I): void { $I->wantTo('Open ticket and add time'); $I->amOnPage('/#/tickets/showTicket/10'); $I->waitForElementVisible('#ui-id-8'); $I->clickWithRetry('#ui-id-8'); $I->waitForElementVisible('#hours'); $I->fillField('#hours', 4); $I->clickWithRetry('.formModal input[type=submit][name=saveTimes]'); $I->wait(1); // Go and see if the total is correct. $I->amOnPage('/timesheets/showMy'); $I->waitForElementVisible('#finalSum'); $I->seeInSource('11'); } #[Group('timesheet')] #[Depends('createMyTimesheet', 'editTimesheet', 'logTimeOnTicketTimesheet')] public function showAllTimesheet(AcceptanceTester $I): void { $I->wantTo('Show all timesheet list'); $I->amOnPage('/timesheets/showAll'); $I->waitForElementVisible('#allTimesheetsTable'); $I->see('2', '//*//tr[@class="odd"]//td', '2'); $I->see('2', '//*//tr[@class="odd"]//td', '-2'); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function showAllEditsTimesheet(AcceptanceTester $I): void { $I->wantTo('Show all timesheet list'); $I->amOnPage('/timesheets/showAll'); $I->waitForElementVisible('#allTimesheetsTable'); // Maker paid $I->checkOption('//*//input[@id="checkAllPaid"]'); $I->clickWithRetry('#allTimesheetsTable_wrapper input[name=saveInvoice]'); $I->waitForElementVisible('#allTimesheetsTable_wrapper'); $I->wait(2); $I->cantSeeElement('//*//input[@class="paid"]'); // Make Invoiced $I->checkOption('//*/input[@id="checkAllEmpl"]'); $I->clickWithRetry('#allTimesheetsTable_wrapper input[name=saveInvoice]'); $I->waitForElementVisible('#allTimesheetsTable_wrapper'); $I->wait(2); $I->cantSeeElement('//*//input[@class="invoicedEmpl"]'); // Make MGR Approval $I->checkOption('//*//input[@id="checkAllComp"]'); $I->clickWithRetry('#allTimesheetsTable_wrapper input[name=saveInvoice]'); $I->waitForElementVisible('#allTimesheetsTable_wrapper'); $I->wait(2); $I->cantSeeElement('//*//input[@class="invoicedComp"]'); } #[Group('timesheet')] #[Depends('createMyTimesheet')] public function deleteTimesheet(AcceptanceTester $I): void { $I->wantTo('Delete timesheet'); $I->amOnPage('/timesheets/showMyList'); $I->waitForElementVisible('#allTimesheetsTable'); $I->see('#1 - Edit'); $I->clickWithRetry('#editTimesheet-1'); $I->waitForElementVisible('.delete'); $I->clickWithRetry('.stdformbutton .delete'); $I->wait(5); $I->see('Should the timesheet really be deleted?'); $I->clickWithRetry('.nyroModalLink input[type=submit]'); $I->waitForElementVisible('#allTimesheetsTable'); $I->wait(5); $I->cantSee('#1 - Edit'); } /** * Change the timezone for the logged-in user. * * @param AcceptanceTester $I The AcceptanceTester object representing the test runner. * @param string $timezone The timezone to be set. Defaults to 'America/Los_Angeles'. */ private function changeUsersTimeZone(AcceptanceTester $I, string $timezone = 'America/Los_Angeles'): void { $I->amOnPage('/users/editOwn#settings'); $I->waitForElementVisible('#timezone'); $I->selectOption('#timezone', $timezone); $I->waitForElementClickable('#saveSettings'); $I->clickWithRetry('#saveSettings', 90); $I->waitForText($timezone, 20); $I->wait(5); } }