diff --git a/index.js b/index.js index a53f6bd..839a618 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,9 @@ import uploadSubmitAResourcePage from './tests/Upload/uploadSubmitAResourcePage. import uploadBatchUploadPage from './tests/Upload/uploadBatchUpload.js'; import uploadImportAlignmentsPage from './tests/Upload/uploadImportAlignmentsPage.js'; +//ACTIVITY REPORT +import activityReportPage from './tests/ActivityReport/ActivityReportPage.js'; + //Content import ExACT_contentPage from './tests/ExACT_contentPage.js'; import ExACT_editItem from './tests/ExACT_editItem.js'; @@ -75,6 +78,9 @@ app.get('/', (req, res) => {
Submit A Resource Page
Batch Upload Page
Import Alignments Page
+ +

ACTIVITY REPORT

+
Activity Report Page
| ACTIVITY REPORT PAGE |<-------------'); + const errors = []; + + await driver.findElement(By.css('.form-control:nth-child(2)')).sendKeys('exact_juan'); + await driver.findElement(By.css('.passfield')).sendKeys('Edgate1!'); + await driver.findElement(By.css('.login')).click(); + console.log('----->| NEXT ACTION: Entered credentials and logged in'); + + //Wait for page readyState + await driver.wait(async () => { + const readyState = await driver.executeScript('return document.readyState'); + return readyState === 'complete'; + }, 30000, 'ExACT Dashboard did not fully load within 30 seconds'); + + //Wait for the dashboard container to exist in DOM + await driver.wait( + until.elementLocated(By.css('.gap-idle-wrap > img')), + 30000, + 'Dashboard image did not appear within 30 seconds' + ); + + //Wait for it to be visible + await driver.wait(async () => { + try { + const img = await driver.findElement(By.css('.gap-idle-wrap > img')); + return await img.isDisplayed(); + } catch (e) { + return false; + } + }, 30000, 'Dashboard image did not become visible within 30 seconds'); + + //Wait for any loading spinners to disappear + await driver.wait(async () => { + try { + const spinners = await driver.findElements(By.css('.spinner-border')); + for (const spinner of spinners) { + if (await spinner.isDisplayed()) return false; + } + return true; + } catch (e) { + return true; + } + }, 30000, 'Loading spinners did not disappear within 30 seconds'); + + //Wait for the slowest resource to complete + await driver.wait(async () => { + const completed = await driver.executeScript(` + const entries = performance.getEntriesByType('resource'); + return entries.some(entry => + entry.name.includes('content_sets.php') && + entry.responseEnd > 0 + ); + `); + return completed; + }, 30000, 'My Content widget (content_sets.php) did not complete loading within 30 seconds'); + console.log('Passed: My Content widget (content_sets.php) loaded successfully - Dashboard fully loaded'); + + //Final sleep to allow any remaining dynamic content to settle + await driver.sleep(2000); + + console.log('Passed: ExACT Dashboard loaded successfully'); + + if (errors.length > 0) { + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + throw new Error(errors.join('\n')); + } + } + }, + + //Dashboard title + { + description: 'Dashboard title text, size, and color', + action: async () => { + const multipleChecks = 'Dashboard title'; + + const element = await driver.findElement(By.css('.e-heading')); + + //Get text, font, size, and color + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //text + if (elementText === 'Correlation Dashboard') { + console.log('Passed: Dashboard title text matched as expected'); + } else { + errors.push(`Expected: "Correlation Dashboard"; Actual: "${elementText}"`); + } + + //font + if (elementFont === `"DM Serif Display", serif`) { + console.log('Passed: Dashboard title font-family matched as expected'); + } else { + errors.push(`Expected: Dashboard title font-family "DM Serif Display, serif"; Actual: ${elementFont}`); + } + + //size + if (elementSize === '32px') { + console.log('Passed: Dashboard title text font-size matched as expected'); + } else { + errors.push(`Expected: Dashboard title text font-size "32px"; Actual: "${elementSize}"`); + } + + //color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Dashboard title text color matched as expected'); + } else { + errors.push(`Expected: Dashboard title text color: "rgba(40, 39, 90, 1)"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //NEXT ACTION + { + description: 'Click Activity Report navigation link', + action: async () => { + await driver.findElement(By.linkText('Activity Report')).click(); + console.log('----->| NEXT ACTION: Clicked Activity Report navigation link'); + + //Wait for page readyState + await driver.wait(async () => { + const readyState = await driver.executeScript('return document.readyState'); + return readyState === 'complete'; + }, 30000, 'Activity Reports page did not fully load within 30 seconds'); + + //Wait until the element exists in the DOM + const activityReportPageTitle = await driver.wait( + until.elementLocated(By.css('h2')), + 30000 + ); + + //Wait until it becomes visible + await driver.wait( + until.elementIsVisible(activityReportPageTitle), + 30000 + ); + } + }, + + //Activity Reports page title + { + description: 'Activity Reports page title text, size, color, and background color', + action: async () => { + const multipleChecks = 'Activity Reports page title'; + + const element = await driver.findElement(By.css('h2')); + + //Get text, font, size, color, and background color + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //element text + if (elementText === 'Activity Reports') { + console.log('Passed: Activity Reports page title text matched as expected'); + } else { + errors.push(`Expected: "Activity Reports"; Actual: "${elementText}"`); + } + + //element font + if (elementFont === `"DM Serif Display", serif`) { + console.log('Passed: Activity Reports page title font-family matched as expected'); + } else { + errors.push(`Expected: Activity Reports page title font-family "DM Serif Display, serif"; Actual: ${elementFont}`); + } + + //element size + if (elementSize === '32px') { + console.log('Passed: Activity Reports page title text font-size matched as expected'); + } else { + errors.push(`Expected: Activity Reports page title text font-size "32px"; Actual: "${elementSize}"`); + } + + //element color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Activity Reports page title text color matched as expected'); + } else { + errors.push(`Expected: Activity Reports page title text color: "rgba(40, 39, 90, 1"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //Filter By widget title + { + description: 'Filter By widget title text, size, color, and background color', + action: async () => { + const multipleChecks = 'Filter By widget title'; + + const element = await driver.findElement(By.css('h3:nth-child(2)')); + + //Get text, font, size, color, and background color + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //element text + if (elementText === 'Filter(s) By') { + console.log('Passed: Filter(s) By widget title text matched as expected'); + } else { + errors.push(`Expected: "Filter(s) By"; Actual: "${elementText}"`); + } + + //element font + if (elementFont === 'Poppins, sans-serif') { + console.log('Passed: Filter(s) By widget title font-family matched as expected'); + } else { + errors.push(`Expected: Filter(s) By widget title font-family "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //element size + if (elementSize === '20px') { + console.log('Passed: Filter(s) By widget title text font-size matched as expected'); + } else { + errors.push(`Expected: Filter(s) By widget title text font-size "20px"; Actual: "${elementSize}"`); + } + + //element color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Filter(s) By widget title text color matched as expected'); + } else { + errors.push(`Expected: Filter(s) By widget title text color: "rgba(40, 39, 90, 1"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //Start label and textbox + { + description: 'Start label text, size, color, and background color', + action: async () => { + const multipleChecks = 'Start label and textbox'; + + const element = await driver.findElement(By.css('tr:nth-child(1) > td:nth-child(1) > label')); + + //Get text, font, size, color, and background color + const elementClass = await driver.findElement(By.css('#startdate')).getAttribute('class'); + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //textbox class + if (elementClass === 'form-control d-inline hasDatepicker') { + console.log('Passed: Start textbox class: Date picker matched as expected'); + } else { + errors.push(`Expected: Start textbox class to be: "form-control d-inline hasDatepicker"; Actual: ${elementClass}`); + } + + //element text + if (elementText === 'Start') { + console.log('Passed: Start label title text matched as expected'); + } else { + errors.push(`Expected: "Start"; Actual: "${elementText}"`); + } + + //element font + if (elementFont === 'Poppins, sans-serif') { + console.log('Passed: Start label title font-family matched as expected'); + } else { + errors.push(`Expected: Start label title font-family "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //element size + if (elementSize === '12px') { + console.log('Passed: Start label title text font-size matched as expected'); + } else { + errors.push(`Expected: Start label title text font-size "132px"; Actual: "${elementSize}"`); + } + + //element color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Start label title text color matched as expected'); + } else { + errors.push(`Expected: Start label title text color: "rgba(40, 39, 90, 1"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //End label + { + description: 'End label text, size, color, and background color', + action: async () => { + const multipleChecks = 'End label'; + + const element = await driver.findElement(By.css('tr:nth-child(1) > td:nth-child(2) > label')); + + //Get text, font, size, color, and background color + const elementClass = await driver.findElement(By.css('#enddate')).getAttribute('class'); + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //textbox class + if (elementClass === 'form-control d-inline hasDatepicker') { + console.log('Passed: End textbox class: Date picker matched as expected'); + } else { + errors.push(`Expected: End textbox class to be: "form-control d-inline hasDatepicker"; Actual: ${elementClass}`); + } + + //element text + if (elementText === 'End') { + console.log('Passed: End label title text matched as expected'); + } else { + errors.push(`Expected: "End"; Actual: "${elementText}"`); + } + + //element font + if (elementFont === 'Poppins, sans-serif') { + console.log('Passed: End label title font-family matched as expected'); + } else { + errors.push(`Expected: End label title font-family "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //element size + if (elementSize === '12px') { + console.log('Passed: End label title text font-size matched as expected'); + } else { + errors.push(`Expected: End label title text font-size "12px"; Actual: "${elementSize}"`); + } + + //element color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: End label title text color matched as expected'); + } else { + errors.push(`Expected: End label title text color: "rgba(40, 39, 90, 1"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //Activity Type label + { + description: 'Activity Type label text, size, color, and background color', + action: async () => { + const multipleChecks = 'Activity Type label'; + + const element = await driver.findElement(By.css('tr:nth-child(2) > td:nth-child(1) > label')); + + //Get text, font, size, color, and background color + const elementText = await element.getText(); + const elementFont = await element.getCssValue('font-family'); + const elementSize = await element.getCssValue('font-size'); + const elementColor = await element.getCssValue('color'); + + //Track all errors + const errors = []; + + //element text + if (elementText === 'Activity Type:') { + console.log('Passed: Activity Type: label title text matched as expected'); + } else { + errors.push(`Expected: "Activity Type:"; Actual: "${elementText}"`); + } + + //element font + if (elementFont === 'Poppins, sans-serif') { + console.log('Passed: Activity Type: label title font-family matched as expected'); + } else { + errors.push(`Expected: Activity Type: label title font-family "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //element size + if (elementSize === '12px') { + console.log('Passed: Activity Type: label title text font-size matched as expected'); + } else { + errors.push(`Expected: Activity Type: label title text font-size "12px"; Actual: "${elementSize}"`); + } + + //element color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Activity Type: label title text color matched as expected'); + } else { + errors.push(`Expected: Activity Type: label title text color: "rgba(40, 39, 90, 1"; Actual: "${elementColor}"`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + //Add summary line only when multiple checks failed + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + + //Throw collected messages — catch() will prefix with "FAILED:" + throw new Error(errors.join('\n')); + } + } + }, + + //Activity Type dropdown values + { + description: 'Activity Type dropdown values', + action: async () => { + const multipleChecks = 'Activity Type dropdown values'; + + const dropdown = await driver.wait(until.elementLocated(By.css('tr:nth-child(2) > td:nth-child(1) > .form-control')), 5000); + + //Wrap with Select class for full dropdown functionality + const selectElement = new Select(dropdown); + + //Verify default selected value + const defaultOption = await selectElement.getFirstSelectedOption(); + const defaultText = await defaultOption.getText(); + const elementFont = await defaultOption.getCssValue('font-family'); + const elementSize = await defaultOption.getCssValue('font-size'); + const elementColor = await defaultOption.getCssValue('color'); + + //Track all errors + const errors = []; + + if (defaultText === 'Alignment Activity') { + console.log('Passed: Activity Type dropdown default value matched as expected'); + } else { + errors.push(`Expected: Activity Type dropdown default value "Alignment Activity"; Actual: "${defaultText}"`); + } + + //font + if (elementFont === 'Poppins, sans-serif') { + console.log('Passed: Activity Type label dropdown default font-family matched as expected'); + } else { + errors.push(`Expected: Activity Type label dropdown default font-family "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //size + if (elementSize === '13px') { + console.log('Passed: Activity Type label dropdown default text font-size matched as expected'); + } else { + errors.push(`Expected: Activity Type label dropdown default text font-size "13px"; Actual: "${elementSize}"`); + } + + //color + if (elementColor === 'rgba(40, 39, 90, 1)') { + console.log('Passed: Activity Type label dropdown default text color matched as expected'); + } else { + errors.push(`Expected: Activity Type label dropdown default text color: "rgba(40, 39, 90, 1)"; Actual: "${elementColor}"`); + } + + //Verify all dropdown options + const options = await selectElement.getOptions(); + const expected = [ + 'Alignment Activity', + 'Framework Activity' + ]; + + const actual = []; + for (const opt of options) { + const text = (await opt.getText()).trim(); + actual.push(text); + } + + if (JSON.stringify(actual) === JSON.stringify(expected)) { + console.log('Passed: Activity Type dropdown list matched as expected'); + } else { + errors.push(`Expected: Activity Type dropdown list: ${JSON.stringify(expected)}; Actual: ${JSON.stringify(actual)}`); + } + + //Throw summary if any validation failed + if (errors.length > 0) { + if (errors.length > 1) { + errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`); + } + throw new Error(errors.join('\n')); + } + } + }, + + //By user radio icon, label and dropdown values + { + description: 'By user radio icon, label text, size, and color', + action: async () => { + const multipleChecks = 'By user radio icon, label and dropdown values'; + + const elementRadioButton = await driver.findElement(By.css('tr:nth-child(2) > td:nth-child(2) > input')); + const elementRadioButtonValue = await elementRadioButton.getAttribute('checked'); + //Select2 hides the real with Select class to read its options + const selectElement = new Select(dropdown); + + //Verify default selected value - read from the visible Select2 box + const defaultText = (await dropdownDisplay.getText()).trim(); + const elementFont = await dropdownDisplay.getCssValue('font-family'); + const elementSize = await dropdownDisplay.getCssValue('font-size'); + const elementColor = await dropdownDisplay.getCssValue('color'); + + //Track all errors + const errors = []; + + //radio button + if (await elementRadioButton.isDisplayed()) { + console.log('Passed: By user radio button icon was displayed as expected'); + } else { + errors.push('Expected: By user radio button icon was not displayed'); + } + + //radio button checked + if (elementRadioButtonValue === null) { + console.log('Passed: By user radio button was not checked as expected'); + } else { + errors.push('Expected: By user radio button was checked'); + } + + //text + if (defaultText === 'Select one user') { + console.log('Passed: By user dropdown default value matched as expected'); + } else { + errors.push(`Expected: By user dropdown default value "Select one user"; Actual: "${defaultText}"`); + } + + //font-family + if (elementFont === "Poppins, sans-serif") { + console.log('Passed: By user button font matched as expected'); + } else { + errors.push(`Expected: By user radio button font "Poppins, sans-serif"; Actual: ${elementFont}`); + } + + //font size + if (elementSize === '12px') { + console.log('Passed: By user radio button text font-size matched as expected'); + } else { + errors.push(`Expected: By user radio button text font-size "12px"; Actual: "${elementSize}"`); + } + + //color + if (elementColor === 'rgba(68, 68, 68, 1)') { + console.log('Passed: By user radio button text color matched as expected'); + } else { + errors.push(`Expected: By user radio button text color: "rgba(68, 68, 68, 1)"; Actual: "${elementColor}"`); + } + + //Verify all dropdown options + const options = await selectElement.getOptions(); + const expected = [ + 'Select one user', + 'exact_juan', + 'exact_daniel', + 'exact_admin', + 'exactbasic', + 'exact_ctuser', + 'exactkidemo', + 'ifehri', + 'jhuerta', + 'exactss', + 'sschullerexact', + 'testreport' + ]; + + const actual = []; + for (const opt of options) { + //Options of a hidden