package com.exner.tools.analyticstdd.SiteInfrastructureTests; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Assert; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import cucumber.api.java.After; import cucumber.api.java.Before; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; public class PageSteps { private static final Logger logger = LogManager.getLogger("PageTests"); private WebDriver driver; private JavascriptExecutor _jsExecutor; @Before public void beforeTest() { logger.info("Test setup..."); ChromeOptions chromeOptions = new ChromeOptions(); chromeOptions.addArguments("--headless"); // driver = new ChromeDriver(chromeOptions); if (logger.isDebugEnabled()) { logger.debug("Initialising ChromeDriver..."); } driver = new RemoteWebDriver(CucumberFeatureTest.getService().getUrl(), chromeOptions); _jsExecutor = (JavascriptExecutor) driver; logger.info("Test setup complete."); } /*** * General tests for vendor-independent data */ @Given("^the page \"(.*)\" is loaded$") public void the_page_is_loaded(String url) { logger.info("Loading page {}...", url); driver.get(url); } @Given("^the snippet \"(.*)\" is executed$") public void the_snippet_is_executed(String snippet) { logger.info("Executing JS snippet {}...", snippet); _jsExecutor.executeScript(snippet); } @Given("^we wait for (\\d+) seconds?$") public void we_waited_for_seconds(int seconds) { logger.info("Waiting {} seconds...", seconds); try { Thread.sleep(1000l * seconds); } catch (InterruptedException e) { logger.warn("Sleep interrupted {}", e.getLocalizedMessage()); } } @Then("^the \"(.*)\" data layer element is \"(.*)\"$") public void the_data_layer_element_is(String dataLayerElementName, String value) { logger.info("Testing - data layer element {} must be {}...", dataLayerElementName, value); TestTools.assertScriptExecutionReturnsCorrectStringValue(driver, "return " + dataLayerElementName, value); } @Then("^the \"(.*)\" data layer element is (\\d+)$") public void the_data_layer_element_is_numeric(String dataLayerElementName, long value) { logger.info("Testing - data layer element {} must be {}...", dataLayerElementName, value); TestTools.assertScriptExecutionReturnsCorrectNumericalValue(driver, "return " + dataLayerElementName, value); } @Then("^there is a data layer element called \"(.*)\"$") public void there_is_a_data_layer_element_called(String elementName) { logger.info("Testing - data layer element {} must exist...", elementName); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof " + elementName + " !== 'undefined') { return true } else { return false }"); } @Then("^the DOM element \"(.*)\" exists$") public void the_DOM_element_exists(String elementSelector) { logger.info("Testing - DOM element {} must exist...", elementSelector); WebElement element = null; try { element = driver.findElement(By.cssSelector(elementSelector)); } catch (NoSuchElementException e) { // it ain't there Assert.fail(); } // make sure the element exists Assert.assertNotNull(element); } @Then("^the DOM element \"(.*)\" exists (\\d+) times$") public void the_DOM_element_exists_times(String elementSelector, int n) { logger.info("Testing - DOM element {} must exist {} times...", elementSelector, n); List<WebElement> element = null; try { element = driver.findElements(By.cssSelector(elementSelector)); } catch (NoSuchElementException e) { // it ain't there Assert.fail(); } // make sure the element exists n times Assert.assertEquals(n, element.size()); } @Then("^the snippet \"(.*)\" returns true$") public void the_snippet_returns_true_on_this_page(String snippet) { logger.info("Testing - JS snippet {} must return true...", snippet); TestTools.assertScriptExecutionReturnsTrue(driver, snippet); } /*** * General tests for infrastructure on pages */ @Then("^DTM is present$") public void dtm_is_present() { logger.info("Testing - {} must be present...", Tools.DTM); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof _satellite !== 'undefined' && _satellite && typeof _satellite.appVersion !== 'undefined' && _satellite.appVersion) { return true } else { return false }"); } @Then("^Launch is present$") public void launch_is_present() { logger.info("Testing - {} must be present...", Tools.LAUNCH); // TBD have to fix TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof _satellite !== 'undefined' && _satellite && typeof _satellite.buildInfo !== 'undefined' && _satellite.buildInfo) { return true } else { return false }"); } @Then("^the DTM library is \"(.*)\"$") public void the_DTM_library_is(String libraryName) { logger.info("Testing - {} library must be {}...", Tools.DTM, libraryName); TestTools.assertScriptExecutionReturnsCorrectStringValue(driver, "return _satellite && _satellite.settings && _satellite.settings.libraryName", libraryName); } @Then("^the Launch property is called \"(.*)\"$") public void the_Launch_property_name_is(String propertyName) { logger.info("Testing - {} property name must be {}...", Tools.LAUNCH, propertyName); TestTools.assertScriptExecutionReturnsCorrectStringValue(driver, "return _satellite && _satellite.property && _satellite.property.name", propertyName); } @Then("^jQuery is present$") public void jquery_is_present() { logger.info("Testing - {} must be present...", Tools.JQUERY); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof jQuery !== 'undefined') { return true } else { return false }"); } @Then("^the jQuery version is \"(.*)\" or later$") public void the_jQuery_version_is_or_later(String minVersion) { logger.info("Testing - {} version must be {} or later...", Tools.JQUERY, minVersion); TestTools.assertToolVersionIsOrLater(driver, "if (typeof jQuery !== 'undefined') { return jQuery.fn.jquery } else { return 'unavailable' }", minVersion); } @Then("^the jQuery version is below \"(.*)\"$") public void the_jQuery_version_is_below(String maxVersion) { logger.info("Testing - {} version must be below {}...", Tools.JQUERY, maxVersion); TestTools.assertToolVersionIsBelow(driver, "if (typeof jQuery !== 'undefined') { return jQuery.fn.jquery } else { return 'unavailable' }", maxVersion); } /*** * out of scope tests for Adobe Tools */ @Then("^(?:MCID|ECID|Experience Cloud ID Service) is present$") public void ecid_is_present() { logger.info("Testing - {} must be present...", Tools.MCVID); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof Visitor === 'function') { return true } else { return false }"); } @Then("^(?:MCID|ECID|Experience Cloud ID Service) version is \"(.*)\" or later$") public void ecid_version_is_or_later(String minVersion) { logger.info("Testing - {} version must be {} or later...", Tools.MCVID, minVersion); TestTools.assertToolVersionIsOrLater(driver, "if (typeof Visitor !== 'undefined') { for (vv in s_c_il) { var nvv = s_c_il[vv]; if (typeof nvv._c !== 'undefined' && nvv._c == \"Visitor\") { return nvv.version; } } return 'unavailable' } else { return 'unavailable' }", minVersion); } @Then("^(?:MCID|ECID|Experience Cloud ID Service) version is below \"(.*)\"$") public void ecid_version_is_below(String maxVersion) { logger.info("Testing - {} version must be below {}...", Tools.MCVID, maxVersion); TestTools.assertToolVersionIsBelow(driver, "if (typeof Visitor !== 'undefined') { return Visitor.version } else { return 'unavailable' }", maxVersion); } @Then("^(?:AA|Adobe Analytics) is present$") public void aa_is_present() { logger.info("Testing - {} must be present...", Tools.AA); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof AppMeasurement == 'function' || typeof s_gi == 'function') { return true; } else { return false; }"); } @Then("^(?:AA|Adobe Analytics) version is \"(.*)\" or later$") public void aa_version_is_or_later(String minVersion) { logger.info("Testing - {} version must be {} or later...", Tools.AA, minVersion); TestTools.assertToolVersionIsOrLater(driver, "if (typeof AppMeasurement !== 'undefined') { return (new AppMeasurement()).version } else if (typeof s_gi !== 'undefined') { return s.version } else { return 'unavailable' }", minVersion); } @Then("^(?:AA|Adobe Analytics) lib type is \"(.*)\"$") public void aa_lib_type_is(String libType) { logger.info("Testing - {} library must be {}...", Tools.AA, libType); Object response = _jsExecutor.executeScript( "if (typeof AppMeasurement == 'function' ) { return 'AppMeasurement' } else if (typeof s_gi == 'function') { return 'legacy'; } else { return 'none'; }"); // make sure the element exists if (String.class.isAssignableFrom(response.getClass())) { Assert.assertEquals(libType, (String) response); } else { Assert.fail(); } } @Then("^an (?:AA|Adobe Analytics) call has been sent for report suite id \"(.*)\"$") public void aa_tag_for_reportsuite_fired(String rsid) { logger.info("Testing - {} must have fired a call to report suite id {}...", Tools.AA, rsid); // replace "," between rsids with "_" rsid = rsid.replace(',', '_'); TestTools.assertScriptExecutionReturnsTrue(driver, "var rstest='\" + rsid\r\n" + " + \"';var rsprfx='s_i_';var retVal=false;for(var b in window){if(window['hasOwnProperty'](b)){if(b['indexOf'](rsprfx)===0){rsarr=b['substr'](rsprfx['length'],b['length'])['split']('_');if(rsarr['indexOf'](rstest)>=0){retVal=true}}}};return retVal"); } @Then("^latest (?:AA|Adobe Analytics) tracking call contains key \"(.*)\" with value \"(.*)\"$") public void latest_aa_tracking_call_contains_key_with_value(String key, String value) { logger.info("Testing - {} tracking call must contain key {} with value {}", Tools.AA, key, value); String snippet = "var entryList = performance.getEntriesByType('resource');var result = false;for (var i = entryList.length - 1; i > 0; i--) {if ('undefined' !== typeof entryList[i].name && entryList[i].name.indexOf('/b/ss/') >= 0) {var keys = entryList[i].name.split('&');for (var i = keys.length - 1; i > 0; i--) {var tmp = keys[i].split('=');if ('" + key + "' === tmp[0]) {if ('" + value + "' === decodeURIComponent(tmp[1])) {result = true;}break;}}}} return result;"; TestTools.assertScriptExecutionReturnsTrue(driver, snippet); } @Then("^(?:AT|Adobe Target) is present$") public void at_is_present() { logger.info("Testing - {} must be present...", Tools.AT); TestTools.assertScriptExecutionReturnsTrue(driver, "if ('undefined' !== adobe && adobe && 'undefined' !== adobe.target && adobe.target) { return true; } else { if (typeof TNT == 'object') { return true; } else { return false; } }"); } @Then("^(?:AT|Adobe Target) version is \"(.*)\" or later$") public void at_version_is_or_later(String minVersion) { logger.info("Testing - {} version must be {} or later...", Tools.AT, minVersion); TestTools.assertToolVersionIsOrLater(driver, "if (typeof mboxVersion !== 'undefined') { return mboxVersion } else if (typeof adobe !== 'undefined' && typeof adobe.target !== 'undefined' && typeof adobe.target.VERSION !== 'undefined') { return adobe.target.VERSION } else { return 'unavailable' }", minVersion); } @Then("^(?:AT|Adobe Target) lib type is \"(.*)\"$") public void at_lib_type_is(String libType) { logger.info("Testing - {} library must be {}...", Tools.AT, libType); Object response = _jsExecutor.executeScript( "if (typeof mboxVersion !== 'undefined' ) { return 'legacy' } else if (typeof adobe !== 'undefined' && typeof adobe.target !== 'undefined' && typeof adobe.target.VERSION !== 'undefined') { return 'at.js'; } else { return 'none'; }"); // make sure the element exists if (String.class.isAssignableFrom(response.getClass())) { Assert.assertEquals(libType, (String) response); } else { Assert.fail(); } } @Then("^an (?:AT|Adobe Target) mbox named \"(.*)\" exists $") public void at_mbox_named_exists(String mboxName) { logger.info("Testing - {} mbox called {} must exist...", Tools.AT, mboxName); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof mboxCurrent != 'undefined' && mboxCurrent.getName() == '" + mboxName + "') { return true; } else { " + "var resources = performance.getEntriesByType('resource'); if ('undefined' !== resources && resources) { for(var i in resources) { if (resources[i].initiatorType === 'xmlhttprequest' && resources[i].name.match(/mbox\\/json\\?mbox=/)) { var mboxName = resources[i].name.replace(/.*\\/json\\?mbox=/, '').replace(/&.*/, ''); if ('undefined' !== mboxName && mboxName && mboxName === '" + mboxName + "') { return true; } } } return false; };"); } /*** * Some experimental tests */ @Then("^GTM is present$") public void gtm_is_present() { logger.info("Testing - {} must be present...", Tools.GTM); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof google_tag_manager === 'object') { return true } else { return false }"); } @Then("^Ensighten Manage is present$") public void ensighten_manage_is_present() { logger.info("Testing - {} must be present...", Tools.ENSIGHTEN); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof Bootstrapper === 'object') { return true } else { return false }"); } @Then("^Tealium IQ is present$") public void tealium_iq_is_present() { logger.info("Testing - {} must be present...", Tools.TEALIUM); TestTools.assertScriptExecutionReturnsTrue(driver, "if (typeof utag === 'object') { return true } else { return false }"); } @Then("^log Browser Performance Timing$") public void log_browser_performance_timing() { logger.info("Testing - logging Performance TImings to file..."); Object response = _jsExecutor.executeScript("return JSON.stringify(performance.timing)"); if (null != response && String.class.isAssignableFrom(response.getClass())) { // write to file try { FileWriter fileWriter = new FileWriter("timings.csv", true); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); bufferedWriter.write(driver.getCurrentUrl()); bufferedWriter.write(","); bufferedWriter.write((String) response); bufferedWriter.newLine(); bufferedWriter.close(); } catch (IOException e) { Assert.fail("Error writing timings to file: " + e.getLocalizedMessage()); } } else { Assert.fail("Unable to write timings to file, timings empty or not a string."); } Assert.assertTrue(true); } @After public void afterTest() { logger.info("Test teardown..."); driver.quit(); } }