diff --git a/src/js/components/CandidateListRoot/CandidateListRoot.jsx b/src/js/components/CandidateListRoot/CandidateListRoot.jsx index d2d7bc23a..7093acd3e 100644 --- a/src/js/components/CandidateListRoot/CandidateListRoot.jsx +++ b/src/js/components/CandidateListRoot/CandidateListRoot.jsx @@ -404,7 +404,7 @@ class CandidateListRoot extends Component { titleTextForList.length && candidateList) && ( - + {titleTextForList} )} diff --git a/src/js/components/RepresentativeListRoot/RepresentativeListRoot.jsx b/src/js/components/RepresentativeListRoot/RepresentativeListRoot.jsx index d8b17c5da..8fb4e5123 100644 --- a/src/js/components/RepresentativeListRoot/RepresentativeListRoot.jsx +++ b/src/js/components/RepresentativeListRoot/RepresentativeListRoot.jsx @@ -403,7 +403,7 @@ class RepresentativeListRoot extends Component { titleTextForList.length && representativeList) && ( - + {titleTextForList} )} diff --git a/tests/browserstack_automation/page_objects/candidates.page.js b/tests/browserstack_automation/page_objects/candidates.page.js new file mode 100644 index 000000000..604d8a3f1 --- /dev/null +++ b/tests/browserstack_automation/page_objects/candidates.page.js @@ -0,0 +1,56 @@ +import { $, $$ } from '@wdio/globals'; +import Page from './page'; +import TopNavigation from './topnavigation'; + +class CandidatesPage extends Page { + async load () { + await super.open(''); + await TopNavigation.toggleCandidatesTab(); + } + + get stateSelect () { + return $("//select[@id='outlined-age-native-simple']"); + } + + get stateSelectOptions () { + return $$("//select[@id='outlined-age-native-simple']//option"); + } + + get pageHeaders () { + return $$('h2#WhatIsHappeningTitle'); + } + + get CandidateCardList () { + return $$("//div[contains(@id,'cardForListBodyWrapper')]"); + } + + async getCandidateCardCandidateName(cardId) { + const candidate = await $(`//div[@id='${cardId}']//a[@id='candidateCardDisplayName' or @id='representativeCardDisplayName']`); + const candidateName = await candidate.getText(); + return candidateName; + } + + async getCandidateCardState(cardId) { + const candidate = await $(`//div[@id='${cardId}']//div[contains(@id,'stateName')]`); + const stateText = await candidate.getText(); + return stateText; + } + + async getCandidateCardPartyName (cardId) { + const candidateParty = await $(`//div[@id='${cardId}']//div[contains(@class,'PoliticalParty')]`); + const candidatePartyExists = await candidateParty.isExisting(); + if (candidatePartyExists) { + const partyText = await candidateParty.getText(); + return partyText; + } else { + return null; + } + } + + async getCandidateCardOffice (cardId) { + const candidateOffice = await $(`//div[@id='${cardId}']//div[contains(@class,'OfficeNameWrapper')]/div`); + const officeText = candidateOffice.getText(); + return officeText; + } +} +export default new CandidatesPage(); diff --git a/tests/browserstack_automation/specs/CandidatesPage.js b/tests/browserstack_automation/specs/CandidatesPage.js new file mode 100644 index 000000000..ab9f6facd --- /dev/null +++ b/tests/browserstack_automation/specs/CandidatesPage.js @@ -0,0 +1,155 @@ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-use-before-define */ +import { driver } from '@wdio/globals'; +import CandidatesPage from '../page_objects/candidates.page'; + +const testDataPath = 'tests/browserstack_automation/testDataForScripts/'; +const fs = require('fs'); +const assert = require('assert'); + +const waitTime = 8000; + +/* eslint-disable no-undef */ +// This eslint-disable turns off warnings for describe() and it() + +describe('Candidates Page', () => { + // Candidates_001 + it('verifyAllStateNamesPresentforChooseState', async () => { + await CandidatesPage.load(); + await driver.pause(waitTime); + await CandidatesPage.stateSelect.click(); + const options = await CandidatesPage.stateSelectOptions; + const expectedStates = readTestDataStates('all'); + const actualStates = []; + await options.forEach(async (option) => { + const stateName = await option.getText(); + if (!stateName.includes('Choose state')) { + actualStates.push(stateName); + } + }); + await expectedStates.forEach((state) => { + assert(actualStates.includes(state), `State -> '${state}' .. not found on the Choose state Dropdown Options .`); + }); + }); + + // Candidates_002 + const stateNamesRandomTC2 = readTestDataStates('random', 3); + stateNamesRandomTC2.forEach((state) => { + it('verifyTitleWhenStateSelected', async () => { + const titleStr = ' Candidates - WeVote'; + console.log(`Running verifyTitleWhenStateSelected -> Using sate: ${state}`); + await CandidatesPage.load(); + await CandidatesPage.stateSelect.selectByVisibleText(state); + await driver.pause(waitTime); + const expectedTitle = state + titleStr; + const actualTitle = await driver.getTitle(); + assert.equal(actualTitle, expectedTitle); + }); + }); + + // Candidates_003 + const stateNamesRandomTC3 = readTestDataStates('random', 3); + const possibleHeaders = readTestDataAllPossibleHeaders(); + stateNamesRandomTC3.forEach((state) => { + it('verifyHeadersMatchPossibleHeaders', async () => { + console.log(`Running verifyHeadersMatchPossibleHeaders -> Using sate: ${state}`); + CandidatesPage.load(); + await driver.pause(waitTime); + await CandidatesPage.stateSelect.selectByVisibleText(state); + await driver.pause(waitTime); + const actualHeaders = await CandidatesPage.pageHeaders; + await actualHeaders.forEach(async (header) => { + const headerText = await header.getText(); + console.log(`Checking if Header found on page: '${headerText}' is one of the expected headers.`); + assert(possibleHeaders.includes(headerText), `Header section -> '${headerText}' .. does not match with any of the expected Headers -> [${possibleHeaders}]`); + }); + }); + }); + + // Candidates_004 + const stateNamesRandomTC4 = readTestDataStates('random', 3); + const MandatoryHeaders = readTestDataMandatoryHeaders(); + stateNamesRandomTC4.forEach((state) => { + it('verifyMandatoryHeaderPresent', async () => { + console.log(`Running verifyMandatoryHeaderPresent -> Using sate: ${state}`); + CandidatesPage.load(); + await driver.pause(waitTime); + await CandidatesPage.stateSelect.selectByVisibleText(state); + await driver.pause(waitTime); + const actualHeaders = await CandidatesPage.pageHeaders; + const actualHeadersText = []; + await actualHeaders.forEach(async (header) => { + actualHeadersText.push(await header.getText()); + }); + MandatoryHeaders.forEach((mandatoryHeader) => { + console.log(`Checking if mandatory header '${mandatoryHeader}' is found on the page.`); + assert(actualHeadersText.includes(mandatoryHeader), `Mandatory Header section -> '${mandatoryHeader}' .. not found on the page..`); + }); + }); + }); + + // Candidates_005, Candidates_006, Candidates_007, Candidates_008 + const stateNamesRandomTC5 = readTestDataStates('random', 3); + stateNamesRandomTC5.forEach((state) => { + const errors = []; + it('verifyCandidateCardHasSectionsDisplayed', async () => { + console.log(`Running verifyCandidateCardHasSectionsDisplayed -> Using sate: ${state}`); + CandidatesPage.load(); + await driver.pause(waitTime); + await CandidatesPage.stateSelect.selectByVisibleText(state); + await driver.pause(waitTime); + const candidateCards = await CandidatesPage.CandidateCardList; + for (let i = 0; i < candidateCards.length; i++) { + const card = candidateCards[i]; + const cardId = await card.getAttribute('id'); + const candidateNameDisplayed = await CandidatesPage.getCandidateCardCandidateName(cardId); + const stateNameDisplayed = await CandidatesPage.getCandidateCardState(cardId); + const partyNameDisplayed = await CandidatesPage.getCandidateCardPartyName(cardId); + const officeNameDisplayed = (await CandidatesPage.getCandidateCardOffice(cardId)); + const errMsgNoCandidateName = `Candidate Name not displayed for candidate card: ${cardId}`; + const errMsgNoStateName = `State not displayed for candidate: ${candidateNameDisplayed}`; + const errMsgNoPartyName = `Party not displayed for candidate: ${candidateNameDisplayed}`; + const errMsgNoOfficeName = `Office not displayed for candidate: ${candidateNameDisplayed}`; + if (candidateNameDisplayed === null) errors.push(errMsgNoCandidateName); + if (stateNameDisplayed === null) errors.push(errMsgNoStateName); + if (partyNameDisplayed === null) errors.push(errMsgNoPartyName); + if (officeNameDisplayed === null) errors.push(errMsgNoOfficeName); + } + if (errors.length > 0) { + let errorsAll = ''; + for (let i = 0; i < errors.length; i++) { + errorsAll += `${errors[i]}\n`; + } + throw new Error(errorsAll); + } + }); + }); + + + // read All Possible Headers from candidatesPage_TC001.json + function readTestDataAllPossibleHeaders () { + const jsonObjH = JSON.parse(fs.readFileSync(`${testDataPath}candidatesPage_TDHeaders.json`)); + const possibleHeadersData = jsonObjH.map((i) => i.HeaderText); + return possibleHeadersData; + } + // read Mandatory Headers from candidatesPage_TC001.json + function readTestDataMandatoryHeaders () { + const jsonObjH = JSON.parse(fs.readFileSync(`${testDataPath}candidatesPage_TDHeaders.json`)); + const MandatoryHeadersData = (jsonObjH.filter((header) => header.Mandatory === 'Y')).map((i) => i.HeaderText); + return MandatoryHeadersData; + } + // read stateNames from candidatesPage_TDStates.json, return n random states for test run + function readTestDataStates (type, count) { + const jsonObjSt = JSON.parse(fs.readFileSync(`${testDataPath}candidatesPage_TDStates.json`)); + const allStateNames = (jsonObjSt[0]).States; + let testStates = []; + if (type === 'all') { + testStates = allStateNames; + } else if (type === 'random') { + for (let cnt = 0; cnt < count; cnt++) { + testStates.push(allStateNames[Math.floor(Math.random() * allStateNames.length)]); + } + } + return testStates; + } +}); diff --git a/tests/browserstack_automation/testDataForScripts/candidatesPage_TDHeaders.json b/tests/browserstack_automation/testDataForScripts/candidatesPage_TDHeaders.json new file mode 100644 index 000000000..4080b50de --- /dev/null +++ b/tests/browserstack_automation/testDataForScripts/candidatesPage_TDHeaders.json @@ -0,0 +1,18 @@ +[ + { + "HeaderText":"Candidates in Close Races", + "Mandatory":"N" + }, + { + "HeaderText":"On Your Ballot", + "Mandatory":"N" + }, + { + "HeaderText":"More Politicians", + "Mandatory":"Y" + }, + { + "HeaderText":"Current Representatives", + "Mandatory":"N" + } +] \ No newline at end of file diff --git a/tests/browserstack_automation/testDataForScripts/candidatesPage_TDStates.json b/tests/browserstack_automation/testDataForScripts/candidatesPage_TDStates.json new file mode 100644 index 000000000..448c0ae94 --- /dev/null +++ b/tests/browserstack_automation/testDataForScripts/candidatesPage_TDStates.json @@ -0,0 +1,57 @@ +[ + { + "States":[ + "Alabama", + "Alaska", + "Arizona", + "Arkansas", + "California", + "Colorado", + "Connecticut", + "Delaware", + "District of Columbia", + "Florida", + "Georgia", + "Hawaii", + "Idaho", + "Illinois", + "Indiana", + "Iowa", + "Kansas", + "Kentucky", + "Louisiana", + "Maine", + "Maryland", + "Massachusetts", + "Michigan", + "Minnesota", + "Mississippi", + "Missouri", + "Montana", + "Nebraska", + "Nevada", + "New Hampshire", + "New Jersey", + "New Mexico", + "New York", + "North Carolina", + "North Dakota", + "Ohio", + "Oklahoma", + "Oregon", + "Pennsylvania", + "Rhode Island", + "South Carolina", + "South Dakota", + "Tennessee", + "Texas", + "Utah", + "Vermont", + "Virginia", + "Washington", + "West Virginia", + "Wisconsin", + "Wyoming" + ] + } +] \ No newline at end of file