From 7502a2ce93be9aed3beb4860c9908416975e436f Mon Sep 17 00:00:00 2001 From: Christopher Mead Date: Wed, 9 Oct 2024 07:39:02 -0600 Subject: [PATCH] Python App Tests (#4947) Python App Tests * Dash * Gradio * FastApi - disabled and bug filed for ubuntu * Streamlit Only streamlit currently works is web mode, so web execution is only enabled for it. Note that you may need to update your streamlit package to get this to pass locally. ### QA Notes All smoke tests should pass --- .../automation/src/positron/positronEditor.ts | 5 ++ .../automation/src/positron/positronViewer.ts | 12 ++- .../areas/positron/apps/pythonApps.test.ts | 85 +++++++++++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 test/smoke/src/areas/positron/apps/pythonApps.test.ts diff --git a/test/automation/src/positron/positronEditor.ts b/test/automation/src/positron/positronEditor.ts index a79fbe622ad..0318ccf5f63 100644 --- a/test/automation/src/positron/positronEditor.ts +++ b/test/automation/src/positron/positronEditor.ts @@ -8,12 +8,17 @@ import { Code } from '../code'; // currently a dupe of declaration in ../editor.ts but trying not to modifiy that file const EDITOR = (filename: string) => `.monaco-editor[data-uri$="${filename}"]`; const CURRENT_LINE = '.view-overlays .current-line'; +const PLAY_BUTTON = '.codicon-play'; export class PositronEditor { constructor(private code: Code) { } + async pressPlay(): Promise { + await this.code.driver.getLocator(PLAY_BUTTON).click(); + } + async pressToLine(filename: string, lineNumber: number, press: string): Promise { const editor = EDITOR(filename); const line = `${editor} .view-lines > .view-line:nth-child(${lineNumber})`; diff --git a/test/automation/src/positron/positronViewer.ts b/test/automation/src/positron/positronViewer.ts index 61848ddd189..7c6eafac04d 100644 --- a/test/automation/src/positron/positronViewer.ts +++ b/test/automation/src/positron/positronViewer.ts @@ -18,11 +18,17 @@ export class PositronViewer { constructor(private code: Code) { } - getViewerLocator(sublocator: string): Locator { + getViewerLocator(sublocator: string, additionalNesting = false): Locator { const outerFrame = this.code.driver.getFrame(OUTER_FRAME); const innerFrame = outerFrame.frameLocator(INNER_FRAME); - const element = innerFrame.locator(sublocator); - return element; + if (!additionalNesting) { + const element = innerFrame.locator(sublocator); + return element; + } else { + const innerInnerFrame = innerFrame.frameLocator('//iframe'); + const element = innerInnerFrame.locator(sublocator); + return element; + } } getViewerFrame(frameLocator: string): FrameLocator { diff --git a/test/smoke/src/areas/positron/apps/pythonApps.test.ts b/test/smoke/src/areas/positron/apps/pythonApps.test.ts new file mode 100644 index 00000000000..38b8119c652 --- /dev/null +++ b/test/smoke/src/areas/positron/apps/pythonApps.test.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + +import { expect } from '@playwright/test'; +import { Application, PositronPythonFixtures } from '../../../../../automation/out'; +import { setupAndStartApp } from '../../../test-runner/test-hooks'; +import { join } from 'path'; + +describe('Python Applications #pr', () => { + setupAndStartApp(); + + describe('Python Applications', () => { + before(async function () { + await this.app.workbench.positronConsole.waitForReadyOrNoInterpreter(); + + await PositronPythonFixtures.SetupFixtures(this.app as Application); + }); + + afterEach(async function () { + await this.app.workbench.positronTerminal.sendKeysToTerminal('Control+C'); + + // unreliable on ubuntu: + // await this.app.workbench.terminal.waitForTerminalText(buffer => buffer.some(line => line.includes('^C'))); + + await this.app.workbench.positronViewer.refreshViewer(); + }); + + it('Python - Verify Basic Dash App [C903305]', async function () { + const app = this.app as Application; + + await app.workbench.quickaccess.openFile(join(app.workspacePathOrFolder, 'workspaces', 'python_apps', 'dash_example', 'dash_example.py')); + + await app.workbench.positronEditor.pressPlay(); + + const headerLocator = app.workbench.positronViewer.getViewerLocator('#_dash-app-content'); + + await expect(headerLocator).toHaveText('Hello World', { timeout: 30000 }); + + }); + + // https://github.com/posit-dev/positron/issues/4949 + // FastAPI is not working as expected on Ubuntu + it.skip('Python - Verify Basic FastAPI App [C903306]', async function () { + const app = this.app as Application; + + await app.workbench.quickaccess.openFile(join(app.workspacePathOrFolder, 'workspaces', 'python_apps', 'fastapi_example', 'fastapi_example.py')); + + await app.workbench.positronEditor.pressPlay(); + + const headerLocator = app.workbench.positronViewer.getViewerLocator('h2.title'); + + await expect(headerLocator).toContainText('FastAPI', { timeout: 30000 }); + + }); + + it('Python - Verify Basic Gradio App [C903307]', async function () { + const app = this.app as Application; + + await app.workbench.quickaccess.openFile(join(app.workspacePathOrFolder, 'workspaces', 'python_apps', 'gradio_example', 'gradio_example.py')); + + await app.workbench.positronEditor.pressPlay(); + + const headerLocator = app.workbench.positronViewer.getViewerLocator('button.primary'); + + await expect(headerLocator).toHaveText('Submit', { timeout: 30000 }); + + }); + + it('Python - Verify Basic Streamlit App [C903308] #web', async function () { + const app = this.app as Application; + + await app.workbench.quickaccess.openFile(join(app.workspacePathOrFolder, 'workspaces', 'python_apps', 'streamlit_example', 'streamlit_example.py')); + + await app.workbench.positronEditor.pressPlay(); + + const headerLocator = app.workbench.positronViewer.getViewerLocator('div.stAppDeployButton', this.app.web); + + await expect(headerLocator).toHaveText('Deploy', { timeout: 30000 }); + + }); + }); +}); +