diff --git a/test/e2e/infra/fixtures/interpreter.ts b/test/e2e/infra/fixtures/interpreter.ts index 2d3c91070c0..b247cea065c 100644 --- a/test/e2e/infra/fixtures/interpreter.ts +++ b/test/e2e/infra/fixtures/interpreter.ts @@ -46,14 +46,8 @@ export class Interpreter { await test.step(`Select interpreter via Quick Access: ${interpreterType}`, async () => { interpreterType === 'Python' - ? await this.console.selectInterpreter(InterpreterType.Python, DESIRED_PYTHON) - : await this.console.selectInterpreter(InterpreterType.R, DESIRED_R); - - if (waitForReady) { - interpreterType === 'Python' - ? await this.console.waitForReady('>>>', 30000) - : await this.console.waitForReady('>', 30000); - } + ? await this.console.selectInterpreter(InterpreterType.Python, DESIRED_PYTHON, waitForReady) + : await this.console.selectInterpreter(InterpreterType.R, DESIRED_R, waitForReady); }); }; diff --git a/test/e2e/tests/_test.setup.ts b/test/e2e/tests/_test.setup.ts index 153d88e80e5..c792ff1876d 100644 --- a/test/e2e/tests/_test.setup.ts +++ b/test/e2e/tests/_test.setup.ts @@ -109,13 +109,13 @@ export const test = base.extend({ }, { scope: 'worker', auto: true, timeout: 60000 }], interpreter: [async ({ app, page }, use) => { - const setInterpreter = async (desiredInterpreter: 'Python' | 'R') => { + const setInterpreter = async (desiredInterpreter: 'Python' | 'R', waitForReady = true) => { const currentInterpreter = await page.locator('.top-action-bar-interpreters-manager').textContent() || ''; if (!currentInterpreter.startsWith(desiredInterpreter)) { desiredInterpreter === 'Python' - ? await app.workbench.interpreter.startInterpreterViaQuickAccess('Python') - : await app.workbench.interpreter.startInterpreterViaQuickAccess('R'); + ? await app.workbench.interpreter.startInterpreterViaQuickAccess('Python', waitForReady) + : await app.workbench.interpreter.startInterpreterViaQuickAccess('R', waitForReady); } }; diff --git a/test/e2e/tests/reticulate/reticulate.test.ts b/test/e2e/tests/reticulate/reticulate.test.ts index 9cee32559a5..d33bdbcc9af 100644 --- a/test/e2e/tests/reticulate/reticulate.test.ts +++ b/test/e2e/tests/reticulate/reticulate.test.ts @@ -19,10 +19,7 @@ test.describe('Reticulate', { }, () => { test.beforeAll(async function ({ app, userSettings }) { try { - // remove this once https://github.com/posit-dev/positron/issues/5226 - // is resolved await userSettings.set([ - ['kernelSupervisor.enable', 'false'], ['positron.reticulate.enabled', 'true'] ]); @@ -32,6 +29,10 @@ test.describe('Reticulate', { } }); + // if running tests in sequence, we will need to skip waiting for ready because interpreters + // will already be running + let sequential = false; + test('R - Verify Basic Reticulate Functionality [C...]', async function ({ app, r, interpreter }) { await app.workbench.console.pasteCodeToConsole('reticulate::repl_python()'); @@ -46,19 +47,69 @@ test.describe('Reticulate', { } await app.workbench.console.waitForReady('>>>'); - await app.workbench.console.pasteCodeToConsole('x=100'); - await app.workbench.console.sendEnterKey(); - await interpreter.set('R'); + await verifyReticulateFunctionality(app, interpreter, false); - await app.workbench.console.pasteCodeToConsole('y<-reticulate::py$x'); - await app.workbench.console.sendEnterKey(); - await app.workbench.layouts.enterLayout('fullSizedAuxBar'); + sequential = true; + + }); + + test('R - Verify Reticulate Stop/Restart Functionality [C...]', async function ({ app, interpreter }) { + + // web only test but we don't have another way to skip electron tests + if (!app.web) { + return; + } + + await app.workbench.interpreter.selectInterpreter('Python', 'Python (reticulate)', !sequential); + + await verifyReticulateFunctionality(app, interpreter, sequential); + + await app.workbench.layouts.enterLayout('stacked'); + + await app.workbench.console.barPowerButton.click(); + + await app.workbench.console.waitForConsoleContents('shut down successfully'); + + await app.code.driver.page.locator('.positron-console').getByRole('button', { name: 'Restart R' }).click(); + + await app.workbench.console.waitForReady('>'); - await expect(async () => { - const variablesMap = await app.workbench.variables.getFlatVariables(); - expect(variablesMap.get('y')).toStrictEqual({ value: '100', type: 'int' }); - }).toPass({ timeout: 60000 }); + await app.code.driver.page.locator('.positron-console').locator('.action-bar-button-drop-down-arrow').click(); + + await app.code.driver.page.locator('.action-label', { hasText: 'Python (reticulate)' }).hover(); + + await app.code.driver.page.keyboard.press('Enter'); + + await app.code.driver.page.locator('.positron-console').getByRole('button', { name: 'Restart Python' }).click(); + + await app.workbench.console.waitForReady('>>>'); + + await verifyReticulateFunctionality(app, interpreter, sequential); }); }); + +async function verifyReticulateFunctionality(app, interpreter, sequential) { + + await app.workbench.console.pasteCodeToConsole('x=100'); + await app.workbench.console.sendEnterKey(); + + await app.workbench.console.barClearButton.click(); + + await interpreter.set('R', !sequential); + + await app.workbench.console.pasteCodeToConsole('y<-reticulate::py$x'); + await app.workbench.console.sendEnterKey(); + + await app.workbench.console.barClearButton.click(); + + await app.workbench.layouts.enterLayout('fullSizedAuxBar'); + + await expect(async () => { + const variablesMap = await app.workbench.variables.getFlatVariables(); + expect(variablesMap.get('y')).toStrictEqual({ value: '100', type: 'int' }); + }).toPass({ timeout: 60000 }); + + await app.workbench.layouts.enterLayout('stacked'); +};