From 9d949ffcb1d591d34aeb20bbca00ca0f765269ed Mon Sep 17 00:00:00 2001 From: Riccardo Beltrami Date: Tue, 29 Aug 2023 15:52:51 +0200 Subject: [PATCH 1/3] Dataviz - Do not display child plot in Popup when there is no data --- lizmap/www/assets/js/dataviz/dataviz.js | 110 ++++++++++++------ .../cypress/integration/dataviz-ghaction.js | 43 +++++-- 2 files changed, 106 insertions(+), 47 deletions(-) diff --git a/lizmap/www/assets/js/dataviz/dataviz.js b/lizmap/www/assets/js/dataviz/dataviz.js index 57fcea6ff4..93b8d450ea 100644 --- a/lizmap/www/assets/js/dataviz/dataviz.js +++ b/lizmap/www/assets/js/dataviz/dataviz.js @@ -114,8 +114,16 @@ var lizDataviz = function() { } } - function getPlot(plot_id, exp_filter, target_id){ - if ( $('#'+target_id).length == 0) return; + /** + * Get the plot data from the backend + * and draw the plot with the buildPlot method + * + * @param {integer} plot_id The id of the plot. + * @param {string} exp_filter The optional data filter. + * @param {string} target_id The ID of the target dom element. + * + */ + async function getPlot(plot_id, exp_filter, target_id) { exp_filter = typeof exp_filter !== 'undefined' ? exp_filter : null; target_id = typeof target_id !== 'undefined' ? target_id : new Date().valueOf()+btoa(Math.random()).substring(0,12); @@ -153,44 +161,70 @@ var lizDataviz = function() { } // No cache -> get data - $.getJSON(datavizConfig.url, - lparams, - function(json){ - if( 'errors' in json ){ - console.log('Dataviz configuration error'); - console.log(json.errors); - return false; - } - // Store json only if no filter - // Because we use cache for the full data - // and we do not want to override it - if (!exp_filter) { - dv.plots[plot_id]['cache'] = json; - } - dv.plots[plot_id]['json'] = json; - - // Store filter - dv.plots[plot_id]['filter'] = exp_filter; - - // Hide container if no data - if( !json.data || json.data.length < 1){ - // hide full container - $('#' + target_id + '_container').hide(); - $('#'+target_id).prev('.dataviz-waiter:first').hide(); - $('#'+target_id).parents('div.lizdataviz.lizmapPopupChildren:first').hide(); - return false; - } - // Show container if needed - if (dv.plots[plot_id]['show_plot']) { - $('#' + target_id + '_container').show(); - } + try { + const response = await fetch(datavizConfig.url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(lparams), + }); - // Build plot - // Pass plot_id to inherit custom configurations in child charts - var plot = buildPlot(target_id, json, plot_id); - $('#'+target_id).prev('.dataviz-waiter:first').hide(); + // Check content type + const contentType = response.headers.get("content-type"); + if (!contentType || !contentType.includes("application/json")) { + throw new TypeError("Wrong content-type. JSON Expected !"); } - ); + + // Get the JSON response + const jsonData = await response.json(); + + // Process the JSON data + if ('errors' in jsonData) { + console.log('Dataviz error'); + console.log(jsonData.errors); + } + + // Store json only if no filter + // Because we use cache for the full data + // and we do not want to override it + if (!exp_filter && !('errors' in jsonData)) { + dv.plots[plot_id]['cache'] = jsonData; + dv.plots[plot_id]['json'] = jsonData; + } + + // Store filter + dv.plots[plot_id]['filter'] = exp_filter; + + // Hide container if no data + if (!jsonData.data || jsonData.data.length < 1) { + // hide the full container + $('#' + target_id + '_container').hide(); + // Hide the infinite progress bar + $('#' + target_id).prev('.dataviz-waiter:first').hide(); + $('#' + target_id).parents('div.lizdataviz.lizmapPopupChildren:first').hide(); + + return false; + } + + // Show container if needed + if (dv.plots[plot_id]['show_plot']) { + $('#' + target_id + '_container').show(); + } + + // The data has been successfully fetched + dv.plots[plot_id]['data_fetched'] = true; + + // Build plot + // Pass plot_id to inherit custom configurations in child charts + buildPlot(target_id, jsonData, plot_id); + + // Hide the infinite progress bar + $('#' + target_id).prev('.dataviz-waiter:first').hide(); + + } catch (error) { + console.error("Error:", error); + } } function buildHtmlPlot(id, data, layout) { diff --git a/tests/end2end/cypress/integration/dataviz-ghaction.js b/tests/end2end/cypress/integration/dataviz-ghaction.js index 98595e46c6..52170b9f29 100644 --- a/tests/end2end/cypress/integration/dataviz-ghaction.js +++ b/tests/end2end/cypress/integration/dataviz-ghaction.js @@ -10,15 +10,15 @@ describe('Dataviz tests', function () { }) }).as('getMap') - cy.intercept('*request=getPlot*', - { middleware: true }, - (req) => { - req.on('before:response', (res) => { - // force all API responses to not be cached - // It is needed when launching tests multiple time in headed mode - res.headers['cache-control'] = 'no-store' - }) - }).as('getPlot') + cy.intercept('*/dataviz/service*', + { middleware: true }, + (req) => { + req.on('before:response', (res) => { + // force all API responses to not be cached + // It is needed when launching tests multiple time in headed mode + res.headers['cache-control'] = 'no-store' + }) + }).as('getPlot') }) it('Test dataviz plots are rendered', function () { @@ -28,8 +28,33 @@ describe('Dataviz tests', function () { // Wait for map displayed 2 layers are displayed cy.wait(['@getMap', '@getMap']) + // Click on the dataviz menu cy.get('#button-dataviz').click() + // Check the plots are organized as configured in plugin (HTML Drag & drop layout) + cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(1) > a') + .should('have.text', 'First tab') + cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(2) > a') + .should('have.text', 'Second tab') + cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(1) > legend') + .should('have.text', 'Group A') + cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > legend') + .should('have.text', 'Group B') + cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(1) > a:nth-child(1)') + .should('have.text', 'Sub-Tab X') + cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(2) > a:nth-child(1)') + .should('have.text', 'Sub-tab Y') + + // Click on the other tabs to make the other plots visible + // Sub tab Y + cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(1) > a') + .click() + cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(2) > a:nth-child(1)') + .click() + // Second tab + cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(2) > a') + .click() + // Wait for graphics displayed 4 plots are displayed cy.wait(['@getPlot', '@getPlot', '@getPlot', '@getPlot']) From eb5b191f3e46a50fb61684531c3a7e3226af699b Mon Sep 17 00:00:00 2001 From: Riccardo Beltrami Date: Thu, 31 Aug 2023 15:13:49 +0200 Subject: [PATCH 2/3] back to dataviz 3.6 e2e test --- .../cypress/integration/dataviz-ghaction.js | 433 +++++++++--------- 1 file changed, 204 insertions(+), 229 deletions(-) diff --git a/tests/end2end/cypress/integration/dataviz-ghaction.js b/tests/end2end/cypress/integration/dataviz-ghaction.js index 52170b9f29..4191ba2ef1 100644 --- a/tests/end2end/cypress/integration/dataviz-ghaction.js +++ b/tests/end2end/cypress/integration/dataviz-ghaction.js @@ -1,230 +1,205 @@ describe('Dataviz tests', function () { - beforeEach(() => { - cy.intercept('*REQUEST=GetMap*', - { middleware: true }, - (req) => { - req.on('before:response', (res) => { - // force all API responses to not be cached - // It is needed when launching tests multiple time in headed mode - res.headers['cache-control'] = 'no-store' - }) - }).as('getMap') - - cy.intercept('*/dataviz/service*', - { middleware: true }, - (req) => { - req.on('before:response', (res) => { - // force all API responses to not be cached - // It is needed when launching tests multiple time in headed mode - res.headers['cache-control'] = 'no-store' - }) - }).as('getPlot') - }) - - it('Test dataviz plots are rendered', function () { - - cy.visit('/index.php/view/map/?repository=testsrepository&project=dataviz') - - // Wait for map displayed 2 layers are displayed - cy.wait(['@getMap', '@getMap']) - - // Click on the dataviz menu - cy.get('#button-dataviz').click() - - // Check the plots are organized as configured in plugin (HTML Drag & drop layout) - cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(1) > a') - .should('have.text', 'First tab') - cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(2) > a') - .should('have.text', 'Second tab') - cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(1) > legend') - .should('have.text', 'Group A') - cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > legend') - .should('have.text', 'Group B') - cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(1) > a:nth-child(1)') - .should('have.text', 'Sub-Tab X') - cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(2) > a:nth-child(1)') - .should('have.text', 'Sub-tab Y') - - // Click on the other tabs to make the other plots visible - // Sub tab Y - cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(1) > a') - .click() - cy.get('div#dataviz-dnd-0-39cdf0321d593be51760b8c205de3f3e > fieldset:nth-child(2) > div:nth-child(2) > ul:nth-child(1) > li:nth-child(2) > a:nth-child(1)') - .click() - // Second tab - cy.get('#dataviz > #dataviz-container > #dataviz-content > div.tab-content > ul > li:nth-child(2) > a') - .click() - - // Wait for graphics displayed 4 plots are displayed - cy.wait(['@getPlot', '@getPlot', '@getPlot', '@getPlot']) - - // Test first plot - Municipalities - cy.get('#dataviz_plot_0_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') - .should('have.text', 'Municipalities') - - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer') - .should('have.length', 1) - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot') - .should('have.length', 1) - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') - .should('have.length', 1) - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') - .should('have.length', 1) - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - - // Test - Bar bakeries by municipalities - cy.get('#dataviz_plot_1_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') - .should('have.text', 'Bar Bakeries by municipalities') - - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - - // Test - Pie bakeries by municipalities - cy.get('#dataviz_plot_2_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') - .should('have.text', 'Pie Bakeries by municipalities') - - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer') - .should('have.length', 1) - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace') - .should('have.length', 1) - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') - .should('have.length', 10) - - // Test - Horizontal bar bakeries in municipalities - cy.get('#dataviz_plot_3_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') - .should('have.text', 'Horizontal bar bakeries in municipalities') - - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - - // Using locate by layer to filter layers and plots - cy.get('#locate-layer-polygons ~ span.custom-combobox > a.custom-combobox-toggle').click() - cy.get('ul.ui-menu.ui-autocomplete:visible > li.ui-menu-item:nth-child(3)').click() - - // Wait for visible graphics updated 2 plots are visible - cy.wait(['@getPlot', '@getPlot']) - - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - - // Scroll the dataviz dock to update graphics - cy.get('#dock-content').scrollTo('bottom') - cy.wait(['@getPlot', '@getPlot']) - - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - - // Scroll to top - cy.get('#dock-content').scrollTo('top') - - // Zoom and filter to an other feature - cy.get('#locate-layer-polygons ~ span.custom-combobox > a.custom-combobox-toggle').click() - cy.get('ul.ui-menu.ui-autocomplete:visible > li.ui-menu-item:nth-child(5)').click() - - // Wait for visible graphics updated 2 plots are visible - cy.wait(['@getPlot', '@getPlot']) - - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - - // Scroll the dataviz dock to update graphics - cy.get('#dock-content').scrollTo('bottom') - cy.wait(['@getPlot', '@getPlot']) - - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') - .should('have.length', 1) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 1) - - // Scroll to top - cy.get('#dock-content').scrollTo('top') - - // Deactivate filter provided by locate by layer - cy.get('#locate-clear').click() - // Wait for map updated, because plots are in cache - cy.wait(['@getMap', '@getMap']) - - cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - - // Scroll the dataviz dock to update graphics - cy.get('#dock-content').scrollTo('bottom') - cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') - .should('have.length', 10) - cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') - .should('have.length', 10) - - // This test is not really covering the dataviz capabilities for now. - }) - - it('Test filtered dataviz plots are rendered in a popup', function () { - const path = require("path") - const PNG = require('pngjs').PNG; - const pixelmatch = require('pixelmatch'); - const downloadsFolder = Cypress.config("downloadsFolder") - - cy.visit('/index.php/view/map/?repository=testsrepository&project=dataviz_filtered_in_popup') - - // Dataviz button does not exist because every dataviz has to be displayed in popup - cy.get('#button-dataviz').should('not.exist') - - // Popup - cy.mapClick(550, 400) - cy.get('#popupcontent').should('be.visible') - - cy.get('#popupcontent .lizmapPopupChildren.lizdataviz > h4').should('have.text', 'Number of bakeries by polygon') - - cy.get('#popupcontent .lizmapPopupChildren.lizdataviz .dataviz-waiter').should('not.be.visible') - cy.get('#popupcontent .lizmapPopupChildren.lizdataviz .plot-container') - .should('be.visible').should('have.class', 'plotly') - .children().first() //
- .should('have.class', 'svg-container') - .should('have.css', 'height', '400px') - - cy.get('[data-title="Download plot as a png"]').click() - - let expected_diff = 0 - let fixture_path = 'images/plotly/plot_montpellier_bakeries.png' - if (Cypress.isBrowser('firefox')) { - fixture_path = 'images/plotly/plot_montpellier_bakeries_firefox.png' - expected_diff = 235 - } - cy.fixture(fixture_path).then((expected) => { - // newplot.png is maybe not the last one if the download folder is not empty ... - cy.readFile(path.join(downloadsFolder, "newplot.png"), 'base64').then((image) => { - - // We can make a easier function to compare two images - const img1 = PNG.sync.read(Buffer.from(image, 'base64')); - const { width, height } = img1; - const img2 = PNG.sync.read(Buffer.from(expected, 'base64')); - - expect(pixelmatch(img1.data, img2.data, null, width, height, { threshold: 0.1 }), 'expect plot').to.lessThan(expected_diff + 1) - }) - }) - }) -}) + beforeEach(() => { + cy.intercept('*REQUEST=GetMap*', + { middleware: true }, + (req) => { + req.on('before:response', (res) => { + // force all API responses to not be cached + // It is needed when launching tests multiple time in headed mode + res.headers['cache-control'] = 'no-store' + }) + }).as('getMap') + + cy.intercept('*request=getPlot*', + { middleware: true }, + (req) => { + req.on('before:response', (res) => { + // force all API responses to not be cached + // It is needed when launching tests multiple time in headed mode + res.headers['cache-control'] = 'no-store' + }) + }).as('getPlot') + }) + + it('Test dataviz plots are rendered', function () { + + cy.visit('/index.php/view/map/?repository=testsrepository&project=dataviz') + + // Wait for map displayed 2 layers are displayed + cy.wait(['@getMap', '@getMap']) + + cy.get('#button-dataviz').click() + + // Wait for graphics displayed 4 plots are displayed + cy.wait(['@getPlot', '@getPlot', '@getPlot', '@getPlot']) + + // Test first plot - Municipalities + cy.get('#dataviz_plot_0_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') + .should('have.text', 'Municipalities') + + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer') + .should('have.length', 1) + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot') + .should('have.length', 1) + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') + .should('have.length', 1) + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') + .should('have.length', 1) + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + + // Test - Bar bakeries by municipalities + cy.get('#dataviz_plot_1_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') + .should('have.text', 'Bar Bakeries by municipalities') + + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + + // Test - Pie bakeries by municipalities + cy.get('#dataviz_plot_2_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') + .should('have.text', 'Pie Bakeries by municipalities') + + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer') + .should('have.length', 1) + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace') + .should('have.length', 1) + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') + .should('have.length', 10) + + // Test - Horizontal bar bakeries in municipalities + cy.get('#dataviz_plot_3_container > h3:nth-child(1) > span:nth-child(1) > span:nth-child(2)') + .should('have.text', 'Horizontal bar bakeries in municipalities') + + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + + // Using locate by layer to filter layers and plots + cy.get('#locate-layer-polygons ~ span.custom-combobox > a.custom-combobox-toggle').click() + cy.get('ul.ui-menu.ui-autocomplete:visible > li.ui-menu-item:nth-child(3)').click() + + // Wait for visible graphics updated 2 plots are visible + cy.wait(['@getPlot', '@getPlot']) + + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + + // Scroll the dataviz dock to update graphics + cy.get('#dock-content').scrollTo('bottom') + cy.wait(['@getPlot', '@getPlot']) + + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + + // Scroll to top + cy.get('#dock-content').scrollTo('top') + + // Zoom and filter to an other feature + cy.get('#locate-layer-polygons ~ span.custom-combobox > a.custom-combobox-toggle').click() + cy.get('ul.ui-menu.ui-autocomplete:visible > li.ui-menu-item:nth-child(5)').click() + + // Wait for visible graphics updated 2 plots are visible + cy.wait(['@getPlot', '@getPlot']) + + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + + // Scroll the dataviz dock to update graphics + cy.get('#dock-content').scrollTo('bottom') + cy.wait(['@getPlot', '@getPlot']) + + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') + .should('have.length', 1) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 1) + + // Scroll to top + cy.get('#dock-content').scrollTo('top') + + // Deactivate filter provided by locate by layer + cy.get('#locate-clear').click() + // Wait for map updated, because plots are in cache + cy.wait(['@getMap', '@getMap']) + + cy.get('#dataviz_plot_0 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + cy.get('#dataviz_plot_1 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + + // Scroll the dataviz dock to update graphics + cy.get('#dock-content').scrollTo('bottom') + cy.get('#dataviz_plot_2 div.svg-container svg.main-svg g.pielayer g.trace g.slice') + .should('have.length', 10) + cy.get('#dataviz_plot_3 div.svg-container svg.main-svg g.cartesianlayer g.plot g.trace.bars g.points g.point') + .should('have.length', 10) + + // This test is not really covering the dataviz capabilities for now. + }) + + it('Test filtered dataviz plots are rendered in a popup', function () { + const path = require("path") + const PNG = require('pngjs').PNG; + const pixelmatch = require('pixelmatch'); + const downloadsFolder = Cypress.config("downloadsFolder") + + cy.visit('/index.php/view/map/?repository=testsrepository&project=dataviz_filtered_in_popup') + + // Dataviz button does not exist because every dataviz has to be displayed in popup + cy.get('#button-dataviz').should('not.exist') + + // Popup + cy.mapClick(550, 400) + cy.get('#popupcontent').should('be.visible') + + cy.get('#popupcontent .lizmapPopupChildren.lizdataviz > h4').should('have.text', 'Number of bakeries by polygon') + + cy.get('#popupcontent .lizmapPopupChildren.lizdataviz .dataviz-waiter').should('not.be.visible') + cy.get('#popupcontent .lizmapPopupChildren.lizdataviz .plot-container') + .should('be.visible').should('have.class', 'plotly') + .children().first() //
+ .should('have.class', 'svg-container') + .should('have.css', 'height', '400px') + + cy.get('[data-title="Download plot as a png"]').click() + + let expected_diff = 0 + let fixture_path = 'images/plotly/plot_montpellier_bakeries.png' + if (Cypress.isBrowser('firefox')) { + fixture_path = 'images/plotly/plot_montpellier_bakeries_firefox.png' + expected_diff = 235 + } + cy.fixture(fixture_path).then((expected) => { + // newplot.png is maybe not the last one if the download folder is not empty ... + cy.readFile(path.join(downloadsFolder, "newplot.png"), 'base64').then((image) => { + + // We can make a easier function to compare two images + const img1 = PNG.sync.read(Buffer.from(image, 'base64')); + const { width, height } = img1; + const img2 = PNG.sync.read(Buffer.from(expected, 'base64')); + + expect(pixelmatch(img1.data, img2.data, null, width, height, { threshold: 0.1 }), 'expect plot').to.lessThan(expected_diff + 1) + }) + }) + }) + }) \ No newline at end of file From 057c3814e8f73d5f90e666390406142606ce8367 Mon Sep 17 00:00:00 2001 From: Riccardo Beltrami Date: Thu, 31 Aug 2023 16:29:15 +0200 Subject: [PATCH 3/3] fix e2e dataviz service --- lizmap/www/assets/js/dataviz/dataviz.js | 10 ++++++++-- tests/end2end/cypress/integration/dataviz-ghaction.js | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lizmap/www/assets/js/dataviz/dataviz.js b/lizmap/www/assets/js/dataviz/dataviz.js index 93b8d450ea..351eefb1ee 100644 --- a/lizmap/www/assets/js/dataviz/dataviz.js +++ b/lizmap/www/assets/js/dataviz/dataviz.js @@ -124,6 +124,12 @@ var lizDataviz = function() { * */ async function getPlot(plot_id, exp_filter, target_id) { + if ($('#' + target_id).length == 0) { + return; + } + + // Show the infinite progress bar + $('#' + target_id).prev('.dataviz-waiter:first').show(); exp_filter = typeof exp_filter !== 'undefined' ? exp_filter : null; target_id = typeof target_id !== 'undefined' ? target_id : new Date().valueOf()+btoa(Math.random()).substring(0,12); @@ -154,8 +160,8 @@ var lizDataviz = function() { } // Build plot - var plot = buildPlot(target_id, dv.plots[plot_id]['cache']); - $('#'+target_id).prev('.dataviz-waiter:first').hide(); + buildPlot(target_id, dv.plots[plot_id]['cache']); + $('#' + target_id).prev('.dataviz-waiter:first').hide(); return true; } diff --git a/tests/end2end/cypress/integration/dataviz-ghaction.js b/tests/end2end/cypress/integration/dataviz-ghaction.js index 4191ba2ef1..075caab8b0 100644 --- a/tests/end2end/cypress/integration/dataviz-ghaction.js +++ b/tests/end2end/cypress/integration/dataviz-ghaction.js @@ -10,7 +10,7 @@ describe('Dataviz tests', function () { }) }).as('getMap') - cy.intercept('*request=getPlot*', + cy.intercept('*/dataviz/service*', { middleware: true }, (req) => { req.on('before:response', (res) => { @@ -202,4 +202,4 @@ describe('Dataviz tests', function () { }) }) }) - }) \ No newline at end of file + })