From 8b2b8b658c8089dd9e11e68487fbdd072b623e92 Mon Sep 17 00:00:00 2001 From: Oskar Hane Date: Fri, 22 Nov 2019 15:18:40 +0100 Subject: [PATCH] Allow `:use xx` in multi-statement Added E2E tests --- e2e_tests/integration/multistatements.spec.js | 74 ++++++++++++++++--- e2e_tests/support/commands.js | 10 +++ src/browser/modules/Sidebar/Sidebar.jsx | 2 +- .../Stream/CypherScriptFrame/Summary.jsx | 21 +++--- src/shared/modules/commands/commandsDuck.js | 3 +- .../services/commandInterpreterHelper.js | 30 +++++--- 6 files changed, 107 insertions(+), 33 deletions(-) diff --git a/e2e_tests/integration/multistatements.spec.js b/e2e_tests/integration/multistatements.spec.js index e222442098b..cb224970b6f 100644 --- a/e2e_tests/integration/multistatements.spec.js +++ b/e2e_tests/integration/multistatements.spec.js @@ -28,21 +28,14 @@ describe('Multi statements', () => { .title() .should('include', 'Neo4j Browser') cy.wait(5000) - cy.get('[data-testid="drawerSettings"]').click() - cy.get('[data-testid="enableMultiStatementMode"]').click() - cy.get('[data-testid="drawerSettings"]').click() + cy.enableMultiStatement() }) after(() => { - cy.get('[data-testid="drawerSettings"]').click() - cy.get('[data-testid="enableMultiStatementMode"]').click() - cy.get('[data-testid="drawerSettings"]').click() + cy.disableMultiStatement() }) it('can connect', () => { const password = Cypress.config('password') - cy.connect( - 'neo4j', - password - ) + cy.connect('neo4j', password) }) it('can run multiple statements (non open by default)', () => { cy.executeCommand(':clear') @@ -119,4 +112,65 @@ describe('Multi statements', () => { .first() .should('contain', 'ERROR') }) + if (Cypress.config('serverVersion') >= 4.0) { + it('Can use :use command in multi-statements', () => { + cy.executeCommand(':clear') + // Create databases + cy.executeCommand(':use system') + cy.get('[data-testid="frame"]', { timeout: 10000 }).should( + 'have.length', + 1 + ) + cy.executeCommand('DROP DATABASE test1') + cy.executeCommand('DROP DATABASE test2') + cy.get('[data-testid="frame"]', { timeout: 10000 }).should( + 'have.length', + 3 + ) + cy.executeCommand(':clear') + + cy.executeCommand('CREATE DATABASE test1') + cy.get('[data-testid="frame"]', { timeout: 10000 }).should( + 'have.length', + 1 + ) + cy.executeCommand('CREATE DATABASE test2') + cy.get('[data-testid="frame"]', { timeout: 10000 }).should( + 'have.length', + 2 + ) + cy.executeCommand(':clear') + + // Time to try it + const query = ':use test1; CREATE(:Test1); :use test2; CREATE(:Test2);' + cy.executeCommand(query) + cy.get('[data-testid="frame"]', { timeout: 10000 }).should( + 'have.length', + 1 + ) + const frame = cy.get('[data-testid="frame"]', { timeout: 10000 }).first() + frame.get('[data-testid="multi-statement-list"]').should('have.length', 1) + frame + .get('[data-testid="multi-statement-list-title"]') + .should('have.length', 4) + frame + .get('[data-testid="multi-statement-list-content"]') + .should('have.length', 0) + + // Check sidebar for test1 + cy.executeCommand(':use test1') + cy.get('[data-testid="drawerDBMS"]').click() + cy.contains('[data-testid="sidebarMetaItem"]', 'Test1', { timeout: 5000 }) + cy.get('[data-testid="drawerDBMS"]').click() + + cy.executeCommand(':use test2') + cy.get('[data-testid="drawerDBMS"]').click() + cy.contains('[data-testid="sidebarMetaItem"]', 'Test2', { timeout: 5000 }) + cy.get('[data-testid="drawerDBMS"]').click() + + cy.executeCommand(':use system') + cy.executeCommand('DROP DATABASE test1') + cy.executeCommand('DROP DATABASE test2') + }) + } }) diff --git a/e2e_tests/support/commands.js b/e2e_tests/support/commands.js index 1984c9253ff..49d696e6e91 100644 --- a/e2e_tests/support/commands.js +++ b/e2e_tests/support/commands.js @@ -134,3 +134,13 @@ Cypress.Commands.add('addUser', (userName, password, role, force) => { .contains('Add User') .click() }) +Cypress.Commands.add('enableMultiStatement', () => { + cy.get('[data-testid="drawerSettings"]').click() + cy.get('[data-testid="enableMultiStatementMode"]').check() + cy.get('[data-testid="drawerSettings"]').click() +}) +Cypress.Commands.add('disableMultiStatement', () => { + cy.get('[data-testid="drawerSettings"]').click() + cy.get('[data-testid="enableMultiStatementMode"]').uncheck() + cy.get('[data-testid="drawerSettings"]').click() +}) diff --git a/src/browser/modules/Sidebar/Sidebar.jsx b/src/browser/modules/Sidebar/Sidebar.jsx index 9f574dca06c..947cce68eed 100644 --- a/src/browser/modules/Sidebar/Sidebar.jsx +++ b/src/browser/modules/Sidebar/Sidebar.jsx @@ -61,7 +61,7 @@ function Sidebar (props) { const AboutDrawer = About const topNavItemsList = [ { - name: 'DB', + name: 'DBMS', title: 'Database', icon: isOpen => ( . */ import React from 'react' -import ClickToCode from 'browser/modules/ClickToCode/index' import { getBodyAndStatusBarMessages } from 'browser/modules/Stream/CypherFrame/helpers' import { errorMessageFormater } from 'browser/modules/Stream/errorMessageFormater' import { @@ -28,6 +27,7 @@ import { StyledCypherInfoMessage } from 'browser/modules/Stream/styled' import { MessageArea, PaddedStatsBar } from './styled' +import { whitelistedMultiCommands } from 'shared/modules/commands/commandsDuck' const ucFirst = str => str[0].toUpperCase() + str.slice(1) @@ -64,8 +64,12 @@ const GenericSummary = ({ status }) => { WARNING - Only cypher and :param commands will be executed in the - multi statement mode. + Only the commands{' '} + {whitelistedMultiCommands().map((cmd, i) => { + const maybeComma = i > 0 ? ', ' : '' + return [maybeComma, {cmd}] + })}{' '} + and Cypher will be executed in the multi-statement mode. ) @@ -105,7 +109,7 @@ export const CypherSummary = ({ status, request }) => { } } -export const Summary = ({ status }) => { +export const Summary = ({ status, request }) => { switch (status) { case 'ignored': return @@ -119,7 +123,7 @@ export const Summary = ({ status }) => { return ( SUCCESS - Parameter was successfully set + Command was successfully executed ) case 'error': @@ -127,12 +131,7 @@ export const Summary = ({ status }) => { ERROR - Error while setting parameter. Usage:{' '} - :param x => [1, 2, 3]. See{' '} - - :help param - {' '} - for more info. + {(request.result || {}).message || 'Unknown error'} ) diff --git a/src/shared/modules/commands/commandsDuck.js b/src/shared/modules/commands/commandsDuck.js index 34e679beb23..4dca907e0d6 100644 --- a/src/shared/modules/commands/commandsDuck.js +++ b/src/shared/modules/commands/commandsDuck.js @@ -70,6 +70,7 @@ export const listDbsCommand = `dbs` const initialState = {} export const getErrorMessage = state => state[NAME].errorMessage +export const whitelistedMultiCommands = () => [':param', ':use'] export default function reducer (state = initialState, action) { if (action.type === APP_START) { @@ -174,7 +175,7 @@ export const handleCommandEpic = (action$, store) => cmd = cleanCommand(cmd) const requestId = v4() const cmdId = v4() - const whitelistedCommands = [`${cmdchar}param`] + const whitelistedCommands = whitelistedMultiCommands() const isWhitelisted = whitelistedCommands.filter(wcmd => !!cmd.startsWith(wcmd)).length > 0 diff --git a/src/shared/services/commandInterpreterHelper.js b/src/shared/services/commandInterpreterHelper.js index 78eec33705a..e876d5550cf 100644 --- a/src/shared/services/commandInterpreterHelper.js +++ b/src/shared/services/commandInterpreterHelper.js @@ -204,7 +204,7 @@ const availableCommands = [ if (!existingDb) { throw createErrorObject( NotFoundError, - 'Database with that name not found.' + 'A database with that name not found.' ) } // Everything ok @@ -217,15 +217,25 @@ const availableCommands = [ useDb: existingDb.name }) ) - } catch (e) { - put( - frames.add({ - useDb: getUseDb(store.getState()), - ...action, - type: 'error', - error: e - }) - ) + if (action.requestId) { + put(updateQueryResult(action.requestId, null, 'success')) + } + return true + } catch (error) { + if (!action.parentId) { + put( + frames.add({ + useDb: getUseDb(store.getState()), + ...action, + type: 'error', + error + }) + ) + } + if (action.requestId) { + put(updateQueryResult(action.requestId, error, 'error')) + } + throw error } } },