From e34895989bb7ca8c5b0cf0b782835ea88fd112b5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 25 Feb 2022 14:18:26 +0000 Subject: [PATCH 1/3] Improve REST query naming in navigation --- .../DatasourceNavigator.svelte | 8 +++-- packages/builder/src/helpers/data/utils.js | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte index 661c125377..45ff66a901 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte @@ -8,7 +8,11 @@ import EditQueryPopover from "./popovers/EditQueryPopover.svelte" import NavItem from "components/common/NavItem.svelte" import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte" - import { customQueryIconText, customQueryIconColor } from "helpers/data/utils" + import { + customQueryIconText, + customQueryIconColor, + customQueryText, + } from "helpers/data/utils" import ICONS from "./icons" import { notifications } from "@budibase/bbui" @@ -137,7 +141,7 @@ icon="SQLQuery" iconText={customQueryIconText(datasource, query)} iconColor={customQueryIconColor(datasource, query)} - text={query.name} + text={customQueryText(datasource, query)} opened={$queries.selected === query._id} selected={$queries.selected === query._id} on:click={() => onClickQuery(query)} diff --git a/packages/builder/src/helpers/data/utils.js b/packages/builder/src/helpers/data/utils.js index 0e99109189..8fe7b617a2 100644 --- a/packages/builder/src/helpers/data/utils.js +++ b/packages/builder/src/helpers/data/utils.js @@ -109,6 +109,36 @@ export function customQueryIconColor(datasource, query) { } } +export function customQueryText(datasource, query) { + if (!query.name || datasource.source !== IntegrationTypes.REST) { + return query.name + } + + // Remove protocol + let name = query.name + if (name.includes("://")) { + name = name.split("://")[1] + } + + // If no path, return the full name + if (!name.includes("/")) { + return name + } + + // Remove trailing slash + if (name.endsWith("/")) { + name = name.slice(0, -1) + } + + // Only use path + const split = name.split("/") + if (split[1]) { + return `/${split.slice(1).join("/")}` + } else { + return split[0] + } +} + export function flipHeaderState(headersActivity) { if (!headersActivity) { return {} From 02725e08d21ee257569c3b373ba6c8e27f0385fb Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 25 Feb 2022 14:29:25 +0000 Subject: [PATCH 2/3] Handle leading double slash when displaying REST queries in navigation --- packages/builder/src/helpers/data/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/helpers/data/utils.js b/packages/builder/src/helpers/data/utils.js index 8fe7b617a2..47a8075070 100644 --- a/packages/builder/src/helpers/data/utils.js +++ b/packages/builder/src/helpers/data/utils.js @@ -116,8 +116,8 @@ export function customQueryText(datasource, query) { // Remove protocol let name = query.name - if (name.includes("://")) { - name = name.split("://")[1] + if (name.includes("//")) { + name = name.split("//")[1] } // If no path, return the full name From 40273b7148633011ff2e27b43cdc1b880c8580de Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 25 Feb 2022 16:24:36 +0000 Subject: [PATCH 3/3] Pls cypress --- .../integration/datasources/rest.spec.js | 80 ++++----- .../queryLevelTransformers.spec.js | 154 ++++++++++-------- packages/builder/cypress/support/commands.js | 4 +- 3 files changed, 132 insertions(+), 106 deletions(-) diff --git a/packages/builder/cypress/integration/datasources/rest.spec.js b/packages/builder/cypress/integration/datasources/rest.spec.js index f39d174831..58ba74795a 100644 --- a/packages/builder/cypress/integration/datasources/rest.spec.js +++ b/packages/builder/cypress/integration/datasources/rest.spec.js @@ -1,43 +1,45 @@ import filterTests from "../../support/filterTests" -filterTests(['smoke', 'all'], () => { - context("REST Datasource Testing", () => { - before(() => { - cy.login() - cy.createTestApp() - }) - - const datasource = "REST" - const restUrl = "https://api.openbrewerydb.org/breweries" - - it("Should add REST data source with incorrect API", () => { - // Select REST data source - cy.selectExternalDatasource(datasource) - // Enter incorrect api & attempt to send query - cy.wait(500) - cy.get(".spectrum-Button").contains("Add query").click({ force: true }) - cy.intercept('**/preview').as('queryError') - cy.get("input").clear().type("random text") - cy.get(".spectrum-Button").contains("Send").click({ force: true }) - // Intercept Request after button click & apply assertions - cy.wait("@queryError") - cy.get("@queryError").its('response.body') - .should('have.property', 'message', 'Invalid URL: http://random text?') - cy.get("@queryError").its('response.body') - .should('have.property', 'status', 400) - }) - - it("should add and configure a REST datasource", () => { - // Select REST datasource and create query - cy.selectExternalDatasource(datasource) - cy.wait(500) - // createRestQuery confirms query creation - cy.createRestQuery("GET", restUrl) - // Confirm status code response within REST datasource - cy.get(".spectrum-FieldLabel") - .contains("Status") - .children() - .should('contain', 200) - }) +filterTests(["smoke", "all"], () => { + context("REST Datasource Testing", () => { + before(() => { + cy.login() + cy.createTestApp() }) + + const datasource = "REST" + const restUrl = "https://api.openbrewerydb.org/breweries" + + it("Should add REST data source with incorrect API", () => { + // Select REST data source + cy.selectExternalDatasource(datasource) + // Enter incorrect api & attempt to send query + cy.wait(500) + cy.get(".spectrum-Button").contains("Add query").click({ force: true }) + cy.intercept("**/preview").as("queryError") + cy.get("input").clear().type("random text") + cy.get(".spectrum-Button").contains("Send").click({ force: true }) + // Intercept Request after button click & apply assertions + cy.wait("@queryError") + cy.get("@queryError") + .its("response.body") + .should("have.property", "message", "Invalid URL: http://random text?") + cy.get("@queryError") + .its("response.body") + .should("have.property", "status", 400) + }) + + it("should add and configure a REST datasource", () => { + // Select REST datasource and create query + cy.selectExternalDatasource(datasource) + cy.wait(500) + // createRestQuery confirms query creation + cy.createRestQuery("GET", restUrl, "/breweries") + // Confirm status code response within REST datasource + cy.get(".spectrum-FieldLabel") + .contains("Status") + .children() + .should("contain", 200) + }) + }) }) diff --git a/packages/builder/cypress/integration/queryLevelTransformers.spec.js b/packages/builder/cypress/integration/queryLevelTransformers.spec.js index d6d4278eb4..e96a6dba29 100644 --- a/packages/builder/cypress/integration/queryLevelTransformers.spec.js +++ b/packages/builder/cypress/integration/queryLevelTransformers.spec.js @@ -1,115 +1,139 @@ import filterTests from "../support/filterTests" -filterTests(['smoke', 'all'], () => { +filterTests(["smoke", "all"], () => { context("Query Level Transformers", () => { before(() => { cy.login() cy.deleteApp("Cypress Tests") cy.createApp("Cypress Tests") }) - + it("should write a transformer function", () => { - // Add REST datasource - contains API for breweries - const datasource = "REST" - const restUrl = "https://api.openbrewerydb.org/breweries" - cy.selectExternalDatasource(datasource) - cy.createRestQuery("GET", restUrl) - cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() - // Get Transformer Function from file - cy.readFile("cypress/support/queryLevelTransformerFunction.js").then((transformerFunction) => { + // Add REST datasource - contains API for breweries + const datasource = "REST" + const restUrl = "https://api.openbrewerydb.org/breweries" + cy.selectExternalDatasource(datasource) + cy.createRestQuery("GET", restUrl, "/breweries") + cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() + // Get Transformer Function from file + cy.readFile("cypress/support/queryLevelTransformerFunction.js").then( + transformerFunction => { cy.get(".CodeMirror textarea") - // Highlight current text and overwrite with file contents - .type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) - .type(transformerFunction, { parseSpecialCharSequences: false }) - }) - // Send Query - cy.intercept('**/queries/preview').as('query') - cy.get(".spectrum-Button").contains("Send").click({ force: true }) - cy.wait("@query") - // Assert against Status Code, body, & body rows - cy.get("@query").its('response.statusCode') - .should('eq', 200) - cy.get("@query").its('response.body').should('not.be.empty') - cy.get("@query").its('response.body.rows').should('not.be.empty') - }) - + // Highlight current text and overwrite with file contents + .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", { + force: true, + }) + .type(transformerFunction, { parseSpecialCharSequences: false }) + } + ) + // Send Query + cy.intercept("**/queries/preview").as("query") + cy.get(".spectrum-Button").contains("Send").click({ force: true }) + cy.wait("@query") + // Assert against Status Code, body, & body rows + cy.get("@query").its("response.statusCode").should("eq", 200) + cy.get("@query").its("response.body").should("not.be.empty") + cy.get("@query").its("response.body.rows").should("not.be.empty") + }) + it("should add data to the previous query", () => { // Add REST datasource - contains API for breweries const datasource = "REST" const restUrl = "https://api.openbrewerydb.org/breweries" cy.selectExternalDatasource(datasource) - cy.createRestQuery("GET", restUrl) + cy.createRestQuery("GET", restUrl, "/breweries") cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() // Get Transformer Function with Data from file - cy.readFile("cypress/support/queryLevelTransformerFunctionWithData.js").then((transformerFunction) => { + cy.readFile( + "cypress/support/queryLevelTransformerFunctionWithData.js" + ).then(transformerFunction => { //console.log(transformerFunction[1]) cy.get(".CodeMirror textarea") - // Highlight current text and overwrite with file contents - .type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) - .type(transformerFunction, { parseSpecialCharSequences: false }) + // Highlight current text and overwrite with file contents + .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", { + force: true, + }) + .type(transformerFunction, { parseSpecialCharSequences: false }) }) // Send Query - cy.intercept('**/queries/preview').as('query') + cy.intercept("**/queries/preview").as("query") cy.get(".spectrum-Button").contains("Send").click({ force: true }) cy.wait("@query") // Assert against Status Code, body, & body rows - cy.get("@query").its('response.statusCode') - .should('eq', 200) - cy.get("@query").its('response.body').should('not.be.empty') - cy.get("@query").its('response.body.rows').should('not.be.empty') + cy.get("@query").its("response.statusCode").should("eq", 200) + cy.get("@query").its("response.body").should("not.be.empty") + cy.get("@query").its("response.body.rows").should("not.be.empty") }) - + it("should run an invalid query within the transformer section", () => { // Add REST datasource - contains API for breweries const datasource = "REST" const restUrl = "https://api.openbrewerydb.org/breweries" cy.selectExternalDatasource(datasource) - cy.createRestQuery("GET", restUrl) + cy.createRestQuery("GET", restUrl, "/breweries") cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() // Clear the code box and add "test" cy.get(".CodeMirror textarea") - .type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) - .type("test") + .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", { + force: true, + }) + .type("test") // Run Query and intercept - cy.intercept('**/preview').as('queryError') + cy.intercept("**/preview").as("queryError") cy.get(".spectrum-Button").contains("Send").click({ force: true }) cy.wait("@queryError") cy.wait(500) // Assert against message and status for the query error - cy.get("@queryError").its('response.body').should('have.property', 'message', "test is not defined") - cy.get("@queryError").its('response.body').should('have.property', 'status', 400) + cy.get("@queryError") + .its("response.body") + .should("have.property", "message", "test is not defined") + cy.get("@queryError") + .its("response.body") + .should("have.property", "status", 400) }) - + xit("should run an invalid query via POST request", () => { // POST request with transformer as null - cy.request({method: 'POST', - url: `${Cypress.config().baseUrl}/api/queries/`, - body: {fields : {"headers":{},"queryString":null,"path":null}, - parameters : [], - schema : {}, - name : "test", - queryVerb : "read", - transformer : null, - datasourceId: "test"}, - // Expected 400 error - Transformer must be a string - failOnStatusCode: false}).then((response) => { + cy.request({ + method: "POST", + url: `${Cypress.config().baseUrl}/api/queries/`, + body: { + fields: { headers: {}, queryString: null, path: null }, + parameters: [], + schema: {}, + name: "test", + queryVerb: "read", + transformer: null, + datasourceId: "test", + }, + // Expected 400 error - Transformer must be a string + failOnStatusCode: false, + }).then(response => { expect(response.status).to.equal(400) - expect(response.body.message).to.include('Invalid body - "transformer" must be a string') + expect(response.body.message).to.include( + 'Invalid body - "transformer" must be a string' + ) }) }) - + xit("should run an empty query", () => { // POST request with Transformer as an empty string - cy.request({method: 'POST', - url: `${Cypress.config().baseUrl}/api/queries/preview`, - body: {fields : {"headers":{},"queryString":null,"path":null}, - queryVerb : "read", - transformer : "", - datasourceId: "test"}, - // Expected 400 error - Transformer is not allowed to be empty - failOnStatusCode: false}).then((response) => { + cy.request({ + method: "POST", + url: `${Cypress.config().baseUrl}/api/queries/preview`, + body: { + fields: { headers: {}, queryString: null, path: null }, + queryVerb: "read", + transformer: "", + datasourceId: "test", + }, + // Expected 400 error - Transformer is not allowed to be empty + failOnStatusCode: false, + }).then(response => { expect(response.status).to.equal(400) - expect(response.body.message).to.include('Invalid body - "transformer" is not allowed to be empty') + expect(response.body.message).to.include( + 'Invalid body - "transformer" is not allowed to be empty' + ) }) }) }) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 40fe6706c9..8e205f7d67 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -435,7 +435,7 @@ Cypress.Commands.add("addDatasourceConfig", (datasource, skipFetch) => { } }) -Cypress.Commands.add("createRestQuery", (method, restUrl) => { +Cypress.Commands.add("createRestQuery", (method, restUrl, queryPrettyName) => { // addExternalDatasource should be called prior to this // Configures REST datasource & sends query cy.wait(1000) @@ -450,5 +450,5 @@ Cypress.Commands.add("createRestQuery", (method, restUrl) => { cy.get(".spectrum-Button").contains("Save").click({ force: true }) cy.get(".hierarchy-items-container") .should("contain", method) - .and("contain", restUrl) + .and("contain", queryPrettyName) })