001/* 002 * (C) Copyright 2015-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Anahide Tchertchian 018 */ 019package org.nuxeo.functionaltests; 020 021import static org.junit.Assert.fail; 022 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.List; 026 027import org.openqa.selenium.WebDriver; 028 029import net.jsourcerer.webdriver.jserrorcollector.JavaScriptError; 030 031/** 032 * Helper class to collect JavaScript errors on a page. 033 * 034 * @since 8.1 035 */ 036public class JavaScriptErrorCollector { 037 038 protected final WebDriver driver; 039 040 protected List<JavaScriptErrorIgnoreRule> ignores; 041 042 public JavaScriptErrorCollector(WebDriver driver) { 043 super(); 044 this.driver = driver; 045 ignores = new ArrayList<>(); 046 // Add this error per default which are actually a warning for FF 42 047 ignore(JavaScriptErrorIgnoreRule.startsWith("mutating the [[Prototype]] of an object")); 048 } 049 050 /** 051 * @since 9.3 052 */ 053 public static JavaScriptErrorCollector from(WebDriver driver) { 054 return new JavaScriptErrorCollector(driver); 055 } 056 057 /** 058 * @since 9.3 059 */ 060 public JavaScriptErrorCollector ignore(JavaScriptErrorIgnoreRule... ignores) { 061 this.ignores.addAll(Arrays.asList(ignores)); 062 return this; 063 } 064 065 /** 066 * Throws an {@link AssertionError} when JavaScript errors are detected on current page. 067 */ 068 public void checkForErrors() { 069 if (driver == null) { 070 return; 071 } 072 073 List<JavaScriptError> jsErrors = JavaScriptError.readErrors(driver); 074 if (jsErrors != null && !jsErrors.isEmpty()) { 075 StringBuilder msg = new StringBuilder(); 076 int i = 0; 077 for (JavaScriptError jsError : jsErrors) { 078 // skip errors that match an ignored rule 079 if (ignores.stream().anyMatch(e -> e.isIgnored(jsError))) { 080 continue; 081 } 082 if (i != 0) { 083 msg.append(", "); 084 } 085 i++; 086 msg.append("\"").append(jsError.getErrorMessage()).append("\""); 087 msg.append(" at ").append(jsError.getSourceName()); 088 msg.append(" line ").append(jsError.getLineNumber()); 089 } 090 if (i > 0) { 091 msg.append("]"); 092 msg.insert(0, jsErrors.size() + " Javascript error(s) detected: " + "["); 093 fail(msg.toString()); 094 } 095 } 096 } 097 098 /** 099 * @since 9.3 100 */ 101 public static class JavaScriptErrorIgnoreRule { 102 protected String text = ""; 103 104 protected String source = ""; 105 106 protected JavaScriptErrorIgnoreRule(String text) { 107 this.text = text; 108 } 109 110 /** 111 * Ensure that error has to be ignored or not. 112 */ 113 protected boolean isIgnored(JavaScriptError error) { 114 if (error.getErrorMessage().startsWith(text)) { 115 return error.getSourceName().startsWith(source); 116 } 117 118 return false; 119 } 120 121 public JavaScriptErrorIgnoreRule withSource(String source) { 122 this.source = source; 123 return this; 124 } 125 126 public static JavaScriptErrorIgnoreRule startsWith(String text) { 127 return new JavaScriptErrorIgnoreRule(text); 128 } 129 130 public static JavaScriptErrorIgnoreRule fromSource(String source) { 131 return new JavaScriptErrorIgnoreRule("").withSource(source); 132 } 133 } 134}