diff options
27 files changed, 314 insertions, 101 deletions
diff --git a/plugins/API/API.php b/plugins/API/API.php index f897145a1e..5a80d22478 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -413,9 +413,11 @@ class API extends \Piwik\Plugin\API * @param bool|string $legendAppendMetric * @param bool|string $labelUseAbsoluteUrl * @param bool|int $idDimension + * @param string $labelSeries + * @param string|int $showGoalMetricsForGoal * @return array */ - public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $idDimension = false, $labelSeries = false) + public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $idDimension = false, $labelSeries = false, $showGoalMetricsForGoal = false) { // check if site exists $idSite = (int) $idSite; @@ -443,7 +445,7 @@ class API extends \Piwik\Plugin\API $rowEvolution = new RowEvolution(); return $rowEvolution->getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $column, - $language, $apiParameters, $legendAppendMetric, $labelUseAbsoluteUrl, $labelSeries); + $language, $apiParameters, $legendAppendMetric, $labelUseAbsoluteUrl, $labelSeries, $showGoalMetricsForGoal); } /** diff --git a/plugins/API/RowEvolution.php b/plugins/API/RowEvolution.php index fe046e9ffb..1822d3e963 100644 --- a/plugins/API/RowEvolution.php +++ b/plugins/API/RowEvolution.php @@ -12,14 +12,20 @@ use Exception; use Piwik\API\DataTableManipulator\LabelFilter; use Piwik\API\DataTablePostProcessor; use Piwik\API\Request; +use Piwik\Cache; use Piwik\Common; use Piwik\DataTable; +use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal; use Piwik\DataTable\Filter\CalculateEvolutionFilter; use Piwik\DataTable\Filter\SafeDecodeLabel; use Piwik\DataTable\Row; use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\API\Filter\DataComparisonFilter; +use Piwik\Plugins\Goals\Columns\Metrics\GoalSpecific\ConversionRate; +use Piwik\Plugins\Goals\Columns\Metrics\GoalSpecific\Conversions; +use Piwik\Plugins\Goals\Columns\Metrics\GoalSpecific\Revenue; +use Piwik\Plugins\Goals\Columns\Metrics\GoalSpecific\RevenuePerVisit; use Piwik\Site; use Piwik\Url; @@ -29,15 +35,15 @@ use Piwik\Url; */ class RowEvolution { - private static $actionsUrlReports = array( + private static $actionsUrlReports = [ 'getPageUrls', 'getPageUrlsFollowingSiteSearch', 'getEntryPageUrls', 'getExitPageUrls', 'getPageUrl' - ); + ]; - public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $apiParameters = array(), $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $labelSeries = '') + public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $apiParameters = [], $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $labelSeries = '', $showGoalMetricsForGoal = false) { // validation of requested $period & $date if ($period == 'range') { @@ -54,10 +60,64 @@ class RowEvolution $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $apiParameters); - $dataTable = $this->loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $apiParameters); + // if goal metrics should be shown, we replace the metrics + if ($showGoalMetricsForGoal !== false) { + $metadata['metrics'] = [ + 'nb_visits' => $metadata['metrics']['nb_visits'], + ]; + + // Use ecommerce specific metrics / column names when only showing ecommerce metrics + if ($showGoalMetricsForGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { + $metadata['metrics']['goal_ecommerceOrder_nb_conversions'] = Piwik::translate('General_EcommerceOrders'); + $metadata['metrics']['goal_ecommerceOrder_revenue'] = Piwik::translate('General_TotalRevenue'); + $metadata['metrics']['goal_ecommerceOrder_conversion_rate'] = Piwik::translate('Goals_ConversionRate', Piwik::translate('General_EcommerceOrders')); + $metadata['metrics']['goal_ecommerceOrder_avg_order_revenue'] = Piwik::translate('General_AverageOrderValue'); + $metadata['metrics']['goal_ecommerceOrder_items'] = Piwik::translate('General_PurchasedProducts'); + $metadata['metrics']['goal_ecommerceOrder_revenue_per_visit'] = Piwik::translate('General_ColumnValuePerVisit'); + } else { + $goalsToProcess = $this->getGoalsToProcess($showGoalMetricsForGoal, $idSite); + + foreach ($goalsToProcess as $idGoal) { + if ($idGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { + + $metadata['metrics']['goal_ecommerceOrder_conversion_rate'] = Piwik::translate('Goals_ConversionRate', Piwik::translate('General_EcommerceOrders')); + + if ((int) $showGoalMetricsForGoal === AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW) { + // only conversion rate is used for goals overview + continue; + } + + $metadata['metrics']['goal_ecommerceOrder_nb_conversions'] = Piwik::translate('Goals_Conversions', Piwik::translate('General_EcommerceOrders')); + $metadata['metrics']['goal_ecommerceOrder_revenue'] = Piwik::translate('General_EcommerceOrders') . ' ' . Piwik::translate('General_ColumnRevenue'); + $metadata['metrics']['goal_ecommerceOrder_revenue_per_visit'] = Piwik::translate('General_EcommerceOrders') . ' ' . Piwik::translate('General_ColumnValuePerVisit'); + continue; + } + + $conversionRateMetric = new ConversionRate($idSite, $idGoal); + $metadata['metrics'][$conversionRateMetric->getName()] = $conversionRateMetric->getTranslatedName(); + + if ((int) $showGoalMetricsForGoal === AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW) { + // only conversion rate is used for goals overview + continue; + } + + $conversionsMetric = new Conversions($idSite, $idGoal); + $revenueMetric = new Revenue($idSite, $idGoal); + $revenuePerVisitMetric = new RevenuePerVisit($idSite, $idGoal); + + $metadata['metrics'][$conversionsMetric->getName()] = $conversionsMetric->getTranslatedName(); + $metadata['metrics'][$revenueMetric->getName()] = $revenueMetric->getTranslatedName(); + $metadata['metrics'][$revenuePerVisitMetric->getName()] = $revenuePerVisitMetric->getTranslatedName(); + } + + $metadata['metrics']['revenue_per_visit'] = Piwik::translate('General_ColumnValuePerVisit'); + } + } + + $dataTable = $this->loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $apiParameters, $showGoalMetricsForGoal); if (empty($dataTable->getDataTables())) { - return array(); + return []; } if (empty($labels)) { @@ -90,6 +150,44 @@ class RowEvolution return $data; } + protected function getGoalsToProcess($goalId, $idSite): array + { + switch ($goalId) { + case AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE: + case AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW: + return $this->getAllGoalIds($idSite); + case Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER: + default: + return [$goalId]; + } + } + + protected function getAllGoalIds($idSite): array + { + $cache = Cache::getTransientCache(); + $key = 'RowEvolution_allGoalIds_' . $idSite; + + if ($cache->contains($key)) { + return $cache->fetch($key); + } + + $goalIds = []; + + if (Site::isEcommerceEnabledFor($idSite)) { + $goalIds[] = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER; + } + + $siteGoals = Request::processRequest('Goals.getGoals', ['idSite' => $idSite, 'filter_limit' => '-1'], $default = []); + + foreach ($siteGoals as $goal) { + $goalIds[] = $goal['idgoal']; + } + + $cache->save($key, $goalIds); + + return $goalIds; + } + /** * @param array $labels * @param DataTable\Map $dataTable @@ -186,11 +284,11 @@ class RowEvolution $actualLabel = $this->formatQueryLabelForDisplay($idSite, $apiModule, $apiAction, $label); } - $return = array( + $return = [ 'label' => SafeDecodeLabel::decodeLabelSafe($actualLabel), 'reportData' => $dataTable, - 'metadata' => $metadata - ); + 'metadata' => $metadata, + ]; if (!empty($logo)) { $return['logo'] = $logo; } @@ -248,20 +346,20 @@ class RowEvolution * @param string $date * @param string $apiModule * @param string $apiAction - * @param string|bool $label + * @param string|bool|array $label * @param string|bool $segment * @param array $apiParameters * @throws Exception * @return DataTable\Map|DataTable */ - private function loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $apiParameters) + private function loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $apiParameters, $showGoalMetricsForGoal) { if (!is_array($label)) { - $label = array($label); + $label = [$label]; } $label = array_map('rawurlencode', $label); - $parameters = array( + $parameters = [ 'method' => $apiModule . '.' . $apiAction, 'label' => $label, 'idSite' => $idSite, @@ -277,7 +375,14 @@ class RowEvolution // row corresponds with which label (since the labels can change, and rows // can be sorted in a different order) 'labelFilterAddLabelIndex' => count($label) > 1 ? 1 : 0, - ); + ]; + + if ($showGoalMetricsForGoal !== false) { + $parameters['filter_show_goal_columns_process_goals'] = implode(',', $this->getGoalsToProcess($showGoalMetricsForGoal, $idSite)); + $parameters['filter_update_columns_when_show_all_goals'] = 1; + $parameters['idGoal'] = $showGoalMetricsForGoal; + } + if (!empty($apiParameters) && is_array($apiParameters)) { foreach ($apiParameters as $param => $value) { $parameters[$param] = $value; @@ -353,9 +458,9 @@ class RowEvolution private function enhanceRowEvolutionMetaData(&$metadata, $dataTable) { // prepare result array for metrics - $metricsResult = array(); + $metricsResult = []; foreach ($metadata['metrics'] as $metric => $name) { - $metricsResult[$metric] = array('name' => $name); + $metricsResult[$metric] = ['name' => $name]; if (!empty($metadata['logos'][$metric])) { $metricsResult[$metric]['logo'] = $metadata['logos'][$metric]; @@ -377,7 +482,7 @@ class RowEvolution $lastDataTableRow = $lastDataTable->getFirstRow(); // Process min/max values - $firstNonZeroFound = array(); + $firstNonZeroFound = []; foreach ($subDataTables as $subDataTable) { // $subDataTable is the report for one period, it has only one row $firstRow = $subDataTable->getFirstRow(); @@ -436,7 +541,7 @@ class RowEvolution } // get the processed label and logo (if any) for every requested label - $actualLabels = $logos = array(); + $actualLabels = $logos = []; foreach ($labels as $labelIdx => $label) { foreach ($dataTable->getDataTables() as $table) { $labelRow = $this->getRowEvolutionRowFromLabelIdx($table, $labelIdx); @@ -469,8 +574,8 @@ class RowEvolution } } - // convert rows to be array($column.'_'.$labelIdx => $value) as opposed to - // array('label' => $label, 'column' => $value). + // convert rows to be [$column.'_'.$labelIdx => $value] as opposed to + // ['label' => $label, 'column' => $value]. $dataTableMulti = $dataTable->getEmptyClone(); foreach ($dataTable->getDataTables() as $tableLabel => $table) { $newRow = new Row(); @@ -505,7 +610,7 @@ class RowEvolution // metadata / metrics should document the rows that are compared // this way, UI code can be reused - $metadata['metrics'] = array(); + $metadata['metrics'] = []; foreach ($actualLabels as $labelIndex => $label) { if ($legendAppendMetric) { $label .= ' (' . $metadata['columns'][$column] . ')'; @@ -520,11 +625,11 @@ class RowEvolution $this->enhanceRowEvolutionMetaData($metadata, $dataTableMulti); - return array( + return [ 'column' => $column, 'reportData' => $dataTableMulti, - 'metadata' => $metadata - ); + 'metadata' => $metadata, + ]; } /** @@ -551,8 +656,7 @@ class RowEvolution private function cleanOriginalLabel($label) { $label = str_replace(LabelFilter::SEPARATOR_RECURSIVE_LABEL, ' - ', $label); - $label = SafeDecodeLabel::decodeLabelSafe($label); - return $label; + return SafeDecodeLabel::decodeLabelSafe($label); } private function checkDataTableInstance($lastDataTable) diff --git a/plugins/CoreHome/javascripts/dataTable_rowactions.js b/plugins/CoreHome/javascripts/dataTable_rowactions.js index 5283944e32..2c95333d29 100644 --- a/plugins/CoreHome/javascripts/dataTable_rowactions.js +++ b/plugins/CoreHome/javascripts/dataTable_rowactions.js @@ -76,6 +76,11 @@ DataTable_RowActions_Registry.register({ if (dataTable === null && param) { // when row evolution is triggered from the url (not a click on the data table) // we look for the data table instance in the dom + // This actually doesn't work very good, as opening a row evolution using url params + // directly also triggers loading the report datatable, which might not yet be finished at + // this state, so the datatable might not yet be available + // When migrating/refactoring this it might be good to use promises in some way, so it would + // be possible to actually trigger the row evolution popover once the origin report was loaded. var report = param.split(':')[0]; var div = $(require('piwik/UI').DataTable.getDataTableByReport(report)); if (div.length && div.data('uiControlObject')) { @@ -316,11 +321,25 @@ DataTable_RowActions_RowEvolution.prototype.performAction = function (label, tr, $.each(this.dataTable.param, function (index, value) { // we automatically add fields like idDimension, idGoal etc. - if (index !== 'idSite' && index.indexOf('id') === 0 && $.isNumeric(value)) { + if (index !== 'idSite' && index.indexOf('id') === 0 && ($.isNumeric(value) || value.indexOf('ecommerce') === 0)) { extraParams[index] = value; } }); + if (this.dataTable && this.dataTable.jsViewDataTable === 'tableGoals') { + // When there is a idGoal parameter available, the user is currently viewing a Goal or Ecommerce page + // In this case we want to show the specific goal metrics in the row evolution + if (extraParams['idGoal']) { + extraParams['showGoalMetricsForGoal'] = extraParams['idGoal']; + delete(extraParams['idGoal']); + } + // If no idGoal is available it is a random report switched to goal visualization + // we then ensure the row evolution will show the goal overview metrics + else { + extraParams['showGoalMetricsForGoal'] = -1; + } + } + // check if abandonedCarts is in the dataTable params and if so, propagate to row evolution request if (this.dataTable.param.abandonedCarts !== undefined) { extraParams['abandonedCarts'] = this.dataTable.param.abandonedCarts; @@ -437,7 +456,7 @@ DataTable_RowActions_RowEvolution.prototype.showRowEvolution = function (apiMeth box.find('select.multirowevoltion-metric').change(function () { var metric = $(this).val(); Piwik_Popover.onClose(false); // unbind listener that resets multiEvolutionRows - var extraParams = {action: 'getMultiRowEvolutionPopover', column: metric}; + extraParams.column = metric; self.openPopover(apiMethod, extraParams, label); return true; }); @@ -463,13 +482,6 @@ DataTable_RowActions_RowEvolution.prototype.showRowEvolution = function (apiMeth } } - if (self.dataTable && self.dataTable.jsViewDataTable === 'tableGoals') { - // remove idGoal param, when it's set for goal visualizations - if (extraParams['idGoal']) { - delete(extraParams['idGoal']); - } - } - $.extend(requestParams, extraParams); var ajaxRequest = new ajaxHelper(); diff --git a/plugins/CoreHome/templates/getRowEvolutionPopover.twig b/plugins/CoreHome/templates/getRowEvolutionPopover.twig index 8b95dd680f..b45ce4f154 100644 --- a/plugins/CoreHome/templates/getRowEvolutionPopover.twig +++ b/plugins/CoreHome/templates/getRowEvolutionPopover.twig @@ -18,7 +18,7 @@ </td> <td class="text"> <span class="evolution-graph-colors" data-name="series{{ (i % seriesColorCount) + 1 }}"> - {{- metric.label|raw -}} + {{- metric.label|rawSafeDecoded -}} </span> {% if metric.details %}: <span class="details" title="{{ metric.minmax }}">{{ metric.details|raw }}</span> diff --git a/plugins/Goals/tests/UI/GoalsPages_spec.js b/plugins/Goals/tests/UI/GoalsPages_spec.js new file mode 100644 index 0000000000..a8180b5e79 --- /dev/null +++ b/plugins/Goals/tests/UI/GoalsPages_spec.js @@ -0,0 +1,110 @@ +/*! + * Matomo - free/libre analytics platform + * + * Screenshot integration tests. + * + * @link https://matomo.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +describe("GoalsPages", function () { + this.timeout(0); + + var generalParams = 'idSite=1&period=year&date=2012-08-09', + urlBaseGeneric = 'module=CoreHome&action=index&', + urlBase = urlBaseGeneric + generalParams; + + // goals pages + it('should load the goals > ecommerce page correctly', async function () { + await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=General_Overview") + await page.waitForNetworkIdle(); + + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('ecommerce'); + }); + + it('should load the goals > overview page correctly', async function () { + await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=General_Overview"); + await page.waitForNetworkIdle(); + + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('overview'); + }); + + it('should load row evolution with goal metrics', async function() { + const row = await page.waitForSelector('.reportsByDimensionView tbody tr:first-child'); + await row.hover(); + + const icon = await page.waitForSelector('.reportsByDimensionView tbody tr:first-child a.actionRowEvolution'); + await icon.click(); + + await page.waitForSelector('.ui-dialog'); + await page.waitForNetworkIdle(); + + const dialog = await page.$('.ui-dialog'); + expect(await dialog.screenshot()).to.matchImage('overview_row_evolution'); + }); + + it('should load row evolution with goal metrics again when reloading the page url', async function() { + // page.reload() won't work with url hashes + const url = await page.evaluate('location.href'); + await page.goto('about:blank'); + await page.goto(url); + + await page.waitForSelector('.ui-dialog'); + await page.waitForNetworkIdle(); + + const dialog = await page.$('.ui-dialog'); + expect(await dialog.screenshot()).to.matchImage('overview_row_evolution_reloaded'); + }); + + it('should load the goals > management page correctly', async function () { + await page.goto("?" + generalParams + "&module=Goals&action=manage"); + await page.waitForNetworkIdle(); + + expect(await page.screenshotSelector('#content,.top_bar_sites_selector,.entityContainer')).to.matchImage('manage'); + }); + + it('should load the goals > single goal page correctly', async function () { + await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=1"); + await page.waitForNetworkIdle(); + + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('individual_goal'); + }); + + it('should update the evolution chart if a sparkline is clicked', async function () { + elem = await page.jQuery('.sparkline.linked:contains(%)'); + await elem.click(); + await page.waitForNetworkIdle(); + await page.mouse.move(-10, -10); + + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('individual_goal_updated'); + }); + + // should load the row evolution [see #11526] + it('should show rov evolution for goal tables', async function () { + await page.waitForNetworkIdle(); + + const row = await page.waitForSelector('.dataTable tbody tr:first-child'); + await row.hover(); + + const icon = await page.waitForSelector('.dataTable tbody tr:first-child a.actionRowEvolution'); + await icon.click(); + + await page.waitForSelector('.rowevolution'); + await page.waitForNetworkIdle(); + + expect(await page.screenshotSelector('.ui-dialog')).to.matchImage('individual_row_evolution'); + }); + + it('should load row evolution with goal metrics again when reloading the page url', async function() { + // page.reload() won't work with url hashes + const url = await page.evaluate('location.href'); + await page.goto('about:blank'); + await page.goto(url); + + await page.waitForSelector('.ui-dialog'); + await page.waitForNetworkIdle(); + + const dialog = await page.$('.ui-dialog'); + expect(await dialog.screenshot()).to.matchImage('individual_row_evolution_reloaded'); + }); +}); diff --git a/tests/UI/specs/GoalsTable_spec.js b/plugins/Goals/tests/UI/GoalsTable_spec.js index 828a2fb67f..828a2fb67f 100644 --- a/tests/UI/specs/GoalsTable_spec.js +++ b/plugins/Goals/tests/UI/GoalsTable_spec.js diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_ecommerce.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_ecommerce.png index 0d2e28a482..0d2e28a482 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_ecommerce.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_ecommerce.png diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_goal.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_goal.png index a7dbc81084..a7dbc81084 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_goal.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_goal.png diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_goal_updated.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_goal_updated.png index e95f6576e6..e95f6576e6 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_goal_updated.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_goal_updated.png diff --git a/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution.png new file mode 100644 index 0000000000..6201921ddd --- /dev/null +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40b8aa2e147e3f3d012ef827fa680e1629fffd81a7427ff6d06744f92909e13a +size 79278 diff --git a/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution_reloaded.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution_reloaded.png new file mode 100644 index 0000000000..f33eddee94 --- /dev/null +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_individual_row_evolution_reloaded.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a554ae7a8249dd867010724260abf32dd65351433f28c2c07ff4fac309b1f4ae +size 59883 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_manage.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_manage.png index 34fedec0a5..34fedec0a5 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_manage.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_manage.png diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_overview.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview.png index 110323f1c6..110323f1c6 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_overview.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview.png diff --git a/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution.png new file mode 100644 index 0000000000..be7b352951 --- /dev/null +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c424966632880c030448e4fba43643d099b2a6ae4cf8446dd5c58981f1a7e16 +size 177941 diff --git a/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution_reloaded.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution_reloaded.png new file mode 100644 index 0000000000..57910939c1 --- /dev/null +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsPages_overview_row_evolution_reloaded.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca6c2269f463d0918fc864b094ba7cdb5791d90392749ab3a6c8aeb8b6f33a1a +size 158599 diff --git a/tests/UI/expected-screenshots/GoalsTable_goals_table_abandoned_carts.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_abandoned_carts.png index 885810d277..885810d277 100644 --- a/tests/UI/expected-screenshots/GoalsTable_goals_table_abandoned_carts.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_abandoned_carts.png diff --git a/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce.png index 323b44e395..323b44e395 100644 --- a/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce.png diff --git a/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce_view.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce_view.png index a693202456..a693202456 100644 --- a/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce_view.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_ecommerce_view.png diff --git a/tests/UI/expected-screenshots/GoalsTable_goals_table_full.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_full.png index 07d7dedd70..07d7dedd70 100644 --- a/tests/UI/expected-screenshots/GoalsTable_goals_table_full.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_full.png diff --git a/tests/UI/expected-screenshots/GoalsTable_goals_table_single.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_single.png index c64083dc31..c64083dc31 100644 --- a/tests/UI/expected-screenshots/GoalsTable_goals_table_single.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_goals_table_single.png diff --git a/tests/UI/expected-screenshots/GoalsTable_initial.png b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_initial.png index c3ca30817f..c3ca30817f 100644 --- a/tests/UI/expected-screenshots/GoalsTable_initial.png +++ b/plugins/Goals/tests/UI/expected-screenshots/GoalsTable_initial.png diff --git a/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view.png b/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view.png new file mode 100644 index 0000000000..bea685de86 --- /dev/null +++ b/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ade776bd2bbf4bc2e43d0c0ace6796b21a01d4c2c2510d57085dd5cf1e7ab03 +size 91617 diff --git a/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view_reload.png b/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view_reload.png new file mode 100644 index 0000000000..bea685de86 --- /dev/null +++ b/tests/UI/expected-screenshots/RowEvolution_row_evolution_goal_view_reload.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ade776bd2bbf4bc2e43d0c0ace6796b21a01d4c2c2510d57085dd5cf1e7ab03 +size 91617 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png index 72596a2cd9..7a057fa3e7 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97283bcac38de15ea354376e3554411827912136de9cd25542b0d53721729abf -size 4994214 +oid sha256:d92406e3cf6894abda91dcf4a0e71c645a8a48c5451e649df4ccc982e8dbacd4 +size 4995440 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_row_evolution.png b/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_row_evolution.png deleted file mode 100644 index ad9461ebb1..0000000000 --- a/tests/UI/expected-screenshots/UIIntegrationTest_goals_individual_row_evolution.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6fa8eb9fe92f45054973d474a76f2385527083a395c9c6916ec10aad81fb168a -size 65721 diff --git a/tests/UI/specs/RowEvolution_spec.js b/tests/UI/specs/RowEvolution_spec.js index 2ed7337f99..a503aeeb30 100644 --- a/tests/UI/specs/RowEvolution_spec.js +++ b/tests/UI/specs/RowEvolution_spec.js @@ -79,6 +79,34 @@ describe("RowEvolution", function () { expect(await dialog.screenshot()).to.matchImage('multirow_evolution_other_metric'); }); + it('should load row evolution for goals view', async function() { + await page.goto(viewDataTableUrl + '&forceView=1&viewDataTable=tableGoals'); + const row = await page.waitForSelector('tbody tr:first-child'); + await row.hover(); + + const icon = await page.waitForSelector('tbody tr:first-child a.actionRowEvolution'); + await icon.click(); + + await page.waitForSelector('.ui-dialog'); + await page.waitForNetworkIdle(); + + const dialog = await page.$('.ui-dialog'); + expect(await dialog.screenshot()).to.matchImage('row_evolution_goal_view'); + }); + + it('should load row evolution with goal metrics again when reloading the page url', async function() { + // page.reload() won't work with url hashes + const url = await page.evaluate('location.href'); + await page.goto('about:blank'); + await page.goto(url); + + await page.waitForSelector('.ui-dialog'); + await page.waitForNetworkIdle(); + + const dialog = await page.$('.ui-dialog'); + expect(await dialog.screenshot()).to.matchImage('row_evolution_goal_view_reload'); + }); + it('should display row evolution for an ecommerce item report correctly', async function() { await page.goto(ecommerceItemReportWidgetized); const row = await page.waitForSelector('tbody tr:first-child'); diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js index 1cc69b0e34..a2680e5643 100644 --- a/tests/UI/specs/UIIntegration_spec.js +++ b/tests/UI/specs/UIIntegration_spec.js @@ -229,7 +229,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? testEnvironment.queryParamOverride['ignoreClearAllViewDataTableParameters'] = 1; - // use columns query param to make sure columns works when supplied in URL fragment + // use columns query param to make sure columns works when supplied in URL fragment await page.goto("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=General_Overview&columns=nb_visits,nb_actions"); await page.waitForNetworkIdle(); @@ -572,64 +572,6 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? }); }); - describe("GoalsPages", function () { - this.title = parentSuite.title; // to make sure the screenshot prefix is the same - - // goals pages - it('should load the goals > ecommerce page correctly', async function () { - await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=General_Overview") - await page.waitForNetworkIdle(); - - expect(await page.screenshotSelector('.pageWrap')).to.matchImage('goals_ecommerce'); - }); - - it('should load the goals > overview page correctly', async function () { - await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=General_Overview"); - await page.waitForNetworkIdle(); - - expect(await page.screenshotSelector('.pageWrap')).to.matchImage('goals_overview'); - }); - - it('should load the goals > management page correctly', async function () { - await page.goto("?" + generalParams + "&module=Goals&action=manage"); - await page.waitForNetworkIdle(); - - expect(await page.screenshotSelector('#content,.top_bar_sites_selector,.entityContainer')).to.matchImage('goals_manage'); - }); - - it('should load the goals > single goal page correctly', async function () { - await page.goto("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=1"); - await page.waitForNetworkIdle(); - - expect(await page.screenshotSelector('.pageWrap')).to.matchImage('goals_individual_goal'); - }); - - it('should update the evolution chart if a sparkline is clicked', async function () { - elem = await page.jQuery('.sparkline.linked:contains(%)'); - await elem.click(); - await page.waitForNetworkIdle(); - await page.mouse.move(-10, -10); - - expect(await page.screenshotSelector('.pageWrap')).to.matchImage('goals_individual_goal_updated'); - }); - - // should load the row evolution [see #11526] - it('should show rov evolution for goal tables', async function () { - await page.waitForNetworkIdle(); - - const row = await page.waitForSelector('.dataTable tbody tr:first-child'); - await row.hover(); - - const icon = await page.waitForSelector('.dataTable tbody tr:first-child a.actionRowEvolution'); - await icon.click(); - - await page.waitForSelector('.rowevolution'); - await page.waitForNetworkIdle(); - - expect(await page.screenshotSelector('.ui-dialog')).to.matchImage('goals_individual_row_evolution'); - }); - }); - describe("EventsPages", function () { this.title = parentSuite.title; // to make sure the screenshot prefix is the same |