diff --git a/.travis.yml b/.travis.yml index 5a28f29340a49b10579e8234725664ce74692e1c..0ade48a0fe60c7945dc67787859ede5bcd91ea5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,10 @@ env: - TEST_SUITE=PluginTests - TEST_SUITE=CoreTests - TEST_SUITE=IntegrationTests + #- TEST_DIR=UI global: secure: "AMhZmPZx4SUcuZRBzGHlQPxzM4D8FvFB3UThDa52gbi9KIBrwcumzV2VGi6B\n5fgjwtB4XTE1In7qhY2HMikPWBmWYYOQ5QcMPJsqqHt4iMmahx8WKzne6NOk\nNpqAuje/fulNGeP2LJZi0nrub3Fh4VwXaOvpNloKNQN/2JuqPtM=" - + # Run PHP 5.4 for aa tests to generate # code coverage. diff --git a/core/AssetManager.php b/core/AssetManager.php index 086f538a3f5933898fbf24b883b89b67f7301d9d..541157dc2f3decbe62680cacbe92fb3f413abdd5 100644 --- a/core/AssetManager.php +++ b/core/AssetManager.php @@ -284,6 +284,7 @@ class AssetManager 'plugins/Zeitgeist/stylesheets/', 'plugins/', 'plugins/Dashboard/stylesheets/dashboard.less', + 'tests/', ); return self::prioritySort($priorityCssOrdered, $cssFiles); @@ -380,6 +381,7 @@ class AssetManager 'plugins/Zeitgeist/javascripts/', 'plugins/CoreHome/javascripts/broadcast.js', 'plugins/', + 'tests/', ); return self::prioritySort($priorityJsOrdered, $jsFiles); diff --git a/core/DataTable/Filter/Limit.php b/core/DataTable/Filter/Limit.php index 5d751ddbc47532a16481fb165d747828a59a8c7d..e040244a0be7b9db6de6f60208ad0d15a2507476 100644 --- a/core/DataTable/Filter/Limit.php +++ b/core/DataTable/Filter/Limit.php @@ -29,14 +29,11 @@ class Limit extends Filter * @param int $limit Number of rows to keep (specify -1 to keep all rows) * @param bool $keepSummaryRow Whether to keep the summary row or not. */ - public function __construct($table, $offset, $limit = null, $keepSummaryRow = false) + public function __construct($table, $offset, $limit = -1, $keepSummaryRow = false) { parent::__construct($table); $this->offset = $offset; - if (is_null($limit)) { - $limit = -1; - } $this->limit = $limit; $this->keepSummaryRow = $keepSummaryRow; } diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php index a07f79054290453b2407011c32f9041111caca9d..533cef4bb2dedce2b34f8e3c800822c778801bb8 100644 --- a/core/ViewDataTable.php +++ b/core/ViewDataTable.php @@ -318,9 +318,6 @@ class ViewDataTable 'filter_excludelowpop_value', 'filter_pattern', 'filter_column', - 'filter_limit', - 'filter_sort_column', - 'filter_sort_order', ); if ($this->visualizationClass) { @@ -706,7 +703,13 @@ class ViewDataTable $requestArray['expanded'] = 1; } - $requestArray = array_merge($requestArray, $this->viewProperties['request_parameters_to_modify']); + $requestArray = array_merge($requestArray, $this->request_parameters_to_modify); + + if (!empty($requestArray['filter_limit']) + && $requestArray['filter_limit'] === 0 + ) { + unset($requestArray['filter_limit']); + } return $requestArray; } @@ -1060,10 +1063,6 @@ class ViewDataTable if (!PluginsManager::getInstance()->isPluginActivated('Goals')) { $this->viewProperties['show_goals'] = false; } - - if ($this->viewProperties['filter_limit'] == 0) { - $this->viewProperties['filter_limit'] = false; - } } protected function buildView() @@ -1105,12 +1104,132 @@ class ViewDataTable $view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet(); $view->clientSidePropertiesToSet = $this->getClientSidePropertiesToSet(); $view->properties = $this->viewProperties; // TODO: should be $this. need to move non-view properties from the class + $view->footerIcons = $this->getFooterIconsToShow(); - $nonCoreVisualizations = DataTableVisualization::getNonCoreVisualizations(); - $view->nonCoreVisualizations = DataTableVisualization::getVisualizationInfoFor($nonCoreVisualizations); $this->view = $view; } + private function getFooterIconsToShow() + { + $result = array(); + + // add normal view icons (eg, normal table, all columns, goals) + $normalViewIcons = array( + 'class' => 'tableAllColumnsSwitch', + 'buttons' => array(), + ); + + if ($this->show_table) { + $normalViewIcons['buttons'][] = array( + 'format' => 'table', + 'var' => 'table', + 'title' => Piwik_Translate('General_DisplaySimpleTable'), + 'icon' => 'plugins/Zeitgeist/images/table.png', + ); + } + + if ($this->show_table_all_columns) { + $normalViewIcons['buttons'][] = array( + 'format' => 'tableAllColumns', + 'var' => 'tableAllColumns', + 'title' => Piwik_Translate('General_DisplayTableWithMoreMetrics'), + 'icon' => 'plugins/Zeitgeist/images/table_more.png' + ); + } + + if ($this->show_goals) { + if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') { + $icon = 'plugins/Zeitgeist/images/ecommerceOrder.gif'; + } else { + $icon = 'plugins/Zeitgeist/images/goal.png'; + } + + $normalViewIcons['buttons'][] = array( + 'format' => 'tableGoals', + 'var' => 'tableGoals', + 'title' => Piwik_Translate('General_DisplayTableWithGoalMetrics'), + 'icon' => $icon + ); + } + + if ($this->show_ecommerce) { + $normalViewIcons['buttons'][] = array( + 'format' => 'ecommerceOrder', + 'var' => 'ecommerceOrder', + 'title' => Piwik_Translate('General_EcommerceOrders'), + 'icon' => 'plugins/Zeitgeist/images/ecommerceOrder.gif', + 'text' => Piwik_Translate('General_EcommerceOrders') + ); + + $normalViewIcons['buttons'][] = array( + 'format' => 'ecommerceAbandonedCart', + 'var' => 'ecommerceAbandonedCart', + 'title' => Piwik_Translate('General_AbandonedCarts'), + 'icon' => 'plugins/Zeitgeist/images/ecommerceAbandonedCart.gif', + 'text' => Piwik_Translate('General_AbandonedCarts') + ); + } + + if (!empty($normalViewIcons['buttons'])) { + $result[] = $normalViewIcons; + } + + // add graph views + $graphViewIcons = array( + 'class' => 'tableGraphViews tableGraphCollapsed', + 'buttons' => array(), + ); + + if ($this->show_all_views_icons) { + if ($this->show_bar_chart) { + $graphViewIcons['buttons'][] = array( + 'format' => 'graphVerticalBar', + 'var' => 'graphVerticalBar', // TODO: is var actually used anywhere? + 'title' => Piwik_Translate('General_VBarGraph'), + 'icon' => 'plugins/Zeitgeist/images/chart_bar.png' + ); + } + + if ($this->show_pie_chart) { + $graphViewIcons['buttons'][] = array( + 'format' => 'graphPie', + 'var' => 'graphPie', + 'title' => Piwik_Translate('General_Piechart'), + 'icon' => 'plugins/Zeitgeist/images/chart_pie.png' + ); + } + + if ($this->show_tag_cloud) { + $graphViewIcons['buttons'][] = array( + 'format' => 'cloud', + 'var' => 'cloud', + 'title' => Piwik_Translate('General_TagCloud'), + 'icon' => 'plugins/Zeitgeist/images/tagcloud.png' + ); + } + + if ($this->show_non_core_visualizations) { + $nonCoreVisualizations = DataTableVisualization::getNonCoreVisualizations(); + $nonCoreVisualizationInfo = DataTableVisualization::getVisualizationInfoFor($nonCoreVisualizations); + + foreach ($nonCoreVisualizationInfo as $format => $info) { + $graphViewIcons['buttons'][] = array( + 'format' => $format, + 'var' => $format, + 'title' => Piwik_Translate($info['title']), + 'icon' => $info['icon'] + ); + } + } + } + + if (!empty($graphViewIcons['buttons'])) { + $result[] = $graphViewIcons; + } + + return $result; + } + public function getDefaultDataTableCssClass() { return 'dataTableViz' . Piwik::getUnnamespacedClassName($this->visualizationClass); @@ -1141,4 +1260,4 @@ class ViewDataTable { return is_bool($value) ? (int)$value : $value; } -} +} \ No newline at end of file diff --git a/core/Visualization/Graph.php b/core/Visualization/Graph.php index 45f328bed45f6d8c55a829b60fd881140bd2aa5b..efd9d27a3409d1d4374838a4506b0b0d71e876d5 100644 --- a/core/Visualization/Graph.php +++ b/core/Visualization/Graph.php @@ -79,6 +79,13 @@ abstract class Graph extends DataTableVisualization $view->translations['nb_conversions'] = Piwik_Translate('Goals_ColumnConversions'); $view->translations['revenue'] = Piwik_Translate('General_TotalRevenue'); } + + $view->request_parameters_to_modify['filter_limit'] = false; + $view->request_parameters_to_modify['filter_offset'] = false; + + if ($view->visualization_properties->max_graph_elements) { + $view->request_parameters_to_modify['filter_truncate'] = $view->visualization_properties->max_graph_elements - 1; + } } public static function getDefaultPropertyValues() diff --git a/plugins/Annotations/stylesheets/annotations.less b/plugins/Annotations/stylesheets/annotations.less index 6de537dc9d1dd8d988d46cd1209b79e677fcf4d0..3a01ca398d60ae093ff04588298a1acd90337387 100755 --- a/plugins/Annotations/stylesheets/annotations.less +++ b/plugins/Annotations/stylesheets/annotations.less @@ -9,6 +9,7 @@ .evolution-annotations > span { position: absolute; + top:10px; } .annotation-manager { diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js index 7b0a3bfe240be23dc7a6c2b8ac74c8022a66c89d..761404efbd3a15df8e9ff394341ad69c6b0423d4 100644 --- a/plugins/CoreHome/javascripts/broadcast.js +++ b/plugins/CoreHome/javascripts/broadcast.js @@ -394,16 +394,13 @@ var broadcast = { } } - var ajaxRequest = { - type: 'POST', - url: urlAjax, - dataType: 'html', - async: true, - error: broadcast.customAjaxHandleError, // Callback when the request fails - success: sectionLoaded, // Callback when the request succeeds - data: {} - }; - globalAjaxQueue.push($.ajax(ajaxRequest)); + var ajax = new ajaxHelper(); + ajax.setUrl(urlAjax); + ajax.setErrorCallback(broadcast.customAjaxHandleError); + ajax.setCallback(sectionLoaded); + ajax.setFormat('html'); + ajax.send(); + return false; }, diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js index 05fa11b55bef18a6973ba92806b966d1cd36bc6c..6831a6a215d61c1a1cec9ca26fdf2c94f55138d0 100644 --- a/plugins/CoreHome/javascripts/dataTable.js +++ b/plugins/CoreHome/javascripts/dataTable.js @@ -714,8 +714,6 @@ dataTable.prototype = // we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30 // this value is stored in config file General->datatable_default_limit but this is more an edge case so ok to set it to 10 - self.setActiveIcon(this, domElem); - var viewDataTable = $(this).attr('format'); self.param.viewDataTable = viewDataTable; @@ -735,7 +733,6 @@ dataTable.prototype = $('.tableGraphViews a', domElem) .click(function () { var viewDataTable = $(this).attr('format'); - self.setActiveIcon(this, domElem); var filters = self.resetAllFilters(); self.param.flat = filters.flat; @@ -778,8 +775,7 @@ dataTable.prototype = $(this).show('fast', function () {self.graphViewStartingThreads--}); } else if (self.graphViewEnabled) { - //set footer arrow position - $('.dataTableFooterActiveItem', domElem).animate({left: $(this).parent().position().left + i * (this.offsetWidth + 1)}, "fast", function () {self.graphViewStartingThreads--}); + self.graphViewStartingThreads--; } }); self.exportToFormatHide(domElem); @@ -792,10 +788,6 @@ dataTable.prototype = //hide other icons $(this).hide('fast'); } - else if (self.graphViewEnabled) { - //set footer arrow position - $('.dataTableFooterActiveItem', domElem).animate({left: $(this).parent().position().left}, "fast"); - } }); $(this).removeClass('tableIconsGroupActive'); } @@ -805,7 +797,7 @@ dataTable.prototype = self.exportToFormat = null; $('.exportToFormatIcons a', domElem).click(function () { self.exportToFormat = {}; - self.exportToFormat.lastActiveIcon = self.setActiveIcon(this, domElem); + self.exportToFormat.lastActiveIcon = this; self.exportToFormat.target = $(this).parent().siblings('.exportToFormatItems').show('fast'); self.exportToFormat.obj = $(this).hide(); }); @@ -892,12 +884,6 @@ dataTable.prototype = return str; } ); - - // Initialize arrow footer to correct icon - $('.dataTableFooterWrap a.tableIcon', domElem).each(function () { - if (self.jsViewDataTable == $(this).attr('var')) self.setActiveIcon(this, domElem); - }); - }, exportToFormatHide: function (domElem, noAnimation) { @@ -1060,30 +1046,6 @@ dataTable.prototype = } }, - //footer arrow position handler - setActiveIcon: function (obj, domElem) { - if (!obj) return false; - - var lastActiveIcon = this.lastActiveIcon; - - if (lastActiveIcon) { - $(lastActiveIcon).removeClass("activeIcon"); - } - - $(obj).addClass("activeIcon"); - this.lastActiveIcon = obj; - - var target = $('.dataTableFooterActiveItem', domElem); - - //set arrow position with delay (for ajax widget loading) - setTimeout(function () { - target.css({left: $(obj).position().left}); - }, 100); - - return lastActiveIcon; - - }, - // Tell parent widget that the parameters of this table was updated, notifyWidgetParametersChange: function (domWidget, parameters) { var widget = $(domWidget).parents('[widgetId]'); @@ -1603,7 +1565,6 @@ actionDataTable.prototype = onClickSort: dataTable.prototype.onClickSort, truncate: dataTable.prototype.truncate, handleOffsetInformation: dataTable.prototype.handleOffsetInformation, - setActiveIcon: dataTable.prototype.setActiveIcon, resetAllFilters: dataTable.prototype.resetAllFilters, restoreAllFilters: dataTable.prototype.restoreAllFilters, exportToFormatHide: dataTable.prototype.exportToFormatHide, diff --git a/plugins/CoreHome/stylesheets/coreHome.less b/plugins/CoreHome/stylesheets/coreHome.less index 2c82ad95b4f7a91c9bc3e0e275f4cf1326a1fa8b..71a130f9996a7baaada5a83e5befbcab0a801112 100644 --- a/plugins/CoreHome/stylesheets/coreHome.less +++ b/plugins/CoreHome/stylesheets/coreHome.less @@ -40,7 +40,6 @@ h3 { .pageWrap { border-left: 1px solid #DDDDDD; border-right: 1px solid #DDDDDD; - max-height: 681px; min-height: 10px; overflow: visible; padding: 15px 15px 0; diff --git a/plugins/CoreHome/stylesheets/dataTable/_dataTable.less b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less index 6083dd1ccaf8d13a163b2b6546391ba36393e50a..4b2cd407d0ff6b4e156b2cbf871b9cb1d26fc72d 100644 --- a/plugins/CoreHome/stylesheets/dataTable/_dataTable.less +++ b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less @@ -286,6 +286,11 @@ table.dataTable img { background: #e9e8e1; } +.tableIconsGroup > span > span { + position:relative; + float:left; +} + .dataTableFooterActiveItem { position: absolute; top: -6px; diff --git a/plugins/CoreHome/templates/_dataTableFooter.twig b/plugins/CoreHome/templates/_dataTableFooter.twig index 3a800944c99a5c9c5682274777cab3757afd7463..1655c5d18e35bbb84029552121e7c597bf97bf41 100644 --- a/plugins/CoreHome/templates/_dataTableFooter.twig +++ b/plugins/CoreHome/templates/_dataTableFooter.twig @@ -26,68 +26,27 @@ {% if properties.show_footer_icons %} <div class="dataTableFooterIcons"> <div class="dataTableFooterWrap" var="{{ javascriptVariablesToSet.viewDataTable }}"> - {% if properties.show_active_view_icon %} - <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/> - {% endif %} + {% for footerIconGroup in footerIcons %} <div class="tableIconsGroup"> - <span class="tableAllColumnsSwitch"> - {% if properties.show_table %} - <a class="tableIcon" format="table" var="table"> - <img title="{{ 'General_DisplaySimpleTable'|translate }}" src="plugins/Zeitgeist/images/table.png"/> - </a> - {% endif %} - {% if properties.show_table_all_columns %} - <a class="tableIcon" format="tableAllColumns" var="tableAllColumns"> - <img title="{{ 'General_DisplayTableWithMoreMetrics'|translate }}" src="plugins/Zeitgeist/images/table_more.png"/> - </a> - {% endif %} - {% if properties.show_goals %} - <a class="tableIcon" format="tableGoals" var="tableGoals"> - <img title="{{ 'General_DisplayTableWithGoalMetrics'|translate }}" - src="plugins/Zeitgeist/images/{% if javascriptVariablesToSet.idGoal is defined and javascriptVariablesToSet.idGoal=='ecommerceOrder' %}ecommerceOrder.gif{% else %}goal.png{% endif %}"/> - </a> - {% endif %} - {% if properties.show_ecommerce %} - <a class="tableIcon" format="ecommerceOrder" var="ecommerceOrder"> - <img title="{{ 'General_EcommerceOrders'|translate }}" src="plugins/Zeitgeist/images/ecommerceOrder.gif" /> - <span>{{ 'General_EcommerceOrders'|translate }}</span> - </a> - <a class="tableIcon" format="ecommerceAbandonedCart" var="ecommerceAbandonedCart"> - <img title="{{ 'General_AbandonedCarts'|translate }}" src="plugins/Zeitgeist/images/ecommerceAbandonedCart.gif" /> - <span>{{ 'General_AbandonedCarts'|translate }}</span> - </a> - {% endif %} - </span> + <span class="{{ footerIconGroup.class }}"> + {% for footerIcon in footerIconGroup.buttons %} + <span> + {% if properties.show_active_view_icon and javascriptVariablesToSet.viewDataTable == footerIcon.format %} + <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/> + {% endif %} + <a class="tableIcon {% if javascriptVariablesToSet.viewDataTable == footerIcon.format %}activeIcon{% endif %}" format="{{ footerIcon.format }}" var="{{ footerIcon.var }}"> + <img width="16" height="16" title="{{ footerIcon.title }}" src="{{ footerIcon.icon }}"/> + {% if footerIcon.text is defined %}<span>{{ footerIcon.text }}</span>{% endif %} + </a> + </span> + {% endfor %} + </span> </div> - {% if properties.show_all_views_icons %} + {% endfor %} <div class="tableIconsGroup"> - <span class="tableGraphViews tableGraphCollapsed"> - {% if properties.show_bar_chart %} - <a class="tableIcon" format="graphVerticalBar" var="graphVerticalBar"> - <img width="16" height="16" src="plugins/Zeitgeist/images/chart_bar.png" title="{{ 'General_VBarGraph'|translate }}"/> - </a> - {% endif %} - {% if properties.show_pie_chart %} - <a class="tableIcon" format="graphPie" var="graphPie"> - <img width="16" height="16" src="plugins/Zeitgeist/images/chart_pie.png" title="{{ 'General_Piechart'|translate }}"/> - </a> - {% endif %} - {% if properties.show_tag_cloud %} - <a class="tableIcon" format="cloud" var="cloud"> - <img width="16" height="16" src="plugins/Zeitgeist/images/tagcloud.png" title="{{ 'General_TagCloud'|translate }}"/> - </a> - {% endif %} - {% if properties.show_non_core_visualizations %} - {% for format, info in nonCoreVisualizations %} - <a class="tableIcon" format="{{ format }}" var="{{ format }}"> - <img width="16" height="16" src="{{ info.table_icon }}" title="{{ info.title|translate }}"/> - </a> - {% endfor %} + {% if footerIcons is empty %} + <img src="plugins/Zeitgeist/images/data_table_footer_active_item.png" class="dataTableFooterActiveItem"/> {% endif %} - </span> - </div> - {% endif %} - <div class="tableIconsGroup"> <span class="exportToFormatIcons"> <a class="tableIcon" var="export"> <img width="16" height="16" src="plugins/Zeitgeist/images/export.png" title="{{ 'General_ExportThisReport'|translate }}"/> diff --git a/plugins/CoreVisualizations/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php index 9642aabf1b256acc217e8f87de0c744878bf9b38..6de29e226b43867d5180eadabb827aed5373ca25 100644 --- a/plugins/CoreVisualizations/JqplotDataGenerator.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator.php @@ -83,16 +83,6 @@ class JqplotDataGenerator */ public function generate($dataTable) { - if (!empty($this->properties['visualization_properties']->max_graph_elements)) { - $offsetStartSummary = $this->properties['visualization_properties']->max_graph_elements - 1; - $sortColumn = !empty($this->properties['filter_sort_column']) - ? $this->properties['filter_sort_column'] - : Metrics::INDEX_NB_VISITS; - - $dataTable->filter( - 'AddSummaryRow', array($offsetStartSummary, Piwik_Translate('General_Others'), $sortColumn)); - } - if ($dataTable->getRowsCount() > 0) { // if addTotalRow was called in GenerateGraphHTML, add a row containing totals of // different metrics diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php index 614721b686bba328444540c8192cbad9eb3d3d05..e7c86e6b0561c96a5d4f81875c3e9f586f7abcf4 100644 --- a/plugins/CoreVisualizations/Visualizations/HtmlTable.php +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php @@ -87,6 +87,9 @@ class HtmlTable extends DataTableVisualization static public $clientSideParameters = array( 'search_recursive', + 'filter_limit', + 'filter_sort_column', + 'filter_sort_order', ); static public $clientSideProperties = array( diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php index 567eb00571a13a6028944075266d1458e9f5cfef..71a9ef9b2c84c08042c4e9f323725f9a6aee450a 100644 --- a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php @@ -46,13 +46,8 @@ class JqplotGraph extends Graph */ public function __construct($view) { - // Graphs require the full dataset, so no filters - $this->request_parameters_to_modify['disable_generic_filters'] = true; + parent::__construct($view); - // the queued filters will be manually applied later. This is to ensure that filtering using search - // will be done on the table before the labels are enhanced (see ReplaceColumnNames) - $this->request_parameters_to_modify['disable_queued_filters'] = true; - // do not sort if sorted column was initially "label" or eg. it would make "Visits by Server time" not pretty if ($view->filter_sort_column != 'label') { $columns = $view->columns_to_display; diff --git a/plugins/Zeitgeist/javascripts/ajaxHelper.js b/plugins/Zeitgeist/javascripts/ajaxHelper.js index f12d451bbe8f7bdf32ee5b1f106b6bd25ddf7a8d..b3915f589730af547f1ecba73f3bd5f9a73821db 100644 --- a/plugins/Zeitgeist/javascripts/ajaxHelper.js +++ b/plugins/Zeitgeist/javascripts/ajaxHelper.js @@ -11,19 +11,32 @@ * @type {Array} array holding XhrRequests with automatic cleanup */ var globalAjaxQueue = []; +globalAjaxQueue.active = 0; /** - * Extend Array.push with automatic cleanup for finished requests - * - * @return {Object} + * Removes all finished requests from the queue. + * + * @return {void} */ -globalAjaxQueue.push = function () { - // cleanup ajax queue +globalAjaxQueue.clean = function () { for (var i = this.length; i--;) { if (!this[i] || this[i].readyState == 4) { this.splice(i, 1); } } +}; + +/** + * Extend Array.push with automatic cleanup for finished requests + * + * @return {Object} + */ +globalAjaxQueue.push = function () { + this.active += arguments.length; + + // cleanup ajax queue + this.clean(); + // call original array push return Array.prototype.push.apply(this, arguments); }; @@ -40,6 +53,8 @@ globalAjaxQueue.abort = function () { } // remove all elements from array this.splice(0, this.length); + + this.active = 0; }; /** @@ -85,6 +100,13 @@ function ajaxHelper() { */ this.getParams = {}; + /** + * Base URL used in the AJAX request. Can be set by setUrl. + * @type {String} + * @see ajaxHelper.setUrl + */ + this.getUrl = 'index.php?'; + /** * Params to be passed as GET params * @type {Object} @@ -119,6 +141,10 @@ function ajaxHelper() { * @return {void} */ this.addParams = function (params, type) { + if (typeof params == 'string') { + params = broadcast.getValuesFromUrl(params); + } + for (var key in params) { if(type.toLowerCase() == 'get') { this.getParams[key] = params[key]; @@ -128,6 +154,15 @@ function ajaxHelper() { } }; + /** + * Sets the base URL to use in the AJAX request. + * + * @param {string} url + */ + this.setUrl = function (url) { + this.getUrl = url; + }; + /** * Gets this helper instance ready to send a bulk request. Each argument to this * function is a single request to use. @@ -300,7 +335,10 @@ function ajaxHelper() { var parameters = this._mixinDefaultGetParams(this.getParams); - var url = 'index.php?'; + var url = this.getUrl; + if (url[url.length - 1] != '?') { + url += '&'; + } // we took care of encoding &segment properly already, so we don't use $.param for it ($.param URL encodes the values) if(parameters['segment']) { @@ -328,10 +366,17 @@ function ajaxHelper() { $(that.errorElement).html(response.message).fadeIn(); piwikHelper.lazyScrollTo(that.errorElement, 250); } - return; + } else { + that.callback(response); } - that.callback(response); + --globalAjaxQueue.active; + var piwik = window.piwik; + if (piwik + && piwik.ajaxRequestFinished + ) { + piwik.ajaxRequestFinished(); + } }, data: this._mixinDefaultPostParams(this.postParams) }; diff --git a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html index f93a03e8e899551a6dfe14d417c9f2b086d4c013..177fbdd63a1c247acec24ae327c8fd9ff1b4b279 100644 --- a/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html +++ b/tests/PHPUnit/Integration/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__PDFReports.generateReport_month.original.html @@ -291,7 +291,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Website @@ -374,7 +374,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitsSummary_get" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -383,7 +383,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Name @@ -452,7 +452,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -461,7 +461,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Server time @@ -1041,7 +1041,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitTime_getVisitInformationPerLocalTime" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -1050,7 +1050,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Local time @@ -1630,7 +1630,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitTime_getByDayOfWeek" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -1639,7 +1639,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Day of the week @@ -1828,7 +1828,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_get" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -1837,7 +1837,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Name @@ -1922,7 +1922,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getPageUrls" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -1931,7 +1931,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page URL @@ -2059,7 +2059,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getEntryPageUrls" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2068,7 +2068,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page URL @@ -2119,7 +2119,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getExitPageUrls" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2128,7 +2128,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page URL @@ -2179,7 +2179,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getPageTitles" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2188,7 +2188,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page Name @@ -2308,7 +2308,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getEntryPageTitles" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2317,7 +2317,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page Name @@ -2364,7 +2364,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getExitPageTitles" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2373,7 +2373,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Page Name @@ -2420,7 +2420,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Actions_getOutlinks" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2439,7 +2439,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Referrer Type @@ -2513,7 +2513,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Referers_getAll" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2522,7 +2522,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Referrer @@ -2573,7 +2573,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Referers_getKeywords" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2587,7 +2587,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Website @@ -2638,7 +2638,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Referers_getSearchEngines" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2662,7 +2662,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Name @@ -2707,7 +2707,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Goals_getVisitsUntilConversion" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2726,7 +2726,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Country @@ -2779,7 +2779,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserCountry_getContinent" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2788,7 +2788,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Continent @@ -2839,7 +2839,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserCountry_getRegion" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2848,7 +2848,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Region @@ -2901,7 +2901,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserCountry_getCity" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2910,7 +2910,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> City @@ -2963,7 +2963,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="CustomVariables_getCustomVariables" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -2977,7 +2977,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Visit duration @@ -3070,7 +3070,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3079,7 +3079,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Pages per visit @@ -3172,7 +3172,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3181,7 +3181,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Visits by Visit Number @@ -3351,7 +3351,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3360,7 +3360,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Visits by days since last visit @@ -3493,7 +3493,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="VisitFrequency_get" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3502,7 +3502,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Name @@ -3563,7 +3563,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="Provider_getProvider" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3572,7 +3572,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Provider @@ -3625,7 +3625,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getType" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3634,7 +3634,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Device type @@ -3687,7 +3687,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getBrand" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3696,7 +3696,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Device brand @@ -3749,7 +3749,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getModel" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3758,7 +3758,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Device model @@ -3809,7 +3809,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getOsFamilies" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3818,7 +3818,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Operating System families @@ -3871,7 +3871,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getOsVersions" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3880,7 +3880,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Operating System versions @@ -3933,7 +3933,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getBrowserFamilies" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -3942,7 +3942,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Browsers families @@ -4020,7 +4020,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4029,7 +4029,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Browser versions @@ -4107,7 +4107,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getResolution" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4116,7 +4116,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Resolution @@ -4190,7 +4190,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getBrowser" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4199,7 +4199,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Browser @@ -4277,7 +4277,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getBrowserVersion" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4286,7 +4286,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Browser version @@ -4364,7 +4364,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getBrowserType" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4373,7 +4373,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Browser family @@ -4447,7 +4447,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getPlugin" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4456,7 +4456,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Plugin @@ -4602,7 +4602,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getWideScreen" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4611,7 +4611,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Type of screen @@ -4689,7 +4689,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getOS" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4698,7 +4698,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Operating system @@ -4751,7 +4751,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getConfiguration" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4760,7 +4760,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Configuration @@ -4834,7 +4834,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getOSFamily" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4843,7 +4843,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Operating system family @@ -4896,7 +4896,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getMobileVsDesktop" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4905,7 +4905,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Mobile vs Desktop @@ -4983,7 +4983,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> <h2 id="UserSettings_getLanguage" style="color: rgb(126,115,99); font-size: 11pt;"> @@ -4992,7 +4992,7 @@ - <table style="border-collapse:collapse; margin-left: 5px"> + <table style="border-collapse:collapse; margin-left: 5px;"> <thead style="background-color: rgb(228,226,215); color: rgb(37,87,146); font-size: 11pt;"> <th style="padding: 6px 0;"> Language @@ -5043,7 +5043,7 @@ </tbody> </table> <br/> - <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt" href="#reportTop"> + <a style="text-decoration:none; color: rgb(126,115,99); font-size: 9pt;" href="#reportTop"> Back to top </a> </body> diff --git a/tests/PHPUnit/IntegrationTestCase.php b/tests/PHPUnit/IntegrationTestCase.php index cfcf72c5810d4caa6171e8ae74cea45f24b5d317..ed567452ae9aedeaf8b2ce2125be7af0d5581b17 100755 --- a/tests/PHPUnit/IntegrationTestCase.php +++ b/tests/PHPUnit/IntegrationTestCase.php @@ -635,7 +635,7 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase $abandonedCarts = false, $idGoal = false, $apiModule = false, $apiAction = false, $otherRequestParameters = array(), $supertableApi = false, $fileExtension = false) { - list($pathProcessed, $pathExpected) = $this->getProcessedAndExpectedDirs(); + list($pathProcessed, $pathExpected) = self::getProcessedAndExpectedDirs(); if ($periods === false) { $periods = 'day'; @@ -866,9 +866,9 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase return $input; } - protected function getProcessedAndExpectedDirs() + protected static function getProcessedAndExpectedDirs() { - $path = $this->getPathToTestDirectory(); + $path = self::getPathToTestDirectory(); return array($path . '/processed/', $path . '/expected/'); } @@ -879,7 +879,7 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase $filename .= ".$format"; } - list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs(); + list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs(); return array($processedDir . $filename, $expectedDir . $filename); } @@ -1062,9 +1062,9 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase } /** - * Path where expected/processed output files are stored. Can be overridden. + * Path where expected/processed output files are stored. */ - public function getPathToTestDirectory() + public static function getPathToTestDirectory() { return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Integration'; } diff --git a/tests/PHPUnit/Plugins/SegmentEditorTest.php b/tests/PHPUnit/Plugins/SegmentEditorTest.php index 696f19bcbc333017fe6aaecc2feecfdca86b3af6..12f7cc713856dcd5a5953dea49e6b79ef087983c 100644 --- a/tests/PHPUnit/Plugins/SegmentEditorTest.php +++ b/tests/PHPUnit/Plugins/SegmentEditorTest.php @@ -140,6 +140,11 @@ class SegmentEditorTest extends DatabaseTestCase ); $newSegment = API::getInstance()->get($idSegment2); + + // avoid test failures for when ts_created/ts_last_edit are different by between 1/2 secs + $this->removeSecondsFromSegmentInfo($updatedSegment); + $this->removeSecondsFromSegmentInfo($newSegment); + $this->assertEquals($newSegment, $updatedSegment); // Check the other segmenet was not updated @@ -164,4 +169,14 @@ class SegmentEditorTest extends DatabaseTestCase // and this should work API::getInstance()->get($idSegment1); } + + private function removeSecondsFromSegmentInfo(&$segmentInfo) + { + $timestampProperties = array('ts_last_edit', 'ts_created'); + foreach ($timestampProperties as $propertyName) { + if (isset($segmentInfo[$propertyName])) { + $segmentInfo[$propertyName] = substr($segmentInfo[$propertyName], 0, strlen($segmentInfo[$propertyName] - 2)); + } + } + } } diff --git a/tests/PHPUnit/TestingEnvironment.php b/tests/PHPUnit/TestingEnvironment.php index 99d2822ef6fedd1c221d21aa41d2a07ceff5f9b7..171ce749010e84236265309f571760c22dcaed1a 100644 --- a/tests/PHPUnit/TestingEnvironment.php +++ b/tests/PHPUnit/TestingEnvironment.php @@ -23,5 +23,12 @@ class Piwik_TestingEnvironment Piwik_AddAction('FrontController.dispatch', function() { \Piwik\Plugins\CoreVisualizations\Visualizations\Cloud::$debugDisableShuffle = true; }); + Piwik_AddAction('AssetManager.getCssFiles', function(&$cssFiles) { + $cssFiles[] = 'tests/resources/screenshot-override/override.css'; + }); + Piwik_AddAction('AssetManager.getJsFiles', function(&$jsFiles) { + $jsFiles[] = 'tests/resources/screenshot-override/jquery.waitforimages.js'; + $jsFiles[] = 'tests/resources/screenshot-override/override.js'; + }); } } \ No newline at end of file diff --git a/tests/PHPUnit/UI/UIIntegrationTest.php b/tests/PHPUnit/UI/UIIntegrationTest.php index 7d63301b8e8d15669a6bd1b711e3f0f12d5583ca..b1b95e0df67f48f27ec1f0d99e32eaabe40d17cc 100644 --- a/tests/PHPUnit/UI/UIIntegrationTest.php +++ b/tests/PHPUnit/UI/UIIntegrationTest.php @@ -13,7 +13,7 @@ use Piwik\Plugins\VisitsSummary\API; /** * Tests UI code by grabbing screenshots of webpages and comparing with expected files. * - * Uses cutycapt. + * Uses slimerjs or phantomjs. * * TODO: * - allow instrumentation javascript to be injected before screenshot is taken (so we can, say, @@ -22,10 +22,9 @@ use Piwik\Plugins\VisitsSummary\API; class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase { const IMAGE_TYPE = 'png'; - const CUTYCAPT_DELAY = 1000; + const CAPTURE_PROGRAM = 'phantomjs'; public static $fixture = null; // initialized below class definition - private static $useXvfb = false; public static function createAccessInstance() { @@ -35,11 +34,18 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase public static function setUpBeforeClass() { - if (self::isXvfbAvailable()) { - self::$useXvfb = true; - } else if (!self::isCutyCaptAvailable()) { - self::markTestSkipped("cutycapt is not available, skipping UI integration tests. " - . "(install with 'sudo apt-get intsall cutycapt')"); + if (!self::isXvfbAvailable()) { + self::markTestSkipped("xvfb is not available, skipping UI integration tests. (install with 'sudo apt-get install xvfb')"); + } else if (self::CAPTURE_PROGRAM == 'slimerjs' + && !self::isSlimerJsAvailable() + ) { + self::markTestSkipped("slimerjs is not available, skipping UI integration tests. " + . "(install by downloading http://slimerjs.org/download.html)"); + } else if (self::CAPTURE_PROGRAM == 'phantomjs' + && !self::isPhantomJsAvailable() + ) { + self::markTestSkipped("phantomjs is not available, skipping UI integration tests. " + . "(install by downloading http://phantomjs.org/download.html)"); } parent::setUpBeforeClass(); @@ -48,10 +54,35 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase // launch archiving so tests don't run out of time API::getInstance()->get(self::$fixture->idSite, 'year', '2012-08-09'); + + // make sure processed & expected dirs exist + list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs(); + if (!is_dir($processedDir)) { + mkdir($processedDir); + } + if (!is_dir($expectedDir)) { + mkdir($expectedDir); + } + + // run slimerjs/phantomjs w/ all urls so we only invoke it once + $urls = array(); + foreach (self::getUrlsForTesting() as $testInfo) { + list($name, $urlQuery) = $testInfo; + + list($processedScreenshotPath, $expectedScreenshotPath) = self::getProcessedAndExpectedScreenshotPaths($name); + $urls[] = array($processedScreenshotPath, self::getProxyUrl() . $urlQuery); + } + + echo "Generating screenshots...\n"; + self::runCaptureProgram($urls); } public static function tearDownAfterClass() { + if (file_exists("C:\\nppdf32Log\\debuglog.txt")) { // remove slimerjs oddity + unlink("C:\\nppdf32Log\\debuglog.txt"); + } + if (!Zend_Registry::get('db')) { Piwik::createDatabaseObject(); } @@ -63,14 +94,6 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase { parent::setUp(); - list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs(); - if (!is_dir($processedDir)) { - mkdir($processedDir); - } - if (!is_dir($expectedDir)) { - mkdir($expectedDir); - } - if (!Zend_Registry::get('db')) { Piwik::createDatabaseObject(); } @@ -84,7 +107,7 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase \Zend_Registry::set('db', false); } - public function getUrlsForTesting() + public static function getUrlsForTesting() { $generalParams = 'idSite=1&period=week&date=2012-08-09'; $evolutionParams = 'idSite=1&period=day&date=2012-08-11&evolution_day_last_n=30'; @@ -196,33 +219,26 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase */ public function testUIUrl($name, $urlQuery) { - list($processedDir, $expectedDir) = $this->getProcessedAndExpectedDirs(); - - $processedScreenshotPath = $processedDir . "$name." . self::IMAGE_TYPE; - $expectedScreenshotPath = $expectedDir . "$name." . self::IMAGE_TYPE; - - // run cutycapt w/ url and output to /processed-ui-screenshots/$name.svg - $this->runCutyCapt($urlQuery, $processedScreenshotPath); + list($processedScreenshotPath, $expectedScreenshotPath) = self::getProcessedAndExpectedScreenshotPaths($name); // compare processed w/ expected $this->compareScreenshot($name, $expectedScreenshotPath, $processedScreenshotPath, $urlQuery); } - private function runCutyCapt($urlQuery, $processedPath) + private static function runCaptureProgram($urlInfo) { - $url = self::getProxyUrl() . $urlQuery; - - $cmd = "cutycapt --url=\"$url\" --out=\"$processedPath\" --min-width=1366 --delay=".self::CUTYCAPT_DELAY." 2>&1"; - if (self::$useXvfb) { - $cmd = 'xvfb-run --server-args="-screen 0, 1024x768x24" ' . $cmd; - } + file_put_contents(PIWIK_INCLUDE_PATH . '/tmp/urls.txt', json_encode($urlInfo)); + $cmd = self::CAPTURE_PROGRAM . " \"" . PIWIK_INCLUDE_PATH . "/tests/resources/screenshot-capture/capture.js\" 2>&1"; + $cmd = 'xvfb-run --server-args="-screen 0, 1024x768x24" ' . $cmd; exec($cmd, $output, $result); - - if ($result !== 0) { - throw new Exception("cutycapt failed: " . implode("\n", $output) . "\n\ncommand used: $cmd"); + $output = implode("\n", $output); + if ($result !== 0 + || strpos($output, "ERROR") !== false + ) { + echo self::CAPTURE_PROGRAM . " failed: " . $output . "\n\ncommand used: $cmd\n"; + throw new Exception("phantomjs failed"); } - return $output; } @@ -241,21 +257,40 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase $this->assertTrue($expected == $processed, "screenshot compare failed for '$processedPath'"); } - private static function isCutyCaptAvailable() + private static function isSlimerJsAvailable() { - exec("cutycapt --help 2>&1", $output, $result); - return $result === 0 || $result === 1; + return self::isProgramAvailable('slimerjs'); + } + + private static function isPhantomJsAvailable() + { + return self::isProgramAvailable('phantomjs'); } private static function isXvfbAvailable() { - exec("xvfb-run --help 2>&1", $output, $result); + return self::isProgramAvailable('xvfb-run'); + } + + private static function isProgramAvailable($name) + { + exec($name . ' --help 2>&1', $output, $result); return $result === 0 || $result === 1; } + + private static function getProcessedAndExpectedScreenshotPaths($name) + { + list($processedDir, $expectedDir) = self::getProcessedAndExpectedDirs(); + + $processedScreenshotPath = $processedDir . "$name." . self::IMAGE_TYPE; + $expectedScreenshotPath = $expectedDir . "$name." . self::IMAGE_TYPE; + + return array($processedScreenshotPath, $expectedScreenshotPath); + } - protected function getProcessedAndExpectedDirs() + protected static function getProcessedAndExpectedDirs() { - $path = $this->getPathToTestDirectory() . '/../UI'; + $path = self::getPathToTestDirectory() . '/../UI'; return array($path . '/processed-ui-screenshots/', $path . '/expected-ui-screenshots/'); } @@ -265,4 +300,4 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase } } -Test_Piwik_Integration_UIIntegrationTest::$fixture = new Test_Piwik_Fixture_ManySitesImportedLogsWithXssAttempts(); +Test_Piwik_Integration_UIIntegrationTest::$fixture = new Test_Piwik_Fixture_ManySitesImportedLogsWithXssAttempts(); \ No newline at end of file diff --git a/tests/resources/screenshot-capture/capture.js b/tests/resources/screenshot-capture/capture.js new file mode 100644 index 0000000000000000000000000000000000000000..34ac2f8068100e0bbb25dbb75566b31638ea5174 --- /dev/null +++ b/tests/resources/screenshot-capture/capture.js @@ -0,0 +1,126 @@ +var fs = require('fs'); +var app = typeof slimer === 'undefined' ? phantom : slimer; +var readFileSync = fs.readFileSync || fs.read; + +var PageRenderer = function() { + this.start = new Date(); + + this.urlIndex = 0; + this.urls = JSON.parse(readFileSync('../../tmp/urls.txt')); + + this.webpage = require('webpage').create(); + this.outputPath = ''; + this.url = ''; + + this._setupWebpageEvents(); + this._setScriptTimeout(); +}; + +PageRenderer.prototype = { + renderAll: function () { + this._saveCurrentUrl(); + }, + + _saveCurrentUrl: function () { + if (this.urlIndex >= this.urls.length) { + app.exit(); + return; + } + + this.outputPath = this.urls[this.urlIndex][0]; + this.url = this.urls[this.urlIndex][1]; + + console.log("SAVING " + this.url + " at " + this._getElapsedExecutionTime()); + + this.webpage.viewportSize = {width:1350, height:768}; + this.webpage.open(this.url); + + this._setPageTimeouts(); + }, + + _setPageTimeouts: function () { + var url = this.url, self = this; + this.webpage.onLoadFinished = function () { + // check that we're still on the same url + if (url != self.url) { + return; + } + + // in case there are no ajax requests, try triggering after a sec + setTimeout(function () { + if (url == self.url) { + self.webpage.evaluate(function () { + window.piwik.ajaxRequestFinished(); + }); + } + }, 1000) + + // only allowed at most one minute to load + setTimeout(function () { + if (url == self.url) { + self.webpage.evaluate(function () { + window.piwik._triggerRenderInsane(); + }); + } + }, 1000 * 60); + }; + }, + + _setupWebpageEvents: function () { + this.webpage.onError = function (message) { + console.log("Webpage error: " + message); + }; + + var self = this; + this.webpage.onConsoleMessage = function (message) { + if (message == "__AJAX_DONE__") { + try { + self._setCorrectViewportSize(); + self.webpage.render(self.outputPath); + + self._renderNextUrl(); + } catch (e) { + console.log("ERROR: " + e.message); + app.exit(1); + } + } else { + console.log("LOGGED: " + message); + } + }; + }, + + _renderNextUrl: function () { + ++this.urlIndex; + this._saveCurrentUrl(); + }, + + _setCorrectViewportSize: function () { + this.webpage.viewportSize = {width:1350, height:768}; + var height = Math.max(768, this.webpage.evaluate(function() { + return document.body.offsetHeight; + })); + this.webpage.viewportSize = {width:1350, height: height}; + }, + + _getElapsedExecutionTime: function () { + var now = new Date(), + elapsed = now.getTime() - this.start.getTime(); + + return (elapsed / 1000.0) + "s"; + }, + + _setScriptTimeout: function () { + setTimeout(function() { + console.log("ERROR: Timed out!"); + app.exit(1); + }, Math.max(1000 * 15 * this.urls.length, 1000 * 60 * 5)); + }, +}; + +try { + var renderer = new PageRenderer(); + renderer.renderAll(); +} catch (e) { + console.log("ERROR: " + e.message); + app.exit(1); +} \ No newline at end of file diff --git a/tests/resources/screenshot-override/jquery.waitforimages.js b/tests/resources/screenshot-override/jquery.waitforimages.js new file mode 100644 index 0000000000000000000000000000000000000000..eba523b8bb459fd2c380b0437c9ba90676a6709e --- /dev/null +++ b/tests/resources/screenshot-override/jquery.waitforimages.js @@ -0,0 +1,136 @@ +/*! waitForImages jQuery Plugin - v1.5.0 - 2013-07-20 +* https://github.com/alexanderdickson/waitForImages +* Copyright (c) 2013 Alex Dickson; Licensed MIT */ +;(function ($) { + // Namespace all events. + var eventNamespace = 'waitForImages'; + + // CSS properties which contain references to images. + $.waitForImages = { + hasImageProperties: ['backgroundImage', 'listStyleImage', 'borderImage', 'borderCornerImage', 'cursor'] + }; + + // Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded. + $.expr[':'].uncached = function (obj) { + // Ensure we are dealing with an `img` element with a valid `src` attribute. + if (!$(obj).is('img[src!=""]')) { + return false; + } + + // Firefox's `complete` property will always be `true` even if the image has not been downloaded. + // Doing it this way works in Firefox. + var img = new Image(); + img.src = obj.src; + return !img.complete; + }; + + $.fn.waitForImages = function (finishedCallback, eachCallback, waitForAll) { + + var allImgsLength = 0; + var allImgsLoaded = 0; + + // Handle options object. + if ($.isPlainObject(arguments[0])) { + waitForAll = arguments[0].waitForAll; + eachCallback = arguments[0].each; + // This must be last as arguments[0] + // is aliased with finishedCallback. + finishedCallback = arguments[0].finished; + } + + // Handle missing callbacks. + finishedCallback = finishedCallback || $.noop; + eachCallback = eachCallback || $.noop; + + // Convert waitForAll to Boolean + waitForAll = !! waitForAll; + + // Ensure callbacks are functions. + if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { + throw new TypeError('An invalid callback was supplied.'); + } + + return this.each(function () { + // Build a list of all imgs, dependent on what images will be considered. + var obj = $(this); + var allImgs = []; + // CSS properties which may contain an image. + var hasImgProperties = $.waitForImages.hasImageProperties || []; + // To match `url()` references. + // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri + var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; + + if (waitForAll) { + + // Get all elements (including the original), as any one of them could have a background image. + obj.find('*').addBack().each(function () { + var element = $(this); + + // If an `img` element, add it. But keep iterating in case it has a background image too. + if (element.is('img:uncached')) { + allImgs.push({ + src: element.attr('src'), + element: element[0] + }); + } + + $.each(hasImgProperties, function (i, property) { + var propertyValue = element.css(property); + var match; + + // If it doesn't contain this property, skip. + if (!propertyValue) { + return true; + } + + // Get all url() of this element. + while (match = matchUrl.exec(propertyValue)) { + allImgs.push({ + src: match[2], + element: element[0] + }); + } + }); + }); + } else { + // For images only, the task is simpler. + obj.find('img:uncached') + .each(function () { + allImgs.push({ + src: this.src, + element: this + }); + }); + } + + allImgsLength = allImgs.length; + allImgsLoaded = 0; + + // If no images found, don't bother. + if (allImgsLength === 0) { + finishedCallback.call(obj[0]); + } + + $.each(allImgs, function (i, img) { + + var image = new Image(); + + // Handle the image loading and error with the same callback. + $(image).on('load.' + eventNamespace + ' error.' + eventNamespace, function (event) { + allImgsLoaded++; + + // If an error occurred with loading the image, set the third argument accordingly. + eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load'); + + if (allImgsLoaded == allImgsLength) { + finishedCallback.call(obj[0]); + return false; + } + + }); + + image.src = img.src; + }); + }); + }; +}(jQuery)); diff --git a/tests/resources/screenshot-override/open_sans.woff b/tests/resources/screenshot-override/open_sans.woff new file mode 100644 index 0000000000000000000000000000000000000000..55b25f867099eb26c436b1c9fecff14a51290d46 Binary files /dev/null and b/tests/resources/screenshot-override/open_sans.woff differ diff --git a/tests/resources/screenshot-override/open_sans_b.woff b/tests/resources/screenshot-override/open_sans_b.woff new file mode 100644 index 0000000000000000000000000000000000000000..27619e7cea1c29f9d71567b78470fdd705c174dc Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_b.woff differ diff --git a/tests/resources/screenshot-override/open_sans_bi.woff b/tests/resources/screenshot-override/open_sans_bi.woff new file mode 100644 index 0000000000000000000000000000000000000000..e12c3a9f273c2f0e4952293bb852406c2ab1eb0a Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_bi.woff differ diff --git a/tests/resources/screenshot-override/open_sans_i.woff b/tests/resources/screenshot-override/open_sans_i.woff new file mode 100644 index 0000000000000000000000000000000000000000..cedefb8f6ff406c6b77e75ae55ee88e2bd88dc17 Binary files /dev/null and b/tests/resources/screenshot-override/open_sans_i.woff differ diff --git a/tests/resources/screenshot-override/override.css b/tests/resources/screenshot-override/override.css new file mode 100644 index 0000000000000000000000000000000000000000..8bc65e63d38884ded4d8af5e7fc6ef32b41d673f --- /dev/null +++ b/tests/resources/screenshot-override/override.css @@ -0,0 +1,28 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: url(tests/resources/screenshot-override/open_sans.woff) format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: url(tests/resources/screenshot-override/open_sans_b.woff) format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: url(tests/resources/screenshot-override/open_sans_i.woff) format('woff'); +} +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: url(tests/resources/screenshot-override/open_sans_bi.woff) format('woff'); +} + +* { + font-family: 'Open Sans'; +} \ No newline at end of file diff --git a/tests/resources/screenshot-override/override.js b/tests/resources/screenshot-override/override.js new file mode 100644 index 0000000000000000000000000000000000000000..c354d5ca132786ffb87ee854d9328b666db4c0cb --- /dev/null +++ b/tests/resources/screenshot-override/override.js @@ -0,0 +1,41 @@ +(function ($) { + + var DEBUG_LOGGING = true; + + if (DEBUG_LOGGING) { + var log = function(message) { + console.log(message); + }; + } else { + var log = function() {}; + } + + var triggerRenderInsane = function () { + console.log("__AJAX_DONE__"); + }; + + var triggerRender = function () { + if (window.globalAjaxQueue.active === 0) { // sanity check + triggerRenderInsane(); + } + }; + + var triggerRenderIfNoAjax = function () { + setTimeout(function () { // allow other javascript to execute in case they execute ajax/add images/set the src of images + if (window.globalAjaxQueue.active === 0) { + $('body').waitForImages({ + waitForAll: true, + finished: function () { + // wait some more to make sure other javascript is executed & the last image is rendered + setTimeout(triggerRender, 1000); + }, + }); + } + }, 1); + }; + + window.piwik = window.piwik || {}; + window.piwik.ajaxRequestFinished = triggerRenderIfNoAjax; + window.piwik._triggerRenderInsane = triggerRenderInsane; + +}(jQuery)); \ No newline at end of file diff --git a/tests/travis/prepare.sh b/tests/travis/prepare.sh index b45bbe7039f32c9e9dbf87274a1670f66b44a9cc..04f50f03548fe2dc4bb2b42844f9c66a88ef0107 100755 --- a/tests/travis/prepare.sh +++ b/tests/travis/prepare.sh @@ -4,6 +4,20 @@ set -e # Install XMLStarlet sudo apt-get install -qq xmlstarlet +# Install phantomjs 1.9.1 for UI tests +if [ "$TEST_DIR" = "UI" ]; +then + cd tmp + wget "https://phantomjs.googlecode.com/files/phantomjs-1.9.1-linux-x86_64.tar.bz2" -O phantomjs.tar.bz2 + tar xvjf phantomjs.tar.bz2 + cd phantomjs* + export PATH=$PATH:`pwd`/bin + cd ../.. + + echo "Using phantomjs version:" + phantomjs --version +fi + # Copy Piwik configuration echo "Install config.ini.php" cp ./tests/PHPUnit/config.ini.travis.php ./config/config.ini.php diff --git a/tests/travis/upload_artifacts.sh b/tests/travis/upload_artifacts.sh index 1d829c4ca5b0fd5ed26edd707ccc6a3d4fa4a0bb..84cbab9efeb33454e1bd385a15a36442d634ec51 100755 --- a/tests/travis/upload_artifacts.sh +++ b/tests/travis/upload_artifacts.sh @@ -1,16 +1,30 @@ -if [ "$TEST_SUITE" != "IntegrationTests" ]; +#!/bin/bash + +if [ "$TEST_SUITE" = "IntegrationTests" ]; then - echo "No artifacts for $TEST_SUITE tests."; - exit; -fi + url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER" + + echo "Uploading artifacts for $TEST_SUITE..." -url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER" + cd ./tests/PHPUnit/Integration -echo "Uploading artifacts for $TEST_SUITE..." + # upload processed tarball + tar -cjf processed.tar.bz2 processed --exclude='.gitkeep' + curl -X POST --data-binary @processed.tar.bz2 "$url" +else + if [ "$TEST_DIR" = "UI" ]; + then + url="http://builds-artifacts.piwik.org/upload.php?auth_key=$ARTIFACTS_PASS&artifact_name=processed-ui-screenshots&branch=$TRAVIS_BRANCH&build_id=$TRAVIS_JOB_NUMBER" -cd ./tests/PHPUnit/Integration + echo "Uploading artifacts for $TEST_DIR..." -# upload processed tarball -tar -cjf processed.tar.bz2 processed --exclude='.gitkeep' -curl -X POST --data-binary @processed.tar.bz2 "$url" + cd ./tests/PHPUnit/UI + # upload processed tarball + tar -cjf processed-ui-screenshots.tar.bz2 processed-ui-screenshots --exclude='.gitkeep' + curl -X POST --data-binary @processed-ui-screenshots.tar.bz2 "$url" + else + echo "No artifacts for $TEST_SUITE tests." + exit + fi +fi \ No newline at end of file