TimeTrex Community Edition v16.2.0
This commit is contained in:
522
unit_tests/testcases/selenium/CAPayrollDeductionCRACompare.php
Normal file
522
unit_tests/testcases/selenium/CAPayrollDeductionCRACompare.php
Normal file
@ -0,0 +1,522 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
//Each Year:
|
||||
// Copy testcases/payroll_deduction/CAPayrollDeductionCRATest2019.csv to the new year. Clear out all lines but the header.
|
||||
// Update below "$this->year = 2021;" to the new year.
|
||||
// Run: ./run_selenium.sh --filter CAPayrollDeductionCRACompareTest::testCRAToCSVFile <-- This will add lines to the above CSV file once its complete.
|
||||
// Run: ./run_selenium.sh --filter CAPayrollDeductionCRACompareTest::testCRAFromCSVFile <-- This will test the PDOC numbers against our own.
|
||||
|
||||
/**
|
||||
* @group CAPayrollDeductionCRACompareTest
|
||||
*/
|
||||
class CAPayrollDeductionCRACompareTest extends PHPUnit\Extensions\Selenium2TestCase {
|
||||
private $default_wait_timeout = 4000;//100000;
|
||||
|
||||
function waitUntilByXPath( $xpath, $timeout = null ) {
|
||||
if ( $timeout == null ) {
|
||||
$timeout = $this->default_wait_timeout;
|
||||
}
|
||||
|
||||
$this->waitUntil( function () use ( $xpath ) {
|
||||
try {
|
||||
$element = $this->byXPath( $xpath );
|
||||
if ( $element->displayed() ) {
|
||||
return true;
|
||||
}
|
||||
} catch ( PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e ) {
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}, $timeout );
|
||||
}
|
||||
|
||||
public function setUp(): void {
|
||||
global $selenium_config;
|
||||
$this->selenium_config = $selenium_config;
|
||||
|
||||
Debug::text( 'Running setUp(): ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
require_once( Environment::getBasePath() . '/classes/payroll_deduction/PayrollDeduction.class.php' );
|
||||
|
||||
$this->year = 2022;
|
||||
|
||||
$this->tax_table_file = dirname( __FILE__ ) . '/../payroll_deduction/CAPayrollDeductionTest' . $this->year . '.csv';
|
||||
$this->cra_deduction_test_csv_file = dirname( $this->tax_table_file ) . DIRECTORY_SEPARATOR . 'CAPayrollDeductionCRATest' . $this->year . '.csv';
|
||||
|
||||
$this->company_id = PRIMARY_COMPANY_ID;
|
||||
|
||||
$this->selenium_test_case_runs = 0;
|
||||
|
||||
TTDate::setTimeZone( 'Etc/GMT+8', true ); //Due to being a singleton and PHPUnit resetting the state, always force the timezone to be set.
|
||||
|
||||
$this->setHost( $selenium_config['host'] );
|
||||
$this->setBrowser( $selenium_config['browser'] );
|
||||
$this->setBrowserUrl( $selenium_config['default_url'] );
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
Debug::text( 'Running tearDown(): ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function CRAPayrollDeductionOnlineCalculator( $args = [] ) {
|
||||
if ( ENABLE_SELENIUM_REMOTE_TESTS != true ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug::Arr( $args, 'Args: ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( count( $args ) == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( $this->selenium_test_case_runs == 0 ) {
|
||||
$url = 'https://www.canada.ca/en/revenue-agency/services/e-services/e-services-businesses/payroll-deductions-online-calculator.html';
|
||||
Debug::text( 'Navigating to URL: ' . $url, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->url( $url );
|
||||
|
||||
|
||||
//Click "I Accept"
|
||||
$this->waitUntilByXPath( '//a[contains(.,\'I accept\')]' );
|
||||
$ae = $this->byXPath( '//a[contains(.,\'I accept\')]' );
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
|
||||
$this->waitUntilByXPath( '//*[@id="welcome_button_next"]' );
|
||||
$ae = $this->byXPath( '//*[@id="welcome_button_next"]' );
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
} else {
|
||||
usleep( 500000 );
|
||||
$this->waitUntilByXPath( '//*[@id="payrollDeductionsResults_button_modifyCalculationButton"]' );
|
||||
$ae = $this->byXPath( '//*[@id="payrollDeductionsResults_button_modifyCalculationButton"]' ); //Modify the current calculation
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
}
|
||||
|
||||
$province_options = [
|
||||
'AB' => 'ALBERTA',
|
||||
'BC' => 'BRITISH_COLUMBIA',
|
||||
'SK' => 'SASKATCHEWAN',
|
||||
'MB' => 'MANITOBA',
|
||||
'QC' => 'QUEBEC',
|
||||
'ON' => 'ONTARIO',
|
||||
'NL' => 'NEWFOUNDLAND_AND_LABRADOR',
|
||||
'NB' => 'NEW_BRUNSWICK',
|
||||
'NS' => 'NOVA_SCOTIA',
|
||||
'PE' => 'PRINCE_EDWARD_ISLAND',
|
||||
'NT' => 'NORTHWEST_TERRITORIES',
|
||||
'YT' => 'YUKON',
|
||||
'NU' => 'NUNAVUT',
|
||||
];
|
||||
Debug::Arr( Option::getByKey( $args['province'], $province_options ), 'Attempting to Select Province Value: ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$this->waitUntilByXPath( '//*[@id="jurisdiction"]' );
|
||||
$ae = $this->byId( 'jurisdiction' );
|
||||
$this->select( $ae )->selectOptionByValue( Option::getByKey( $args['province'], $province_options ) );
|
||||
|
||||
$pp_options = [
|
||||
52 => 'WEEKLY_52PP',
|
||||
26 => 'BI_WEEKLY',
|
||||
24 => 'SEMI_MONTHLY',
|
||||
];
|
||||
$ae = $this->byId( 'payPeriodFrequency' );
|
||||
$this->select( $ae )->selectOptionByValue( Option::getByKey( $args['pay_period_schedule'], $pp_options ) );
|
||||
|
||||
$ae = $this->byId( 'datePaidYear' );
|
||||
$this->select( $ae )->selectOptionByLabel( date( 'Y', $args['date'] ) );
|
||||
|
||||
$ae = $this->byId( 'datePaidMonth' );
|
||||
$this->select( $ae )->selectOptionByLabel( date( 'm', $args['date'] ) ); //Leading 0
|
||||
|
||||
$ae = $this->byId( 'datePaidDay' );
|
||||
$this->select( $ae )->selectOptionByLabel( date( 'd', $args['date'] ) ); //Leading 0
|
||||
|
||||
$ae = $this->byId( 'payrollDeductionsStep1_button_next' );
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
|
||||
$this->waitUntilByXPath( '//*[@id="incomeAmount"]' );
|
||||
usleep( 500000 );
|
||||
$ae = $this->byId( 'incomeAmount' );
|
||||
$ae->click();
|
||||
$this->keys( $args['gross_income'] ); //Sometimes some keystrokes get missed, try putting a wait above here.
|
||||
|
||||
$ae = $this->byId( 'payrollDeductionsStep2a_button_next' );
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
|
||||
//$this->waitUntilByXPath( '//*[@id="federalClaimCode"]' );
|
||||
//if ( isset( $args['federal_claim'] ) ) {
|
||||
// $ae = $this->byId( 'federalClaimCode' );
|
||||
// $this->select( $ae )->selectOptionByValue( ( $args['federal_claim'] == 0 ? 'CLAIM_CODE_0' : 'CLAIM_CODE_1' ) ); //Only support 0=$1, 1=Basic Claim
|
||||
//}
|
||||
//
|
||||
//if ( isset( $args['provincial_claim'] ) && $args['province'] != 'QC' ) { //QC doesn't have provincial claim code.
|
||||
// $ae = $this->byId( 'provinceTerritoryClaimCode' );
|
||||
// $this->select( $ae )->selectOptionByValue( ( $args['provincial_claim'] == 0 ? 'CLAIM_CODE_0' : 'CLAIM_CODE_1' ) ); //Only support 0=$1, 1=Basic Claim
|
||||
//}
|
||||
|
||||
if ( isset( $args['federal_claim'] ) ) {
|
||||
$this->waitUntilByXPath( '//*[@id="td1ClaimAmountFed"]' );
|
||||
$ae = $this->byId( 'td1ClaimAmountFed' );
|
||||
$ae->click();
|
||||
$this->keys( $args['federal_claim'] ); //Sometimes some keystrokes get missed, try putting a wait above here.
|
||||
}
|
||||
|
||||
if ( isset( $args['provincial_claim'] ) && $args['province'] != 'QC' ) {
|
||||
$this->waitUntilByXPath( '//*[@id="td1ClaimAmountProv"]' );
|
||||
$ae = $this->byId( 'td1ClaimAmountProv' );
|
||||
$ae->click();
|
||||
$this->keys( $args['provincial_claim'] ); //Sometimes some keystrokes get missed, try putting a wait above here.
|
||||
}
|
||||
|
||||
$result_row_offset = 1;
|
||||
|
||||
if ( isset( $args['ytd_cpp_earnings'] ) ) {
|
||||
$ae = $this->byId( 'pensionableEarningsYearToDate' );
|
||||
$ae->click();
|
||||
$this->keys( $args['ytd_cpp_earnings'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['ytd_cpp'] ) ) {
|
||||
$ae = $this->byId( 'cppOrQppContributionsDeductedYearToDate' );
|
||||
$ae->click();
|
||||
$this->keys( $args['ytd_cpp'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['ytd_ei_earnings'] ) ) {
|
||||
$ae = $this->byId( 'insurableEarningsYearToDate' );
|
||||
$ae->click();
|
||||
$this->keys( $args['ytd_ei_earnings'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['ytd_ei'] ) ) {
|
||||
$ae = $this->byId( 'employmentInsuranceDeductedYearToDate' );
|
||||
$ae->click();
|
||||
$this->keys( $args['ytd_ei'] );
|
||||
}
|
||||
|
||||
usleep( 500000 );
|
||||
$ae = $this->byId( 'payrollDeductionsStep3_button_calculate' );
|
||||
Debug::text( 'Active Element Text: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae->click();
|
||||
|
||||
//
|
||||
//Handle results here
|
||||
//
|
||||
$screenshot_file_name = '/tmp/cra_result_screenshot-' . $args['province'] . '-' . $args['federal_claim'] . '-' . $args['provincial_claim'] . '-' . $args['gross_income'] . '.png';
|
||||
file_put_contents( $screenshot_file_name, $this->currentScreenshot() );
|
||||
|
||||
//Make sure the gross income matches first.
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[1]/td[1]' ); //Was: 1
|
||||
Debug::Text( 'AE Text (Gross Income) [1]: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[1]/td[3]' );
|
||||
Debug::Text( 'AE Text (Gross Income) [1]: ' . $ae->text() . ' Expecting: ' . $args['gross_income'], __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$retarr['gross_inc'] = TTi18n::parseFloat( $ae->text() );
|
||||
$this->assertEquals( TTi18n::parseFloat( $ae->text() ), $args['gross_income'] );
|
||||
|
||||
$result_row_offset += 5;
|
||||
|
||||
//Federal Tax
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[' . $result_row_offset . ']' ); //Was: 7
|
||||
Debug::Text( 'AE Text (Federal) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[' . $result_row_offset . ']/td[2]' );
|
||||
Debug::Text( 'AE Text (Federal) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$retarr['federal_deduction'] = TTi18n::parseFloat( $ae->text() );
|
||||
|
||||
$result_row_offset += 1;
|
||||
//Provincial Tax
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[' . $result_row_offset . ']' ); //Was: 8
|
||||
Debug::Text( 'AE Text (Province) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae = $this->byXPath( '/html/body/div/div/main/section[2]/table[1]/tbody/tr[' . $result_row_offset . ']/td[2]' );
|
||||
Debug::Text( 'AE Text (Province) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$retarr['provincial_deduction'] = TTi18n::parseFloat( $ae->text() );
|
||||
|
||||
$result_row_offset += 2;
|
||||
//CPP
|
||||
$ae = $this->byXPath( "/html/body/div/div/main/section[2]/table[1]/tbody/tr[" . $result_row_offset . "]" );
|
||||
Debug::Text( 'AE Text (CPP) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae = $this->byXPath( "/html/body/div/div/main/section[2]/table[1]/tbody/tr[" . $result_row_offset . "]/td[3]" );
|
||||
Debug::Text( 'AE Text (CPP) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$retarr['cpp_deduction'] = TTi18n::parseFloat( $ae->text() );
|
||||
|
||||
$result_row_offset += 1;
|
||||
//EI
|
||||
$ae = $this->byXPath( "/html/body/div/div/main/section[2]/table[1]/tbody/tr[" . $result_row_offset . "]" );
|
||||
Debug::Text( 'AE Text (EI) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$ae = $this->byXPath( "/html/body/div/div/main/section[2]/table[1]/tbody/tr[" . $result_row_offset . "]/td[3]" );
|
||||
Debug::Text( 'AE Text (EI) [' . $result_row_offset . ']: ' . $ae->text(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$retarr['ei_deduction'] = TTi18n::parseFloat( $ae->text() );
|
||||
|
||||
//Debug::Arr( $this->source(), 'Raw Source: ', __FILE__, __LINE__, __METHOD__, 10);
|
||||
//sleep(5);
|
||||
|
||||
$this->selenium_test_case_runs++;
|
||||
} catch ( Exception $e ) {
|
||||
Debug::Text( 'Exception: ' . $e->getMessage(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
file_put_contents( tempnam( '/tmp/', 'cra_result_screenshot_exception' ) . '.png', $this->currentScreenshot() );
|
||||
sleep( 15 );
|
||||
}
|
||||
|
||||
if ( isset( $retarr ) ) {
|
||||
Debug::Arr( $retarr, 'Retarr: ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
return $retarr;
|
||||
}
|
||||
|
||||
Debug::Text( 'ERROR: Returning FALSE!', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Simple control test to ensure the numbers match for the previous year.
|
||||
function testCRAControlCurrentYear() {
|
||||
$pd_obj = new PayrollDeduction( 'CA', 'BC' );
|
||||
$pd_obj->setDate( TTDate::getEndYearEpoch( ( TTDate::getBeginYearEpoch() - 86400 ) ) );
|
||||
$pd_obj->setEnableCPPAndEIDeduction( true ); //Deduct CPP/EI.
|
||||
$pd_obj->setAnnualPayPeriods( 26 );
|
||||
$pd_obj->setFederalTotalClaimAmount( 1 ); //1=Basic Claim Amount
|
||||
$pd_obj->setProvincialTotalClaimAmount( 1 ); //1=Basic Claim Amount
|
||||
$pd_obj->setEIExempt( false );
|
||||
$pd_obj->setCPPExempt( false );
|
||||
$pd_obj->setFederalTaxExempt( false );
|
||||
$pd_obj->setProvincialTaxExempt( false );
|
||||
$pd_obj->setYearToDateCPPContribution( 0 );
|
||||
$pd_obj->setYearToDateEIContribution( 0 );
|
||||
$pd_obj->setGrossPayPeriodIncome( 9933.99 );
|
||||
|
||||
$args = [
|
||||
'date' => strtotime( $pd_obj->getDate() ), //Must be epoch.
|
||||
'province' => $pd_obj->getProvince(),
|
||||
'pay_period_schedule' => $pd_obj->getAnnualPayPeriods(),
|
||||
'federal_claim' => $pd_obj->getFederalTotalClaimAmount(),
|
||||
'provincial_claim' => $pd_obj->getProvincialTotalClaimAmount(),
|
||||
'gross_income' => $pd_obj->getGrossPayPeriodIncome(),
|
||||
];
|
||||
$retarr = $this->CRAPayrollDeductionOnlineCalculator( $args );
|
||||
|
||||
$this->assertEquals( $this->mf( $pd_obj->getFederalPayPeriodDeductions() ), $retarr['federal_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getProvincialPayPeriodDeductions() ), $retarr['provincial_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getEmployeeCPP() ), $retarr['cpp_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getEmployeeEI() ), $retarr['ei_deduction'] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Simple control test to ensure the numbers match for the next year.
|
||||
// Since this would normally be run sometimes in December, this will compare the values for the upcoming tax year.
|
||||
function testCRAControlNextYear() {
|
||||
$pd_obj = new PayrollDeduction( 'CA', 'BC' );
|
||||
$pd_obj->setDate( ( TTDate::getEndYearEpoch( time() ) + 86400 ) ); //**NOTE: this will fail if its run in the most recent tax year.
|
||||
$pd_obj->setEnableCPPAndEIDeduction( true ); //Deduct CPP/EI.
|
||||
$pd_obj->setAnnualPayPeriods( 26 );
|
||||
$pd_obj->setFederalTotalClaimAmount( 1 ); //1=Basic Claim Amount
|
||||
$pd_obj->setProvincialTotalClaimAmount( 1 ); //1=Basic Claim Amount
|
||||
$pd_obj->setEIExempt( false );
|
||||
$pd_obj->setCPPExempt( false );
|
||||
$pd_obj->setFederalTaxExempt( false );
|
||||
$pd_obj->setProvincialTaxExempt( false );
|
||||
$pd_obj->setYearToDateCPPContribution( 0 );
|
||||
$pd_obj->setYearToDateEIContribution( 0 );
|
||||
$pd_obj->setGrossPayPeriodIncome( 9933.99 );
|
||||
|
||||
$args = [
|
||||
'date' => strtotime( $pd_obj->getDate() ), //Must be epoch.
|
||||
'province' => $pd_obj->getProvince(),
|
||||
'pay_period_schedule' => $pd_obj->getAnnualPayPeriods(),
|
||||
'federal_claim' => $pd_obj->getFederalTotalClaimAmount(),
|
||||
'provincial_claim' => $pd_obj->getProvincialTotalClaimAmount(),
|
||||
'gross_income' => $pd_obj->getGrossPayPeriodIncome(),
|
||||
];
|
||||
$retarr = $this->CRAPayrollDeductionOnlineCalculator( $args );
|
||||
|
||||
$this->assertEquals( $this->mf( $pd_obj->getFederalPayPeriodDeductions() ), $retarr['federal_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getProvincialPayPeriodDeductions() ), $retarr['provincial_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getEmployeeCPP() ), $retarr['cpp_deduction'] );
|
||||
$this->assertEquals( $this->mf( $pd_obj->getEmployeeEI() ), $retarr['ei_deduction'] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mf( $amount ) {
|
||||
return Misc::MoneyRound( $amount );
|
||||
}
|
||||
|
||||
function testCRAToCSVFile() {
|
||||
$this->assertEquals( true, file_exists( $this->tax_table_file ) );
|
||||
|
||||
if ( file_exists( $this->cra_deduction_test_csv_file ) ) {
|
||||
$file = new SplFileObject( $this->cra_deduction_test_csv_file, 'r' );
|
||||
$file->seek( PHP_INT_MAX );
|
||||
|
||||
$total_compare_lines = $file->key() + 1;
|
||||
unset( $file );
|
||||
Debug::text( 'Found existing CRATest file to resume with lines: ' . $total_compare_lines, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
|
||||
$test_rows = Misc::parseCSV( $this->tax_table_file, true );
|
||||
|
||||
$total_rows = ( count( $test_rows ) + 1 );
|
||||
$i = 2;
|
||||
foreach ( $test_rows as $row ) {
|
||||
if ( isset( $total_compare_lines ) && $i < $total_compare_lines ) {
|
||||
Debug::text( ' Skipping to line: ' . $total_compare_lines . '/' . $i, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::text( 'Province: ' . $row['province'] . ' Income: ' . $row['gross_income'], __FILE__, __LINE__, __METHOD__, 10 );
|
||||
if ( isset( $row['gross_income'] ) && isset( $row['low_income'] ) && isset( $row['high_income'] )
|
||||
&& $row['gross_income'] == '' && $row['low_income'] != '' && $row['high_income'] != '' ) {
|
||||
$row['gross_income'] = ( $row['low_income'] + ( ( $row['high_income'] - $row['low_income'] ) / 2 ) );
|
||||
}
|
||||
|
||||
if ( $row['country'] != '' && $row['gross_income'] != '' ) {
|
||||
//echo $i.'/'.$total_rows.'. Testing Province: '. $row['province'] .' Income: '. $row['gross_income'] ."\n";
|
||||
Debug::text( $i . '/' . $total_rows . '. Testing Province: ' . $row['province'] . ' Income: ' . $row['gross_income'], __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$args = [
|
||||
'date' => strtotime( $row['date'] ),
|
||||
'province' => $row['province'],
|
||||
'pay_period_schedule' => 26,
|
||||
'federal_claim' => $this->mf( $row['federal_claim'] ),
|
||||
'provincial_claim' => $this->mf( $row['provincial_claim'] ),
|
||||
'gross_income' => $this->mf( $row['gross_income'] ),
|
||||
];
|
||||
|
||||
|
||||
//Debug::Arr( $row, 'aFinal Row: ', __FILE__, __LINE__, __METHOD__, 10);
|
||||
$tmp_cra_data = $this->CRAPayrollDeductionOnlineCalculator( $args );
|
||||
if ( is_array( $tmp_cra_data ) ) {
|
||||
$retarr[] = array_merge( $row, $tmp_cra_data );
|
||||
|
||||
//Debug::Arr( $retarr, 'bFinal Row: ', __FILE__, __LINE__, __METHOD__, 10);
|
||||
//sleep(2); //Should we be friendly to the Gov't server?
|
||||
// if ( $i > 5 ) {
|
||||
// break;
|
||||
// }
|
||||
} else {
|
||||
Debug::text( 'ERROR! Data from CRA is invalid!', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ( isset( $retarr ) ) {
|
||||
//generate column array.
|
||||
$column_keys = array_keys( $retarr[0] );
|
||||
foreach ( $column_keys as $column_key ) {
|
||||
$columns[$column_key] = $column_key;
|
||||
}
|
||||
|
||||
//var_dump($test_data);
|
||||
//var_dump($retarr);
|
||||
//echo Misc::Array2CSV( $retarr, $columns, FALSE, TRUE );
|
||||
file_put_contents( $this->cra_deduction_test_csv_file, Misc::Array2CSV( $retarr, $columns, false, true ), FILE_APPEND );
|
||||
|
||||
//Make sure all rows are tested.
|
||||
$this->assertEquals( $total_rows, ( $i - 1 ) );
|
||||
} else {
|
||||
$this->assertEquals( true, false );
|
||||
}
|
||||
}
|
||||
|
||||
function testCRAFromCSVFile() {
|
||||
$this->assertEquals( true, file_exists( $this->cra_deduction_test_csv_file ) );
|
||||
|
||||
$test_rows = Misc::parseCSV( $this->cra_deduction_test_csv_file, true );
|
||||
|
||||
$total_rows = ( count( $test_rows ) + 1 );
|
||||
$i = 2;
|
||||
foreach ( $test_rows as $row ) {
|
||||
//Debug::text('Province: '. $row['province'] .' Income: '. $row['gross_income'], __FILE__, __LINE__, __METHOD__, 10);
|
||||
if ( isset( $row['gross_income'] ) && isset( $row['low_income'] ) && isset( $row['high_income'] )
|
||||
&& $row['gross_income'] == '' && $row['low_income'] != '' && $row['high_income'] != '' ) {
|
||||
$row['gross_income'] = ( $row['low_income'] + ( ( $row['high_income'] - $row['low_income'] ) / 2 ) );
|
||||
}
|
||||
if ( $row['country'] != '' && $row['gross_income'] != '' ) {
|
||||
//echo $i.'/'.$total_rows.'. Testing Province: '. $row['province'] .' Income: '. $row['gross_income'] ."\n";
|
||||
|
||||
$pd_obj = new PayrollDeduction( $row['country'], $row['province'] );
|
||||
$pd_obj->setDate( strtotime( $row['date'] ) );
|
||||
$pd_obj->setEnableCPPAndEIDeduction( true ); //Deduct CPP/EI.
|
||||
$pd_obj->setAnnualPayPeriods( $row['pay_periods'] );
|
||||
|
||||
$pd_obj->setFederalTotalClaimAmount( $row['federal_claim'] ); //Amount from 2005, Should use amount from 2007 automatically.
|
||||
$pd_obj->setProvincialTotalClaimAmount( $row['provincial_claim'] );
|
||||
|
||||
$pd_obj->setEIExempt( false );
|
||||
$pd_obj->setCPPExempt( false );
|
||||
|
||||
$pd_obj->setFederalTaxExempt( false );
|
||||
$pd_obj->setProvincialTaxExempt( false );
|
||||
|
||||
$pd_obj->setYearToDateCPPContribution( 0 );
|
||||
$pd_obj->setYearToDateEIContribution( 0 );
|
||||
|
||||
$pd_obj->setGrossPayPeriodIncome( $this->mf( $row['gross_income'] ) );
|
||||
|
||||
$this->assertEquals( $this->mf( $pd_obj->getGrossPayPeriodIncome() ), $this->mf( $row['gross_income'] ) );
|
||||
if ( $row['federal_deduction'] != '' ) {
|
||||
$this->assertEqualsWithDelta( (float)$this->mf( $row['federal_deduction'] ), (float)$this->mf( $pd_obj->getFederalPayPeriodDeductions() ), 0.015, 'I: '. $i .' Gross Income: '. $row['gross_income'] .' Province: '. $row['province'] .' Federal Claim: '. $row['federal_claim'] ); //0.015=Allowed Delta
|
||||
}
|
||||
if ( $row['provincial_deduction'] != '' ) {
|
||||
$this->assertEqualsWithDelta( (float)$this->mf( $row['provincial_deduction'] ), (float)$this->mf( $pd_obj->getProvincialPayPeriodDeductions() ), 0.015, 'I: '. $i .' Gross Income: '. $row['gross_income'] .' Province: '. $row['province'] .' Provincial Claim: '. $row['provincial_claim'] ); //0.015=Allowed Delta
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
//Make sure all rows are tested.
|
||||
$this->assertEquals( $total_rows, ( $i - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
90
unit_tests/testcases/selenium/LanguageTest.php
Normal file
90
unit_tests/testcases/selenium/LanguageTest.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
require_once( 'TTSeleniumGlobal.php' );
|
||||
|
||||
/**
|
||||
* @group UI
|
||||
*/
|
||||
class UILanguageTest extends TTSeleniumGlobal {
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function setUpPage() {
|
||||
//$this->currentWindow()->maximize();
|
||||
$this->currentWindow()->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
}
|
||||
|
||||
function testUILanguage() {
|
||||
$user = 'demoadmin2';
|
||||
$pass = 'demo.de';
|
||||
|
||||
$this->goToLogin( $user );
|
||||
|
||||
$this->changeLanguageLogin( 'es' );
|
||||
sleep( 5 ); //Sleep not ideal but waits for language to change.
|
||||
|
||||
$this->assertEquals( 'Logueo Seguro', $this->byId( 'secure-login-text' )->text() );
|
||||
|
||||
$this->Login( $user, $pass );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->assertEquals( 'Panel de control', $this->byId( 'main-menu-link-home' )->text() );
|
||||
|
||||
$this->changeLanguagePreference( 'en' );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->assertEquals( 'Dashboard', $this->byId( 'main-menu-link-home' )->text() );
|
||||
|
||||
$this->changeLanguagePreference( 'es' );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->assertEquals( 'Panel de control', $this->byId( 'main-menu-link-home' )->text() );
|
||||
|
||||
$this->changeLanguagePreference( 'en' );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->assertEquals( 'Dashboard', $this->byId( 'main-menu-link-home' )->text() );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
134
unit_tests/testcases/selenium/LoginTest.php
Normal file
134
unit_tests/testcases/selenium/LoginTest.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
require_once( 'TTSeleniumGlobal.php' );
|
||||
|
||||
/**
|
||||
* @group UI
|
||||
*/
|
||||
class UILoginTest extends TTSeleniumGlobal {
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function setUpPage() {
|
||||
//$this->currentWindow()->maximize();
|
||||
$this->currentWindow()->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
}
|
||||
|
||||
function testUILoginLogout() {
|
||||
$this->Login( 'demoadmin2', 'demo.de' );
|
||||
$this->Logout();
|
||||
}
|
||||
|
||||
// function testEditUser() {
|
||||
// //TODO: Use input field names/ids rather then positions or xpath indexes.
|
||||
// $this->Login();
|
||||
//
|
||||
// //Go to employee list
|
||||
// $this->getText('xpath=//div[@id=\'ribbon\']/ul/li[11]/a');
|
||||
// $this->click('link=Employee');
|
||||
// $this->click('css=#Employee > img');
|
||||
// $this->waitForAttribute( 'css=div.view@init_complete' );
|
||||
//
|
||||
// //Add new employee.
|
||||
// $this->getText('xpath=//div[@id=\'ribbon\']/ul/li[11]/a');
|
||||
// $this->click('css=#addIcon > img');
|
||||
// $this->waitForAttribute( 'css=div.view@init_complete' );
|
||||
//
|
||||
// //Enter employee information.
|
||||
// $this->type('xpath=id(\'tab0_content_div\')/div[1]/div[13]/div[2]/input', 'selenium.test');
|
||||
// $this->fireEvent('xpath=id(\'tab0_content_div\')/div[1]/div[13]/div[2]/input', 'keyup');
|
||||
// $this->waitForElementPresent('xpath=id(\'tab0_content_div\')/div[1]/div[13]/div[2]/input[contains(@class,\'error-tip\')]', FALSE );
|
||||
//
|
||||
// $this->type('xpath=id(\'tab0_content_div\')/div[1]/div[15]/div[2]/input', 'demo');
|
||||
// $this->fireEvent('xpath=id(\'tab0_content_div\')/div[1]/div[15]/div[2]/input', 'keyup');
|
||||
// $this->waitForElementPresent('xpath=id(\'tab0_content_div\')/div[1]/div[15]/div[2]/input[contains(@class,\'error-tip\')]', FALSE );
|
||||
//
|
||||
// $this->type('xpath=id(\'tab0_content_div\')/div[1]/div[17]/div[2]/input', 'demo');
|
||||
// $this->fireEvent('xpath=id(\'tab0_content_div\')/div[1]/div[17]/div[2]/input', 'keyup');
|
||||
// $this->waitForElementPresent('xpath=id(\'tab0_content_div\')/div[1]/div[17]/div[2]/input[contains(@class,\'error-tip\')]', FALSE );
|
||||
//
|
||||
// $this->type('xpath=(//input[@type=\'text\'])[12]', 'selenium');
|
||||
// $this->fireEvent('xpath=(//input[@type=\'text\'])[12]', 'keyup');
|
||||
// $this->type('xpath=(//input[@type=\'text\'])[13]', 'test');
|
||||
// $this->fireEvent('xpath=(//input[@type=\'text\'])[13]', 'keyup');
|
||||
// $this->waitForElementPresent('xpath=(//input[@type=\'text\'])[13][contains(@class,\'error-tip\')]', FALSE );
|
||||
//
|
||||
// $this->waitForElementPresent('xpath=id(\'EmployeeContextMenu\')/div/div/div[1]/ul/li[8][contains(@class,\'disable-image\')]', FALSE );
|
||||
// $this->waitForAttribute( 'css=div.edit-view@validate_complete' );
|
||||
//
|
||||
// //Save employee
|
||||
// $this->click('xpath=id(\'EmployeeContextMenu\')/div/div/div[1]/ul/li[8]');
|
||||
// $this->waitForElementPresent('css=div.popup-loading' );
|
||||
// $this->waitForElementPresent('css=div.edit-view', FALSE );
|
||||
// $this->waitForAttribute( 'css=div.view@init_complete' );
|
||||
//
|
||||
// //Search for newly created user
|
||||
// $this->click('link=BASIC SEARCH');
|
||||
// $this->waitForElementPresent('div.ui-tabs-hide', FALSE );
|
||||
// $this->type('css=input.t-text-input', 'selenium');
|
||||
// $this->click('id=searchBtn');
|
||||
// $this->waitForAttribute( 'css=div.search-panel@search_complete' );
|
||||
//
|
||||
// //Select employee
|
||||
// $this->uncheck('xpath=//input[contains(@id,\'jqg_employee_view_container_\')]');
|
||||
// $this->click('xpath=//input[contains(@id,\'jqg_employee_view_container_\')]');
|
||||
// $this->waitForElementPresent('xpath=id(\'EmployeeContextMenu\')/div/div/div[1]/ul/li[5][contains(@class,\'disable-image\')]', FALSE );
|
||||
//
|
||||
// //Delete employee
|
||||
// $this->click('id=deleteIcon');
|
||||
// $this->isElementPresent('css=div.confirm-alert');
|
||||
//
|
||||
// //Confirm delete
|
||||
// $this->click('id=yesBtn');
|
||||
// $this->isElementPresent('css=div.no-result-div');
|
||||
//
|
||||
//
|
||||
// $this->Logout();
|
||||
// }
|
||||
}
|
||||
|
||||
?>
|
77
unit_tests/testcases/selenium/MiscTest.php
Normal file
77
unit_tests/testcases/selenium/MiscTest.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
require_once( 'TTSeleniumGlobal.php' );
|
||||
|
||||
/**
|
||||
* @group UI
|
||||
*/
|
||||
class UIMiscTest extends TTSeleniumGlobal {
|
||||
|
||||
public function setUpPage() {
|
||||
//$this->currentWindow()->maximize();
|
||||
$this->currentWindow()->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
}
|
||||
|
||||
function testUIGetGlobalVariable() {
|
||||
$this->Login( 'demoadmin2', 'demo.de' );
|
||||
|
||||
$javascript = [ 'script' => 'return Global.getUIReadyStatus();', 'args' => [] ];
|
||||
$var = $this->execute( $javascript );
|
||||
Debug::text( 'Global variable 1 retrieved: ' . print_r( $var, true ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
$this->clickMainMenuItem( 'Attendance' );
|
||||
$this->clickMainMenuItem( 'TimeSheet' );
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$javascript = [ 'script' => 'return Global.UIReadyStatus;', 'args' => [] ];
|
||||
$var2 = $this->execute( $javascript );
|
||||
Debug::text( 'Global variable 2 retrieved: ' . print_r( $var, true ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$this->assertNotEmpty( $var );
|
||||
$this->assertNotEmpty( $var2 );
|
||||
|
||||
$this->Logout();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
80
unit_tests/testcases/selenium/QUnitTest.php
Normal file
80
unit_tests/testcases/selenium/QUnitTest.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
require_once( 'TTSeleniumGlobal.php' );
|
||||
|
||||
use \PHPUnit\Extensions\Selenium2TestCase\Keys as Keys;
|
||||
|
||||
/**
|
||||
* @group UI
|
||||
*/
|
||||
class UIQUnitTest extends TTSeleniumGlobal {
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function setUpPage() {
|
||||
//$this->currentWindow()->maximize();
|
||||
$this->currentWindow()->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
}
|
||||
|
||||
function testUIQUnit() {
|
||||
$user = 'demoadmin2';
|
||||
$pass = 'demo.de';
|
||||
|
||||
$this->Login( $user, $pass );
|
||||
//WebDriverKeys::PAGE_DOWN;
|
||||
$this->keys( Keys::CONTROL . Keys::ALT . Keys::SHIFT . Keys::F12 );
|
||||
|
||||
$this->waitUntilByCssSelector( '#tt_debug_console #qunit_test_button' );
|
||||
$this->byId( 'qunit_test_button' )->click();
|
||||
|
||||
$this->waitUntilByCssSelector( '#qunit-banner.qunit-pass', 60000 );
|
||||
|
||||
$this->assertTrue( $this->byCssSelector( '#qunit-banner.qunit-pass' )->displayed() );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
782
unit_tests/testcases/selenium/ScreenShotTest.php
Normal file
782
unit_tests/testcases/selenium/ScreenShotTest.php
Normal file
@ -0,0 +1,782 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
require_once( 'TTSeleniumGlobal.php' );
|
||||
|
||||
/**
|
||||
* @group UI
|
||||
*/
|
||||
class UIScreenShotTest extends TTSeleniumGlobal {
|
||||
|
||||
public $user_name = '';
|
||||
public $screenshot_path = '';
|
||||
|
||||
public function setUpPage() {
|
||||
//$this->currentWindow()->maximize();
|
||||
$this->currentWindow()->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
}
|
||||
|
||||
function testUIScreenShot() {
|
||||
//$this->screenshot_path = DIRECTORY_SEPARATOR . 'home' . DIRECTORY_SEPARATOR . $this->getOSUser() . DIRECTORY_SEPARATOR . 'public_html' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'UIScreenShotTest' . DIRECTORY_SEPARATOR . APPLICATION_VERSION . '-' . date( 'Ymd-His' );
|
||||
$this->screenshot_path = DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'www' . DIRECTORY_SEPARATOR . 'UIScreenShotTest' . DIRECTORY_SEPARATOR . $this->getOSUser() . '-' . APPLICATION_VERSION . '-' . date( 'Ymd-His' );
|
||||
|
||||
$user_login_info = [
|
||||
'demoadmin2' => 'demo.de',
|
||||
'john.doe2' => 'demo.jo',
|
||||
'jane.doe2' => 'demo.ja',
|
||||
];
|
||||
|
||||
$resolution_array = [
|
||||
[ 'w' => 1920, 'h' => 1080 ],
|
||||
//array( 'w' => 1440, 'h' => 900), //Not serving much purpose at this time.
|
||||
[ 'w' => 1280, 'h' => 800 ],
|
||||
//array( 'w' => 1366, 'h' => 768 ),
|
||||
|
||||
//array( 'w' => 320, 'h' => 568 ), //iphone crashes tests, can find anything (maybe because it's off screen?)
|
||||
//array( 'w' => 1027, 'h' => 728 ), //too small
|
||||
//array( 'w' => 1280 , 'h' => 720 ), //smallest?
|
||||
];
|
||||
|
||||
//single entry point to make error trapping easier
|
||||
try {
|
||||
foreach ( $resolution_array as $resolution ) {
|
||||
$this->width = $resolution['w'];
|
||||
$this->height = $resolution['h'];
|
||||
$win = $this->currentWindow();
|
||||
$win->size( [ 'width' => $this->width, 'height' => $this->height ] );
|
||||
|
||||
foreach ( $user_login_info as $user => $pass ) {
|
||||
Debug::Text( 'logging in as ' . $user, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->startTesting( $user, $pass );
|
||||
$this->assertEquals( true, true, 'Test Completed Successfully.' );
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
//Do not use $e->getTrace() here or there will be a very hard to diagnose infinite loop and memory exhaustion.
|
||||
Debug::Text( $e->getMessage(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
Debug::Arr( $e->getTraceAsString(), 'An error occcured while running automated testing. in ' . $e->getFile() . ' on line: ' . $e->getLine(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
$this->takeScreenshot( $this->screenshot_path . DIRECTORY_SEPARATOR . 'error.png' );
|
||||
$this->assertEquals( false, true, 'The test exited with an error: ' . $e->getMessage() );
|
||||
|
||||
$this->quit(); //Close browser.
|
||||
}
|
||||
}
|
||||
|
||||
function startTesting( $user, $pass ) {
|
||||
$this->user_name = $user;
|
||||
//uncomment these to limit the tests to a specific top level menu
|
||||
//$debug_menu_item = 'block'; //used for testing user and resolution loops
|
||||
//$debug_menu_item = 'main-menu-link-attendance_menu';
|
||||
//$debug_menu_item = 'main-menu-link-schedule_menu';
|
||||
//$debug_menu_item = 'main-menu-link-employee_menu';
|
||||
//$debug_menu_item = 'main-menu-link-company_menu';
|
||||
//$debug_menu_item = 'main-menu-link-payroll_menu';
|
||||
//$debug_menu_item = 'main-menu-link-policy_menu';
|
||||
//$debug_menu_item = 'main-menu-link-invoice_menu';
|
||||
//$debug_menu_item = 'main-menu-link-hr_menu';
|
||||
//$debug_menu_item = 'main-menu-link-recruitment_menu';
|
||||
//$debug_menu_item = 'main-menu-link-document_menu';
|
||||
//$debug_menu_item = 'main-menu-link-report_menu';
|
||||
//$debug_menu_item = 'main-menu-link-ui_kit';
|
||||
|
||||
$hit_debugger = false;
|
||||
|
||||
$this->Login( $user, $pass );
|
||||
|
||||
//In case users are set to timesheet as default screen, prevents crash
|
||||
$this->waitForUIInitComplete();
|
||||
$this->goToDashboard();
|
||||
|
||||
//Process profile menu items first.
|
||||
if ( isset( $debug_menu_item ) == false || ( isset( $debug_menu_item ) == true && $debug_menu_item == 'profile_menu_items' ) ) {
|
||||
$this->processProfileMenu( $this->screenshot_path . DIRECTORY_SEPARATOR . $this->width . 'x' . $this->height . DIRECTORY_SEPARATOR . $this->user_name . DIRECTORY_SEPARATOR . 'profile-menu-items' );
|
||||
}
|
||||
|
||||
//Get the top level menu items only.
|
||||
$menu_elements = $this->getArrayBySelector( '#main-menu > li > a' );
|
||||
|
||||
foreach ( $menu_elements as $menu_element ) {
|
||||
if ( $menu_element->attribute('id') == 'main-menu-link-home' || ( isset( $debug_menu_item ) && $debug_menu_item != $menu_element->attribute( 'id' ) && $hit_debugger == false ) ) {
|
||||
|
||||
Debug::Text( 'Menu skipped or debug limited - B.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
continue;
|
||||
} else {
|
||||
$hit_debugger = true; // comment this out to test just the debug item. Defualt is to test everything forward of specified debug menu item.
|
||||
}
|
||||
|
||||
$resolution = $this->width . 'x' . $this->height;
|
||||
$menu_screenshot_path = $this->screenshot_path . DIRECTORY_SEPARATOR . $resolution . DIRECTORY_SEPARATOR . $this->user_name . DIRECTORY_SEPARATOR . $menu_element->attribute( 'id' );
|
||||
$screenshot_filename = $menu_screenshot_path . '.png';
|
||||
|
||||
$this->clickMainMenuItem( $menu_element->attribute( 'id' ) );
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
if ( $menu_element->attribute( 'id' ) != 'main-menu-link-home' ) {
|
||||
Debug::Text( 'Processing Top Level Menu Element: [' . $menu_element->attribute( 'id' ) . '] screenshot filename: ' . $screenshot_filename, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $screenshot_filename );
|
||||
$this->processSubMenu( $menu_element, $menu_screenshot_path );
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
$this->clickMainMenuItem( $menu_element->attribute( 'id' ) );
|
||||
}
|
||||
|
||||
Debug::Text( 'logging out', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->Logout();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
function processProfileMenu( $menu_screenshot_path ) {
|
||||
//Uncomment to test specific profile menu items.
|
||||
//$debug_menu_item = 'profile-in-out';
|
||||
|
||||
$edit_only_menus = [
|
||||
'profile-menu-LoginUserPreference',
|
||||
'profile-menu-LoginUserContact',
|
||||
'profile-menu-ChangePassword',
|
||||
'profile-in-out',
|
||||
'profile-help',
|
||||
];
|
||||
|
||||
$header_icons = [
|
||||
'profile-in-out',
|
||||
'profile-notifications',
|
||||
'profile-help',
|
||||
];
|
||||
|
||||
//Get all the profile menu items.
|
||||
$menu_elements = $this->getArrayBySelector( '#profile-menu-items > li > button' );
|
||||
|
||||
//Check if topbar header icons are visibiile and add them to list of menu elements to traverse.
|
||||
if ( $this->isThere( '#profile-in-out' ) ) {
|
||||
$menu_elements[] = $this->byId( 'profile-in-out' );
|
||||
}
|
||||
if ( $this->isThere( '#profile-notifications' ) ) {
|
||||
$menu_elements[] = $this->byId( 'profile-notifications' );
|
||||
}
|
||||
|
||||
if ( $this->isThere( '#profile-help' ) ) {
|
||||
$menu_elements[] = $this->byId( 'profile-help' );
|
||||
}
|
||||
|
||||
foreach ( $menu_elements as $menu_element ) {
|
||||
|
||||
if ( $menu_element->attribute( 'id' ) == 'profile-menu-Logout' || ( isset( $debug_menu_item ) && $debug_menu_item != $menu_element->attribute( 'id' ) ) ) {
|
||||
Debug::Text( 'Skipping menu item.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( in_array( $menu_element->attribute( 'id' ), $header_icons ) ) {
|
||||
$menu_element->click();
|
||||
|
||||
if ( $menu_element->attribute( 'id' ) == 'profile-help' ) {
|
||||
if ( $this->isThere( '#profile-menu-About' ) ) {
|
||||
$this->byId( 'profile-menu-About' )->click();
|
||||
} else {
|
||||
//User cannot view About page.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->clickProfileMenuItem( $menu_element->attribute( 'id' ) );
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$profile_menu_screenshot_path = $menu_screenshot_path . DIRECTORY_SEPARATOR . $menu_element->attribute( 'id' );
|
||||
$profile_menu_screenshot_filename = $profile_menu_screenshot_path . '.png';
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
Debug::Text( 'Taking screenshot for profile menu element: ' . $menu_element->attribute( 'id' ) . ' screenshot filename: ' . $profile_menu_screenshot_filename, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $profile_menu_screenshot_filename );
|
||||
|
||||
if ( in_array( $menu_element->attribute( 'id' ), $edit_only_menus ) === false ) {
|
||||
$this->processContextIcons( $profile_menu_screenshot_path, $this->byId( 'profile-menu-items' ), $menu_element );
|
||||
$this->processEditScreen( $profile_menu_screenshot_path, $this->byId( 'profile-menu-items' ), $menu_element, false );
|
||||
} else {
|
||||
$edit_view_context_menu_id = $this->getCurrentContextMenuId();
|
||||
$this->processTabs( $profile_menu_screenshot_path, $menu_element->attribute( 'id' ), $edit_view_context_menu_id, true );
|
||||
}
|
||||
|
||||
$this->sectionCleanUp( $profile_menu_screenshot_path, $this->byId( 'profile-menu-items' ), $menu_element );
|
||||
}
|
||||
}
|
||||
|
||||
function processSubMenu( $root_el, $menu_screenshot_path ) {
|
||||
$sub_menu_li_id = str_replace( 'main-menu-link', 'main-menu-item', $root_el->attribute( 'id' ) );
|
||||
$sub_menu_ul = $this->byCssSelector( '#' . $sub_menu_li_id . ' ul' );
|
||||
|
||||
//array of submenus to limit testing to
|
||||
//$debug_sub_menu = array('PayPeriodSchedule');
|
||||
|
||||
//array of sub elements in which we do not want to click any action icons.
|
||||
//these are mostly actions that have only save and cancel buttons
|
||||
|
||||
$no_context_menus = [
|
||||
//wizards
|
||||
'main-menu-link-ProcessPayrollWizard',
|
||||
'main-menu-link-PayrollRemittanceAgencyEventWizardController',
|
||||
'main-menu-link-ImportCSV',
|
||||
];
|
||||
|
||||
$skip_menus = [
|
||||
'main-menu-link-QuickStartWizard', //Skip as progressing this wizard modifies the data
|
||||
];
|
||||
|
||||
$edit_only_views = [
|
||||
'main-menu-link-Company',
|
||||
'main-menu-link-InvoiceConfig',
|
||||
'main-menu-link-RecruitmentPortalConfig',
|
||||
];
|
||||
|
||||
$nested_sub_menu_views = [
|
||||
'main-menu-link-report_employee_reports',
|
||||
'main-menu-link-report_timesheet_reports',
|
||||
'main-menu-link-report_payroll_reports',
|
||||
'main-menu-link-report_job_tracking_reports',
|
||||
'main-menu-link-report_invoice_reports',
|
||||
'main-menu-link-report_tax_reports',
|
||||
'main-menu-link-report_hr_reports',
|
||||
];
|
||||
|
||||
Debug::Text( 'Processing Submenus at: #' . $root_el->attribute( 'id' ) . ' .ribbon-sub-menu-icon', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
//Do not select further nested menus such as Employee Reports, TimeSheet Reports, etc. Those are handled further below.
|
||||
$sub_menu_elements = $sub_menu_ul->elements(
|
||||
$this->using( 'css selector' )->value( 'ul:not([style="display: none;"]) > li > a' )
|
||||
);
|
||||
|
||||
if ( count( $sub_menu_elements ) > 0 ) {
|
||||
foreach ( $sub_menu_elements as $sub_menu_element ) {
|
||||
|
||||
if ( in_array( $sub_menu_element->attribute( 'id' ), $skip_menus ) || isset( $debug_sub_menu ) && in_array( $sub_menu_element->attribute( 'id' ), $debug_sub_menu ) ) {
|
||||
Debug::Text( 'Menu item debug limited or skipped. - D.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::Text( 'Processing Submenus for selector: ' . $sub_menu_element->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->clickMainMenuItem( $sub_menu_element->attribute( 'id' ) );
|
||||
|
||||
Debug::Text( $sub_menu_element->attribute( 'id' ) . ' submenu clicked.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$submenu_screenshot_path = $menu_screenshot_path . DIRECTORY_SEPARATOR . $sub_menu_element->attribute( 'id' );
|
||||
$submenu_screenshot_filename = $submenu_screenshot_path . '.png';
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
Debug::Text( 'Taking screenshot for submenu element: ' . $sub_menu_element->attribute( 'id' ) . ' screenshot filename: ' . $submenu_screenshot_filename, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $submenu_screenshot_filename );
|
||||
|
||||
if ( in_array( $sub_menu_element->attribute( 'id' ), $no_context_menus ) === false && in_array( $sub_menu_element->attribute( 'id' ), $edit_only_views ) === false && in_array( $sub_menu_element->attribute( 'id' ), $nested_sub_menu_views ) === false ) {
|
||||
$this->processContextIcons( $submenu_screenshot_path, $root_el, $sub_menu_element );
|
||||
}
|
||||
|
||||
//Reports and other views are nested another layer down
|
||||
if ( in_array( $sub_menu_element->attribute( 'id' ), $nested_sub_menu_views ) ) {
|
||||
|
||||
$parent_sub_menu_element = $sub_menu_element->byXPath( "./.." );
|
||||
Debug::Text( 'Processing nested sub menus for selector: ' . $parent_sub_menu_element->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$nested_sub_menu_elements = $parent_sub_menu_element->elements(
|
||||
$this->using( 'css selector' )->value( 'ul > li > a' )
|
||||
);
|
||||
|
||||
array_shift( $nested_sub_menu_elements ); //Remove the first element, which is the current submenu
|
||||
|
||||
foreach ( $nested_sub_menu_elements as $nested_sub_menu_element ) {
|
||||
Debug::Text( 'Processing nested submenu menus for selector: ' . $nested_sub_menu_element->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->clickMainMenuItem( $nested_sub_menu_element->attribute( 'id' ) );
|
||||
|
||||
Debug::Text( $nested_sub_menu_element->attribute( 'id' ) . ' nested sub menu clicked.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$report_submenu_screenshot_path = $menu_screenshot_path . DIRECTORY_SEPARATOR . $nested_sub_menu_element->attribute( 'id' );
|
||||
$report_submenu_screenshot_filename = $report_submenu_screenshot_path . '.png';
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
Debug::Text( 'Taking screenshot for nested sub menu element: ' . $nested_sub_menu_element->attribute( 'id' ) . ' screenshot filename: ' . $report_submenu_screenshot_filename, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $report_submenu_screenshot_filename );
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$this->processTabs( $report_submenu_screenshot_path, $nested_sub_menu_element, $this->getCurrentContextMenuId(), true );
|
||||
$this->clickCancel( $this->getCurrentContextMenuId() );
|
||||
}
|
||||
} else {
|
||||
$this->sectionCleanUp( $submenu_screenshot_path, $root_el, $sub_menu_element );
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
|
||||
//Debug::Text( 'Reset to the top-level menu: ' . $sub_menu_element->attribute('id'), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$this->clickMainMenuItem( $sub_menu_element->attribute('id') );
|
||||
//$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentContextMenuId() {
|
||||
if ( $this->isThere( '.edit-view .context-menu-mount-container' ) ) {
|
||||
return $this->byCssSelector( '.edit-view .context-menu-mount-container' )->attribute( 'id' );
|
||||
}
|
||||
|
||||
$this->waitUntilByCssSelector( '.context-menu-mount-container' );
|
||||
|
||||
return $this->byCssSelector( '.context-menu-mount-container' )->attribute( 'id' );
|
||||
}
|
||||
|
||||
function sectionCleanUp( $submenu_screenshot_path, $root_el, $sub_menu_element ) {
|
||||
$context_menu_id = $this->getCurrentContextMenuId();
|
||||
//cleanup etc before going to the next submenu
|
||||
switch ( $sub_menu_element->attribute( 'id' ) ) {
|
||||
case 'profile-in-out':
|
||||
$this->clickCancel( $context_menu_id );
|
||||
$this->waitThenClick( '#yesBtn' );
|
||||
break;
|
||||
case 'profile-notifications':
|
||||
$this->byId( 'context-button-read' )->click();
|
||||
break;
|
||||
case 'profile-help':
|
||||
break;
|
||||
case 'main-menu-link-ProcessPayrollWizard':
|
||||
case 'main-menu-link-PayrollRemittanceAgencyEventWizardController':
|
||||
case 'main-menu-link-ImportCSV':
|
||||
$this->processWizard( $submenu_screenshot_path, $root_el, $sub_menu_element );
|
||||
break;
|
||||
case 'main-menu-link-QuickStartWizard':
|
||||
$this->processWizard( $submenu_screenshot_path, $root_el, $sub_menu_element );
|
||||
|
||||
//might need this for a fresh install, but not after shutting off quick start nag screen.
|
||||
// if ( $this->byId('yesBtn') ) {
|
||||
// $this->byId('yesBtn')->click();
|
||||
// }
|
||||
break;
|
||||
case 'main-menu-link-RecruitmentPortalConfig':
|
||||
break;
|
||||
default:
|
||||
$this->processEditScreen( $submenu_screenshot_path, $root_el, $sub_menu_element, false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function clickRootAndSub( $root_el, $sub_el ) {
|
||||
$this->waitForUIInitComplete();
|
||||
$this->waitThenClick( '#' . $root_el->attribute( 'id' ) );
|
||||
$this->waitForUIInitComplete();
|
||||
$this->waitThenClick( '#' . $sub_el->attribute( 'id' ) );
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function clickMinimizedWindow() {
|
||||
Debug::Text( 'Clicking minimized tab...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->waitThenClick( '.view-min-tab' );
|
||||
sleep( 1 ); //For some reason without this we get this exception often when going to Payroll -> Pay Stubs, Pay Stub Transaction, then clicking the minimized window: #ribbon .context-menu a - stale element reference: element is not attached to the page document
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function processContextIcons( $path, $root_el, $sub_el ) {
|
||||
Debug::Text( 'processContextIcons: Root ID: ' . $root_el->attribute( 'id' ) . ' Sub Element: ' . $sub_el->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$context_menu_debug_id = 'editclienticon';
|
||||
|
||||
//array of action icons we do not wish to click
|
||||
$skip_array = [
|
||||
//no need
|
||||
'context-button-save',
|
||||
'context-button-delete_icon',
|
||||
'context-button-cancel',
|
||||
'context-button-copy',
|
||||
'context-button-move',
|
||||
'context-button-print_menu',
|
||||
'context-button-export_excel',
|
||||
'context-group-export_excel-split-menu',
|
||||
'context-group-read',
|
||||
'context-group-navigate',
|
||||
'context-button-read',
|
||||
'context-button-unread',
|
||||
'context-button-navigate',
|
||||
'context-button-jump_to',
|
||||
'context-group-jump_to_header',
|
||||
'',
|
||||
|
||||
'context-button-inboxicon',
|
||||
'context-button-senticon',
|
||||
'context-button-authorizationrequesticon',
|
||||
'context-button-authorizationtimesheeticon',
|
||||
'context-button-authorizationexpenseicon',
|
||||
|
||||
//disabled for now due to bugs
|
||||
//all of these have submenu icons and the context icons are not working yet
|
||||
'context-button-re_calculate_timesheet',
|
||||
'context-button-generate_pay_stub',
|
||||
|
||||
//'context-button-clientcontacticon',
|
||||
//'context-button-invoiceicon',
|
||||
//'context-button-transactionicon',
|
||||
//'context-button-paymentmethodicon',
|
||||
//'context-button-accumulatedtimeicon',
|
||||
];
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$this->waitUntilByCssSelector( '.context-menu-mount-container' );
|
||||
$context_menu_id = $this->byCssSelector( '.context-menu-mount-container' )->attribute( 'id' );
|
||||
|
||||
$button_groups = $this->getArrayBySelector( '#' . $context_menu_id . ' div div div' );
|
||||
//Parse the button types and add to $action_element_groups
|
||||
|
||||
foreach ( $button_groups as $button_group ) {
|
||||
Debug::Text( 'Parsing buttons in button group: ' . $button_group->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
//Now get each button in the group if it is not disabled
|
||||
$buttons_in_group = $button_group->elements(
|
||||
$this->using( 'css selector' )->value( 'button:not(.p-disabled)' )
|
||||
);
|
||||
|
||||
//Only click the first button in button group for now
|
||||
$buttons_in_group = array_slice( $buttons_in_group, 0, 1 );
|
||||
|
||||
$previous_context_menu_id = '';
|
||||
|
||||
foreach ( $buttons_in_group as $context_button ) {
|
||||
|
||||
if ( in_array( $context_button->attribute( 'id' ), $skip_array ) == false ) {
|
||||
if ( ( !isset( $context_menu_debug_id ) || stristr( $context_button->attribute( 'id' ), $context_menu_debug_id ) ) == false ) {
|
||||
$this->waitForUIInitComplete();
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug::Text( 'Clicking: #' . $context_button->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$context_button->click();
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
//If context button such as Employee -> New opens a dialog, click yes
|
||||
if ( $this->isThere( '#yesBtn' ) ) {
|
||||
$this->byId( 'yesBtn' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
//Get the new context menu on the new view if it exists. This happens when clicking "New" and other actions.
|
||||
//Check an edit view was even created in first place
|
||||
if ( $this->isThere( '.edit-view .context-menu-mount-container' ) ) {
|
||||
$edit_view_context_menu = $this->byCssSelector( '.edit-view .context-menu-mount-container' );
|
||||
$edit_view_context_menu_id = $edit_view_context_menu->attribute( 'id' );
|
||||
} else {
|
||||
$edit_view_context_menu_id = 'no_context_menu';
|
||||
$edit_view_context_menu = null;
|
||||
}
|
||||
|
||||
if ( $edit_view_context_menu_id != $previous_context_menu_id ) {
|
||||
Debug::Text( 'New context menu id: ' . $edit_view_context_menu_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$previous_context_menu_id = $edit_view_context_menu_id;
|
||||
$new_context_menu = true;
|
||||
} else {
|
||||
$new_context_menu = false;
|
||||
}
|
||||
|
||||
Debug::Text( '******** Taking screenshot for edit context menu #' . $edit_view_context_menu_id . ' screenshot filename: ' . $path . DIRECTORY_SEPARATOR . $edit_view_context_menu_id . '.png', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $path . DIRECTORY_SEPARATOR . $edit_view_context_menu_id . '.png', true );
|
||||
|
||||
//process tabs on applicable views
|
||||
$this->waitForUIInitComplete();
|
||||
//after screenshot is taken, some views need custom closure code
|
||||
switch ( $context_button->attribute( 'id' ) ) {
|
||||
case 'context-button-in_out':
|
||||
Debug::Text( 'Shutting down an inout screen: ' . $edit_view_context_menu_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->clickCancel( $edit_view_context_menu_id );
|
||||
$this->waitThenClick( '#yesBtn' );
|
||||
break;
|
||||
//TODO: Handle the below buttons as they are in dropdowns now
|
||||
//case 'scheduleicon':
|
||||
//case 'paystubicon':
|
||||
// $this->clickMinimizedWindow();
|
||||
// break;
|
||||
//case 'clientcontacticon':
|
||||
//case 'invoiceicon':
|
||||
//case 'transactionicon':
|
||||
//case 'paymentmethodicon':
|
||||
// $this->processTabs( $path . DIRECTORY_SEPARATOR . $id, $root_id, $sub_el_id, $id ); //fix
|
||||
// $this->clickMinimizedWindow();
|
||||
// break;
|
||||
//case 'recalculatetimesheet':
|
||||
//case 'generatepaystub':
|
||||
//case 'jobinvoiceicon':
|
||||
case 'quickstartwizard':
|
||||
case 'context-button-import_icon':
|
||||
case 'context-button-share_report':
|
||||
$this->processWizard( $path . DIRECTORY_SEPARATOR . $edit_view_context_menu_id, $root_el, $sub_el );
|
||||
break;
|
||||
case 'accumulatedtimeicon':
|
||||
// $this->processTabs ( $path . DIRECTORY_SEPARATOR . $id, $root_id , $sub_el_id, $el->attribute('id'));
|
||||
break;
|
||||
case 'paystubtransactionicon':
|
||||
Debug::Text( 'paystubtransaction context icon...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->clickMinimizedWindow();
|
||||
break;
|
||||
// case 'remittancesourceaccount':
|
||||
// $this->processTabs ( $path . DIRECTORY_SEPARATOR . $id, $root_id, $sub_el_id, $id, TRUE );
|
||||
// break;
|
||||
default:
|
||||
if ( $edit_view_context_menu !== null ) {
|
||||
//If there is a new context menu, process the tabs
|
||||
if ( $new_context_menu == true ) {
|
||||
$this->processTabs( $path . DIRECTORY_SEPARATOR . $edit_view_context_menu_id, $context_button->attribute( 'id' ), $edit_view_context_menu_id, true );
|
||||
}
|
||||
|
||||
$this->clickCancel( $edit_view_context_menu_id );
|
||||
}
|
||||
//$this->byCssSelector( '.context-menu-bar .tticon-cancel_black_24dp' )->byXPath("./..")->click(); //TODO: Fix cancel button for all context menus.
|
||||
//no hashtag
|
||||
//$this->clickCancel();
|
||||
// if ( $this->byCssSelector('#'. $this->byCssSelector('#ribbon .context-menu a')->attribute('ref') .' li:not(.disable-image):not(.invisible-image) #cancelIcon') ) {
|
||||
// Debug::Text( 'clicking: #cancelIcon.', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//
|
||||
// $this->waitThenClick('#'. $this->byCssSelector('#ribbon .context-menu a')->attribute('ref') .' li:not(.disable-image):not(.invisible-image) #cancelIcon' );
|
||||
// }
|
||||
}
|
||||
|
||||
//Make sure that cancel icon is not invisible or disabled.
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug::Text( 'Done! Clicking context menu now...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$this->waitThenClick( '#ribbon .context-menu a' );
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
function processTabs( $path, $icon_clicked, $context_menu_id = false, $is_edit_view = false ) {
|
||||
|
||||
Debug::Text( 'Retrieving Tabs for: ' . $context_menu_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$tabs = $this->getTabs( $icon_clicked, $context_menu_id );
|
||||
|
||||
Debug::Text( 'Processing Tabs for: ' . $context_menu_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( count( $tabs ) > 1 ) {
|
||||
$first_tab = array_shift( $tabs );
|
||||
foreach ( $tabs as $tab_el ) {
|
||||
$name = $tab_el->attribute( 'ref' );
|
||||
|
||||
Debug::Text( 'Processing Tab: ' . $name, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( $tab_el->displayed() ) {
|
||||
$tab_el->click();
|
||||
} else {
|
||||
//TODO: Scroll the tab buttons if tab is not visible.
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
if ( $is_edit_view != false ) {
|
||||
$screenshotFileName = $path . DIRECTORY_SEPARATOR . 'edit_view_' . $name . '.png';
|
||||
} else {
|
||||
$screenshotFileName = $path . DIRECTORY_SEPARATOR . $name . '.png';
|
||||
}
|
||||
Debug::Text( 'Taking screenshot for Tab: ' . $name . ' screenshot filename: ' . $screenshotFileName, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $screenshotFileName, true );
|
||||
}
|
||||
|
||||
if ( $first_tab->displayed() ) {
|
||||
$first_tab->click(); //click first tab before cancel.
|
||||
} else {
|
||||
//TODO: Scroll the tab buttons if tab is not visible.
|
||||
}
|
||||
} else {
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
||||
|
||||
function getTabs( $clicked_icon_name, $context_menu_id ) {
|
||||
$ignore_array = [
|
||||
//causes crash as tries to click invisible audit tab
|
||||
'profile-in-out',
|
||||
];
|
||||
|
||||
if ( in_array( $clicked_icon_name, $ignore_array ) == true ) {
|
||||
Debug::Text( 'Not even looking at tabs', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$parent_context_border = $this->byCssSelector( '#' . $context_menu_id )->byXPath( "./.." );
|
||||
|
||||
//Find none hidden tabs
|
||||
Debug::Text( 'Finding all tabs for:' . $context_menu_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$tabs = $parent_context_border->elements(
|
||||
$this->using( 'css selector' )->value( 'ul.ui-tabs-nav > li:not([style="display: none;"]) > a' )
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
function processWizard( $submenu_screenshot_path, $root_el, $sub_el ) {
|
||||
$root_id = $root_el->attribute( 'id' );
|
||||
$sub_id = $sub_el->attribute( 'id' );
|
||||
Debug::Text( 'Looking At Wizard View: ' . $root_id . ' Sub View: ' . $sub_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
//Wizards save steps so make sure we go to first step before taking screenshots.
|
||||
while ( $this->byId( 'wizard-back-button' )->attribute( 'disabled' ) == false && str_contains( $this->byId( 'wizard-back-button' )->attribute( 'class' ), 'disable-image' ) == false ) {
|
||||
$this->byId( 'wizard-back-button' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
if ( $this->isThere( '#yesBtn' ) ) {
|
||||
$this->byId( 'yesBtn' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
||||
|
||||
//Now go forward to last step in the wizard.
|
||||
$step = 1;
|
||||
|
||||
$screenshotFileName = $submenu_screenshot_path . DIRECTORY_SEPARATOR . 'wizard' . $sub_id . 'step' . $step . '.png';
|
||||
Debug::Text( 'Taking screenshot for wizard View: ' . $root_id . '=>' . $sub_id . ' screenshot filename: ' . $screenshotFileName, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $screenshotFileName );
|
||||
|
||||
while ( $this->byId( 'wizard-forward-button' )->attribute( 'disabled' ) == false && str_contains( $this->byId( 'wizard-forward-button' )->attribute( 'class' ), 'disable-image' ) == false ) {
|
||||
$this->byId( 'wizard-forward-button' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
if ( $this->isThere( '#yesBtn' ) ) {
|
||||
$this->byId( 'yesBtn' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
if ( $this->isThere( '#t-alert-close' ) ) {
|
||||
$this->byId( 't-alert-close' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
$step++;
|
||||
|
||||
$screenshotFileName = $submenu_screenshot_path . DIRECTORY_SEPARATOR . 'wizard' . $sub_id . 'step' . $step . '.png';
|
||||
Debug::Text( 'Taking screenshot for wizard View: ' . $root_id . '=>' . $sub_id . ' screenshot filename: ' . $screenshotFileName, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $screenshotFileName );
|
||||
}
|
||||
|
||||
$this->byId( 'wizard-close-button' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
if ( $this->isThere( '#yesBtn' ) ) {
|
||||
$this->byId( 'yesBtn' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
if ( $this->isThere( '#t-alert-close' ) ) {
|
||||
$this->byId( 't-alert-close' )->click();
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
||||
|
||||
function processEditScreen( $submenu_screenshot_path, $root_el, $sub_el, $context_el ) {
|
||||
$root_id = $root_el->attribute( 'id' );
|
||||
$sub_id = $sub_el->attribute( 'id' );
|
||||
Debug::Text( 'Looking At Edit View: ' . $root_id . ' Sub View: ' . $sub_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( $context_el == false ) {
|
||||
$context_menu_id = $this->byCssSelector( '.context-menu-mount-container' )->attribute( 'id' );
|
||||
}
|
||||
|
||||
$ignore_list = [
|
||||
//popovers that have grids under them so the grid is found and causes a crash.
|
||||
'context-button-in_out',
|
||||
'profile-menu-ChangePassword',
|
||||
'profile-menu-LoginUserPreference',
|
||||
'profile-menu-LoginUserContact',
|
||||
|
||||
//overly complex grids that will need special considerations:
|
||||
'main-menu-link-TimeSheet',
|
||||
'main-menu-link-Schedule',
|
||||
];
|
||||
|
||||
if ( in_array( $sub_id, $ignore_list ) ) {
|
||||
Debug::Text( 'Skipping due to ignore list...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Look at this css selector
|
||||
$css_selector = '.grid-div .ui-jqgrid .ui-jqgrid-btable tr:nth-child(2) td:nth-child(2)';
|
||||
$this->waitForUIInitComplete();
|
||||
if ( $this->isThere( '.grid-div .no-result-div' ) === false && $this->isThere( $css_selector ) === true && $this->isThere( '#' . $context_menu_id . ' .left-view' ) == true ) {
|
||||
Debug::Text( 'Processing Edit View: ' . $root_id . '=>' . $sub_id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$this->waitThenClick( $css_selector );
|
||||
//Don't click view on Pay Stub or Invoice as it will download a file.
|
||||
if ( $sub_id == 'main-menu-link-PayStub' || $sub_id == 'main-menu-link-GovernmentDocument' || $sub_id == 'main-menu-link-Invoice' ) {
|
||||
if ( $this->isThere( '#' . $context_menu_id . ' #context-button-edit' ) ) {
|
||||
$this->waitThenClick( '#' . $context_menu_id . ' #context-button-edit' );
|
||||
}
|
||||
$icon_clicked = 'edit';
|
||||
} else {
|
||||
$this->waitThenClick( '#' . $context_menu_id . ' #context-button-view' );
|
||||
$icon_clicked = 'view';
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
$screenshotFileName = $submenu_screenshot_path . DIRECTORY_SEPARATOR . 'edit_view_' . $sub_id . '.png';
|
||||
|
||||
Debug::Text( 'Taking screenshot for Edit View: ' . $root_id . '=>' . $sub_id . ' screenshot filename: ' . $screenshotFileName, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->takeScreenshot( $screenshotFileName );
|
||||
|
||||
if ( $this->isThere( '.edit-view .context-menu-mount-container' ) ) {
|
||||
$edit_view_context_menu = $this->byCssSelector( '.edit-view .context-menu-mount-container' );
|
||||
$edit_view_context_menu_id = $edit_view_context_menu->attribute( 'id' );
|
||||
$this->processTabs( $submenu_screenshot_path . DIRECTORY_SEPARATOR . 'edit_view_' . $context_menu_id, $icon_clicked, $edit_view_context_menu_id, true );
|
||||
$this->waitForUIInitComplete();
|
||||
Debug::Text( 'Clicking Cancel at end of processEditScreen()', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->clickCancel( $edit_view_context_menu_id );
|
||||
}
|
||||
|
||||
//does every edit have a cancel? NO. Exceptions is the exception, so it's in the ignore_list.
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
Debug::Text( 'Done...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
425
unit_tests/testcases/selenium/TTSeleniumGlobal.php
Normal file
425
unit_tests/testcases/selenium/TTSeleniumGlobal.php
Normal file
@ -0,0 +1,425 @@
|
||||
<?php /** @noinspection PhpMissingDocCommentInspection */
|
||||
/*********************************************************************************
|
||||
*
|
||||
* TimeTrex is a Workforce Management program developed by
|
||||
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by
|
||||
* the Free Software Foundation with the addition of the following permission
|
||||
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
||||
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*
|
||||
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
||||
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
||||
*
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Powered by TimeTrex".
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
/**
|
||||
* Class TTSeleniumGlobal
|
||||
*
|
||||
* weird xpath examples:
|
||||
* // //*[starts-with(@id, 'ceil_')]
|
||||
*/
|
||||
class TTSeleniumGlobal extends PHPUnit\Extensions\Selenium2TestCase {
|
||||
|
||||
private $default_wait_timeout = 4000;//100000;
|
||||
|
||||
public $width = 1440;
|
||||
public $height = 900;
|
||||
|
||||
public function setUp(): void {
|
||||
global $selenium_config;
|
||||
$this->selenium_config = $selenium_config;
|
||||
|
||||
Debug::text( 'Running setUp(): ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
TTDate::setTimeZone( 'Etc/GMT+8', true ); //Due to being a singleton and PHPUnit resetting the state, always force the timezone to be set.
|
||||
|
||||
$this->setHost( $selenium_config['host'] );
|
||||
$this->setPort( (int)$selenium_config['port'] );
|
||||
$this->setBrowser( $selenium_config['browser'] );
|
||||
$this->setBrowserUrl( $selenium_config['default_url'] );
|
||||
|
||||
$this->setDesiredCapabilities( [ 'chromeOptions' => [ 'args' => [ '--incognito' ], ] ] ); //Use incognito mode to help prevent caching between sessions and saving passwords and such.
|
||||
|
||||
|
||||
$this->setDesiredCapabilities( [
|
||||
'goog:chromeOptions' => [
|
||||
'w3c' => false,
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
public function tearDown(): void {
|
||||
Debug::text( 'Running tearDown(): ', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function goToLogin( $user ) {
|
||||
Debug::text( 'Login to: ' . $this->selenium_config['default_url'] . ' Username: ' . $user, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->url( $this->selenium_config['default_url'] );
|
||||
|
||||
sleep( 2.5 ); //have to be sure that Global.js is loaded before we start trying to use it.
|
||||
$this->setUnitTestMode( $user );
|
||||
|
||||
$this->waitUntilByCssSelector( '#user_name' );
|
||||
}
|
||||
|
||||
function Login( $user, $pass ) {
|
||||
//disable the overlay to speed up testing
|
||||
|
||||
$this->goToLogin( $user );
|
||||
|
||||
$this->waitThenClick( '#user_name' );
|
||||
$this->keys( $user );
|
||||
//$this->keys('demoadmin2');
|
||||
|
||||
$this->waitThenClick( '#password' );
|
||||
$this->keys( $pass );
|
||||
|
||||
$this->waitThenClick( '#login_btn' );
|
||||
|
||||
sleep( 1 ); //wait for login
|
||||
$this->waitForUIInitComplete();
|
||||
$this->waitUntilById( 'topbar-company-logo' ); //the css not() selector is there to differentiate the various calls in the server log.
|
||||
|
||||
//needed as development mode reloads and clears the variables.
|
||||
$javascript = [ 'script' => 'Global.setUnitTestMode();', 'args' => [] ];
|
||||
$this->execute( $javascript );
|
||||
|
||||
Debug::text( 'Login Complete...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function Logout() {
|
||||
//because we could want to log out from any point
|
||||
$this->goToDashboard();
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$this->waitUntilById( 'profile-button' );
|
||||
$this->byId( 'profile-button' )->click();
|
||||
|
||||
$this->waitUntilById( 'profile-menu-Logout' );
|
||||
$this->byId( 'profile-menu-Logout' )->click();
|
||||
|
||||
$this->waitUntilById( 'user_name' );
|
||||
Debug::text( 'Logout...', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function waitUntilById( $id, $timeout = null ) {
|
||||
if ( $timeout == null ) {
|
||||
$timeout = $this->default_wait_timeout;
|
||||
}
|
||||
|
||||
$this->waitUntil( function () use ( $id ) {
|
||||
$javascript = [ 'script' => "$('#overlay.overlay:visible').length", 'args' => [] ];
|
||||
if ( $this->execute( $javascript ) == 0 && $this->byId( $id ) ) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, $timeout );
|
||||
}
|
||||
|
||||
function changeLanguageLogin( $language_value ) {
|
||||
$this->waitUntilByCssSelector( '#language-selector' );
|
||||
|
||||
$language_selector = $this->byId( 'language-selector' );
|
||||
$language_selector->click();
|
||||
|
||||
$language_options = $language_selector->elements(
|
||||
$this->using( 'css selector' )->value( 'option' )
|
||||
);
|
||||
|
||||
foreach ( $language_options as $language_option ) {
|
||||
if ( $language_option->value() == $language_value ) {
|
||||
$language_option->click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function changeLanguagePreference( $language_value ) {
|
||||
$this->goToDashboard();
|
||||
|
||||
$this->waitUntilById( 'profile-button' );
|
||||
$this->byId( 'profile-button' )->click();
|
||||
|
||||
$this->waitUntilById( 'profile-menu-LoginUserPreference' );
|
||||
$this->byId( 'profile-menu-LoginUserPreference' )->click();
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$language_selector = $this->byCssSelector( '#tab_preferences_content_div select:first-of-type' );
|
||||
$language_selector->click();
|
||||
|
||||
$language_options = $language_selector->elements(
|
||||
$this->using( 'css selector' )->value( 'option' )
|
||||
);
|
||||
|
||||
foreach ( $language_options as $language_option ) {
|
||||
if ( $language_option->value() == $language_value ) {
|
||||
$language_option->click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->byId( 'context-button-save' )->click();
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
function waitUntilByCssSelector( $selector, $timeout = null ) {
|
||||
if ( $timeout == null ) {
|
||||
$timeout = $this->default_wait_timeout;
|
||||
}
|
||||
|
||||
$this->waitUntil( function () use ( $selector ) {
|
||||
$javascript = [ 'script' => "$('#overlay.overlay:visible').length", 'args' => [] ];
|
||||
if ( $this->execute( $javascript ) == 0 && $this->byCssSelector( $selector ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, $timeout );
|
||||
}
|
||||
|
||||
function takeScreenshot( $screenshot_file_name, $create_dir = true ) {
|
||||
if ( $create_dir === true ) {
|
||||
$dirname = dirname( $screenshot_file_name );
|
||||
if ( file_exists( $dirname ) == false ) {
|
||||
mkdir( $dirname, 0777, true );
|
||||
}
|
||||
}
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
// get the mousepointer and focus away from hover effects and flashing cursors
|
||||
// these cause significant differences in the screenshots.
|
||||
$this->waitUntilByCssSelector( '#powered_by,#copy_right_logo' );
|
||||
$this->moveto( $this->byCssSelector( '#powered_by,#copy_right_logo' ) );
|
||||
$this->waitUntilByCssSelector( '#powered_by,#copy_right_logo' );
|
||||
|
||||
$retval = file_put_contents( $screenshot_file_name, $this->currentScreenshot() );
|
||||
chmod( $screenshot_file_name, 0777 );
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
function getOSUser() {
|
||||
if ( function_exists( 'posix_geteuid' ) && function_exists( 'posix_getpwuid' ) ) {
|
||||
$user = posix_getpwuid( posix_geteuid() );
|
||||
Debug::Text( 'Webserver running as User: ' . $user['name'], __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function goToDashboard() {
|
||||
$this->waitUntilById( 'topbar-company-logo' );
|
||||
$this->byId( 'topbar-company-logo' )->byXPath("./..")->click(); //click on the logo parent (href) to go to the dashboard
|
||||
//dashboard will reliably use init_complete after everything is loaded.
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
|
||||
function waitForUIInitComplete() {
|
||||
$this->waitForUIInitCompleteLoops = 0;
|
||||
$this->waitUntil( function ( $_self_ ) {
|
||||
//Global.getUIReadyStatus will be == 2 when the screens are finished loading.
|
||||
|
||||
$javascript = [ 'script' => 'if ( ( typeof Global != "undefined" && Global.getUIReadyStatus() == 2 ) && ( typeof TTPromise != "undefined" && TTPromise.isPendingPromises() == false ) ) { return true; } else { return false; }', 'args' => [] ];
|
||||
$js_retval = $this->execute( $javascript );
|
||||
Debug::Text( 'waitForUI result: ' . var_export( $js_retval, true ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( isset( $js_retval ) && $js_retval == true ) {
|
||||
return true;
|
||||
} else {
|
||||
$ui_ready_status = $this->execute( [ 'script' => 'if ( typeof Global != "undefined" ) { return Global.getUIReadyStatus(); } else { return null; }', 'args' => [] ] );
|
||||
$pending_promises = $this->execute( [ 'script' => 'if ( typeof TTPromise != "undefined" ) { return TTPromise.isPendingPromises(); } else { return null; }', 'args' => [] ] );
|
||||
Debug::Text( ' waitForUI UIReadyStatus: ' . var_export( $ui_ready_status, true ) . ' Pending Promises: ' . var_export( $pending_promises, true ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
if ( $_self_->waitForUIInitCompleteLoops > 10 ) {
|
||||
//trigger checking promises again to workaround selenium bug where they resolve without firing function
|
||||
$this->execute( [ 'script' => 'TTPromise.wait()', 'args' => [] ] );
|
||||
Debug::Text( ' waitForUI Triggering TTPromise.wait()... Loops: ' . $this->waitForUIInitCompleteLoops, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
$_self_->waitForUIInitCompleteLoops++;
|
||||
|
||||
return null;
|
||||
}
|
||||
}, 60000 ); //Wait for up to 60 seconds.
|
||||
}
|
||||
|
||||
function setUnitTestMode( $username ) {
|
||||
$sf = TTnew( 'StationFactory' ); /** @var StationFactory $sf */
|
||||
$slf = TTnew( 'StationListFactory' ); /** @var StationListFactory $slf */
|
||||
|
||||
$slf->getByStationId( 'UNITTEST' );
|
||||
if ( $slf->getRecordCount() == 0 ) {
|
||||
$ulf = TTNew( 'UserListFactory' ); /** @var UserListFactory $ulf */
|
||||
$ulf->getByUserName( $username );
|
||||
if ( $ulf->getRecordCount() > 0 ) {
|
||||
$sf->setCompany( $ulf->getCurrent()->getCompany() );
|
||||
$sf->setStatus( 20 );
|
||||
$sf->setType( 10 );
|
||||
$sf->setDescription( 'Unit Testing Rig' );
|
||||
$sf->setStation( 'UNITTEST' );
|
||||
$sf->setSource( 'ANY' );
|
||||
$sf->setBranchSelectionType( 10 ); //enabled all
|
||||
$sf->setDepartmentSelectionType( 10 ); //enabled all
|
||||
$sf->setGroupSelectionType( 10 ); //enabled all
|
||||
if ( $sf->isValid() ) {
|
||||
$sf->Save();
|
||||
}
|
||||
} else {
|
||||
Debug::Text( 'username not found in db', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
} else {
|
||||
Debug::Text( 'station exists', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
//run necessary js for unit tests
|
||||
$javascript = [ 'script' => 'Global.setUnitTestMode();', 'args' => [] ];
|
||||
$this->execute( $javascript );
|
||||
|
||||
//$path = Environment::getCookieBaseURL();
|
||||
//set the same sessionid for all tests
|
||||
//$javascript = [ 'script' => "$.cookie( 'StationID', 'UNITTESTS', {expires: 30, path: '$path'} );", 'args' => [] ];
|
||||
$javascript = [ 'script' => "Global.setStationID('UNITTEST')", 'args' => [] ];
|
||||
$this->execute( $javascript );
|
||||
}
|
||||
|
||||
function isThere( $css_selector ) {
|
||||
$result = $this->elements( $this->using( 'css selector' )->value( $css_selector ) );
|
||||
if ( count( $result ) > 0 ) {
|
||||
foreach ( $result as $el ) {
|
||||
if ( $el->displayed() && $el->enabled() ) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function waitThenClick( $selector ) {
|
||||
Debug::Text( 'Attempting to click Selector: ' . $selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
|
||||
$javascript = [ 'script' => "return $('#overlay.overlay').length", 'args' => [] ];
|
||||
$overlay_shown = $this->execute( $javascript );
|
||||
if ( $overlay_shown > 0 ) {
|
||||
Debug::Text( ' Overlay status check: ' . $overlay_shown, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
sleep( 1 );
|
||||
$this->waitThenClick( $selector );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( ( substr( $selector, 0, 1 ) == '#' && strstr( $selector, ' ' ) == false ) || strstr( $selector, 'menu:' ) == true ) {
|
||||
//need to do this because of malformed ids in the top menu causing wating by selector to fail.
|
||||
$id = substr( $selector, 1, strlen( $selector ) );
|
||||
Debug::Text( ' Waiting on ID: ' . $id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->waitUntilById( $id, 10000 );
|
||||
Debug::Text( ' Clicking ID: ' . $id, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->byId( $id )->click();
|
||||
} else {
|
||||
Debug::Text( ' Waiting on selector: ' . $selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$this->waitUntilByCssSelector( $selector, 10000 );
|
||||
Debug::Text( ' Clicking selector: ' . $selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$el = $this->byCssSelector( $selector );
|
||||
//Debug::Text( ' Element about to be clicked: Enabled: '. $el->enabled() .' Displayed: '. $el->displayed(), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
$el->click();
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$this->takeScreenshot( $this->screenshot_path . DIRECTORY_SEPARATOR . 'waitThenClickException.png', true );
|
||||
Debug::Text( 'Click failed on: ' . $selector . ' Screenshot path: ' . $this->screenshot_path, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$javascript = array('script' => "$('" . $selector . "').click()", 'args' => array());
|
||||
//$this->execute( $javascript );
|
||||
throw new Exception( $selector . ' - ' . $e->getMessage() );
|
||||
}
|
||||
|
||||
Debug::Text( 'Done: ' . $selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function getArrayBySelector( $css_selector ) {
|
||||
Debug::Text( 'Getting array by selector: ' . $css_selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
//$this->waitUntilByCssSelector( $css_selector,10000 );
|
||||
|
||||
//http://stackoverflow.com/questions/16637806/select-all-matching-elements-in-phpunit-selenium-2-test-case
|
||||
$retval = $this->elements(
|
||||
$this->using( 'css selector' )->value( $css_selector )
|
||||
);
|
||||
|
||||
if ( isset( $retval ) ) {
|
||||
Debug::Text( count( $retval ) . ' RESULTS FOR: ' . $css_selector, __FILE__, __LINE__, __METHOD__, 10 );
|
||||
// foreach ( $retval as $el ) {
|
||||
// Debug::Text( ' Element: ' . $el->attribute( 'ref' ) .' ID: '. $el->attribute( 'id' ), __FILE__, __LINE__, __METHOD__, 10 );
|
||||
// }
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function clickCancel( $menu_id = false ) {
|
||||
//TODO look at this
|
||||
if ( $menu_id !== false ) {
|
||||
$selector = '#' . $menu_id . ' .tticon-cancel_black_24dp';
|
||||
$this->waitThenClick( $selector );
|
||||
Debug::Text( 'Clicking Cancel [' . $selector . ']', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
} else {
|
||||
//TODO: Fix this branchs
|
||||
$javascript = [ 'script' => "$('#topContainer .ribbon .ribbon-tab-out-side:visible #cancelIcon').click()", 'args' => [] ];
|
||||
$this->execute( $javascript );
|
||||
Debug::Arr( $javascript, 'Executing cancelclick with js', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
}
|
||||
|
||||
function clickMainMenuItem( $menu_id ) {
|
||||
//Only works for main menu horizontal default mode currently.
|
||||
$this->waitUntilByCssSelector( '#main-menu' );
|
||||
$this->byCssSelector( '#main-menu' )->byId( $menu_id )->click();
|
||||
Debug::Text( 'Opening Main Menu Item [' . $menu_id . ']', __FILE__, __LINE__, __METHOD__, 10 );
|
||||
}
|
||||
|
||||
function clickProfileMenuItem( $profile_menu_id ) {
|
||||
$this->waitForUIInitComplete();
|
||||
|
||||
$this->waitUntilById( 'profile-button' );
|
||||
$this->byId( 'profile-button' )->click();
|
||||
|
||||
$this->waitUntilById( $profile_menu_id );
|
||||
$this->byId( $profile_menu_id )->click();
|
||||
|
||||
$this->waitForUIInitComplete();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user