From 3e4c9e16697b3aab36df079a2b44dbc23611327d Mon Sep 17 00:00:00 2001 From: Christopher Mead Date: Thu, 9 Jan 2025 12:00:50 -0700 Subject: [PATCH] E2E tests: save plot from editor tests (#5932) Tests for saving plots from the editor. ### QA Notes All tests should pass. --- test/e2e/pages/plots.ts | 23 +++++++-- test/e2e/tests/plots/plots.test.ts | 83 +++++++++++++++++------------- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/test/e2e/pages/plots.ts b/test/e2e/pages/plots.ts index de562448f2d..270dc9faef4 100644 --- a/test/e2e/pages/plots.ts +++ b/test/e2e/pages/plots.ts @@ -14,7 +14,8 @@ const NEXT_PLOT_BUTTON = '.positron-plots-container .positron-action-bar .positr const PREVIOUS_PLOT_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Show previous plot"]'; const CLEAR_PLOTS_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Clear all plots"]'; const PLOT_SIZE_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Auto"]'; -const SAVE_PLOT_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Save plot"]'; +const SAVE_PLOT_FROM_PLOTS_PANE_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Save plot"]'; +const SAVE_PLOT_FROM_EDITOR_BUTTON = '.editor-actions .codicon-positron-save'; const COPY_PLOT_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Copy plot to clipboard"]'; const ZOOM_PLOT_BUTTON = '.positron-plots-container .positron-action-bar .positron-button[aria-label="Fit"]'; const OUTER_WEBVIEW_FRAME = '.webview'; @@ -30,7 +31,8 @@ export class Plots { previousPlotButton: Locator; clearPlotsButton: Locator; plotSizeButton: Locator; - savePlotButton: Locator; + savePlotFromPlotsPaneButton: Locator; + savePlotFromEditorButton: Locator; copyPlotButton: Locator; zoomPlotButton: Locator; currentPlot: Locator; @@ -42,7 +44,8 @@ export class Plots { this.previousPlotButton = this.code.driver.page.locator(PREVIOUS_PLOT_BUTTON); this.clearPlotsButton = this.code.driver.page.locator(CLEAR_PLOTS_BUTTON); this.plotSizeButton = this.code.driver.page.locator(PLOT_SIZE_BUTTON); - this.savePlotButton = this.code.driver.page.locator(SAVE_PLOT_BUTTON); + this.savePlotFromPlotsPaneButton = this.code.driver.page.locator(SAVE_PLOT_FROM_PLOTS_PANE_BUTTON); + this.savePlotFromEditorButton = this.code.driver.page.locator(SAVE_PLOT_FROM_EDITOR_BUTTON); this.copyPlotButton = this.code.driver.page.locator(COPY_PLOT_BUTTON); this.zoomPlotButton = this.code.driver.page.locator(ZOOM_PLOT_BUTTON); this.currentPlot = this.code.driver.page.locator(CURRENT_PLOT); @@ -110,9 +113,19 @@ export class Plots { await this.code.wait(500); } - async savePlot({ name, format, overwrite = true }: { name: string; format: 'JPEG' | 'PNG' | 'SVG' | 'PDF' | 'TIFF'; overwrite?: boolean }) { + async savePlotFromPlotsPane({ name, format, overwrite = true }: { name: string; format: 'JPEG' | 'PNG' | 'SVG' | 'PDF' | 'TIFF'; overwrite?: boolean }) { // click save and wait for save plot modal - await this.savePlotButton.click(); + await this.savePlotFromPlotsPaneButton.click(); + await this.savePlot({ name, format, overwrite }); + } + + async savePlotFromEditor({ name, format, overwrite = true }: { name: string; format: 'JPEG' | 'PNG' | 'SVG' | 'PDF' | 'TIFF'; overwrite?: boolean }) { + // click save and wait for save plot modal + await this.savePlotFromEditorButton.click(); + await this.savePlot({ name, format, overwrite }); + } + + private async savePlot({ name, format, overwrite = true }: { name: string; format: 'JPEG' | 'PNG' | 'SVG' | 'PDF' | 'TIFF'; overwrite?: boolean }) { await expect(this.savePlotModal).toBeVisible(); // enter new name and select format diff --git a/test/e2e/tests/plots/plots.test.ts b/test/e2e/tests/plots/plots.test.ts index d9af0efdc2f..b450f10e575 100644 --- a/test/e2e/tests/plots/plots.test.ts +++ b/test/e2e/tests/plots/plots.test.ts @@ -108,7 +108,7 @@ test.describe('Plots', { tag: [tags.PLOTS, tags.EDITOR] }, () => { // default plot pane state for action bar await expect(plots.plotSizeButton).not.toBeVisible(); - await expect(plots.savePlotButton).not.toBeVisible(); + await expect(plots.savePlotFromPlotsPaneButton).not.toBeVisible(); await expect(plots.copyPlotButton).not.toBeVisible(); await expect(plots.zoomPlotButton).not.toBeVisible(); @@ -124,7 +124,7 @@ test.describe('Plots', { tag: [tags.PLOTS, tags.EDITOR] }, () => { await expect(plots.nextPlotButton).toBeDisabled(); await expect(plots.previousPlotButton).not.toBeDisabled(); await expect(plots.plotSizeButton).not.toBeDisabled(); - await expect(plots.savePlotButton).not.toBeDisabled(); + await expect(plots.savePlotFromPlotsPaneButton).not.toBeDisabled(); await expect(plots.copyPlotButton).not.toBeDisabled(); // switch to fixed size plot @@ -151,14 +151,29 @@ test.describe('Plots', { tag: [tags.PLOTS, tags.EDITOR] }, () => { }); test('Python - Verifies saving a Python plot [C557005]', { tag: [tags.WIN] }, async function ({ app, logger }) { - logger.log('Sending code to console'); - await app.workbench.console.executeCode('Python', savePlot, '>>>'); - await app.workbench.plots.waitForCurrentPlot(); - await app.workbench.layouts.enterLayout('fullSizedAuxBar'); + await test.step('Sending code to console to create plot', async () => { + await app.workbench.console.executeCode('Python', pythonDynamicPlot, '>>>'); + await app.workbench.plots.waitForCurrentPlot(); + await app.workbench.layouts.enterLayout('fullSizedAuxBar'); + }); + + await test.step('Save plot', async () => { + await app.workbench.plots.savePlotFromPlotsPane({ name: 'Python-scatter', format: 'JPEG' }); + await app.workbench.layouts.enterLayout('stacked'); + await app.workbench.explorer.verifyProjectFilesExist(['Python-scatter.jpeg']); + }); + + await test.step('Open plot in editor', async () => { + await app.workbench.plots.openPlotInEditor(); + await app.workbench.plots.waitForPlotInEditor(); + }); + + await test.step('Save plot from editor', async () => { + await app.workbench.plots.savePlotFromEditor({ name: 'Python-scatter-editor', format: 'JPEG' }); + await app.workbench.explorer.verifyProjectFilesExist(['Python-scatter-editor.jpeg']); + await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors'); + }); - await app.workbench.plots.savePlot({ name: 'Python-scatter', format: 'JPEG' }); - await app.workbench.layouts.enterLayout('stacked'); - await app.workbench.explorer.verifyProjectFilesExist(['Python-scatter.jpeg']); }); test('Python - Verifies bqplot Python widget [C720869]', { tag: [tags.WEB, tags.WIN] }, async function ({ app }) { @@ -307,16 +322,31 @@ test.describe('Plots', { tag: [tags.PLOTS, tags.EDITOR] }, () => { }); test('R - Verifies saving an R plot [C557006]', { tag: [tags.WIN] }, async function ({ app, logger }) { - logger.log('Sending code to console'); + await test.step('Sending code to console to create plot', async () => { + await app.workbench.console.executeCode('R', rSavePlot, '>'); + await app.workbench.plots.waitForCurrentPlot(); + }); - await app.workbench.console.executeCode('R', rSavePlot, '>'); - await app.workbench.plots.waitForCurrentPlot(); + await test.step('Save plot as PNG', async () => { + await app.workbench.plots.savePlotFromPlotsPane({ name: 'plot', format: 'PNG' }); + await app.workbench.explorer.verifyProjectFilesExist(['plot.png']); + }); + + await test.step('Save plot as SVG', async () => { + await app.workbench.plots.savePlotFromPlotsPane({ name: 'R-cars', format: 'SVG' }); + await app.workbench.explorer.verifyProjectFilesExist(['R-cars.svg']); + }); - await app.workbench.plots.savePlot({ name: 'plot', format: 'PNG' }); - await app.workbench.explorer.verifyProjectFilesExist(['plot.png']); + await test.step('Open plot in editor', async () => { + await app.workbench.plots.openPlotInEditor(); + await app.workbench.plots.waitForPlotInEditor(); + }); - await app.workbench.plots.savePlot({ name: 'R-cars', format: 'SVG' }); - await app.workbench.explorer.verifyProjectFilesExist(['R-cars.svg']); + await test.step('Save plot from editor as JPEG', async () => { + await app.workbench.plots.savePlotFromEditor({ name: 'R-cars', format: 'JPEG' }); + await app.workbench.explorer.verifyProjectFilesExist(['R-cars.jpeg']); + await app.workbench.quickaccess.runCommand('workbench.action.closeAllEditors'); + }); }); test('R - Verifies rplot plot [C720873]', { tag: [tags.WEB, tags.WIN] }, async function ({ app }) { @@ -468,27 +498,6 @@ plt.title('My first graph!') # function to show the plot plt.show()`; -// modified snippet from https://www.geeksforgeeks.org/python-pandas-dataframe/ -const savePlot = `import pandas as pd -import matplotlib.pyplot as plt -data_dict = {'name': ['p1', 'p2', 'p3', 'p4', 'p5', 'p6'], - 'age': [20, 20, 21, 20, 21, 20], - 'math_marks': [100, 90, 91, 98, 92, 95], - 'physics_marks': [90, 100, 91, 92, 98, 95], - 'chem_marks': [93, 89, 99, 92, 94, 92] - } - -df = pd.DataFrame(data_dict) - -df.plot(kind='scatter', - x='math_marks', - y='physics_marks', - color='red') - -plt.title('ScatterPlot') -plt.show()`; - - const bgplot = `import bqplot.pyplot as bplt import numpy as np