Merge pull request #4700 from Budibase/rest-api-endpoint-naming

Improve REST query naming in navigation
This commit is contained in:
Andrew Kingston 2022-03-01 11:41:56 +00:00 committed by GitHub
commit 7266712f8f
5 changed files with 168 additions and 108 deletions

View File

@ -1,43 +1,45 @@
import filterTests from "../../support/filterTests" import filterTests from "../../support/filterTests"
filterTests(['smoke', 'all'], () => { filterTests(["smoke", "all"], () => {
context("REST Datasource Testing", () => { context("REST Datasource Testing", () => {
before(() => { before(() => {
cy.login() cy.login()
cy.createTestApp() 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)
})
}) })
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)
})
})
}) })

View File

@ -1,6 +1,6 @@
import filterTests from "../support/filterTests" import filterTests from "../support/filterTests"
filterTests(['smoke', 'all'], () => { filterTests(["smoke", "all"], () => {
context("Query Level Transformers", () => { context("Query Level Transformers", () => {
before(() => { before(() => {
cy.login() cy.login()
@ -9,54 +9,60 @@ filterTests(['smoke', 'all'], () => {
}) })
it("should write a transformer function", () => { it("should write a transformer function", () => {
// Add REST datasource - contains API for breweries // Add REST datasource - contains API for breweries
const datasource = "REST" const datasource = "REST"
const restUrl = "https://api.openbrewerydb.org/breweries" const restUrl = "https://api.openbrewerydb.org/breweries"
cy.selectExternalDatasource(datasource) cy.selectExternalDatasource(datasource)
cy.createRestQuery("GET", restUrl) cy.createRestQuery("GET", restUrl, "/breweries")
cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click()
// Get Transformer Function from file // Get Transformer Function from file
cy.readFile("cypress/support/queryLevelTransformerFunction.js").then((transformerFunction) => { cy.readFile("cypress/support/queryLevelTransformerFunction.js").then(
transformerFunction => {
cy.get(".CodeMirror textarea") cy.get(".CodeMirror textarea")
// Highlight current text and overwrite with file contents // Highlight current text and overwrite with file contents
.type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", {
.type(transformerFunction, { parseSpecialCharSequences: false }) force: true,
}) })
// Send Query .type(transformerFunction, { parseSpecialCharSequences: false })
cy.intercept('**/queries/preview').as('query') }
cy.get(".spectrum-Button").contains("Send").click({ force: true }) )
cy.wait("@query") // Send Query
// Assert against Status Code, body, & body rows cy.intercept("**/queries/preview").as("query")
cy.get("@query").its('response.statusCode') cy.get(".spectrum-Button").contains("Send").click({ force: true })
.should('eq', 200) cy.wait("@query")
cy.get("@query").its('response.body').should('not.be.empty') // Assert against Status Code, body, & body rows
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 add data to the previous query", () => { it("should add data to the previous query", () => {
// Add REST datasource - contains API for breweries // Add REST datasource - contains API for breweries
const datasource = "REST" const datasource = "REST"
const restUrl = "https://api.openbrewerydb.org/breweries" const restUrl = "https://api.openbrewerydb.org/breweries"
cy.selectExternalDatasource(datasource) cy.selectExternalDatasource(datasource)
cy.createRestQuery("GET", restUrl) cy.createRestQuery("GET", restUrl, "/breweries")
cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click()
// Get Transformer Function with Data from file // 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]) //console.log(transformerFunction[1])
cy.get(".CodeMirror textarea") cy.get(".CodeMirror textarea")
// Highlight current text and overwrite with file contents // Highlight current text and overwrite with file contents
.type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", {
.type(transformerFunction, { parseSpecialCharSequences: false }) force: true,
})
.type(transformerFunction, { parseSpecialCharSequences: false })
}) })
// Send Query // Send Query
cy.intercept('**/queries/preview').as('query') cy.intercept("**/queries/preview").as("query")
cy.get(".spectrum-Button").contains("Send").click({ force: true }) cy.get(".spectrum-Button").contains("Send").click({ force: true })
cy.wait("@query") cy.wait("@query")
// Assert against Status Code, body, & body rows // Assert against Status Code, body, & body rows
cy.get("@query").its('response.statusCode') cy.get("@query").its("response.statusCode").should("eq", 200)
.should('eq', 200) cy.get("@query").its("response.body").should("not.be.empty")
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.body.rows').should('not.be.empty')
}) })
it("should run an invalid query within the transformer section", () => { it("should run an invalid query within the transformer section", () => {
@ -64,52 +70,70 @@ filterTests(['smoke', 'all'], () => {
const datasource = "REST" const datasource = "REST"
const restUrl = "https://api.openbrewerydb.org/breweries" const restUrl = "https://api.openbrewerydb.org/breweries"
cy.selectExternalDatasource(datasource) cy.selectExternalDatasource(datasource)
cy.createRestQuery("GET", restUrl) cy.createRestQuery("GET", restUrl, "/breweries")
cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click() cy.get(".spectrum-Tabs-itemLabel").contains("Transformer").click()
// Clear the code box and add "test" // Clear the code box and add "test"
cy.get(".CodeMirror textarea") cy.get(".CodeMirror textarea")
.type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true }) .type(Cypress.platform === "darwin" ? "{cmd}a" : "{ctrl}a", {
.type("test") force: true,
})
.type("test")
// Run Query and intercept // Run Query and intercept
cy.intercept('**/preview').as('queryError') cy.intercept("**/preview").as("queryError")
cy.get(".spectrum-Button").contains("Send").click({ force: true }) cy.get(".spectrum-Button").contains("Send").click({ force: true })
cy.wait("@queryError") cy.wait("@queryError")
cy.wait(500) cy.wait(500)
// Assert against message and status for the query error // 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")
cy.get("@queryError").its('response.body').should('have.property', 'status', 400) .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", () => { xit("should run an invalid query via POST request", () => {
// POST request with transformer as null // POST request with transformer as null
cy.request({method: 'POST', cy.request({
url: `${Cypress.config().baseUrl}/api/queries/`, method: "POST",
body: {fields : {"headers":{},"queryString":null,"path":null}, url: `${Cypress.config().baseUrl}/api/queries/`,
parameters : [], body: {
schema : {}, fields: { headers: {}, queryString: null, path: null },
name : "test", parameters: [],
queryVerb : "read", schema: {},
transformer : null, name: "test",
datasourceId: "test"}, queryVerb: "read",
// Expected 400 error - Transformer must be a string transformer: null,
failOnStatusCode: false}).then((response) => { datasourceId: "test",
},
// Expected 400 error - Transformer must be a string
failOnStatusCode: false,
}).then(response => {
expect(response.status).to.equal(400) 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", () => { xit("should run an empty query", () => {
// POST request with Transformer as an empty string // POST request with Transformer as an empty string
cy.request({method: 'POST', cy.request({
url: `${Cypress.config().baseUrl}/api/queries/preview`, method: "POST",
body: {fields : {"headers":{},"queryString":null,"path":null}, url: `${Cypress.config().baseUrl}/api/queries/preview`,
queryVerb : "read", body: {
transformer : "", fields: { headers: {}, queryString: null, path: null },
datasourceId: "test"}, queryVerb: "read",
// Expected 400 error - Transformer is not allowed to be empty transformer: "",
failOnStatusCode: false}).then((response) => { datasourceId: "test",
},
// Expected 400 error - Transformer is not allowed to be empty
failOnStatusCode: false,
}).then(response => {
expect(response.status).to.equal(400) 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'
)
}) })
}) })
}) })

View File

@ -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 // addExternalDatasource should be called prior to this
// Configures REST datasource & sends query // Configures REST datasource & sends query
cy.wait(1000) cy.wait(1000)
@ -450,5 +450,5 @@ Cypress.Commands.add("createRestQuery", (method, restUrl) => {
cy.get(".spectrum-Button").contains("Save").click({ force: true }) cy.get(".spectrum-Button").contains("Save").click({ force: true })
cy.get(".hierarchy-items-container") cy.get(".hierarchy-items-container")
.should("contain", method) .should("contain", method)
.and("contain", restUrl) .and("contain", queryPrettyName)
}) })

View File

@ -8,7 +8,11 @@
import EditQueryPopover from "./popovers/EditQueryPopover.svelte" import EditQueryPopover from "./popovers/EditQueryPopover.svelte"
import NavItem from "components/common/NavItem.svelte" import NavItem from "components/common/NavItem.svelte"
import TableNavigator from "components/backend/TableNavigator/TableNavigator.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 ICONS from "./icons"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
@ -137,7 +141,7 @@
icon="SQLQuery" icon="SQLQuery"
iconText={customQueryIconText(datasource, query)} iconText={customQueryIconText(datasource, query)}
iconColor={customQueryIconColor(datasource, query)} iconColor={customQueryIconColor(datasource, query)}
text={query.name} text={customQueryText(datasource, query)}
opened={$queries.selected === query._id} opened={$queries.selected === query._id}
selected={$queries.selected === query._id} selected={$queries.selected === query._id}
on:click={() => onClickQuery(query)} on:click={() => onClickQuery(query)}

View File

@ -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) { export function flipHeaderState(headersActivity) {
if (!headersActivity) { if (!headersActivity) {
return {} return {}