Files
EdGateAutomatedRegression/tests/Align/alignContentPage.js
2026-10-23 18:17:42 -07:00

1492 lines
57 KiB
JavaScript

import { Builder, By, Key, until, Select, Browser } from 'selenium-webdriver';
import { Options as ChromeOptions } from 'selenium-webdriver/chrome.js';
import fs, { link } from 'fs';
import XLSX from 'xlsx';
import path from 'path';
const alignContentPage = (req, res) => {
res.send('<h2>ExACT Automated Test Script: Align - Content Page(alignContentPage); Initiated</h2>');
(async function example() {
let driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(
new ChromeOptions()
.addArguments('--disable-features=MediaRouter')
.addArguments('--disable-extensions')
.addArguments('--disable-background-networking')
.addArguments('--log-level=3')
)
.build();
let testStatus = 'Failed';
let workbook;
let worksheet;
const startTime = new Date().toISOString();
const steps = [
{ description: 'Navigate to ExACT Landing Page', action: async () => await driver.navigate().to('https://correlation.edgate.com/exact/login.php') },
{ description: 'Expand browser', action: async () => await driver.manage().window().maximize() },
//Login
{
description: 'Login',
action: async () => {
const multipleChecks = 'Log In';
console.log('------------->| ALIGN - CONTENT 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 Align navigation link',
action: async () => {
await driver.findElement(By.linkText('Align')).click();
console.log('----->| NEXT ACTION: Clicked Align navigation link');
//Wait for page readyState
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 30000, 'Align page did not fully load within 30 seconds');
//Wait until the element exists in the DOM
const contentTab = await driver.wait(
until.elementLocated(By.css('#content-tab')),
30000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(contentTab),
30000
);
}
},
//Content tab
{
description: 'Content tab title text, size, color, and background color',
action: async () => {
const multipleChecks = 'Content tab title';
const element = await driver.findElement(By.linkText('Content'));
//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');
const elementBgColor = await element.getCssValue('background-color');
//Tool-tip lives on the parent <li>; Bootstrap moves "title" into "data-original-title" and blanks "title"
const tooltipHost = await element.findElement(By.xpath('./parent::li'));
const elementTitle = (await tooltipHost.getAttribute('data-original-title')) || (await tooltipHost.getAttribute('title'));
const elementTitleFont = await element.getCssValue('font-family');
const elementTitleSize = await element.getCssValue('font-size');
const elementTitleColor = await element.getCssValue('color');
const elementTitleBgColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//element text
if (elementText === 'Content') {
console.log('Passed: Content tab title text matched as expected');
} else {
errors.push(`Expected: "Content"; Actual: "${elementText}"`);
}
//element font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Content tab title font-family matched as expected');
} else {
errors.push(`Expected: Content tab title font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//element size
if (elementSize === '15px') {
console.log('Passed: Content tab title text font-size matched as expected');
} else {
errors.push(`Expected: Content tab title text font-size "15px"; Actual: "${elementSize}"`);
}
//element color
if (elementColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Content tab title text color matched as expected');
} else {
errors.push(`Expected: Content tab title text color: "rgba(255, 255, 255, 1)"; Actual: "${elementColor}"`);
}
//element background color
if (elementBgColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content tab title background color matched as expected');
} else {
errors.push(`Expected: Content tab title background color: "rgba(40, 39, 90, 1)"; Actual: "${elementBgColor}"`);
}
//element tool-tip text
if (elementTitle === 'Browse content and align by tagging concepts') {
console.log('Passed: Content tab tool-tip text matched as expected');
} else {
errors.push(`Expected: Content tab tool-tip "Browse content and align by tagging concepts"; Actual: "${elementTitle}"`);
}
//element tool-tip font
if (elementTitleFont === 'Poppins, sans-serif') {
console.log('Passed: Content tab tool-tip font-family matched as expected');
} else {
errors.push(`Expected: Content tab tool-tip font-family "Poppins, sans-serif"; Actual: ${elementTitleFont}`);
}
//element tool-tip size
if (elementTitleSize === '15px') {
console.log('Passed: Content tab tool-tip text font-size matched as expected');
} else {
errors.push(`Expected: Content tab tool-tip text font-size "15px"; Actual: "${elementTitleSize}"`);
}
//element tool-tip color
if (elementTitleColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Content tab tool-tip text color matched as expected');
} else {
errors.push(`Expected: Content tab tool-tip text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTitleColor}"`);
}
//element tool-tip background color
if (elementTitleBgColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content tab tool-tip background color matched as expected');
} else {
errors.push(`Expected: Content tab tool-tip background color: "rgba(40, 39, 90, 1)"; Actual: "${elementTitleBgColor}"`);
}
//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'));
}
}
},
//Standards tab
{
description: 'Standards tab title text, size, color, and background color',
action: async () => {
const multipleChecks = 'Standards tab title';
const element = await driver.findElement(By.linkText('Standards'));
//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');
const elementBgColor = await element.getCssValue('background-color');
//Tool-tip lives on the parent <li>; Bootstrap moves "title" into "data-original-title" and blanks "title"
const tooltipHost = await element.findElement(By.xpath('./parent::li'));
const elementTitle = (await tooltipHost.getAttribute('data-original-title')) || (await tooltipHost.getAttribute('title'));
const elementTitleFont = await element.getCssValue('font-family');
const elementTitleSize = await element.getCssValue('font-size');
const elementTitleColor = await element.getCssValue('color');
const elementTitleBgColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//element text
if (elementText === 'Standards') {
console.log('Passed: Standards tab title text matched as expected');
} else {
errors.push(`Expected: "Standards"; Actual: "${elementText}"`);
}
//element font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Standards tab title font-family matched as expected');
} else {
errors.push(`Expected: Standards tab title font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//element size
if (elementSize === '15px') {
console.log('Passed: Standards tab title text font-size matched as expected');
} else {
errors.push(`Expected: Standards tab title text font-size "15px"; Actual: "${elementSize}"`);
}
//element color
if (elementColor === 'rgba(182, 186, 181, 1)') {
console.log('Passed: Standards tab title text color matched as expected');
} else {
errors.push(`Expected: Standards tab title text color: "rgba(182, 186, 181, 1)"; Actual: "${elementColor}"`);
}
//element background color
if (elementBgColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Standards tab title background color matched as expected');
} else {
errors.push(`Expected: Standards tab title background color: "rgba(0, 0, 0, 0)"; Actual: "${elementBgColor}"`);
}
//element tool-tip text
if (elementTitle === 'Browse standards and align content using specific standards') {
console.log('Passed: Standards tab tool-tip text matched as expected');
} else {
errors.push(`Expected: Standards tab tool-tip "Browse standards and align content using specific standards"; Actual: "${elementTitle}"`);
}
//element tool-tip font
if (elementTitleFont === 'Poppins, sans-serif') {
console.log('Passed: Standards tab tool-tip font-family matched as expected');
} else {
errors.push(`Expected: Standards tab tool-tip font-family "Poppins, sans-serif"; Actual: ${elementTitleFont}`);
}
//element tool-tip size
if (elementTitleSize === '15px') {
console.log('Passed: Standards tab tool-tip text font-size matched as expected');
} else {
errors.push(`Expected: Standards tab tool-tip text font-size "15px"; Actual: "${elementTitleSize}"`);
}
//element tool-tip color
if (elementTitleColor === 'rgba(182, 186, 181, 1)') {
console.log('Passed: Standards tab tool-tip text color matched as expected');
} else {
errors.push(`Expected: Standards tab tool-tip text color: "rgba(182, 186, 181, 1)"; Actual: "${elementTitleColor}"`);
}
//element tool-tip background color
if (elementTitleBgColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Standards tab tool-tip background color matched as expected');
} else {
errors.push(`Expected: Standards tab tool-tip background color: "rgba(0, 0, 0, 0)"; Actual: "${elementTitleBgColor}"`);
}
//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'));
}
}
},
//AutoAlign tab
{
description: 'AutoAlign tab title text, size, color, and background color',
action: async () => {
const multipleChecks = 'AutoAlign tab title';
const element = await driver.findElement(By.linkText('AutoAlign'));
//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');
const elementBgColor = await element.getCssValue('background-color');
//Tool-tip lives on the parent <li>; Bootstrap moves "title" into "data-original-title" and blanks "title"
const tooltipHost = await element.findElement(By.xpath('./parent::li'));
const elementTitle = (await tooltipHost.getAttribute('data-original-title')) || (await tooltipHost.getAttribute('title'));
const elementTitleFont = await element.getCssValue('font-family');
const elementTitleSize = await element.getCssValue('font-size');
const elementTitleColor = await element.getCssValue('color');
const elementTitleBgColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//element text
if (elementText === 'AutoAlign') {
console.log('Passed: AutoAlign tab title text matched as expected');
} else {
errors.push(`Expected: "AutoAlign"; Actual: "${elementText}"`);
}
//element font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: AutoAlign tab title font-family matched as expected');
} else {
errors.push(`Expected: AutoAlign tab title font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//element size
if (elementSize === '15px') {
console.log('Passed: AutoAlign tab title text font-size matched as expected');
} else {
errors.push(`Expected: AutoAlign tab title text font-size "15px"; Actual: "${elementSize}"`);
}
//element color
if (elementColor === 'rgba(182, 186, 181, 1)') {
console.log('Passed: AutoAlign tab title text color matched as expected');
} else {
errors.push(`Expected: AutoAlign tab title text color: "rgba(182, 186, 181, 1)"; Actual: "${elementColor}"`);
}
//element background color
if (elementBgColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: AutoAlign tab title background color matched as expected');
} else {
errors.push(`Expected: AutoAlign tab title background color: "rgba(0, 0, 0, 0)"; Actual: "${elementBgColor}"`);
}
//element tool-tip text
if (elementTitle === 'AutoAlign a Content Set') {
console.log('Passed: AutoAlign tab tool-tip text matched as expected');
} else {
errors.push(`Expected: AutoAlign tab tool-tip "AutoAlign a Content Set"; Actual: "${elementTitle}"`);
}
//element tool-tip font
if (elementTitleFont === 'Poppins, sans-serif') {
console.log('Passed: AutoAlign tab tool-tip font-family matched as expected');
} else {
errors.push(`Expected: AutoAlign tab tool-tip font-family "Poppins, sans-serif"; Actual: ${elementTitleFont}`);
}
//element tool-tip size
if (elementTitleSize === '15px') {
console.log('Passed: AutoAlign tab tool-tip text font-size matched as expected');
} else {
errors.push(`Expected: AutoAlign tab tool-tip text font-size "15px"; Actual: "${elementTitleSize}"`);
}
//element tool-tip color
if (elementTitleColor === 'rgba(182, 186, 181, 1)') {
console.log('Passed: AutoAlign tab tool-tip text color matched as expected');
} else {
errors.push(`Expected: AutoAlign tab tool-tip text color: "rgba(182, 186, 181, 1)"; Actual: "${elementTitleColor}"`);
}
//element tool-tip background color
if (elementTitleBgColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: AutoAlign tab tool-tip background color matched as expected');
} else {
errors.push(`Expected: AutoAlign tab tool-tip background color: "rgba(0, 0, 0, 0)"; Actual: "${elementTitleBgColor}"`);
}
//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'));
}
}
},
//Available Content header
{
description: 'Available Content text, size, and color',
action: async () => {
const multipleChecks = 'Available Content header';
const element = await driver.findElement(By.css('#content .fom-title'));
//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 === 'Available Content') {
console.log('Passed: Available Content header text matched as expected');
} else {
errors.push(`Expected: "Available Content"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Available Content header font-family matched as expected');
} else {
errors.push(`Expected: Available Content header font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '13px') {
console.log('Passed: Available Content header text font-size matched as expected');
} else {
errors.push(`Expected: Available Content header text font-size "13px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Available Content header text color matched as expected');
} else {
errors.push(`Expected: Available Content header 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'));
}
}
},
//Available Content List
{
description: 'Available Content - List',
action: async () => {
const multipleChecks = 'Available Content - List';
const errors = [];
const rows = await driver.executeScript(`
const results = [];
//List sits in the <div> right after the "Available Content" <p class="fom-title">
const items = document.querySelectorAll('#content .fom-title + div .list-group-item > a');
items.forEach((link, index) => {
const name = link.textContent.trim();
results.push({ position: index + 1, name });
});
return results;
`);
const expected = [
{ position: 1, name: 'US History III' },
{ position: 2, name: 'English I' },
{ position: 3, name: 'Algebra' },
{ position: 4, name: 'Biology' },
{ position: 5, name: 'Copy Move Delete Test 1' },
{ position: 6, name: 'Copy Move Delete Test 2' },
{ position: 7, name: 'Import Align - Concept Based 1' },
{ position: 8, name: 'Import Align - Concept Based 2' },
{ position: 9, name: 'Import Align - Direct Align 1' },
{ position: 10, name: 'Import Align - Direct Align 2' },
{ position: 11, name: 'Math Alignment Import Test' },
{ position: 12, name: 'create me' },
{ position: 13, name: 'Illustrative Math Test 1' },
{ position: 14, name: 'Illustrative Math Test 2' },
{ position: 15, name: 'Khan URL test' },
{ position: 16, name: 'seesaw test' },
{ position: 17, name: 'ECS-3037 On Prod TC2' },
{ position: 18, name: 'ECS-3037 On Prod TC1' },
{ position: 19, name: 'webinar test' },
{ position: 20, name: 'Review Screen Open' },
{ position: 21, name: 'New One For Agust Post Night' },
{ position: 22, name: 'Post NIght July26' },
{ position: 23, name: 'create import test' }
];
//Entire list - item count must match
if (rows.length === expected.length) {
console.log(`Passed: Available Content list count (${rows.length}) matched as expected`);
} else {
errors.push(`Available Content list count - Expected: ${expected.length}; Actual: ${rows.length}`);
}
for (const exp of expected) {
const actual = rows[exp.position - 1];
if (!actual) {
errors.push(`Available Content ${exp.position}: row not found`);
continue;
}
if (actual.name === exp.name) {
console.log(`Passed: Available Content ${exp.position} - ${exp.name} matched as expected`);
} else {
errors.push(`Available Content ${exp.position} name - Expected: "${exp.name}"; Actual: "${actual.name}"`);
}
}
//Unexpected extra items on the page
rows.slice(expected.length).forEach(r => {
errors.push(`Available Content ${r.position}: unexpected item "${r.name}"`);
});
//On any mismatch, print the actual list in "expected" format so it can be pasted above
if (errors.length > 0) {
console.log('Actual Available Content list:\n' + rows.map(r =>
` { position: ${r.position}, name: '${r.name.replace(/'/g, "\\'")}' },`
).join('\n'));
}
//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'));
}
}
},
//ADVANCED OPTIONS
//Scroll to bottom of page
{
description: 'Scroll to bottom of page',
action: async () => {
await driver.executeScript('window.scrollTo(0, document.body.scrollHeight);');
await driver.sleep(2000);
}
},
//Advanced Options link
{
description: 'Advanced Options link text, size, and color',
action: async () => {
const multipleChecks = 'Advanced Options link';
const element = await driver.findElement(By.css('#link-button-ads'));
//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 === 'Advanced Options') {
console.log('Passed: Advanced Options link text matched as expected');
} else {
errors.push(`Expected: "Advanced Options"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Advanced Options link font-family matched as expected');
} else {
errors.push(`Expected: Advanced Options link font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '13px') {
console.log('Passed: Advanced Options link text font-size matched as expected');
} else {
errors.push(`Expected: Advanced Options link text font-size "13px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Advanced Options link text color matched as expected');
} else {
errors.push(`Expected: Advanced Options link text color: "rgba(48, 200, 172, 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 Advanced Options link',
action: async () => {
await driver.findElement(By.css('#link-button-ads')).click();
console.log('----->| NEXT ACTION: Clicked Advanced Options link');
//Wait for page readyState
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 30000, 'Align page did not fully load within 30 seconds');
//Wait until the element exists in the DOM
const element = await driver.wait(
until.elementLocated(By.css('#searchbox-content > p')),
30000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(element),
30000
);
await driver.executeScript('window.scrollTo(0, document.body.scrollHeight);');
await driver.sleep(2000);
}
},
//Apply filters to results label
{
description: 'Apply filters to results label text, size, and color',
action: async () => {
const multipleChecks = 'Apply filters to results label';
const element = await driver.findElement(By.css('#searchbox-content > p'));
//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 === 'Apply filters to results:') {
console.log('Passed: Apply filters to results label text matched as expected');
} else {
errors.push(`Expected: "Apply filters to results:"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Apply filters to results label font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results label font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '13px') {
console.log('Passed: Apply filters to results label text font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results label text font-size "13px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Apply filters to results label text color matched as expected');
} else {
errors.push(`Expected: Apply filters to results label 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'));
}
}
},
//Apply filters to results- Grade label
{
description: 'Apply filters to results - Grade label text, size, and color',
action: async () => {
const multipleChecks = 'Apply filters to results - Grade label';
//"Grade:" is a bare text node inside the <li> (no wrapping tag); styles are inherited from the <li>
const element = await driver.findElement(By.css('#searchbox-content > ul > li:nth-child(1)'));
//Get label text (direct text nodes only, excludes the dropdown), font, size, and color
const elementText = await driver.executeScript(`
return Array.from(arguments[0].childNodes)
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n => n.textContent.trim())
.join('');
`, element);
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 === 'Grade:') {
console.log('Passed: Apply filters to results - Grade label text matched as expected');
} else {
errors.push(`Expected: "Grade:"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Apply filters to results - Grade label font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade label font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '14.3px') {
console.log('Passed: Apply filters to results - Grade label text font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade label text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Apply filters to results - Grade label text color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade label 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'));
}
}
},
//Apply filters to results- Grade dropdown value and list
{
description: 'Apply filters to results - Grade dropdown value and list',
action: async () => {
const multipleChecks = 'Grade dropdown list';
const element = await driver.findElement(By.css('.list-group-item:nth-child(1) .multiselect-selected-text'));
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');
//Dropdown items are <label> text in the multiselect menu (skip the search "filter" row).
//Read textContent via JS - the menu is hidden until opened, so getText() would return ""
const actual = await driver.executeScript(`
const items = document.querySelectorAll('#searchbox-content > ul > li:nth-child(1) .multiselect-container > li:not(.filter) label');
return Array.from(items).map(label => label.textContent.trim());
`);
//Track all errors
const errors = [];
//text
if (elementText === 'None selected') {
console.log('Passed: Apply filters to results - Grade dropdown text matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade dropdown: "None selected"; Actual: "${elementText}"`);
}
//font
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Apply filters to results - Grade dropdown font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade dropdown font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '16px') {
console.log('Passed: Apply filters to results - Grade dropdown font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade dropdown font-size "16px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Apply filters to results - Grade dropdown color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Grade dropdown color: "rgba(33, 37, 41, 1)"; Actual: "${elementColor}"`);
}
const expected = [
'Select all',
'9 (3948)',
'10 (3912)',
'11 (3716)',
'12 (3367)',
'Y10 (1834)',
'Y11 (1815)',
'KS4 (1808)',
'Y12 (1802)',
'Y13 (1799)',
'8 (1682)',
'7 (1463)',
'6 (1425)',
'Y9 (1162)',
'KS3 (1154)',
'Y8 (1135)',
'5 (1134)',
'Y7 (1110)',
'4 (1014)',
'KS2 (894)',
'Y6 (769)',
'3 (762)',
'Y5 (657)',
'2 (511)',
'1 (484)',
'K (429)',
'Y4 (414)',
'KS1 (330)',
'Y3 (257)',
'Y1 (249)',
'Y2 (248)',
'PreK (3)',
];
if (JSON.stringify(actual) === JSON.stringify(expected)) {
console.log('Passed: Apply filters to results - Grade dropdown list matched as expected');
} else {
//Print actual list in "expected" format so it can be pasted above
console.log('Actual Grade dropdown list:\n' + actual.map(t => ` '${t.replace(/'/g, "\\'")}',`).join('\n'));
errors.push(`Expected: Apply filters to results - Grade dropdown list: ${JSON.stringify(expected)}; Actual: ${JSON.stringify(actual)}`);
}
//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'));
}
}
},
//Apply filters to results- Subject label
{
description: 'Apply filters to results - Subject label text, size, and color',
action: async () => {
const multipleChecks = 'Apply filters to results - Subject label';
//"Grade:" is a bare text node inside the <li> (no wrapping tag); styles are inherited from the <li>
const element = await driver.findElement(By.css('#searchbox-content > ul > li:nth-child(2)'));
//Get label text (direct text nodes only, excludes the dropdown), font, size, and color
const elementText = await driver.executeScript(`
return Array.from(arguments[0].childNodes)
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n => n.textContent.trim())
.join('');
`, element);
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 === 'Subject:') {
console.log('Passed: Apply filters to results - Subject label text matched as expected');
} else {
errors.push(`Expected: "Subject:"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Apply filters to results - Subject label font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject label font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '14.3px') {
console.log('Passed: Apply filters to results - Subject label text font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject label text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Apply filters to results - Subject label text color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject label 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'));
}
}
},
//Apply filters to results- Subject dropdown value and list
{
description: 'Apply filters to results - Subject dropdown value and list',
action: async () => {
const multipleChecks = 'Subject dropdown list';
const element = await driver.findElement(By.css('.list-group-item:nth-child(2) .multiselect-selected-text'));
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');
//Dropdown items are <label> text in the multiselect menu (skip the search "filter" row).
//Read textContent via JS - the menu is hidden until opened, so getText() would return ""
const actual = await driver.executeScript(`
const items = document.querySelectorAll('#searchbox-content > ul > li:nth-child(2) .multiselect-container > li:not(.filter) label');
return Array.from(items).map(label => label.textContent.trim());
`);
//Track all errors
const errors = [];
//text
if (elementText === 'None selected') {
console.log('Passed: Apply filters to results - Subject dropdown text matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject dropdown: "None selected"; Actual: "${elementText}"`);
}
//font
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Apply filters to results - Subject dropdown font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject dropdown font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '16px') {
console.log('Passed: Apply filters to results - Subject dropdown font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject dropdown font-size "16px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Apply filters to results - Subject dropdown color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Subject dropdown color: "rgba(33, 37, 41, 1)"; Actual: "${elementColor}"`);
}
const expected = [
'Select all',
'Mathematics (2758)',
'Science (1675)',
'Social Studies (571)',
'Language Arts (565)',
'Technology Education (174)',
'Early Childhood Education (156)',
'English Language Learners (156)',
'Social and Emotional Learning (156)',
'Health and PE (25)',
'Library Media (1)',
];
if (JSON.stringify(actual) === JSON.stringify(expected)) {
console.log('Passed: Apply filters to results - Subject dropdown list matched as expected');
} else {
//Print actual list in "expected" format so it can be pasted above
console.log('Actual Subject dropdown list:\n' + actual.map(t => ` '${t.replace(/'/g, "\\'")}',`).join('\n'));
errors.push(`Expected: Apply filters to results - Subject dropdown list: ${JSON.stringify(expected)}; Actual: ${JSON.stringify(actual)}`);
}
//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'));
}
}
},
//Apply filters to results- Alignment Status label
{
description: 'Apply filters to results - Alignment Status label text, size, and color',
action: async () => {
const multipleChecks = 'Apply filters to results - Alignment Status label';
//"Grade:" is a bare text node inside the <li> (no wrapping tag); styles are inherited from the <li>
const element = await driver.findElement(By.css('#searchbox-content > ul > li:nth-child(3)'));
//Get label text (direct text nodes only, excludes the dropdown), font, size, and color
const elementText = await driver.executeScript(`
return Array.from(arguments[0].childNodes)
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n => n.textContent.trim())
.join('');
`, element);
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 === 'Alignment Status:') {
console.log('Passed: Apply filters to results - Alignment Status label text matched as expected');
} else {
errors.push(`Expected: "Alignment Status:"; Actual: "${elementText}"`);
}
//font
if (elementFont === 'Poppins, sans-serif') {
console.log('Passed: Apply filters to results - Alignment Status label font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status label font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '14.3px') {
console.log('Passed: Apply filters to results - Alignment Status label text font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status label text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Apply filters to results - Alignment Status label text color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status label 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'));
}
}
},
//Apply filters to results- Subject dropdown value and list
{
description: 'Apply filters to results - Subject dropdown value and list',
action: async () => {
const multipleChecks = 'Subject dropdown list';
const element = await driver.findElement(By.css('.list-group-item:nth-child(3) .multiselect-selected-text'));
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');
//Dropdown items are <label> text in the multiselect menu (skip the search "filter" row).
//Read textContent via JS - the menu is hidden until opened, so getText() would return ""
const actual = await driver.executeScript(`
const items = document.querySelectorAll('#searchbox-content > ul > li:nth-child(3) .multiselect-container > li:not(.filter) label');
return Array.from(items).map(label => label.textContent.trim());
`);
//Track all errors
const errors = [];
//text
if (elementText === 'None selected') {
console.log('Passed: Apply filters to results - Alignment Status dropdown text matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status dropdown: "None selected"; Actual: "${elementText}"`);
}
//font
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Apply filters to results - Alignment Status dropdown font-family matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status dropdown font-family "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//size
if (elementSize === '16px') {
console.log('Passed: Apply filters to results - Alignment Status dropdown font-size matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status dropdown font-size "16px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Apply filters to results - Alignment Status dropdown color matched as expected');
} else {
errors.push(`Expected: Apply filters to results - Alignment Status dropdown color: "rgba(33, 37, 41, 1)"; Actual: "${elementColor}"`);
}
const expected = [
'Select all',
'Not Aligned (2641)',
'ECS Alignment (2261)',
'Pending (115)',
'Aligned (27)',
'Needs Review (1)',
];
if (JSON.stringify(actual) === JSON.stringify(expected)) {
console.log('Passed: Apply filters to results - Alignment Status dropdown list matched as expected');
} else {
//Print actual list in "expected" format so it can be pasted above
console.log('Actual Alignment Status dropdown list:\n' + actual.map(t => ` '${t.replace(/'/g, "\\'")}',`).join('\n'));
errors.push(`Expected: Apply filters to results - Alignment Status dropdown list: ${JSON.stringify(expected)}; Actual: ${JSON.stringify(actual)}`);
}
//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'));
}
}
},
//FOOTER
//EdGate Copyright Logo
{
description: 'EdGate Copyright Logo',
action: async () => {
const multipleChecks = 'EdGate Copyright Logo';
const element = await driver.findElement(By.css('footer .pull-right > a'));
const elementLogo = await element.findElement(By.css('img'));
const expectedHref = 'https://www.edgate.com';
//Track all errors
const errors = [];
//icon present
if (await elementLogo.isDisplayed()) {
console.log('Passed: EdGate Copyright Logo was displayed as expected');
} else {
errors.push('Expected: EdGate Copyright Logo was not displayed');
}
//href - browser resolves the link with a trailing slash, so remove it before comparing
const actualHref = await element.getDomAttribute('href');
if (actualHref && actualHref === expectedHref) {
console.log('Passed: EdGate Copyright Logo href matched as expected');
} else {
errors.push(`Expected: EdGate Copyright Logo href to be "https://www.edgate.com"; actual: "${actualHref}"`);
}
//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: 'Log Out',
action: async () => {
const multipleChecks = 'Log Out';
//Track all errors
const errors = [];
await driver.findElement(By.css('#navbarDropdown > span')).click();
await driver.sleep(2000);
await driver.findElement(By.linkText('Log Out')).click();
console.log('----->| NEXT ACTION: Clicked User Profile and Logged Out');
//Wait until the element exists in the DOM
const exactLogo = await driver.wait(
until.elementLocated(By.css('.logo')),
30000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(exactLogo),
30000
);
//Wait for page to load completely
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 30000, 'ExACT Langing page did not fully load within 30 seconds');
console.log('Passed: ExACT Landing Page loaded successfully');
//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'));
}
}
},
];
const logStep = (worksheet, stepDescription, status, stepIndex, timestamp, screenshotPath) => {
const json_data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
json_data.push([stepIndex, stepDescription, status, timestamp, screenshotPath]);
return XLSX.utils.aoa_to_sheet(json_data);
};
const takeScreenshot = async (driver, stepIndex, stepDescription) => {
const screenshot = await driver.takeScreenshot();
const dir = path.join('screenshots', 'alignContentPage');
const screenshotFileName = `step_${stepIndex}_${stepDescription.replace(/\s+/g, '_')}.png`;
const screenshotPath = path.join(dir, screenshotFileName);
fs.writeFileSync(screenshotPath, screenshot, 'base64');
return screenshotPath;
};
const clearOldResults = () => {
//Remove old screenshots
const screenshotDir = path.join('screenshots', 'alignContentPage');
if (fs.existsSync(screenshotDir)) {
fs.rmSync(screenshotDir, { recursive: true, force: true });
}
fs.mkdirSync(screenshotDir, { recursive: true });
//Remove old Excel file
if (fs.existsSync('alignContentPageResults.xlsx')) {
fs.unlinkSync('alignContentPageResults.xlsx');
}
};
try {
//Initialize workbook and worksheet
clearOldResults();
//Initialize workbook and worksheet
workbook = XLSX.utils.book_new();
worksheet = XLSX.utils.aoa_to_sheet([
['Step Number', 'Step Description', 'Status', 'Timestamp', 'Screenshot']
]);
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
//Log test start time
worksheet = logStep(worksheet, 'Test Start', 'Started', '', startTime, '');
let allStepsPassed = true;
const failedSteps = []; //Track failed steps
for (const step of steps) {
const stepIndex = steps.indexOf(step) + 1;
const timestamp = new Date().toISOString();
try {
//Screenshot of failed step
await step.action();
//Log a successful step with no screenshot
worksheet = logStep(
worksheet,
step.description,
'Passed',
stepIndex,
timestamp,
null //No screenshot for passed steps
);
} catch (error) {
//Only take screenshot if the step fails
const screenshotPath = await takeScreenshot(
driver,
stepIndex,
`${step.description}_Failed`
);
worksheet = logStep(
worksheet,
step.description,
'Failed',
stepIndex,
timestamp,
screenshotPath
);
console.error(`Step ${stepIndex} FAILED: ${error.message}`);
failedSteps.push(`Step ${stepIndex}: ${step.description} - ${error.message}`); //Track failed step
testStatus = 'Failed';
allStepsPassed = false;
}
}
if (allStepsPassed) {
console.log('------------->| THE END |<-------------');
console.log('PASSED: Align - Content Page(alignContentPage); All test steps completed successfully');
testStatus = 'Passed';
} else {
console.log('------------->| THE END |<-------------');
console.log('FAILED: Align - Content Page(alignContentPage); One or more test steps failed');
console.log('FAILED STEPS:');
failedSteps.forEach(step => console.error(` ✗ ${step}`));
testStatus = 'Failed';
}
//Log test end time
const endTime = new Date().toISOString();
worksheet = logStep(worksheet, 'Test End', testStatus, '', endTime, '');
//Write the updated worksheet back to the workbook and save it
workbook.Sheets['Sheet1'] = worksheet;
XLSX.writeFile(workbook, 'alignContentPageResults.xlsx');
} finally {
await driver.quit();
}
})();
}
export default alignContentPage;