Files
EdGateAutomatedRegression/tests/CorrelationDashboard/Widgets/myContentWidget.js

6282 lines
234 KiB
JavaScript

import { Builder, By, until, Select } from 'selenium-webdriver';
import { Options as ChromeOptions } from 'selenium-webdriver/chrome.js';
import fs from 'fs';
import XLSX from 'xlsx';
import path from 'path';
const myContentWidget = (req, res) => {
res.send('<h2>ExACT Automated Test Script: DASHBOARD - My Content Widget(myContentWidget) | 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();
//CONSTANTS
const totalItems = '5045';
//My Content Total DIV
const uniqueTitleTotals = '3472';
const uniqueIdTotals = '3463';
//Biology
const biologyTotalItems = '1493';
const biologyUniqueTitles = '3472';
const biologyUniqueIds = '3463';
//New Content Set
const createContentSetName = 'Automated Algebra Content Set - TO BE DELETED';
//My Content sets - shared by the My Content Totals DIV table and the My Content widget list
//List in default (Count) sort order, which matches the Totals table order
// name = Content Set name
// totalItems = Total Items (Totals table) and count (widget list)
// uniqueTitles = Unique Titles (Totals table)
// uniqueIds = Unique IDs (Totals table)
// id = Content Set ID used in the link and edit icon URLs (null = not captured; URLs checked for format only)
const myContentSets = [
{ name: 'Biology', totalItems: '1493', uniqueTitles: '1482', uniqueIds: '1493', id: '585821587' },
{ name: 'Khan URL test', totalItems: '1118', uniqueTitles: '41', uniqueIds: '1', id: null },
{ name: 'Math Alignment Import Test', totalItems: '730', uniqueTitles: '707', uniqueIds: '728', id: '1423792414' },
{ name: 'English I', totalItems: '388', uniqueTitles: '388', uniqueIds: '388', id: '585821585' },
{ name: 'Copy Move Delete Test 2', totalItems: '327', uniqueTitles: '327', uniqueIds: '328', id: '1228574325' },
{ name: 'Post NIght July26', totalItems: '278', uniqueTitles: '32', uniqueIds: '0', id: null },
{ name: 'Algebra', totalItems: '194', uniqueTitles: '196', uniqueIds: '189', id: '585821586' },
{ name: 'seesaw test', totalItems: '156', uniqueTitles: '156', uniqueIds: '155', id: null },
{ name: 'US History III', totalItems: '68', uniqueTitles: '68', uniqueIds: '67', id: '585821589' },
{ name: 'Import Align - Concept Based 1', totalItems: '44', uniqueTitles: '43', uniqueIds: '44', id: '1323320445' },
{ name: 'Import Align - Concept Based 2', totalItems: '44', uniqueTitles: '43', uniqueIds: '44', id: '1323322624' },
{ name: 'Import Align - Direct Align 1', totalItems: '44', uniqueTitles: '43', uniqueIds: '44', id: '1323322921' },
{ name: 'Import Align - Direct Align 2', totalItems: '44', uniqueTitles: '43', uniqueIds: '44', id: '1323322923' },
{ name: 'Copy Move Delete Test 1', totalItems: '35', uniqueTitles: '23', uniqueIds: '33', id: '1228574323' },
{ name: 'ECS-3037 On Prod TC2', totalItems: '26', uniqueTitles: '26', uniqueIds: '26', id: null },
{ name: 'ECS-3037 On Prod TC1', totalItems: '24', uniqueTitles: '24', uniqueIds: '24', id: null },
{ name: 'create me', totalItems: '9', uniqueTitles: '9', uniqueIds: '9', id: '1427607301' },
{ name: 'Illustrative Math Test 1', totalItems: '5', uniqueTitles: '5', uniqueIds: '5', id: null },
{ name: 'Illustrative Math Test 2', totalItems: '5', uniqueTitles: '5', uniqueIds: '0', id: null },
{ name: 'webinar test', totalItems: '5', uniqueTitles: '5', uniqueIds: '5', id: null },
{ name: 'Review Screen Open', totalItems: '5', uniqueTitles: '5', uniqueIds: '0', id: null },
{ name: 'create import test', totalItems: '3', uniqueTitles: '3', uniqueIds: '3', id: null },
{ name: 'New One For Agust Post Night', totalItems: '0', uniqueTitles: '0', uniqueIds: '0', id: null },
];
//My Content sets sorted by Name (Sort: "Name"), including the newly created Content Set
//Sorting is case-insensitive to match the site (e.g. "create me" sorts between "Copy..." and "ECS...")
//New Content Set ID is generated on create, so id is null (edit URL checked for format only)
const myContentSetsByName = [
...myContentSets,
{ name: createContentSetName, totalItems: '0', uniqueTitles: '0', uniqueIds: '0', id: null },
].sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase(), 'en'));
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('------------->| MY CONTENT WIDGET |<-------------');
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 elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = 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-family
if (elementTextFont === `"DM Serif Display", serif`) {
console.log('Passed: Dashboard title font matched as expected');
} else {
errors.push(`Expected: Dashboard title font "DM Serif Display, serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '32px') {
console.log('Passed: Dashboard title text font-size matched as expected');
} else {
errors.push(`Expected: Dashboard title text font-size "32px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === '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: "${elementTextColor}"`);
}
//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'));
}
}
},
//MY CONTENT WIDGET
//Dashboard My Content Widget title
{
description: 'My Content widget title text, color, and size',
action: async () => {
const multipleChecks = 'My Content widget title';
const element = await driver.findElement(By.css('.h-100 h2:nth-child(2)'));
//Get text, font, size, and color
const elementText = await element.getText();
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'My Content') {
console.log('Passed: My Content widget title text matched as expected');
} else {
errors.push(`Expected: "My Content"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === 'Poppins, sans-serif') {
console.log('Passed: My Content widget title font matched as expected');
} else {
errors.push(`Expected: My Content widget title font "Poppins, sans-serif", serif; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: My Content widget title text font-size matched as expected');
} else {
errors.push(`Expected: My Content widget title text font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: My Content widget title text color matched as expected');
} else {
errors.push(`Expected: My Content widget title text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//My Content total item Count (SPECIAL CASE: with button)
{
description: 'My Content total item count',
action: async () => {
const multipleChecks = 'My Content total item count';
const element = await driver.findElement(By.css('#badge_content_total'));
//Get button text, text font, text size, text color, and button color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText.includes(totalItems)) {
console.log('Passed: Total item count button text matched as expected');
} else {
errors.push(`Expected: "${totalItems}"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Total item count button text font matched as expected');
} else {
errors.push(`Expected: Total item count button text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13.5px') {
console.log('Passed: Total item count button text font-size matched as expected');
} else {
errors.push(`Expected: Total item count button text font-size "13.5px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Total item count button text color matched as expected');
} else {
errors.push(`Expected: Total item count button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Total item count button background color matched as expected');
} else {
errors.push(`Expected: Total item count button background color: "rgba(40, 39, 90, 1)"; Actual: "${elementButtonColor}"`);
}
//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 My Content Items Count button',
action: async () => {
await driver.findElement(By.css('#content_total')).click();
console.log('----->| NEXT ACTION: Clicked Total items count button');
await driver.sleep(2000);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.content_modal_title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//MY CONTENT TOTALS DIV
//Dashboard My Content DIV
{
description: 'My Content Totals DIV title text, color, and size',
action: async () => {
const multipleChecks = 'My Content Totals DIV';
const element = await driver.findElement(By.css('.content_modal_title'));
//Get text, font, size, and color
const elementText = await element.getText();
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'My Content Totals') {
console.log('Passed: My Content Totals DIV title text matched as expected');
} else {
errors.push(`Expected: DIV title: "My Content Totals"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === 'Poppins, sans-serif') {
console.log('Passed: My Content Totals DIV title font matched as expected');
} else {
errors.push(`Expected: My Content Totals DIV title font "Poppins, sans-serif", serif; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: My Content Totals DIV title text font-size matched as expected');
} else {
errors.push(`Expected: My Content Totals DIVt title text font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: My Content Totals DIV title text color matched as expected');
} else {
errors.push(`Expected:My Content Totals DIV title text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Close icon
{
description: 'DIV X icon color',
action: async () => {
const elementStyle = await driver.findElement(By.css('.ready-content span')).getCssValue('color');
if (elementStyle === 'rgba(246, 60, 40, 1)') {
console.log('Passed: My Content Totals DIV X icon color matched as expected');
} else {
throw new Error(`Expected: My Content Totals DIV X icon color did not match; Actual: "${elementStyle}"`);
}
}
},
//My Content Totals DIV - Total Items
{
description: 'My Content Totals DIV - Total Items',
action: async () => {
const multipleChecks = 'My Content Total Item count';
const element = await driver.findElement(By.css('#total > p'));
const elementCount = await driver.findElement(By.css('#total > b'));
//Get button text, text font, text size, text color, and button color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
//Count text, text font, text size, text color
const elementTotalText = await elementCount.getText('');
const elementTotalTextFont = await elementCount.getCssValue('font-family');
const elementTotalTextSize = await elementCount.getCssValue('font-size');
const elementTotalTextColor = await elementCount.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Total Items') {
console.log('Passed: Total Items label matched as expected');
} else {
errors.push(`Expected: "Total Items"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins") {
console.log('Passed: Total Items text font matched as expected');
} else {
errors.push(`Expected: Totals Items text font "Poppins"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '14px') {
console.log('Passed: Total Items text font-size matched as expected');
} else {
errors.push(`Expected: Totals Items text font-size "14px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Total Items label text color matched as expected');
} else {
errors.push(`Expected: Totals Items text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(238, 238, 242, 1)') {
console.log('Passed: Total Items button background color matched as expected');
} else {
errors.push(`Expected: Total Items button background color: "rgba(238, 238, 242, 1)"; Actual: "${elementButtonColor}"`);
}
//Item count
//text
if (elementTotalText === totalItems) {
console.log('Passed: Total Items count label matched as expected');
} else {
errors.push(`Expected: Total Items: "${totalItems}"; Actual: "${elementTotalText}"`);
}
//font-family
if (elementTotalTextFont === "Poppins, sans-serif") {
console.log('Passed: Total Items count text font matched as expected');
} else {
errors.push(`Expected: Totals Items count text font "Poppins, sans-serif"; Actual: ${elementTotalTextFont}`);
}
//font size
if (elementTotalTextSize === '36px') {
console.log('Passed: Total Items text font-size matched as expected');
} else {
errors.push(`Expected: Totals Items count text font-size "36px"; Actual: "${elementTotalTextSize}"`);
}
//color
if (elementTotalTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Total Items label text color matched as expected');
} else {
errors.push(`Expected: Totals Items count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTotalTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Unique Titles
{
description: 'My Content Totals DIV - Unique Titles',
action: async () => {
const multipleChecks = 'My Content Unique Titles count';
const element = await driver.findElement(By.css('#total_titles > p'));
const elementCount = await driver.findElement(By.css('#total_titles > b'));
//Get button text, text font, text size, text color, and button color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
//Count text, text font, text size, text color
const elementTotalText = await elementCount.getText('');
const elementTotalTextFont = await elementCount.getCssValue('font-family');
const elementTotalTextSize = await elementCount.getCssValue('font-size');
const elementTotalTextColor = await elementCount.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Unique Titles') {
console.log('Passed: Unique Titles label matched as expected');
} else {
errors.push(`Expected: "Unique Titles"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins") {
console.log('Passed: Unique Titles label text font matched as expected');
} else {
errors.push(`Expected: Unique Titles text font "Poppins"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '14px') {
console.log('Passed: Unique Titles text font-size matched as expected');
} else {
errors.push(`Expected: Unique Titles text font-size "14px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique Titles label text color matched as expected');
} else {
errors.push(`Expected: Unique Titles text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(238, 238, 242, 1)') {
console.log('Passed: Unique Titles button background color matched as expected');
} else {
errors.push(`Expected: Unique Titles button background color: "rgba(238, 238, 242, 1)"; Actual: "${elementButtonColor}"`);
}
//Item count
//text
if (elementTotalText === uniqueTitleTotals) {
console.log('Passed: Unique Titles count label matched as expected');
} else {
errors.push(`Expected: Unique Titles: "${uniqueTitleTotals}"; Actual: "${elementTotalText}"`);
}
//font-family
if (elementTotalTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique Titles count label text font matched as expected');
} else {
errors.push(`Expected: Unique Titles count text font "Poppins, sans-serif"; Actual: ${elementTotalTextFont}`);
}
//font size
if (elementTotalTextSize === '36px') {
console.log('Passed: Unique Titles text font-size matched as expected');
} else {
errors.push(`Expected: Unique Titles count text font-size "36px"; Actual: "${elementTotalTextSize}"`);
}
//color
if (elementTotalTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique Titles label text color matched as expected');
} else {
errors.push(`Expected: Unique Titles count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTotalTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Unique IDs
{
description: 'My Content Totals DIV - Unique IDs',
action: async () => {
const multipleChecks = 'My Content Unique IDs count';
const element = await driver.findElement(By.css('#total_pubtotalids > p'));
const elementCount = await driver.findElement(By.css('#total_pubtotalids > b'));
//Get button text, text font, text size, text color, and button color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
//Count text, text font, text size, text color
const elementTotalText = await elementCount.getText('');
const elementTotalTextFont = await elementCount.getCssValue('font-family');
const elementTotalTextSize = await elementCount.getCssValue('font-size');
const elementTotalTextColor = await elementCount.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Unique IDs') {
console.log('Passed: Unique IDs label matched as expected');
} else {
errors.push(`Expected: "Unique IDs"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins") {
console.log('Passed: Unique IDs label text font matched as expected');
} else {
errors.push(`Expected: Unique IDs text font "Poppins"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '14px') {
console.log('Passed: Unique IDs text font-size matched as expected');
} else {
errors.push(`Expected: Unique IDs text font-size "14px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique IDs label text color matched as expected');
} else {
errors.push(`Expected: Unique IDs text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(238, 238, 242, 1)') {
console.log('Passed: Unique IDs button background color matched as expected');
} else {
errors.push(`Expected: Unique IDs button background color: "rgba(238, 238, 242, 1)"; Actual: "${elementButtonColor}"`);
}
//Item count
//text
if (elementTotalText === uniqueIdTotals) {
console.log('Passed: Unique IDs count label matched as expected');
} else {
errors.push(`Expected: Unique IDs: "${uniqueIdTotals}"; Actual: "${elementTotalText}"`);
}
//font-family
if (elementTotalTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique IDs count label text font matched as expected');
} else {
errors.push(`Expected: Unique IDs count text font "Poppins, sans-serif"; Actual: ${elementTotalTextFont}`);
}
//font size
if (elementTotalTextSize === '36px') {
console.log('Passed: Unique IDs text font-size matched as expected');
} else {
errors.push(`Expected: Unique IDs count text font-size "36px"; Actual: "${elementTotalTextSize}"`);
}
//color
if (elementTotalTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique IDs label text color matched as expected');
} else {
errors.push(`Expected: Unique IDs count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTotalTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Content Set column header
{
description: 'My Content Totals DIV - Content Set column header',
action: async () => {
const multipleChecks = 'Content Set column headers';
const element = await driver.findElement(By.css('.card-body > .table-sm th:nth-child(1)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content Set') {
console.log('Passed: Content Set column header matched as expected');
} else {
errors.push(`Expected: Column header: "Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set column header text font matched as expected');
} else {
errors.push(`Expected: Content Set column header text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '10px') {
console.log('Passed: Content Set column header text font-size matched as expected');
} else {
errors.push(`Expected: Content Set column header text font-size "10px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content Set column header text color matched as expected');
} else {
errors.push(`Expected: Content Set column header text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Total Items column header
{
description: 'My Content Totals DIV - Total Items column header',
action: async () => {
const multipleChecks = 'Total Items column headers';
const element = await driver.findElement(By.css('.card-body > .table-sm th:nth-child(2)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Total Items') {
console.log('Passed: Total Items column header matched as expected');
} else {
errors.push(`Expected: Column header: "Total Items"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Total Items column header text font matched as expected');
} else {
errors.push(`Expected: Total Items column header text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '10px') {
console.log('Passed: Total Items column header text font-size matched as expected');
} else {
errors.push(`Expected: Total Items column header text font-size "10px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Total Items column header text color matched as expected');
} else {
errors.push(`Expected: Total Items column header text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Unique Titles column header
{
description: 'My Content Totals DIV - Unique Titles column header',
action: async () => {
const multipleChecks = 'Unique Titles column headers';
const element = await driver.findElement(By.css('.card-body > .table-sm th:nth-child(3)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Unique Titles') {
console.log('Passed: Unique Titles column header matched as expected');
} else {
errors.push(`Expected: Column header: "Unique Titles"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique Titles column header text font matched as expected');
} else {
errors.push(`Expected: Unique Titles column header text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '10px') {
console.log('Passed: Unique Titles column header text font-size matched as expected');
} else {
errors.push(`Expected: Unique Titles column header text font-size "10px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique Titles column header text color matched as expected');
} else {
errors.push(`Expected: Unique Titles column header text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Unique IDs column header
{
description: 'My Content Totals DIV - Unique IDs column header',
action: async () => {
const multipleChecks = 'Unique IDs column headers';
const element = await driver.findElement(By.css('.card-body > .table-sm th:nth-child(4)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Unique IDs') {
console.log('Passed: Unique IDs column header matched as expected');
} else {
errors.push(`Expected: Column header: "Unique IDs"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique IDs column header text font matched as expected');
} else {
errors.push(`Expected: Unique IDs column header text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '10px') {
console.log('Passed: Unique IDs column header text font-size matched as expected');
} else {
errors.push(`Expected: Unique IDs column header text font-size "10px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique IDs column header text color matched as expected');
} else {
errors.push(`Expected: Unique IDs column header text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//My Content Totals DIV - Table data (Content Set, Total Items, Unique Titles, Unique IDs)
{
description: 'My Content Totals DIV - Table Content Set, Total Items, Unique Titles, and Unique IDs',
action: async () => {
const multipleChecks = 'My Content Totals table data';
//Expected rows in display order: [Content Set, Total Items, Unique Titles, Unique IDs] (from myContentSets constant)
const expectedRows = myContentSets.map(s => [s.name, s.totalItems, s.uniqueTitles, s.uniqueIds]);
const columns = ['Content Set', 'Total Items', 'Unique Titles', 'Unique IDs'];
//Expected cell styles per column [Content Set, Total Items, Unique Titles, Unique IDs]
const expectedStyles = [
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
];
//Wait for table rows to render
await driver.wait(until.elementLocated(By.css('#content_tbody > tr')), 20000, 'My Content Totals table rows did not load within 20 seconds');
//Read all cells in one call (textContent also works for rows scrolled out of view)
//Colors are normalized from rgb() to rgba() to match Selenium's getCssValue() format
const cellData = await driver.executeScript(`
const toRgba = c => c.startsWith('rgb(') ? c.replace('rgb(', 'rgba(').replace(')', ', 1)') : c;
return Array.from(document.querySelectorAll('#content_tbody > tr')).map(tr =>
Array.from(tr.querySelectorAll('td')).map(td => {
const cs = window.getComputedStyle(td);
return { text: td.textContent.trim(), font: cs.fontFamily, size: cs.fontSize, color: toRgba(cs.color) };
})
);
`);
const actualRows = cellData.map(row => row.map(cell => cell.text));
//Track all errors
const errors = [];
//Row count
if (actualRows.length === expectedRows.length) {
console.log(`Passed: My Content Totals table row count matched as expected, ${expectedRows.length}`);
} else {
errors.push(`Expected: ${expectedRows.length} table rows; Actual: ${actualRows.length}`);
}
//Cell-by-cell comparison
expectedRows.forEach((expected, rowIndex) => {
const actual = actualRows[rowIndex];
if (!actual) {
errors.push(`Row ${rowIndex + 1} ("${expected[0]}") missing from table`);
return;
}
const rowErrors = [];
columns.forEach((column, colIndex) => {
if (actual[colIndex] !== expected[colIndex]) {
rowErrors.push(`${column} Expected: "${expected[colIndex]}"; Actual: "${actual[colIndex]}"`);
}
//Style checks (font-family, font-size, color)
const cell = cellData[rowIndex][colIndex];
const style = expectedStyles[colIndex];
if (!cell) return;
if (cell.font !== style.font) {
rowErrors.push(`${column} font Expected: "${style.font}"; Actual: "${cell.font}"`);
}
if (cell.size !== style.size) {
rowErrors.push(`${column} font-size Expected: "${style.size}"; Actual: "${cell.size}"`);
}
if (cell.color !== style.color) {
rowErrors.push(`${column} color Expected: "${style.color}"; Actual: "${cell.color}"`);
}
});
if (rowErrors.length === 0) {
console.log(`Passed: Row ${rowIndex + 1} "${expected[0]}" - ${columns.map((c, i) => `${c}: ${expected[i]}`).join(', ')} | Text font, size, and color all matched as expected`);
} else {
errors.push(`Row ${rowIndex + 1} ("${expected[0]}"): ${rowErrors.join('; ')}`);
}
});
//Report any unexpected extra rows
actualRows.slice(expectedRows.length).forEach((extra, i) => {
errors.push(`Unexpected row ${expectedRows.length + i + 1}: ${JSON.stringify(extra)}`);
});
//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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('#all_content_modal .btn-secondary'));
//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 elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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'));
}
}
},
//Export button
{
description: 'Export button',
action: async () => {
const multipleChecks = 'Export button';
const element = await driver.findElement(By.css('#export_btn'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export') {
console.log('Passed: Export button text matched as expected');
} else {
errors.push(`Expected: "Export"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Export button text font matched as expected');
} else {
errors.push(`Expected: Export button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Export button text font-size matched as expected');
} else {
errors.push(`Expected: Export button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Export button text color matched as expected');
} else {
errors.push(`Expected: Export button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Export button background color matched as expected');
} else {
errors.push(`Expected: Export button background 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 My Content Items Count Close button',
action: async () => {
await driver.findElement(By.css('.ready-content .btn-secondary')).click();
console.log('----->| NEXT ACTION: Clicked DIV Close button');
await driver.sleep(2000);
}
},
//Ellipsis icon color
{
description: 'Ellipsis icon color',
action: async () => {
const elementStyle = await driver.findElement(By.css('.fa-ellipsis-h')).getCssValue('color');
if (elementStyle === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Ellipsis icon color matched as expected');
} else {
errors.push(`Expected: Ellipsis icon color did not match; Actual: "${elementStyle}"`);
}
}
},
//Search icon color
{
description: 'Search icon color',
action: async () => {
const elementStyle = await driver.findElement(By.css('.col-12 > .fa')).getCssValue('color');
if (elementStyle === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Ellipsis search icon color matched as expected');
} else {
errors.push(`Expected: Ellipsis search icon color did not match; Actual: "${elementStyle}"`);
}
}
},
//Filter textbox placeholder
{
description: 'Filter placeholder text',
action: async () => {
const multipleChecks = 'Filter textbox';
const element = await driver.findElement(By.css('#content-org-filter'));
//Get text, font, size, and color
const elementText = await element.getAttribute('placeholder');
//Get placeholder styles via executeScript since it's a pseudo-element
const elementFont = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('font-family')`,
element
);
const elementSize = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('font-size')`,
element
);
const elementColor = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('color')`,
element
);
//Track all errors
const errors = [];
//text
if (elementText === 'filter...') {
console.log('Passed: Filter placeholder text matched as expected');
} else {
errors.push(`Expected: "filter..." placeholder; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Filter placeholder text font matched as expected');
} else {
errors.push(`Expected: Filter placeholder text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '13.5px') {
console.log('Passed: Filter placeholder text font-size matched as expected');
} else {
errors.push(`Expected: Filter placeholder text font-size "13.5px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgb(108, 117, 125)') {
console.log('Passed: Filter placeholder text color matched as expected');
} else {
errors.push(`Expected: Filter placeholder text color: "rgb(108, 117, 125)"; 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'));
}
}
},
//Sort label
{
description: 'My Sort label',
action: async () => {
const multipleChecks = 'Sort label';
const element = await driver.findElement(By.css('.col-4'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Sort:') {
console.log('Passed: Sort: label text matched as expected');
} else {
errors.push(`Expected: "Sort:" label; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Sort: label text font matched as expected');
} else {
errors.push(`Expected: Sort: label text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '15px') {
console.log('Passed: Sort: label text font-size matched as expected');
} else {
errors.push(`Expected: Sort: label text font-size "15px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Sort: label text color matched as expected');
} else {
errors.push(`Expected: Sort: label text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Sort dropdown values (SPECIAL CASE: validate default selection)
{
description: 'Sort dropdown values',
action: async () => {
const multipleChecks = 'Sort dropdown values';
const dropdown = await driver.wait(until.elementLocated(By.css('#orgsort')), 5000);
//Wrap with Select class for full dropdown functionality
const selectElement = new Select(dropdown);
//Track all errors
const errors = [];
//Verify default selected value
const defaultOption = await selectElement.getFirstSelectedOption();
const defaultText = await defaultOption.getText();
if (defaultText === 'Count') {
console.log('Passed: Sort: dropdown default value matched as expected');
} else {
errors.push(`Expected: Sort dropdown default value "Count"; Actual: "${defaultText}"`);
}
//Verify all dropdown options
const options = await selectElement.getOptions();
const expected = [
'Count',
'Name'
];
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: Sort: dropdown list matched as expected');
} else {
errors.push(`Expected: Sort 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'));
}
}
},
//My Content - Biology
{
description: 'Biology link',
action: async () => {
const multipleChecks = 'My Content - Biology link';
const element = await driver.findElement(By.linkText('Biology'));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
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 = [];
//url
if (elementURL === 'https://correlation.edgate.com/exact/?iPublisherId=585821587&function=listUnits') {
console.log('Passed: Biology link URL matched as expected');
} else {
errors.push(`Expected: "https://correlation.edgate.com/exact/?iPublisherId=585821587&function=listUnits"; Actual: "${elementURL}"`);
}
//text
if (elementText === 'Biology') {
console.log('Passed: Biology link text matched as expected');
} else {
errors.push(`Expected: "Biology"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Biology link text font matched as expected');
} else {
errors.push(`Expected: Biology link text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '14.3px') {
console.log('Passed: Biology link text font-size matched as expected');
} else {
errors.push(`Expected: Biology link text text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Biology link text color matched as expected');
} else {
errors.push(`Expected: Biology link text color: "rgba(73, 80, 87, 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'));
}
}
},
//My Content - Edit Biology icon
{
description: 'Edit Biology icon',
action: async () => {
const multipleChecks = 'My Content - Edit Biology icon';
const element = await driver.findElement(By.css('#content-org-list > li > div.orgname > a.ml-2'));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
const elementText = await element.getAttribute('title');
const elementColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//url
if (elementURL === 'https://correlation.edgate.com/exact/contentset_edit_modal.php?id=585821587') {
console.log('Passed: Edit Biology icon link URL matched as expected');
} else {
errors.push(`Expected: "https://correlation.edgate.com/exact/contentset_edit_modal.php?id=585821587"; Actual: "${elementURL}"`);
}
//text
if (elementText === 'Edit Content Set') {
console.log('Passed: Edit Biology icon title matched as expected');
} else {
errors.push(`Expected: "Edit Content Set" ; Actual: "${elementText}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Edit Biology icon color matched as expected');
} else {
errors.push(`Expected: Edit Biology icon color: "rgba(73, 80, 87, 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'));
}
}
},
//My Content - List data (default sort: Count) - Content Set link, edit icon, and count
{
description: 'My Content list - Content Set name, link, edit icon, and count (default Count sort order)',
action: async () => {
const multipleChecks = 'My Content list data';
const baseURL = 'https://correlation.edgate.com/exact/';
//Expected items in display order: [Content Set, Count, Content Set ID] (from myContentSets constant)
//ID null = ID not yet captured; link and edit URLs are then checked for format and matching IDs only
const expectedItems = myContentSets.map(s => [s.name, s.totalItems, s.id]);
//Expected styles (null = not yet confirmed; actual value is logged instead of checked)
const nameStyle = { font: 'Poppins, sans-serif', size: '14.3px', color: 'rgba(73, 80, 87, 1)' };
const editIconStyle = { title: 'Edit Content Set', color: 'rgba(73, 80, 87, 1)' };
const countStyle = { font: 'Poppins, sans-serif', size: '12.87px', color: 'rgba(40, 39, 90, 1)' };
//Wait for list to render
await driver.wait(until.elementLocated(By.xpath('(//ul[@id="content-org-list"])[1]/li')), 20000, 'My Content list did not load within 20 seconds');
//Read all items in one call. Each item is the nth (nested) ul#content-org-list:
// li > div.orgname > a[1] = Content Set link, a[2] = edit icon; li > div > span = count
//Colors are normalized from rgb() to rgba() to match Selenium's getCssValue() format
const items = await driver.executeScript(`
const toRgba = c => c && c.startsWith('rgb(') ? c.replace('rgb(', 'rgba(').replace(')', ', 1)') : c;
const styleOf = el => {
if (!el) return null;
const cs = window.getComputedStyle(el);
return { font: cs.fontFamily, size: cs.fontSize, color: toRgba(cs.color) };
};
return Array.from(document.querySelectorAll('ul#content-org-list')).map(ul => {
const li = ul.querySelector(':scope > li');
if (!li) return null;
const links = li.querySelectorAll(':scope > div.orgname > a');
const nameLink = links[0] || null;
const editIcon = links[1] || null;
const count = li.querySelector(':scope > div > span');
return {
name: nameLink ? nameLink.textContent.trim() : null,
nameHref: nameLink ? nameLink.href : null,
nameStyle: styleOf(nameLink),
editHref: editIcon ? editIcon.href : null,
editTitle: editIcon ? editIcon.getAttribute('title') : null,
editColor: editIcon ? toRgba(window.getComputedStyle(editIcon).color) : null,
count: count ? count.textContent.trim() : null,
countStyle: styleOf(count),
};
}).filter(Boolean);
`);
//Track all errors
const errors = [];
//Item count
if (items.length === expectedItems.length) {
console.log(`Passed: My Content list item count matched as expected, ${expectedItems.length}`);
} else {
errors.push(`Expected: ${expectedItems.length} list items; Actual: ${items.length}`);
}
//Compare a style object against expected values (null expected = log only)
const checkStyle = (label, actual, expected, itemErrors) => {
if (!actual) {
itemErrors.push(`${label} element not found`);
return;
}
[['font', 'font'], ['size', 'font-size'], ['color', 'color']].forEach(([key, cssName]) => {
if (expected[key] === null) return;
if (actual[key] !== expected[key]) {
itemErrors.push(`${label} ${cssName} Expected: "${expected[key]}"; Actual: "${actual[key]}"`);
}
});
};
//Item-by-item comparison
expectedItems.forEach(([expName, expCount, expId], index) => {
const item = items[index];
const position = index + 1;
if (!item) {
errors.push(`Position ${position} ("${expName}") missing from list`);
return;
}
const itemErrors = [];
//Content Set name (also validates sort order)
if (item.name !== expName) {
itemErrors.push(`Content Set Expected: "${expName}"; Actual: "${item.name}"`);
}
//Count
if (item.count !== expCount) {
itemErrors.push(`Count Expected: "${expCount}"; Actual: "${item.count}"`);
}
//Content Set link and edit icon URLs
const nameId = (item.nameHref || '').match(/[?&]iPublisherId=(\d+)&function=listUnits$/);
const editId = (item.editHref || '').match(/contentset_edit_modal\.php\?id=(\d+)$/);
if (expId) {
const expNameURL = `${baseURL}?iPublisherId=${expId}&function=listUnits`;
const expEditURL = `${baseURL}contentset_edit_modal.php?id=${expId}`;
if (item.nameHref !== expNameURL) {
itemErrors.push(`Content Set link Expected: "${expNameURL}"; Actual: "${item.nameHref}"`);
}
if (item.editHref !== expEditURL) {
itemErrors.push(`Edit icon link Expected: "${expEditURL}"; Actual: "${item.editHref}"`);
}
} else {
if (!nameId || !(item.nameHref || '').startsWith(baseURL)) {
itemErrors.push(`Content Set link Expected format: "${baseURL}?iPublisherId=<id>&function=listUnits"; Actual: "${item.nameHref}"`);
}
if (!editId || !(item.editHref || '').startsWith(baseURL)) {
itemErrors.push(`Edit icon link Expected format: "${baseURL}contentset_edit_modal.php?id=<id>"; Actual: "${item.editHref}"`);
}
if (nameId && editId && nameId[1] !== editId[1]) {
itemErrors.push(`Content Set link ID "${nameId[1]}" does not match edit icon ID "${editId[1]}"`);
}
}
//Edit icon title and color
if (item.editTitle !== editIconStyle.title) {
itemErrors.push(`Edit icon title Expected: "${editIconStyle.title}"; Actual: "${item.editTitle}"`);
}
if (item.editColor !== editIconStyle.color) {
itemErrors.push(`Edit icon color Expected: "${editIconStyle.color}"; Actual: "${item.editColor}"`);
}
//Content Set link and count styles
checkStyle('Content Set', item.nameStyle, nameStyle, itemErrors);
checkStyle('Count', item.countStyle, countStyle, itemErrors);
if (itemErrors.length === 0) {
console.log(`Passed: Position ${position} "${expName}" - Item count: ${expCount}, URL, edit icon, and styles all matched as expected`);
} else {
errors.push(`Position ${position} ("${expName}"): ${itemErrors.join('; ')}`);
}
});
//Log actual count styles while countStyle expected values are not yet set
if (Object.values(countStyle).some(v => v === null) && items[0] && items[0].countStyle) {
console.log(`INFO: Count style not yet validated; actual (position 1): ${JSON.stringify(items[0].countStyle)}`);
}
//Report any unexpected extra items
items.slice(expectedItems.length).forEach((extra, i) => {
errors.push(`Unexpected item at position ${expectedItems.length + i + 1}: "${extra.name}" (${extra.count})`);
});
//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 Biology edit icon',
action: async () => {
await driver.findElement(By.css('#content-org-list > li > div.orgname > a.ml-2')).click();
console.log('----->| NEXT ACTION: Clicked Biology edit icon');
await driver.sleep(2000);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Edit DIV - title
{
description: 'Edit DIV title',
action: async () => {
const multipleChecks = 'Edit DIV title';
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Edit Content Set') {
console.log('Passed: Edit Content Set DIV title matched as expected');
} else {
errors.push(`Expected: DIV title: "Edit Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Edit Content Set DIV title font matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: Edit Content Set DIV title font-size matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Edit Content Set DIV title color matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Edit DIV - label
{
description: 'Edit DIV - Content Set Name label',
action: async () => {
const multipleChecks = 'Edit DIV label';
const element = await driver.findElement(By.css('.modal-lg .form-label'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content Set Name') {
console.log('Passed: Content Set Name DIV label matched as expected');
} else {
errors.push(`Expected: "Content Set Name"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set Name label font matched as expected');
} else {
errors.push(`Expected: Content Set Name label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '15px') {
console.log('Passed: Content Set Name label font-size matched as expected');
} else {
errors.push(`Expected: Content Set Name label font-size "15px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content Set Name label color matched as expected');
} else {
errors.push(`Expected: Content Set Name label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Edit DIV - textbox
{
description: 'Edit DIV textbox',
action: async () => {
const multipleChecks = 'Edit DIV texbox';
const element = await driver.findElement(By.css('#orgname'));
//Get text, font, size, and color
const elementText = await element.getAttribute('value');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Biology') {
console.log('Passed: Biology textbox text matched as expected');
} else {
errors.push(`Expected: "Biology"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Biology textbox font matched as expected');
} else {
errors.push(`Expected: Biology textbox font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '14px') {
console.log('Passed: Biology textbox font-size matched as expected');
} else {
errors.push(`Expected: Biology textbox font-size "14px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Biology textbox color matched as expected');
} else {
errors.push(`Expected: Biology textbox color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Delete button
{
description: 'Delete button',
action: async () => {
const multipleChecks = 'Delete button';
const element = await driver.findElement(By.css('.modal-lg #orgdelete'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
const elementStyle = await element.getAttribute('disabled');
const elementTooltip = await element.getAttribute('title');
//Track all errors
const errors = [];
//text
if (elementText === 'Delete') {
console.log('Passed: Delete button text matched as expected');
} else {
errors.push(`Expected: "Delete"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Delete button text font matched as expected');
} else {
errors.push(`Expected: Delete button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Delete button text font-size matched as expected');
} else {
errors.push(`Expected: Delete button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Delete button text color matched as expected');
} else {
errors.push(`Expected: Delete button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(220, 53, 69, 1)') {
console.log('Passed: Delete button background color matched as expected');
} else {
errors.push(`Expected: Delete button background color: "rgba(220, 53, 69, 1)"; Actual: "${elementButtonColor}"`);
}
//disabled
if (elementStyle === 'true') {
console.log('Passed: Delete button disabled as expected');
} else {
errors.push(`Expected: Delete button style: "disabled"; Actual: "${elementStyle}"`);
}
//tooltip
if (elementTooltip === 'You cannot delete a Content Set that has content items') {
console.log('Passed: Delete button tool-tip matched as expected');
} else {
errors.push(`Expected: Delete button tool-tip: "You cannot delete a Content Set that has content items"; Actual: "${elementTooltip}"`);
}
//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'));
}
}
},
//Save button
{
description: 'Save button',
action: async () => {
const multipleChecks = 'Save button';
const element = await driver.findElement(By.css('#modalop'));
//Get text, font, color, and size
const elementText = await element.getAttribute('value');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Save') {
console.log('Passed: Save button text matched as expected');
} else {
errors.push(`Expected: "Save"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Save button text font matched as expected');
} else {
errors.push(`Expected: Save button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Save button text font-size matched as expected');
} else {
errors.push(`Expected: Save button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Save button text color matched as expected');
} else {
errors.push(`Expected: Save button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Save button background color matched as expected');
} else {
errors.push(`Expected: Save button background 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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('#modalclose'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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 X icon',
action: async () => {
await driver.findElement(By.css('.modal-lg .modal-header span')).click();
console.log('----->| NEXT ACTION: Clicked X icon, to close window');
await driver.sleep(2000);
}
},
//NEXT ACTION
{
description: 'Click Biology content count',
action: async () => {
await driver.findElement(By.css('#mycontentlist > #content-org-list > .content-org .badge')).click();
console.log('----->| NEXT ACTION: Clicked Biology 1493 content link');
await driver.sleep(2000);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.content_modal_title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Biology Totals DIV - title
{
description: 'Biology Totals DIV title',
action: async () => {
const multipleChecks = 'Biology Totals DIV title';
const element = await driver.findElement(By.css('.content_modal_title'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Biology Totals') {
console.log('Passed: Biology Totals DIV title matched as expected');
} else {
errors.push(`Expected: DIV title: "Biology Totals"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Biology Totals DIV title font matched as expected');
} else {
errors.push(`Expected: Biology Totals DIV title font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: Biology Totals DIV title font-size matched as expected');
} else {
errors.push(`Expected: Biology Totals DIV title font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Biology Totals DIV title color matched as expected');
} else {
errors.push(`Expected: Biology Totals DIV title color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Total Items count 1493
{
description: 'Biology DIV - Total Items count',
action: async () => {
const multipleChecks = 'Biology DIV Total Items count';
const element = await driver.findElement(By.css('#total > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === biologyTotalItems) {
console.log(`Passed: Biology Total Items: ${biologyTotalItems} count text matched as expected`);
} else {
errors.push(`Expected: Biology Total Items: "${biologyTotalItems}"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Biology Total Items: Count text font matched as expected');
} else {
errors.push(`Expected: Biology Total Items: Count text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '36px') {
console.log('Passed: Biology Total Items: Count text font-size matched as expected');
} else {
errors.push(`Expected: Biology Total Items: Count text font-size "36px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Biology Total Items: Count text color matched as expected');
} else {
errors.push(`Expected: Biology Total Items: Count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Total Items (SPECIAL CASE: css path with trimmed text)
{
description: 'Biology DIV - Total Items',
action: async () => {
const multipleChecks = 'Biology DIV Total Items';
const element = await driver.findElement(By.css('#total'));
//Extract the bare text node (everything that's not a tag)
const elementTrimmedText = await driver.executeScript(`
const el = arguments[0];
for (const node of el.childNodes) {
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
return node.textContent.trim();
}
}
return null;
`, element);
//Get font, size, and color
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementTrimmedText === 'Total Items') {
console.log('Passed: Total Items text found and matched as expected');
} else {
errors.push(`Expected: Text to contain: "Total Items"; Actual: "${elementTrimmedText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Total Items text font matched as expected');
} else {
errors.push(`Expected: Total Items text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Total Items text font-size matched as expected');
} else {
errors.push(`Expected: Total Items text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Total Items text color matched as expected');
} else {
errors.push(`Expected: Total Items text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Unique Titles count 3230
{
description: 'Biology DIV - Unique Titles count',
action: async () => {
const multipleChecks = 'Biology DIV Unique Titles count';
const element = await driver.findElement(By.css('#total_titles > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === biologyUniqueTitles) {
console.log(`Passed: Biology Unique Titles: ${biologyUniqueTitles} count text matched as expected`);
} else {
errors.push(`Expected: Biology Unique Titles: "${biologyUniqueTitles}"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Biology Unique Titles: Count text font matched as expected');
} else {
errors.push(`Expected: Biology Unique Titles: Count text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '36px') {
console.log('Passed: Biology Unique Titles: Count text font-size matched as expected');
} else {
errors.push(`Expected: Biology Unique Titles: Count text font-size "36px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Biology Unique Titles: Count text color matched as expected');
} else {
errors.push(`Expected: Biology Unique Titles: Count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Unique Titles (SPECIAL CASE: css path with trimmed text)
{
description: 'Biology DIV - Unique Titles',
action: async () => {
const multipleChecks = 'Biology DIV Unique Titles';
const element = await driver.findElement(By.css('#total_titles'));
//Extract the bare text node (everything that's not a tag)
const elementTrimmedText = await driver.executeScript(`
const el = arguments[0];
for (const node of el.childNodes) {
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
return node.textContent.trim();
}
}
return null;
`, element);
//Get font, size, and color
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementTrimmedText === 'Unique Titles') {
console.log('Passed: Unique Titles text found and matched as expected');
} else {
errors.push(`Expected: Text to contain: "Unique Titles"; Actual: "${elementTrimmedText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique Titles text font matched as expected');
} else {
errors.push(`Expected: v text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Unique Titles text font-size matched as expected');
} else {
errors.push(`Expected: Unique Titles text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique Titles text color matched as expected');
} else {
errors.push(`Expected: Unique Titles text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Unique IDs count 3264
{
description: 'Biology DIV - Unique IDs count',
action: async () => {
const multipleChecks = 'Biology DIV Unique IDs count';
const element = await driver.findElement(By.css('#total_pubtotalids > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === biologyUniqueIds) {
console.log(`Passed: Biology Unique IDs: ${biologyUniqueIds} count text matched as expected`);
} else {
errors.push(`Expected: Biology Unique IDs: "${biologyUniqueIds}"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Biology Unique IDs: Count text font matched as expected');
} else {
errors.push(`Expected: Biology Unique IDs: Count text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '36px') {
console.log('Passed: Biology Unique IDs: Count text font-size matched as expected');
} else {
errors.push(`Expected: Biology Unique IDs: Count text font-size "36px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Biology Unique IDs: Count text color matched as expected');
} else {
errors.push(`Expected: Biology Unique IDs: Count text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Biology Unique IDs (SPECIAL CASE: css path with trimmed text)
{
description: 'Biology DIV - Unique IDs',
action: async () => {
const multipleChecks = 'Biology DIV Unique IDs';
const element = await driver.findElement(By.css('#total_pubtotalids'));
//Extract the bare text node (everything that's not a tag)
const elementTrimmedText = await driver.executeScript(`
const el = arguments[0];
for (const node of el.childNodes) {
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
return node.textContent.trim();
}
}
return null;
`, element);
//Get font, size, and color
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementTrimmedText === 'Unique IDs') {
console.log('Passed: Unique IDss text found and matched as expected');
} else {
errors.push(`Expected: Text to contain: "Unique IDs"; Actual: "${elementTrimmedText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Unique IDs text font matched as expected');
} else {
errors.push(`Expected: v text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Unique IDs text font-size matched as expected');
} else {
errors.push(`Expected: Unique IDs text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Unique IDs text color matched as expected');
} else {
errors.push(`Expected: Unique IDs text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('#all_content_modal .btn-secondary'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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'));
}
}
},
//Export button
{
description: 'Export button',
action: async () => {
const multipleChecks = 'Export button';
const element = await driver.findElement(By.css('#export_btn'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export') {
console.log('Passed: Export button text matched as expected');
} else {
errors.push(`Expected: "Export"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Export button text font matched as expected');
} else {
errors.push(`Expected: Export button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Export button text font-size matched as expected');
} else {
errors.push(`Expected: Export button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Export button text color matched as expected');
} else {
errors.push(`Expected: Export button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Export button background color matched as expected');
} else {
errors.push(`Expected: Export button background 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 Close button',
action: async () => {
await driver.findElement(By.css('#all_content_modal .btn-secondary')).click();
console.log('----->| NEXT ACTION: Clicked Close button');
await driver.sleep(2000);
}
},
//NEXT ACTION
{
description: 'Click My Content ellipsis icon',
action: async () => {
await driver.findElement(By.css('.fa-ellipsis-h')).click();
console.log('----->| NEXT ACTION: Clicked My Content ellipsis icon');
//Wait until the element exists in the DOM
const elementVisible = await driver.wait(
until.elementLocated(By.css('.fa-plus')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(elementVisible),
20000
);
}
},
//Create Content Set
{
description: 'Add Create Content Set',
action: async () => {
const multipleChecks = 'Add Create Content Set';
const elementIcon = await driver.findElement(By.css('.fa-plus')).getCssValue('color');
const element = await driver.findElement(By.linkText('Create Content Set'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//icon
if (elementIcon === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Create Content Set add icon color matched as expected');
} else {
errors.push(`Expected: Create Content Set add icon color: "rgba(33, 37, 41, 1)"; Actual: "${elementIcon}"`);
}
//text
if (elementText === 'Create Content Set') {
console.log('Passed: Create Content Set text matched as expected');
} else {
errors.push(`Expected: "Create Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Create Content Set text font matched as expected');
} else {
errors.push(`Expected: Create Content Set text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '12px') {
console.log('Passed: Create Content Set text font-size matched as expected');
} else {
errors.push(`Expected: Create Content Set text font-size "12px"; Actual: "${elementSize}"`);
}
//color
if (elementTextColor === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Create Content Set text color matched as expected');
} else {
errors.push(`Expected: Create Content Set text color: "rgba(33, 37, 41, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Export Content Set
{
description: 'Export Content Set',
action: async () => {
const multipleChecks = 'Export Content Set';
const elementIcon = await driver.findElement(By.css('.fa-download')).getCssValue('color');
const element = await driver.findElement(By.linkText('Export Content Set'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//icon
if (elementIcon === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Export Content Set download icon color matched as expected');
} else {
errors.push(`Expected: Export Content Set download icon color: "rgba(33, 37, 41, 1)"; Actual: "${elementIcon}"`);
}
//text
if (elementText === 'Export Content Set') {
console.log('Passed: Export Content Set text matched as expected');
} else {
errors.push(`Expected: "Export Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Export Content Set text font matched as expected');
} else {
errors.push(`Expected: Export Content Set text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '12px') {
console.log('Passed: Export Content Set text font-size matched as expected');
} else {
errors.push(`Expected: Export Content Set text font-size "12px"; Actual: "${elementSize}"`);
}
//color
if (elementTextColor === 'rgba(33, 37, 41, 1)') {
console.log('Passed: Export Content Set Set text color matched as expected');
} else {
errors.push(`Expected: Export Content Set text color: "rgba(33, 37, 41, 1)"; Actual: "${elementTextColor}"`);
}
//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 Create Content Set link',
action: async () => {
await driver.findElement(By.linkText('Create Content Set')).click();
console.log('----->| NEXT ACTION: Clicked Create Content Set link');
//Wait for the dashboard container to exist in DOM
await driver.wait(
until.elementLocated(By.css('.modal-lg .modal-title')),
30000,
'DIV did not appear within 30 seconds'
);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 30000, 'DIV did not become visible within 30 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Create Content Set DIV - title
{
description: 'Create Content Set DIV title',
action: async () => {
const multipleChecks = 'Create Content Set DIV title';
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Create Content Set') {
console.log('Passed: Create Content Set DIV title matched as expected');
} else {
errors.push(`Expected: DIV title: "Create Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Create Content Set DIV title font matched as expected');
} else {
errors.push(`Expected: Create Content Set DIV title font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: Create Content Set DIV title font-size matched as expected');
} else {
errors.push(`Expected: Create Content Set DIV title font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Create Content Set DIV title color matched as expected');
} else {
errors.push(`Expected: Create Content Set DIV title color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Content Set Name label
{
description: 'Content Set Name label',
action: async () => {
const multipleChecks = 'Content Set Name label';
const element = await driver.findElement(By.css('.form-row:nth-child(2) .form-label'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content Set Name') {
console.log('Passed: Content Set Name label matched as expected');
} else {
errors.push(`Expected: Label: "Content Set Name"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set Name label font matched as expected');
} else {
errors.push(`Expected: Content Set Name label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '15px') {
console.log('Passed: Content Set Name label font-size matched as expected');
} else {
errors.push(`Expected: Content Set Name label font-size "15px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content Set Name label color matched as expected');
} else {
errors.push(`Expected: Content Set Name label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Create button
{
description: 'Create button',
action: async () => {
const multipleChecks = 'Create button';
const element = await driver.findElement(By.css('.modal-lg #modalop'));
//Get text, font, color, and size
const elementText = await element.getAttribute('value');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Create') {
console.log('Passed: Create button text matched as expected');
} else {
errors.push(`Expected: "Create"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Create button text font matched as expected');
} else {
errors.push(`Expected: Create button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Create button text font-size matched as expected');
} else {
errors.push(`Expected: Create button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Create button text color matched as expected');
} else {
errors.push(`Expected: Create button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Create button background color matched as expected');
} else {
errors.push(`Expected: Create button background 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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('#modalclose'));
//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 elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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 Create button',
action: async () => {
await driver.findElement(By.css('.modal-lg #modalop')).click();
console.log('----->| NEXT ACTION: Clicked Create button without Content Set name');
//Wait until the element exists in the DOM
const elementVisible = await driver.wait(
until.elementLocated(By.css('#metawarn > b')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(elementVisible),
20000
);
await driver.sleep(2000);
}
},
//Validation
{
description: 'Empty Content Set name validation message',
action: async () => {
const multipleChecks = 'Empty Content Set Name validation';
const element = await driver.findElement(By.css('#metawarn > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'You must enter a Content Set name.') {
console.log('Passed: Validation text matched as expected');
} else {
errors.push(`Expected: Validation: "You must enter a Content Set name."; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Validation text font matched as expected');
} else {
errors.push(`Expected: Validation text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Validation text font-size matched as expected');
} else {
errors.push(`Expected: Validation text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(220, 53, 69, 1)') {
console.log('Passed: Validation text color matched as expected');
} else {
errors.push(`Expected: Validation text color: "rgba(220, 53, 69, 1)"; Actual: "${elementTextColor}"`);
}
//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: 'Enter organization name and click Create button',
action: async () => {
await driver.findElement(By.css('#orgname')).sendKeys('Biology');
console.log('----->| NEXT ACTION: Entered duplicate Content Set name');
await driver.sleep(2000);
await driver.findElement(By.css('.modal-lg #modalop')).click();
console.log('----->| NEXT ACTION: Clicked Create button');
//Wait until the element exists in the DOM
const elementVisible = await driver.wait(
until.elementLocated(By.css('#namewarn')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(elementVisible),
20000
);
await driver.sleep(2000);
}
},
//Validation
{
description: 'Duplicate Content Set name validation message',
action: async () => {
const multipleChecks = 'Duplicate Content Set Name validation';
const element = await driver.findElement(By.css('#namewarn'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'That name is already in use. Please enter a different name.') {
console.log('Passed: Validation text matched as expected');
} else {
errors.push(`Expected: Validation: "That name is already in use. Please enter a different name."; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Validation text font matched as expected');
} else {
errors.push(`Expected: Validation text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Validation text font-size matched as expected');
} else {
errors.push(`Expected: Validation text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(220, 53, 69, 1)') {
console.log('Passed: Validation text color matched as expected');
} else {
errors.push(`Expected: Validation text color: "rgba(220, 53, 69, 1)"; Actual: "${elementTextColor}"`);
}
//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 Create New Content Set',
action: async () => {
const elementInput = await driver.wait(until.elementLocated(By.css('.form-row:nth-child(2) #orgname')), 5000);
await elementInput.clear();
console.log('----->| NEXT ACTION: Cleared Content Set name');
//Type the deleted Content Set name to filter for it specifically
for (const char of createContentSetName) {
await elementInput.sendKeys(char);
await driver.executeScript(`$(document.querySelector('.form-row:nth-child(2) #orgname')).trigger('keyup');`);
await driver.sleep(100);
}
console.log('----->| NEXT ACTION: Entered new Content Set name');
await driver.findElement(By.css('.modal-lg #modalop')).click();
console.log('----->| NEXT ACTION: Clicked Create button');
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('#statalert'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
await driver.sleep(2000);
}
},
//Alert banner
{
description: 'Alert banner',
action: async () => {
const multipleChecks = 'Alert banner';
const element = await driver.findElement(By.css('strong'));
const elementBanner = await driver.findElement(By.css('#statalert'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementBannerColor = await elementBanner.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'The content set was successfuly created') {
console.log('Passed: Confirmation text matched as expected');
} else {
errors.push(`Expected: Confirmation: "The content set was successfuly created"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Confirmation text font matched as expected');
} else {
errors.push(`Expected: Confirmation text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Confirmation text font-size matched as expected');
} else {
errors.push(`Expected: Confirmation text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Confirmation text color matched as expected');
} else {
errors.push(`Expected: Confirmation text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//banner color
if (elementBannerColor === 'rgba(40, 167, 69, 1)') {
console.log('Passed: Confirmation banner color matched as expected');
} else {
errors.push(`Expected: Confirmation banner color: "rgba(40, 167, 69, 1)"; Actual: "${elementBannerColor}"`);
}
//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'));
}
//Wait until the element exists in the DOM
const biologyLink = await driver.wait(
until.elementLocated(By.linkText('Biology')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(biologyLink),
20000
);
//Wait for page to load completely
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 20000, 'ExACT Dashboard did not fully load within 30 seconds');
console.log('Passed: ExACT Dashboard loaded successfully');
}
},
//My Content - Biology
{
description: 'Biology link',
action: async () => {
const multipleChecks = 'My Content - Biology link';
const element = await driver.findElement(By.linkText('Biology'));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
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 = [];
//url
if (elementURL === 'https://correlation.edgate.com/exact/?iPublisherId=585821587&function=listUnits') {
console.log('Passed: Biology link URL matched as expected');
} else {
errors.push(`Expected: "https://correlation.edgate.com/exact/?iPublisherId=585821587&function=listUnits"; Actual: "${elementURL}"`);
}
//text
if (elementText === 'Biology') {
console.log('Passed: Biology link text matched as expected');
} else {
errors.push(`Expected: "Biology"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Biology link text font matched as expected');
} else {
errors.push(`Expected: Biology link text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '14.3px') {
console.log('Passed: Biology link text font-size matched as expected');
} else {
errors.push(`Expected: Biology link text text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Biology link text color matched as expected');
} else {
errors.push(`Expected: Biology link text color: "rgba(73, 80, 87, 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'));
}
}
},
//My Content - Edit Biology icon
{
description: 'Edit Biology icon',
action: async () => {
const multipleChecks = 'My Content - Edit Biology icon';
const element = await driver.findElement(By.css('#content-org-list > li > div.orgname > a.ml-2'));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
const elementText = await element.getAttribute('title');
const elementColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//url
if (elementURL === 'https://correlation.edgate.com/exact/contentset_edit_modal.php?id=585821587') {
console.log('Passed: Edit Biology icon link URL matched as expected');
} else {
errors.push(`Expected: "https://correlation.edgate.com/exact/contentset_edit_modal.php?id=585821587"; Actual: "${elementURL}"`);
}
//text
if (elementText === 'Edit Content Set') {
console.log('Passed: Edit Biology icon title matched as expected');
} else {
errors.push(`Expected: "Edit Content Set" ; Actual: "${elementText}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Edit Biology icon color matched as expected');
} else {
errors.push(`Expected: Edit Biology icon color: "rgba(73, 80, 87, 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'));
}
}
},
//My Content - Newly created content
{
description: 'Newly created Content Set sort order',
action: async () => {
const multipleChecks = `${createContentSetName} sort order`;
const element = await driver.findElement(By.linkText(`${createContentSetName}`));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
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');
//Edit icon = the <a> sibling right after the Content Set link (NOT the inner <i>, which has no href/title)
const elementEditIcon = await element.findElement(By.xpath('./following-sibling::a[@title="Edit Content Set" or contains(@href, "contentset_edit_modal.php")]'));
//Get href, title, and color
const elementEditIconURL = await elementEditIcon.getAttribute('href');
const elementEditIconTitle = await elementEditIcon.getAttribute('title');
const elementEditIconColor = await elementEditIcon.getCssValue('color');
//Count = badge in the same <li> as the Content Set link (no hardcoded nesting depth)
const elementCount = await element.findElement(By.xpath('./ancestor::li[1]/div/span'));
//Get text, font, size, and color
const elementCountText = await elementCount.getText();
const elementCountFont = await elementCount.getCssValue('font-family');
const elementCountSize = await elementCount.getCssValue('font-size');
const elementCountColor = await elementCount.getCssValue('color');
//All Content Set names in list order (to confirm the new one is last)
const listNames = await driver.executeScript(`
return Array.from(document.querySelectorAll('ul#content-org-list > li > div.orgname > a:first-child'))
.map(a => a.textContent.trim());
`);
const expectedPosition = myContentSets.length + 1;
//Track all errors
const errors = [];
//New Content Set ID is generated on create, so read it from the link and reuse it for the edit icon check
const idMatch = (elementURL || '').match(/^https:\/\/correlation\.edgate\.com\/exact\/\?iPublisherId=(\d+)&function=listUnits$/);
const newContentSetId = idMatch ? idMatch[1] : null;
//url
if (newContentSetId) {
console.log(`Passed: Newly created Content Set link URL matched as expected, ID ${newContentSetId}`);
} else {
errors.push(`Expected: Element URL link format: "https://correlation.edgate.com/exact/?iPublisherId=<id>&function=listUnits"; Actual: "${elementURL}"`);
}
//text
if (elementText === createContentSetName) {
console.log(`Passed: ${createContentSetName} link text matched as expected`);
} else {
errors.push(`Expected: "${createContentSetName}" ; Actual: "${elementText}"`);
}
//sort order - last place
if (listNames.length === expectedPosition && listNames[listNames.length - 1] === createContentSetName) {
console.log(`Passed: ${createContentSetName} listed in last place, position ${expectedPosition} as expected`);
} else {
errors.push(`Expected: Last place (position ${expectedPosition}): "${createContentSetName}"; Actual: position ${listNames.indexOf(createContentSetName) + 1} of ${listNames.length}, last item "${listNames[listNames.length - 1]}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Newly created Content Set link text font matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '14.3px') {
console.log('Passed: Newly created Content Set link text font-size matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Newly created Content Set link text color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text color: "rgba(73, 80, 87, 1)"; Actual: "${elementColor}"`);
}
//icon title
if (elementEditIconTitle === 'Edit Content Set') {
console.log('Passed: Newly created Content Set edit icon title matched as expected');
} else {
errors.push(`Expected: Newly created Content Set edit icon title "Edit Content Set"; Actual: "${elementEditIconTitle}"`);
}
//icon url - must use the same ID as the Content Set link
const expectedEditIconURL = `https://correlation.edgate.com/exact/contentset_edit_modal.php?id=${newContentSetId}`;
if (newContentSetId && elementEditIconURL === expectedEditIconURL) {
console.log(`Passed: Newly created Content Set edit icon URL matched as expected, ID ${newContentSetId}`);
} else {
errors.push(`Expected: Edit icon URL: "${expectedEditIconURL}"; Actual: "${elementEditIconURL}"`);
}
//icon color
if (elementEditIconColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Newly created Content Set edit icon color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set edit icon color: "rgba(73, 80, 87, 1)"; Actual: "${elementEditIconColor}"`);
}
//count
if (elementCountText === '0') {
console.log(`Passed: ${createContentSetName} content count listed in last place as expected`);
} else {
errors.push(`Expected: Last place: ${createContentSetName} content count: "0"; Actual: "${elementCountText}"`);
}
//count font-family
if (elementCountFont === "Poppins, sans-serif") {
console.log('Passed: Newly created Content Set content count font matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count font "Poppins, sans-serif"; Actual: ${elementCountFont}`);
}
//count font size
if (elementCountSize === '12.87px') {
console.log('Passed: Newly created Content Set content count font-size matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count font-size "12.87px"; Actual: "${elementCountSize}"`);
}
//count color
if (elementCountColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Newly created Content Set content count color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count color: "rgba(40, 39, 90, 1)"; Actual: "${elementCountColor}"`);
}
//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 newly created Content Set link',
action: async () => {
await driver.findElement(By.linkText(`${createContentSetName}`)).click();
console.log(`----->| NEXT ACTION: Clicked ${createContentSetName} link`);
//Wait until the element exists in the DOM
const elementVisible = await driver.wait(
until.elementLocated(By.css('.well > b')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(elementVisible),
20000
);
}
},
//Filter Results label
{
description: 'Filter Results label',
action: async () => {
const multipleChecks = 'Filter Results label';
const element = await driver.findElement(By.css('.well > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Filter Results') {
console.log('Passed: Filter Results label matched as expected');
} else {
errors.push(`Expected: Label: "Filter Results"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Filter Results label font matched as expected');
} else {
errors.push(`Expected: Filter Results label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Filter Results label font-size matched as expected');
} else {
errors.push(`Expected: Filter Results label font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Filter Results label color matched as expected');
} else {
errors.push(`Expected: Filter Results label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Grade label
{
description: 'Grade label',
action: async () => {
const multipleChecks = 'Grade label';
const element = await driver.findElement(By.css('.form-group:nth-child(1) > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Grade') {
console.log('Passed: Grade label matched as expected');
} else {
errors.push(`Expected: Label: "Grade"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Grade label font matched as expected');
} else {
errors.push(`Expected: Grade label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Grade label font-size matched as expected');
} else {
errors.push(`Expected: Grade label font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Grade label color matched as expected');
} else {
errors.push(`Expected: Grade label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Subject label
{
description: 'Subject label',
action: async () => {
const multipleChecks = 'Subject label';
const element = await driver.findElement(By.css('.form-group:nth-child(3) > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Subject') {
console.log('Passed: Subject label matched as expected');
} else {
errors.push(`Expected: Label: "Subject"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Subject label font matched as expected');
} else {
errors.push(`Expected: Subject label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Subject label font-size matched as expected');
} else {
errors.push(`Expected: Subject label font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Subject label color matched as expected');
} else {
errors.push(`Expected: Subject label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Reset All link
{
description: 'Reset All link',
action: async () => {
const multipleChecks = 'Reset All link';
const element = await driver.findElement(By.linkText('Reset All'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Reset All') {
console.log('Passed: Reset All link matched as expected');
} else {
errors.push(`Expected: Link: "Reset All"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Reset All link font matched as expected');
} else {
errors.push(`Expected: Reset All link font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Reset All link font-size matched as expected');
} else {
errors.push(`Expected: Reset All link font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Reset All link color matched as expected');
} else {
errors.push(`Expected: Reset All link color: "rgba(73, 80, 87, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Home link
{
description: 'Home link',
action: async () => {
const multipleChecks = 'Home link';
const element = await driver.findElement(By.linkText('Home'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Home') {
console.log('Passed: Home link matched as expected');
} else {
errors.push(`Expected: Link: "Home"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Home link font matched as expected');
} else {
errors.push(`Expected: Home link font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Home link font-size matched as expected');
} else {
errors.push(`Expected: Home link font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Home link color matched as expected');
} else {
errors.push(`Expected: Home link color: "rgba(73, 80, 87, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Content link
{
description: 'Content link',
action: async () => {
const multipleChecks = 'Content link';
const element = await driver.findElement(By.css('.breadcrumb-item:nth-child(2)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content') {
console.log('Passed: Content link matched as expected');
} else {
errors.push(`Expected: Link: "Content"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content link font matched as expected');
} else {
errors.push(`Expected: Content link font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Content link font-size matched as expected');
} else {
errors.push(`Expected: Content link font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Content link color matched as expected');
} else {
errors.push(`Expected: Content link color: "rgba(48, 200, 172, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Results text
{
description: 'Results text',
action: async () => {
const multipleChecks = 'Results text';
const element = await driver.findElement(By.css('b:nth-child(2)'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'There are no items that match your search criteria.') {
console.log('Passed: Results text matched as expected');
} else {
errors.push(`Expected: "There are no items that match your search criteria."; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Results text link font matched as expected');
} else {
errors.push(`Expected: Results text link font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Results text link font-size matched as expected');
} else {
errors.push(`Expected: Results text link font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Results text link color matched as expected');
} else {
errors.push(`Expected: Results text link color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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 Dashboard navigation link',
action: async () => {
await driver.findElement(By.linkText('Dashboard')).click();
console.log(`----->| NEXT ACTION: Clicked Dashboard navigation link`);
//Wait until the element exists in the DOM
const correlationCoveragesImage = await driver.wait(
until.elementLocated(By.css('.gap-idle-wrap > img')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(correlationCoveragesImage),
20000
);
//Wait for page to load completely
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 20000, 'ExACT Dashboard did not fully load within 30 seconds');
console.log('Passed: ExACT Dashboard loaded successfully');
}
},
//NEXT ACTION
{
description: 'Click My Content ellipsis icon',
action: async () => {
await driver.findElement(By.css('.fa-ellipsis-h')).click();
//Wait until the element exists in the DOM
const elementVisible = await driver.wait(
until.elementLocated(By.css('.fa-plus')),
20000
);
await driver.sleep(1000);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(elementVisible),
20000
);
await driver.sleep(1000);
await driver.findElement(By.linkText('Export Content Set')).click();
console.log('----->| NEXT ACTION: Clicked My Content ellipsis icon and Export Content Set link');
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.modal-header:nth-child(5) > .modal-title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Export Content DIV
{
description: 'Export Content DIV',
action: async () => {
const multipleChecks = 'Export Content DIV';
const element = await driver.findElement(By.css('.modal-header:nth-child(5) > .modal-title'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export Content') {
console.log('Passed: Export Content DIV title matched as expected');
} else {
errors.push(`Expected: DIV title: "Export Content"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Export Content DIV title font matched as expected');
} else {
errors.push(`Expected: Export Content DIV title font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: Export Content DIV title font-size matched as expected');
} else {
errors.push(`Expected: Export Content DIV title font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(48, 48, 96, 1)') {
console.log('Passed: Export Content DIV title color matched as expected');
} else {
errors.push(`Expected: Export Content DIV title color: "rgba(48, 48, 96, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Export Content DIV label
{
description: 'Export Content label',
action: async () => {
const multipleChecks = 'Export Content label';
const element = await driver.findElement(By.css('#content-export-container > h5'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Please select one or more content sets to export:') {
console.log('Passed: Export Content DIV label matched as expected');
} else {
errors.push(`Expected: DIV label: "Please select one or more content sets to export:"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Export Content DIV label font matched as expected');
} else {
errors.push(`Expected: Results text label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '20px') {
console.log('Passed: Export Content DIV label font-size matched as expected');
} else {
errors.push(`Expected: Export Content DIV label font-size "20px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Export Content DIV label color matched as expected');
} else {
errors.push(`Expected: Export Content DIV label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Content Set label
{
description: 'Content Set label',
action: async () => {
const multipleChecks = 'Content Set label';
const element = await driver.findElement(By.css('#content_export .form-label'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content Set') {
console.log('Passed: Content Set label matched as expected');
} else {
errors.push(`Expected: Label: "Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set label font matched as expected');
} else {
errors.push(`Expected: Content Set label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '15px') {
console.log('Passed: Content Set label font-size matched as expected');
} else {
errors.push(`Expected: Content Set label font-size "15px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(48, 48, 96, 1)') {
console.log('Passed: Content Set label color matched as expected');
} else {
errors.push(`Expected: Content Set label color: "rgba(48, 48, 96, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Content Set dropdown value
{
description: 'Content Set dropdown value',
action: async () => {
const multipleChecks = 'Content Set dropdown value';
const element = await driver.findElement(By.css('.form-group:nth-child(1) .multiselect-selected-text'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementTitle = await driver.findElement(By.css('.form-group:nth-child(1) .multiselect')).getAttribute('title');
//Track all errors
const errors = [];
//text
if (elementText === 'Please select a Content Set') {
console.log('Passed: Content Set dropdown value matched as expected');
} else {
errors.push(`Expected: "Please select a Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set dropdown value font matched as expected');
} else {
errors.push(`Expected: Content Set dropdown value font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '16px') {
console.log('Passed: Content Set dropdown value font-size matched as expected');
} else {
errors.push(`Expected: Content Set dropdown value font-size "16px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content Set dropdown value color matched as expected');
} else {
errors.push(`Expected: Content Set dropdown value color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//title
if (elementTitle === 'Please select a Content Set') {
console.log('Passed: Content Set dropdown value title matched as expected');
} else {
errors.push(`Expected: Content Set dropdown value title: "Please select a Content Set"; Actual: "${elementTitle}"`);
}
//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'));
}
}
},
//Export button
{
description: 'Export button',
action: async () => {
const multipleChecks = 'Export button';
const element = await driver.findElement(By.css('#exportButton'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export') {
console.log('Passed: Export button text matched as expected');
} else {
errors.push(`Expected: "Export"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Export button text font matched as expected');
} else {
errors.push(`Expected: Export button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '15px') {
console.log('Passed: Export button text font-size matched as expected');
} else {
errors.push(`Expected: Export button text font-size "15px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Export button text color matched as expected');
} else {
errors.push(`Expected: Export button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Export button background color matched as expected');
} else {
errors.push(`Expected: Export button background 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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('.btn:nth-child(3)'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '15px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "15px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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: 'Export DIV alert message',
action: async () => {
const multipleChecks = 'Export DIV alert';
const errors = [];
//Wait for modal to be ready
await driver.wait(until.elementLocated(By.css('.modal-header:nth-child(5) > .modal-title')), 5000);
//Click export button
await driver.wait(until.elementLocated(By.css('#exportButton')), 5000).click();
await driver.sleep(2500);
console.log('----->| NEXT ACTION: Clicked Export button');
//Wait for confirm dialog to appear
const alert = await driver.wait(until.alertIsPresent(), 5000);
console.log('----->| NEXT ACTION: Alert dialog appeared');
//Get alert text
const alertText = await alert.getText();
//Validate alert message text
const expectedText = 'Please select at least one Content Set.';
if (alertText === expectedText) {
console.log('Passed: Export alert message text matched as expected');
} else {
errors.push(`Expected: "${expectedText}"; Actual: "${alertText}"`);
}
//Throw summary before dismissing if errors found
if (errors.length > 0) {
await alert.dismiss(); //Cancel the export if validation failed
if (errors.length > 1) {
errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`);
}
throw new Error(errors.join('\n'));
}
//Accept the alert (click OK) to proceed with export
await alert.accept();
console.log('----->| NEXT ACTION: Clicked OK on alert DIV');
await driver.sleep(2000);
}
},
//Export - Search textbox placeholder
{
description: 'Export Search placeholder text',
action: async () => {
const multipleChecks = 'Export Search textbox';
//Click to expand dropdown list
await driver.findElement(By.css('#content_export > div > div > button > span')).click();
console.log('----->| NEXT ACTION: Clicked Content Set dropdown');
await driver.sleep(2000);
const elementIcon = await driver.findElement(By.css('.show .input-group-prepend img')).getCssValue('color');
const element = await driver.findElement(By.css('.show > .multiselect-item .form-control'));
const elementClearIcon = await driver.findElement(By.css('.form-group:nth-child(1) .input-group-append img')).getCssValue('color');
//Get placeholder text, size, and color
const elementText = await element.getAttribute('placeholder');
//Get placeholder styles via executeScript since it's a pseudo-element
const elementFont = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('font-family')`,
element
);
const elementSize = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('font-size')`,
element
);
const elementColor = await driver.executeScript(
`return window.getComputedStyle(arguments[0], '::placeholder').getPropertyValue('color')`,
element
);
//Track all errors
const errors = [];
//Search icon color
if (elementIcon === 'rgba(169, 169, 189, 1)') {
console.log('Passed: Search icon color matched as expected');
} else {
errors.push(`Expected: Search icon color: "rgba(169, 169, 189, 1)"; Actual: "${elementIcon}"`);
}
//text
if (elementText === 'Search') {
console.log('Passed: Search placeholder text matched as expected');
} else {
errors.push(`Expected: "Search" placeholder; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Search placeholder text font matched as expected');
} else {
errors.push(`Expected: Search placeholder text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '13.5px') {
console.log('Passed: Search placeholder text font-size matched as expected');
} else {
errors.push(`Expected: Search placeholder text font-size "13.5px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgb(108, 117, 125)') {
console.log('Passed: Search placeholder text color matched as expected');
} else {
errors.push(`Expected: Search placeholder text color: "rgb(108, 117, 125)"; Actual: "${elementColor}"`);
}
//Clear icon color
if (elementClearIcon === 'rgba(255, 59, 48, 1)') {
console.log('Passed: Search clear icon color matched as expected');
} else {
errors.push(`Expected: Search clear icon color: "rgba(255, 59, 48, 1)"; Actual: "${elementClearIcon}"`);
}
//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'));
}
}
},
//Sort dropdown values (SPECIAL CASE: multi-selection)
{
description: 'Export multiselect dropdown list',
action: async () => {
const multipleChecks = 'Export multiselect dropdown list';
//Track all errors//
const errors = [];
//Target the correct dropdown directly by its unique id
const dropdown = await driver.wait(until.elementLocated(By.css('#selectOrg')), 5000);
const selectElement = new Select(dropdown);
//Get all options
const options = await selectElement.getOptions();
//console.log('----->| Total options found:', options.length);
const expected = [
'US History III',
'English I',
'Algebra',
'Biology',
'Copy Move Delete Test 1',
'Copy Move Delete Test 2',
'Import Align - Concept Based 1',
'Import Align - Concept Based 2',
'Import Align - Direct Align 1',
'Import Align - Direct Align 2',
'Math Alignment Import Test',
'create me',
'Illustrative Math Test 1',
'Illustrative Math Test 2',
'Khan URL test',
'seesaw test',
'ECS-3037 On Prod TC2',
'ECS-3037 On Prod TC1',
'webinar test',
'Review Screen Open',
'New One For Agust Post Night',
'Automated Algebra Content Set - TO BE DELETED',
'Post NIght July26',
'create import test'
];
const actual = [];
for (const opt of options) {
const text = await driver.executeScript(`
return arguments[0].textContent.trim();
`, opt);
if (text !== '') {
actual.push(text);
//console.log(`----->| Option: "${text}"`);
}
}
//console.log('----->| DEBUG actual:', JSON.stringify(actual));
//Validate list matches expected
if (JSON.stringify(actual) === JSON.stringify(expected)) {
console.log('Passed: Export Content multi-select dropdown list', options.length + ' matched as expected');
} else {
errors.push(`Expected: ${JSON.stringify(expected)}\nActual: ${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'));
}
}
},
//NEXT ACTION
{
description: 'Click filter Content Set list and select newly created Content Set',
action: async () => {
const elementInput = await driver.wait(until.elementLocated(By.css('.show > .multiselect-item .form-control')), 5000);
for (const char of 'Auto') {
await elementInput.sendKeys(char);
await driver.executeScript(`$(document.querySelector('.show > .multiselect-item .form-control')).trigger('keyup');`);
await driver.sleep(100);
}
console.log('----->| NEXT ACTION: Entered search term - Auto');
await driver.findElement(By.css('li:nth-child(24) input')).click();
console.log(`----->| NEXT ACTION: Clicked checkbox for: ${createContentSetName}`);
await driver.sleep(2000);
await driver.findElement(By.css('.modal-header:nth-child(5)')).click();
console.log('----->| NEXT ACTION: Clicked modal to close dropdown list');
await driver.sleep(2000);
await driver.findElement(By.css('#exportButton')).click();
console.log('----->| NEXT ACTION: Clicked Export button');
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('h2'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Export page
{
description: 'Export page title',
action: async () => {
const multipleChecks = 'Export page title';
const element = await driver.findElement(By.css('h2'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export') {
console.log('Passed: Export title matched as expected');
} else {
errors.push(`Expected: DIV title: "Export"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === `"DM Serif Display", serif`) {
console.log('Passed: Export title font matched as expected');
} else {
errors.push(`Expected: Export title font "DM Serif Display, serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '32px') {
console.log('Passed: Export title font-size matched as expected');
} else {
errors.push(`Expected: Export title font-size "32px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Export title color matched as expected');
} else {
errors.push(`Expected: Export title color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Export page label
{
description: 'Export page label',
action: async () => {
const multipleChecks = 'Export page label';
const element = await driver.findElement(By.css('body > div.container.body > div > div.right_col > div > b'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Export complete!') {
console.log('Passed: Export label matched as expected');
} else {
errors.push(`Expected: DIV label: "Export complete!"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Export label font matched as expected');
} else {
errors.push(`Expected: Export label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Export label font-size matched as expected');
} else {
errors.push(`Expected: Export label font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Export label color matched as expected');
} else {
errors.push(`Expected: Export label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Download Export button
{
description: 'Download Export button',
action: async () => {
const multipleChecks = 'Download Export button';
const elementIcon = await driver.wait(until.elementLocated(By.css('.fa-download')), 5000).catch(() => false);
const element = await driver.findElement(By.linkText('Download Export'));
//Get icon, text, color, and size
const elementText = await element.getText();
const elementFont = await element.getCssValue('font-family');
const elementColor = await element.getCssValue('color');
const elementSize = await element.getCssValue('font-size');
//Track all errors
const errors = [];
//icon
if (elementIcon) {
console.log('Passed: Download Export button icon present');
} else {
errors.push('Download Export button icon not found');
}
//text
if (elementText === 'Download Export') {
console.log('Passed: Download Export button text matched as expected');
} else {
errors.push(`Expected: "Download Export"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Download Export button text font matched as expected');
} else {
errors.push(`Expected: Download Export button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//color
if (elementColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Download Export button text color matched as expected');
} else {
errors.push(`Expected: Download Export button text color "rgba(255, 255, 255, 1)"; Actual: "${elementColor}"`);
}
//font size
if (elementSize === '20px') {
console.log('Passed: Download Export button text font-size matched as expected');
} else {
errors.push(`Expected: Download Export button text text font-size "20px"; Actual: "${elementSize}"`);
}
//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 Dashboard navigation link',
action: async () => {
await driver.findElement(By.linkText('Dashboard')).click();
console.log(`----->| NEXT ACTION: Clicked Dashboard navigation link`);
//Wait until the element exists in the DOM
const correlationCoveragesImage = await driver.wait(
until.elementLocated(By.css('.gap-idle-wrap > img')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(correlationCoveragesImage),
20000
);
//Wait for page to load completely
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 20000, 'ExACT Dashboard did not fully load within 30 seconds');
console.log('Passed: ExACT Dashboard loaded successfully');
}
},
//My Content - Sort by Count (default)
{
description: 'Newly created Content Set sort order',
action: async () => {
const multipleChecks = `${createContentSetName} sort order`;
const element = await driver.findElement(By.linkText(`${createContentSetName}`));
//Get href, text, font, size, and color
const elementURL = await element.getAttribute('href');
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');
//Edit icon = the <a> sibling right after the Content Set link (NOT the inner <i>, which has no href/title)
const elementEditIcon = await element.findElement(By.xpath('./following-sibling::a[@title="Edit Content Set" or contains(@href, "contentset_edit_modal.php")]'));
//Get href, title, and color
const elementEditIconURL = await elementEditIcon.getAttribute('href');
const elementEditIconTitle = await elementEditIcon.getAttribute('title');
const elementEditIconColor = await elementEditIcon.getCssValue('color');
//Count = badge in the same <li> as the Content Set link (no hardcoded nesting depth)
const elementCount = await element.findElement(By.xpath('./ancestor::li[1]/div/span'));
//Get text, font, size, and color
const elementCountText = await elementCount.getText();
const elementCountFont = await elementCount.getCssValue('font-family');
const elementCountSize = await elementCount.getCssValue('font-size');
const elementCountColor = await elementCount.getCssValue('color');
//All Content Set names in list order (to confirm the new one is last)
const listNames = await driver.executeScript(`
return Array.from(document.querySelectorAll('ul#content-org-list > li > div.orgname > a:first-child'))
.map(a => a.textContent.trim());
`);
const expectedPosition = myContentSets.length + 1;
//Track all errors
const errors = [];
//New Content Set ID is generated on create, so read it from the link and reuse it for the edit icon check
const idMatch = (elementURL || '').match(/^https:\/\/correlation\.edgate\.com\/exact\/\?iPublisherId=(\d+)&function=listUnits$/);
const newContentSetId = idMatch ? idMatch[1] : null;
//url
if (newContentSetId) {
console.log(`Passed: Newly created Content Set link URL matched as expected, ID ${newContentSetId}`);
} else {
errors.push(`Expected: Element URL link format: "https://correlation.edgate.com/exact/?iPublisherId=<id>&function=listUnits"; Actual: "${elementURL}"`);
}
//text
if (elementText === createContentSetName) {
console.log(`Passed: ${createContentSetName} link text matched as expected`);
} else {
errors.push(`Expected: "${createContentSetName}" ; Actual: "${elementText}"`);
}
//sort order - last place
if (listNames.length === expectedPosition && listNames[listNames.length - 1] === createContentSetName) {
console.log(`Passed: ${createContentSetName} listed in last place, position ${expectedPosition} as expected`);
} else {
errors.push(`Expected: Last place (position ${expectedPosition}): "${createContentSetName}"; Actual: position ${listNames.indexOf(createContentSetName) + 1} of ${listNames.length}, last item "${listNames[listNames.length - 1]}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Newly created Content Set link text font matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '14.3px') {
console.log('Passed: Newly created Content Set link text font-size matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text font-size "14.3px"; Actual: "${elementSize}"`);
}
//color
if (elementColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Newly created Content Set link text color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set link text color: "rgba(73, 80, 87, 1)"; Actual: "${elementColor}"`);
}
//icon title
if (elementEditIconTitle === 'Edit Content Set') {
console.log('Passed: Newly created Content Set edit icon title matched as expected');
} else {
errors.push(`Expected: Newly created Content Set edit icon title "Edit Content Set"; Actual: "${elementEditIconTitle}"`);
}
//icon url - must use the same ID as the Content Set link
const expectedEditIconURL = `https://correlation.edgate.com/exact/contentset_edit_modal.php?id=${newContentSetId}`;
if (newContentSetId && elementEditIconURL === expectedEditIconURL) {
console.log(`Passed: Newly created Content Set edit icon URL matched as expected, ID ${newContentSetId}`);
} else {
errors.push(`Expected: Edit icon URL: "${expectedEditIconURL}"; Actual: "${elementEditIconURL}"`);
}
//icon color
if (elementEditIconColor === 'rgba(73, 80, 87, 1)') {
console.log('Passed: Newly created Content Set edit icon color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set edit icon color: "rgba(73, 80, 87, 1)"; Actual: "${elementEditIconColor}"`);
}
//count
if (elementCountText === '0') {
console.log(`Passed: ${createContentSetName} content count listed in last place as expected`);
} else {
errors.push(`Expected: Last place: ${createContentSetName} content count: "0"; Actual: "${elementCountText}"`);
}
//count font-family
if (elementCountFont === "Poppins, sans-serif") {
console.log('Passed: Newly created Content Set content count font matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count font "Poppins, sans-serif"; Actual: ${elementCountFont}`);
}
//count font size
if (elementCountSize === '12.87px') {
console.log('Passed: Newly created Content Set content count font-size matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count font-size "12.87px"; Actual: "${elementCountSize}"`);
}
//count color
if (elementCountColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Newly created Content Set content count color matched as expected');
} else {
errors.push(`Expected: Newly created Content Set content count color: "rgba(40, 39, 90, 1)"; Actual: "${elementCountColor}"`);
}
//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: 'Filter My Content list',
action: async () => {
const filterInput = await driver.findElement(By.css('#content-org-filter'));
await filterInput.click();
await driver.sleep(500);
for (const char of 'algebra') {
await filterInput.sendKeys(char);
await driver.executeScript(`$(document.querySelector('#content-org-filter')).trigger('keyup');`);
await driver.sleep(100);
}
console.log('----->| NEXT ACTION: Filtered My Content list by - algebra');
await driver.sleep(2000);
//Wait for visible items to reduce
await driver.wait(async () => {
try {
const visibleCount = await driver.executeScript(`
const all = document.querySelectorAll('#mycontentlist .orgname');
return Array.from(all).filter(el => {
const style = window.getComputedStyle(el.closest('li'));
return style.display !== 'none' && style.visibility !== 'hidden';
}).length;
`);
return visibleCount < 13;
} catch (e) {
return false;
}
}, 10000, 'List did not filter within 10 seconds');
console.log('Passed: Filter "algebra" applied successfully');
}
},
//Validate sort order by filter algebra
{
description: 'Sort order by filter algebra',
action: async () => {
const multipleChecks = 'My Content - Sort order by filter algebra';
const errors = [];
const rows = await driver.executeScript(`
const results = [];
const items = document.querySelectorAll('#mycontentlist .orgname');
Array.from(items).forEach((item) => {
//Only include visible items
const li = item.closest('li');
const style = window.getComputedStyle(li);
if (style.display === 'none' || style.visibility === 'hidden') return;
const nameLink = item.querySelector('a:first-child');
const name = nameLink ? nameLink.textContent.trim() : '';
const editLink = item.querySelector('a.ml-2');
const href = editLink ? editLink.getAttribute('href') : '';
const countSpan = li.querySelector('.badge.contnet_set_count');
const count = countSpan ? countSpan.textContent.trim() : '';
results.push({ position: results.length + 1, name, href, count });
});
return results;
`);
//Positions are now 1 and 2 since we only have 2 visible items
const expected = [
{ position: 1, name: 'Algebra', count: '194', href: '/exact/contentset_edit_modal.php?id=585821586' },
{ position: 2, name: 'Automated Algebra Content Set - TO BE DELETED', count: '0', hrefContains: '/exact/contentset_edit_modal.php?id=' }
];
for (const exp of expected) {
const actual = rows[exp.position - 1];
if (!actual) {
errors.push(`Position ${exp.position}: row not found`);
continue;
}
const nameMatch = actual.name === exp.name;
const countMatch = actual.count === exp.count;
//Use includes() for href if exp.hrefContains is defined, otherwise exact match
const hrefMatch = exp.hrefContains
? actual.href.includes(exp.hrefContains)
: actual.href === exp.href;
if (nameMatch && countMatch && hrefMatch) {
console.log(`Passed: Sort Order ${exp.position} - ${exp.name} | Count: ${exp.count} | href | All matched as expected`);
} else {
if (!nameMatch) errors.push(`Sort Order ${exp.position} name - Expected: "${exp.name}"; Actual: "${actual.name}"`);
if (!countMatch) errors.push(`Sort Order ${exp.position} count - Expected: "${exp.count}"; Actual: "${actual.count}"`);
if (!hrefMatch) errors.push(`Sort Order ${exp.position} href - Expected: "${exp.href}"; Actual: "${actual.href}"`);
}
}
//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'));
}
}
},
//NEXT ACTION orgsort
{
description: 'Click Name sort by option',
action: async () => {
//Use Select class for reliable dropdown interaction
const sortDropdown = await driver.wait(until.elementLocated(By.css('#orgsort')), 5000);
const selectElement = new Select(sortDropdown);
await selectElement.selectByVisibleText('Name');
console.log('----->| NEXT ACTION: Selected Sort: "Name" option');
//Wait specifically for the list to re-render with the first Name-sorted Content Set first
const expectedFirst = myContentSetsByName[0].name;
await driver.wait(async () => {
try {
const firstItem = await driver.executeScript(`
const first = document.querySelector('#mycontentlist .orgname a:first-child');
return first ? first.textContent.trim() : '';
`);
return firstItem === expectedFirst;
} catch (e) {
return false;
}
}, 10000, 'List did not re-sort by Name within 10 seconds');
console.log('Passed: Sort by Name applied successfully');
}
},
//Sort by Name
{
description: 'Sort order by Name',
action: async () => {
const multipleChecks = 'My Content - Sort order by Name';
const errors = [];
const rows = await driver.executeScript(`
const results = [];
const items = document.querySelectorAll('#mycontentlist .orgname');
items.forEach((item, index) => {
const nameLink = item.querySelector('a:first-child');
const name = nameLink ? nameLink.textContent.trim() : '';
const editLink = item.querySelector('a.ml-2');
const href = editLink ? editLink.getAttribute('href') : '';
const countSpan = item.closest('li').querySelector('.badge.contnet_set_count');
const count = countSpan ? countSpan.textContent.trim() : '';
results.push({ position: index + 1, name, href, count });
});
return results;
`);
//Expected Name sort order built from the myContentSets constant (+ newly created Content Set)
//Known IDs check the exact edit URL; null IDs (incl. the new Content Set) check the URL format only
const editURL = '/exact/contentset_edit_modal.php?id=';
const expected = myContentSetsByName.map((s, i) => ({
position: i + 1,
name: s.name,
count: s.totalItems,
...(s.id ? { href: `${editURL}${s.id}` } : { hrefContains: editURL }),
}));
//Item count
if (rows.length === expected.length) {
console.log(`Passed: Sort by Name item count matched as expected (${expected.length})`);
} else {
errors.push(`Expected: ${expected.length} items sorted by Name; Actual: ${rows.length}`);
}
for (const exp of expected) {
const actual = rows[exp.position - 1];
if (!actual) {
errors.push(`Position ${exp.position}: row not found`);
continue;
}
const nameMatch = actual.name === exp.name;
const countMatch = actual.count === exp.count;
//Use includes() for href if exp.hrefContains is defined, otherwise exact match
const hrefMatch = exp.hrefContains
? actual.href.includes(exp.hrefContains)
: actual.href === exp.href;
if (nameMatch && countMatch && hrefMatch) {
console.log(`Passed: Sort Order ${exp.position} - ${exp.name} | Count: ${exp.count} | href | All matched as expected`);
} else {
if (!nameMatch) errors.push(`Sort Order ${exp.position} name - Expected: "${exp.name}"; Actual: "${actual.name}"`);
if (!countMatch) errors.push(`Sort Order ${exp.position} count - Expected: "${exp.count}"; Actual: "${actual.count}"`);
if (!hrefMatch) errors.push(`Sort Order ${exp.position} href - Expected: "${exp.href || exp.hrefContains + '<id>'}"; Actual: "${actual.href}"`);
}
}
//Report any unexpected extra items
rows.slice(expected.length).forEach(extra => {
errors.push(`Unexpected item at Sort Order ${extra.position}: "${extra.name}" (${extra.count})`);
});
//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'));
}
}
},
//NEXT ACTION
{
description: 'Click newly created Content Set edit icon',
action: async () => {
await driver.findElement(By.css('#mycontentlist > #content-org-list > #content-org-list > .content-org .fa')).click();
console.log(`----->| NEXT ACTION: Clicked ${createContentSetName} edit icon`);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Modal did not become visible within 20 seconds');
console.log('Passed: DIV loaded successfully');
}
},
//Edit DIV - title
{
description: 'Edit DIV title',
action: async () => {
const multipleChecks = 'Edit DIV title';
const element = await driver.findElement(By.css('.modal-lg .modal-title'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Edit Content Set') {
console.log('Passed: Edit Content Set DIV title matched as expected');
} else {
errors.push(`Expected: DIV title: "Edit Content Set"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Edit Content Set DIV title font matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '18px') {
console.log('Passed: Edit Content Set DIV title font-size matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title font-size "18px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Edit Content Set DIV title color matched as expected');
} else {
errors.push(`Expected: Edit Content Set DIV title color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Edit DIV - label
{
description: 'Edit DIV - Content Set Name label',
action: async () => {
const multipleChecks = 'Edit DIV label';
const element = await driver.findElement(By.css('#divname > .form-label'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === 'Content Set Name') {
console.log('Passed: Content Set Name DIV label matched as expected');
} else {
errors.push(`Expected: "Content Set Name"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Content Set Name label font matched as expected');
} else {
errors.push(`Expected: Content Set Name label font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '15px') {
console.log('Passed: Content Set Name label font-size matched as expected');
} else {
errors.push(`Expected: Content Set Name label font-size "15px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Content Set Name label color matched as expected');
} else {
errors.push(`Expected: Content Set Name label color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Edit DIV - textbox
{
description: 'Edit DIV textbox',
action: async () => {
const multipleChecks = 'Edit DIV texbox';
const element = await driver.findElement(By.css('#orgname'));
//Get text, font, size, and color
const elementText = await element.getAttribute('value');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
//Track all errors
const errors = [];
//text
if (elementText === `${createContentSetName}`) {
console.log(`Passed: ${createContentSetName} textbox text matched as expected`);
} else {
errors.push(`Expected: "${createContentSetName}"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log(`Passed: ${createContentSetName} textbox font matched as expected`);
} else {
errors.push(`Expected: ${createContentSetName} textbox font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '14px') {
console.log(`Passed: ${createContentSetName} textbox font-size matched as expected`);
} else {
errors.push(`Expected: ${createContentSetName} textbox font-size "14px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log(`Passed: ${createContentSetName} textbox color matched as expected`);
} else {
errors.push(`Expected: ${createContentSetName} textbox color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//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'));
}
}
},
//Delete button
{
description: 'Delete button',
action: async () => {
const multipleChecks = 'Delete button';
const element = await driver.findElement(By.css('#orgdelete'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementButtonColor = await element.getCssValue('background-color');
const elementTooltip = await element.getAttribute('title');
//Track all errors
const errors = [];
//text
if (elementText === 'Delete') {
console.log('Passed: Delete button text matched as expected');
} else {
errors.push(`Expected: "Delete"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Delete button text font matched as expected');
} else {
errors.push(`Expected: Delete button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Delete button text font-size matched as expected');
} else {
errors.push(`Expected: Delete button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Delete button text color matched as expected');
} else {
errors.push(`Expected: Delete button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//button color
if (elementButtonColor === 'rgba(220, 53, 69, 1)') {
console.log('Passed: Delete button background color matched as expected');
} else {
errors.push(`Expected: Delete button background color: "rgba(220, 53, 69, 1)"; Actual: "${elementButtonColor}"`);
}
//tooltip
if (elementTooltip === '') {
console.log('Passed: Delete button tool-tip disabled as expected');
} else {
errors.push(`Expected: Delete button tool-tip: "no tool-tip"; Actual: "${elementTooltip}"`);
}
//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'));
}
}
},
//Save button
{
description: 'Save button',
action: async () => {
const multipleChecks = 'Save button';
const element = await driver.findElement(By.css('#modalop'));
//Get text, font, color, and size
const elementText = await element.getAttribute('value');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Save') {
console.log('Passed: Save button text matched as expected');
} else {
errors.push(`Expected: "Save"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Save button text font matched as expected');
} else {
errors.push(`Expected: Save button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Save button text font-size matched as expected');
} else {
errors.push(`Expected: Save button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Save button text color matched as expected');
} else {
errors.push(`Expected: Save button text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(48, 200, 172, 1)') {
console.log('Passed: Save button background color matched as expected');
} else {
errors.push(`Expected: Save button background 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'));
}
}
},
//Close button
{
description: 'Close button',
action: async () => {
const multipleChecks = 'Close button';
const element = await driver.findElement(By.css('#modalclose'));
//Get text, font, color, and size
const elementText = await element.getText('');
const elementFont = await element.getCssValue('font-family');
const elementSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementColor = await element.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'Close') {
console.log('Passed: Close button text matched as expected');
} else {
errors.push(`Expected: "Close"; Actual: "${elementText}"`);
}
//font-family
if (elementFont === "Poppins, sans-serif") {
console.log('Passed: Close button text font matched as expected');
} else {
errors.push(`Expected: Close button text font "Poppins, sans-serif"; Actual: ${elementFont}`);
}
//font size
if (elementSize === '16px') {
console.log('Passed: Close button text font-size matched as expected');
} else {
errors.push(`Expected: Close button text font-size "16px"; Actual: "${elementSize}"`);
}
//text color
if (elementTextColor === 'rgba(40, 39, 90, 1)') {
console.log('Passed: Close button text color matched as expected');
} else {
errors.push(`Expected: Close button text color: "rgba(40, 39, 90, 1)"; Actual: "${elementTextColor}"`);
}
//color
if (elementColor === 'rgba(0, 0, 0, 0)') {
console.log('Passed: Close button background color matched as expected');
} else {
errors.push(`Expected: Close button background color: "rgba(0, 0, 0, 0)"; 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: 'Delete created content and validate alert message',
action: async () => {
const multipleChecks = 'Delete content alert';
const errors = [];
//Wait for modal to be ready
await driver.wait(until.elementLocated(By.css('#myModal')), 5000);
await driver.sleep(1000);
//Click delete button
await driver.wait(until.elementLocated(By.css('#orgdelete')), 5000).click();
await driver.sleep(2500);
console.log('----->| NEXT ACTION: Clicked Delete button');
//Wait for confirm dialog to appear
const alert = await driver.wait(until.alertIsPresent(), 5000);
console.log('----->| NEXT ACTION: Alert dialog appeared');
//Get alert text
const alertText = await alert.getText();
//Validate alert message text
const expectedText = `Are you sure you want to delete ${createContentSetName}? This operation cannot be undone or recovered.`;
if (alertText === expectedText) {
console.log('Passed: Delete alert message text matched as expected');
} else {
errors.push(`Expected: "${expectedText}"; Actual: "${alertText}"`);
}
//Throw summary before dismissing if errors found
if (errors.length > 0) {
await alert.dismiss(); //Cancel the delete if validation failed
if (errors.length > 1) {
errors.unshift(`${multipleChecks} - Multiple validation checks did not pass`);
}
throw new Error(errors.join('\n'));
}
//Accept the alert (click OK) to proceed with deletion
await alert.accept();
console.log('----->| NEXT ACTION: Clicked OK to confirm alert DIV Content Set deletion');
await driver.sleep(2000);
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('#statalert'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'Alert banner did not become visible within 20 seconds');
}
},
//Alert banner
{
description: 'Alert banner',
action: async () => {
const multipleChecks = 'Alert banner';
const element = await driver.findElement(By.css('strong'));
const elementBanner = await driver.findElement(By.css('#statalert'));
//Get text, font, size, and color
const elementText = await element.getText('');
const elementTextFont = await element.getCssValue('font-family');
const elementTextSize = await element.getCssValue('font-size');
const elementTextColor = await element.getCssValue('color');
const elementBannerColor = await elementBanner.getCssValue('background-color');
//Track all errors
const errors = [];
//text
if (elementText === 'The content set was successfuly deleted') {
console.log('Passed: Confirmation text matched as expected');
} else {
errors.push(`Expected: Confirmation: "The content set was successfuly deleted"; Actual: "${elementText}"`);
}
//font-family
if (elementTextFont === "Poppins, sans-serif") {
console.log('Passed: Confirmation text font matched as expected');
} else {
errors.push(`Expected: Confirmation text font "Poppins, sans-serif"; Actual: ${elementTextFont}`);
}
//font size
if (elementTextSize === '13px') {
console.log('Passed: Confirmation text font-size matched as expected');
} else {
errors.push(`Expected: Confirmation text font-size "13px"; Actual: "${elementTextSize}"`);
}
//color
if (elementTextColor === 'rgba(255, 255, 255, 1)') {
console.log('Passed: Confirmation text color matched as expected');
} else {
errors.push(`Expected: Confirmation text color: "rgba(255, 255, 255, 1)"; Actual: "${elementTextColor}"`);
}
//banner color
if (elementBannerColor === 'rgba(40, 167, 69, 1)') {
console.log('Passed: Confirmation banner color matched as expected');
} else {
errors.push(`Expected: Confirmation banner color: "rgba(40, 167, 69, 1)"; Actual: "${elementBannerColor}"`);
}
//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'));
}
//Wait until the element exists in the DOM
const correlationCoveragesImage = await driver.wait(
until.elementLocated(By.css('.gap-idle-wrap > img')),
20000
);
//Wait until it becomes visible
await driver.wait(
until.elementIsVisible(correlationCoveragesImage),
20000
);
//Wait for page to load completely
await driver.wait(async () => {
const readyState = await driver.executeScript('return document.readyState');
return readyState === 'complete';
}, 20000, 'ExACT Dashboard did not fully load within 30 seconds');
console.log('Passed: ExACT Dashboard loaded successfully');
}
},
//Verify content was deleted
{
description: 'Verify Content Set deletion',
action: async () => {
//Clear filter and search for the deleted Content Set by name
const filterInput = await driver.wait(until.elementLocated(By.css('#content-org-filter')), 5000);
await filterInput.clear();
//Trigger keyup after clear to reset the list
await driver.executeScript(`$(document.querySelector('#content-org-filter')).trigger('keyup');`);
await driver.sleep(500);
//Type the deleted Content Set name to filter for it specifically
for (const char of 'Automated Algebra') {
await filterInput.sendKeys(char);
await driver.executeScript(`$(document.querySelector('#content-org-filter')).trigger('keyup');`);
await driver.sleep(100);
}
console.log('----->| NEXT ACTION: Filtered list by "Automated Algebra"');
await driver.sleep(1000);
//Check visible items only
const visibleNames = await driver.executeScript(`
const items = document.querySelectorAll('#mycontentlist .orgname');
return Array.from(items)
.filter(el => {
const style = window.getComputedStyle(el.closest('li'));
return style.display !== 'none' && style.visibility !== 'hidden';
})
.map(el => el.querySelector('a:first-child').textContent.trim());
`);
//console.log('----->| DEBUG visible items after filter:', JSON.stringify(visibleNames));
//Verify deleted Content Set is NOT in the visible list
if (visibleNames.includes(createContentSetName)) {
throw new Error(`Expected: "${createContentSetName}" to be deleted; Actual: Still visible in list`);
} else {
console.log(`Passed: ${createContentSetName} successfully deleted and no longer visible`);
}
//Clear the filter - .clear() fires no key events, so trigger keyup (same event the filter listens to)
await filterInput.clear();
await driver.executeScript(`$(document.querySelector('#content-org-filter')).trigger('keyup');`);
console.log('----->| NEXT ACTION: Deleted filter term');
//Wait until the full list is visible again (all original Content Sets; new one was deleted)
await driver.wait(async () => {
const visibleCount = await driver.executeScript(`
return Array.from(document.querySelectorAll('#mycontentlist .orgname')).filter(el => {
const style = window.getComputedStyle(el.closest('li'));
return style.display !== 'none' && style.visibility !== 'hidden';
}).length;
`);
return visibleCount === myContentSets.length;
}, 10000, `My Content list did not reset to ${myContentSets.length} items within 10 seconds after clearing filter`, 300);
console.log('Passed: My Content list reset after clearing filter');
}
},
//NEXT ACTION - reopen My Content Totals DIV (table rows only load when the DIV is opened)
{
description: 'Click My Content Items Count button (re-validate totals after delete)',
action: async () => {
await driver.findElement(By.css('#content_total')).click();
console.log('----->| NEXT ACTION: Clicked Total items count button');
//Wait until the modal title is located AND visible
await driver.wait(async () => {
try {
const element = await driver.findElement(By.css('.content_modal_title'));
return await element.isDisplayed();
} catch (e) {
return false; //Element not ready yet, keep waiting
}
}, 20000, 'My Content Totals DIV did not become visible within 20 seconds');
//Wait until table rows have loaded
await driver.wait(until.elementLocated(By.css('#content_tbody > tr')), 20000, 'My Content Totals table rows did not load within 20 seconds');
console.log('Passed: My Content Totals DIV loaded successfully');
}
},
//My Content Totals DIV - Table data (Content Set, Total Items, Unique Titles, Unique IDs)
{
description: 'My Content Totals DIV - Table Content Set, Total Items, Unique Titles, and Unique IDs',
action: async () => {
const multipleChecks = 'My Content Totals table data';
//Expected rows in display order: [Content Set, Total Items, Unique Titles, Unique IDs] (from myContentSets constant)
const expectedRows = myContentSets.map(s => [s.name, s.totalItems, s.uniqueTitles, s.uniqueIds]);
const columns = ['Content Set', 'Total Items', 'Unique Titles', 'Unique IDs'];
//Expected cell styles per column [Content Set, Total Items, Unique Titles, Unique IDs]
const expectedStyles = [
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
{ font: 'Poppins, sans-serif', size: '12px', color: 'rgba(40, 39, 90, 1)' },
];
//Wait for table rows to render
await driver.wait(until.elementLocated(By.css('#content_tbody > tr')), 20000, 'My Content Totals table rows did not load within 20 seconds');
//Read all cells in one call (textContent also works for rows scrolled out of view)
//Colors are normalized from rgb() to rgba() to match Selenium's getCssValue() format
const cellData = await driver.executeScript(`
const toRgba = c => c.startsWith('rgb(') ? c.replace('rgb(', 'rgba(').replace(')', ', 1)') : c;
return Array.from(document.querySelectorAll('#content_tbody > tr')).map(tr =>
Array.from(tr.querySelectorAll('td')).map(td => {
const cs = window.getComputedStyle(td);
return { text: td.textContent.trim(), font: cs.fontFamily, size: cs.fontSize, color: toRgba(cs.color) };
})
);
`);
const actualRows = cellData.map(row => row.map(cell => cell.text));
//Track all errors
const errors = [];
//Row count
if (actualRows.length === expectedRows.length) {
console.log(`Passed: My Content Totals table row count matched as expected, ${expectedRows.length}`);
} else {
errors.push(`Expected: ${expectedRows.length} table rows; Actual: ${actualRows.length}`);
}
//Cell-by-cell comparison
expectedRows.forEach((expected, rowIndex) => {
const actual = actualRows[rowIndex];
if (!actual) {
errors.push(`Row ${rowIndex + 1} ("${expected[0]}") missing from table`);
return;
}
const rowErrors = [];
columns.forEach((column, colIndex) => {
if (actual[colIndex] !== expected[colIndex]) {
rowErrors.push(`${column} Expected: "${expected[colIndex]}"; Actual: "${actual[colIndex]}"`);
}
//Style checks (font-family, font-size, color)
const cell = cellData[rowIndex][colIndex];
const style = expectedStyles[colIndex];
if (!cell) return;
if (cell.font !== style.font) {
rowErrors.push(`${column} font Expected: "${style.font}"; Actual: "${cell.font}"`);
}
if (cell.size !== style.size) {
rowErrors.push(`${column} font-size Expected: "${style.size}"; Actual: "${cell.size}"`);
}
if (cell.color !== style.color) {
rowErrors.push(`${column} color Expected: "${style.color}"; Actual: "${cell.color}"`);
}
});
if (rowErrors.length === 0) {
console.log(`Passed: Row ${rowIndex + 1} "${expected[0]}" - ${columns.map((c, i) => `${c}: ${expected[i]}`).join(', ')} | Text font, size, and color all matched as expected`);
} else {
errors.push(`Row ${rowIndex + 1} ("${expected[0]}"): ${rowErrors.join('; ')}`);
}
});
//Report any unexpected extra rows
actualRows.slice(expectedRows.length).forEach((extra, i) => {
errors.push(`Unexpected row ${expectedRows.length + i + 1}: ${JSON.stringify(extra)}`);
});
//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 - close My Content Totals DIV before logging out
{
description: 'Close My Content Totals DIV',
action: async () => {
const closeButton = await driver.findElement(By.css('#all_content_modal .btn-secondary'));
await closeButton.click();
console.log('----->| NEXT ACTION: Clicked My Content Totals DIV Close button');
//Wait until the DIV is hidden
await driver.wait(async () => {
try {
return !(await driver.findElement(By.css('.content_modal_title')).isDisplayed());
} catch (e) {
return true;
}
}, 10000, 'My Content Totals DIV did not close within 10 seconds');
console.log('Passed: My Content Totals DIV closed');
}
},
//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', 'myContentWidget');
const screenshotFileName = `step_${stepIndex}_${stepDescription.replace(/\s+/g, '_')}.png`;
const screenshotPath = path.join(dir, screenshotFileName);
fs.writeFileSync(screenshotPath, screenshot, 'base64');
return screenshotPath;
};
const resultsFile = path.join('results', 'myContentWidget.xlsx');
const clearOldResults = () => {
//Remove old screenshots
const screenshotDir = path.join('screenshots', 'myContentWidget');
if (fs.existsSync(screenshotDir)) {
fs.rmSync(screenshotDir, { recursive: true, force: true });
}
fs.mkdirSync(screenshotDir, { recursive: true });
//Remove old Excel file
if (fs.existsSync(resultsFile)) {
fs.unlinkSync(resultsFile);
}
};
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 {
await step.action();
worksheet = logStep(
worksheet,
step.description,
'Passed',
stepIndex,
timestamp,
null
);
} catch (error) {
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: DASHBOARD - My Content Widget(myContentWidget); All test steps completed successfully');
testStatus = 'Passed';
} else {
console.log('------------->| THE END |<-------------');
console.log('FAILED: DASHBOARD - My Content Widget(myContentWidget); 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, resultsFile);
} finally {
await driver.quit();
}
})();
}
export default myContentWidget;