Fixes for Rest API request UI. Rest test fixes for XML API request body. Fix for raw XML api request body parsing issue. General fixes for query testing.
This commit is contained in:
parent
e75ea3361b
commit
18f2e13a30
|
@ -96,10 +96,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cloneQuery?.fields?.requestBody) {
|
if (cloneQuery?.fields?.requestBody) {
|
||||||
cloneQuery.fields.requestBody = runtimeToReadableBinding(
|
cloneQuery.fields.requestBody =
|
||||||
restBindings,
|
typeof cloneQuery.fields.requestBody === "object"
|
||||||
cloneQuery.fields.requestBody
|
? runtimeToReadableMap(restBindings, cloneQuery.fields.requestBody)
|
||||||
)
|
: runtimeToReadableBinding(
|
||||||
|
restBindings,
|
||||||
|
cloneQuery.fields.requestBody
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cloneQuery?.parameters) {
|
if (cloneQuery?.parameters) {
|
||||||
|
@ -141,10 +144,11 @@
|
||||||
restBindings,
|
restBindings,
|
||||||
newQuery.fields.headers
|
newQuery.fields.headers
|
||||||
)
|
)
|
||||||
newQuery.fields.requestBody = readableToRuntimeBinding(
|
newQuery.fields.requestBody =
|
||||||
restBindings,
|
typeof newQuery.fields.requestBody === "object"
|
||||||
newQuery.fields.requestBody
|
? readableToRuntimeMap(restBindings, newQuery.fields.requestBody)
|
||||||
)
|
: readableToRuntimeBinding(restBindings, newQuery.fields.requestBody)
|
||||||
|
|
||||||
newQuery.fields.path = url.split("?")[0]
|
newQuery.fields.path = url.split("?")[0]
|
||||||
newQuery.fields.queryString = queryString
|
newQuery.fields.queryString = queryString
|
||||||
newQuery.fields.authConfigId = authConfigId
|
newQuery.fields.authConfigId = authConfigId
|
||||||
|
|
|
@ -15,6 +15,15 @@ module FetchMock {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
json: async () => {
|
json: async () => {
|
||||||
|
//x-www-form-encoded body is a URLSearchParams
|
||||||
|
//The call to stringify it leaves it blank
|
||||||
|
if (body?.opts?.body instanceof URLSearchParams) {
|
||||||
|
const paramArray = Array.from(body.opts.body.entries())
|
||||||
|
body.opts.body = paramArray.reduce((acc: any, pair: any) => {
|
||||||
|
acc[pair[0]] = pair[1]
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
return body
|
return body
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,4 +346,170 @@ describe("/queries", () => {
|
||||||
expect(contents).toBe(null)
|
expect(contents).toBe(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("Current User Request Mapping", () => {
|
||||||
|
|
||||||
|
async function previewGet(datasource, fields, params) {
|
||||||
|
return config.previewQuery(request, config, datasource, fields, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function previewPost(datasource, fields, params) {
|
||||||
|
return config.previewQuery(request, config, datasource, fields, params, "create")
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should parse global and query level header mappings", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
|
||||||
|
const datasource = await config.restDatasource({
|
||||||
|
defaultHeaders: {
|
||||||
|
"test": "headerVal",
|
||||||
|
"emailHdr": "{{[user].[email]}}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const res = await previewGet(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "email={{[user].[email]}}",
|
||||||
|
headers: {
|
||||||
|
queryHdr : "{{[user].[firstName]}}",
|
||||||
|
secondHdr : "1234"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
expect(parsedRequest.opts.headers).toEqual({
|
||||||
|
"test": "headerVal",
|
||||||
|
"emailHdr": userDetails.email,
|
||||||
|
"queryHdr": userDetails.firstName,
|
||||||
|
"secondHdr" : "1234"
|
||||||
|
})
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?email=" + userDetails.email)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user to query parameters", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewGet(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "test={{myEmail}}&testName={{myName}}&testParam={{testParam}}",
|
||||||
|
}, {
|
||||||
|
"myEmail" : "{{[user].[email]}}",
|
||||||
|
"myName" : "{{[user].[firstName]}}",
|
||||||
|
"testParam" : "1234"
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?test=" + userDetails.email +
|
||||||
|
"&testName=" + userDetails.firstName + "&testParam=1234")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user the request body - plain text", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewPost(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "testParam={{testParam}}",
|
||||||
|
requestBody: "This is plain text and this is my email: {{[user].[email]}}. This is a test param: {{testParam}}",
|
||||||
|
bodyType: "text"
|
||||||
|
}, {
|
||||||
|
"testParam" : "1234"
|
||||||
|
})
|
||||||
|
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
expect(parsedRequest.opts.body).toEqual(`This is plain text and this is my email: ${userDetails.email}. This is a test param: 1234`)
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user the request body - json", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewPost(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "testParam={{testParam}}",
|
||||||
|
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
||||||
|
bodyType: "json"
|
||||||
|
}, {
|
||||||
|
"testParam" : "1234",
|
||||||
|
"userRef" : "{{[user].[firstName]}}"
|
||||||
|
})
|
||||||
|
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
const test = `{"email":"${userDetails.email}","queryCode":1234,"userRef":"${userDetails.firstName}"}`
|
||||||
|
expect(parsedRequest.opts.body).toEqual(test)
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user the request body - xml", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewPost(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "testParam={{testParam}}",
|
||||||
|
requestBody: "<note> <email>{{[user].[email]}}</email> <code>{{testParam}}</code> " +
|
||||||
|
"<ref>{{userId}}</ref> <somestring>testing</somestring> </note>",
|
||||||
|
bodyType: "xml"
|
||||||
|
}, {
|
||||||
|
"testParam" : "1234",
|
||||||
|
"userId" : "{{[user].[firstName]}}"
|
||||||
|
})
|
||||||
|
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
const test = `<note> <email>${userDetails.email}</email> <code>1234</code> <ref>${userDetails.firstName}</ref> <somestring>testing</somestring> </note>`
|
||||||
|
|
||||||
|
expect(parsedRequest.opts.body).toEqual(test)
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user the request body - form-data", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewPost(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "testParam={{testParam}}",
|
||||||
|
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
||||||
|
bodyType: "form"
|
||||||
|
}, {
|
||||||
|
"testParam" : "1234",
|
||||||
|
"userRef" : "{{[user].[firstName]}}"
|
||||||
|
})
|
||||||
|
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
|
||||||
|
const emailData = parsedRequest.opts.body._streams[1]
|
||||||
|
expect(emailData).toEqual(userDetails.email)
|
||||||
|
|
||||||
|
const queryCodeData = parsedRequest.opts.body._streams[4]
|
||||||
|
expect(queryCodeData).toEqual("1234")
|
||||||
|
|
||||||
|
const userRef = parsedRequest.opts.body._streams[7]
|
||||||
|
expect(userRef).toEqual(userDetails.firstName)
|
||||||
|
|
||||||
|
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should bind the current user the request body - encoded", async () => {
|
||||||
|
const userDetails = config.getUserDetails()
|
||||||
|
const datasource = await config.restDatasource()
|
||||||
|
|
||||||
|
const res = await previewPost(datasource, {
|
||||||
|
path: "www.google.com",
|
||||||
|
queryString: "testParam={{testParam}}",
|
||||||
|
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
||||||
|
bodyType: "encoded"
|
||||||
|
}, {
|
||||||
|
"testParam" : "1234",
|
||||||
|
"userRef" : "{{[user].[firstName]}}"
|
||||||
|
})
|
||||||
|
const parsedRequest = JSON.parse(res.body.extra.raw)
|
||||||
|
|
||||||
|
expect(parsedRequest.opts.body.email).toEqual(userDetails.email)
|
||||||
|
expect(parsedRequest.opts.body.queryCode).toEqual("1234")
|
||||||
|
expect(parsedRequest.opts.body.userRef).toEqual(userDetails.firstName)
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
|
@ -286,7 +286,7 @@ module RestModule {
|
||||||
input.body = form
|
input.body = form
|
||||||
break
|
break
|
||||||
case BodyTypes.XML:
|
case BodyTypes.XML:
|
||||||
if (object != null) {
|
if (object != null && Object.keys(object).length) {
|
||||||
string = new XmlBuilder().buildObject(object)
|
string = new XmlBuilder().buildObject(object)
|
||||||
}
|
}
|
||||||
input.body = string
|
input.body = string
|
||||||
|
|
|
@ -155,12 +155,27 @@ describe("REST Integration", () => {
|
||||||
expect(output.headers["Content-Type"]).toEqual("application/json")
|
expect(output.headers["Content-Type"]).toEqual("application/json")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should allow XML", () => {
|
it("should allow raw XML", () => {
|
||||||
|
const output = config.integration.addBody("xml", "<a>1</a><b>2</b>", {})
|
||||||
|
expect(output.body.includes("<a>1</a>")).toEqual(true)
|
||||||
|
expect(output.body.includes("<b>2</b>")).toEqual(true)
|
||||||
|
expect(output.headers["Content-Type"]).toEqual("application/xml")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should allow a valid js object and parse the contents to xml", () => {
|
||||||
const output = config.integration.addBody("xml", input, {})
|
const output = config.integration.addBody("xml", input, {})
|
||||||
expect(output.body.includes("<a>1</a>")).toEqual(true)
|
expect(output.body.includes("<a>1</a>")).toEqual(true)
|
||||||
expect(output.body.includes("<b>2</b>")).toEqual(true)
|
expect(output.body.includes("<b>2</b>")).toEqual(true)
|
||||||
expect(output.headers["Content-Type"]).toEqual("application/xml")
|
expect(output.headers["Content-Type"]).toEqual("application/xml")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should allow a valid json string and parse the contents to xml", () => {
|
||||||
|
const output = config.integration.addBody("xml", JSON.stringify(input), {})
|
||||||
|
expect(output.body.includes("<a>1</a>")).toEqual(true)
|
||||||
|
expect(output.body.includes("<b>2</b>")).toEqual(true)
|
||||||
|
expect(output.headers["Content-Type"]).toEqual("application/xml")
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("response", () => {
|
describe("response", () => {
|
||||||
|
|
|
@ -91,8 +91,24 @@ describe("migrations", () => {
|
||||||
await clearMigrations()
|
await clearMigrations()
|
||||||
const appId = config.prodAppId
|
const appId = config.prodAppId
|
||||||
const roles = { [appId]: "role_12345" }
|
const roles = { [appId]: "role_12345" }
|
||||||
await config.createUser(undefined, undefined, false, true, roles) // admin only
|
await config.createUser(
|
||||||
await config.createUser(undefined, undefined, false, false, roles) // non admin non builder
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
roles
|
||||||
|
) // admin only
|
||||||
|
await config.createUser(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
roles
|
||||||
|
) // non admin non builder
|
||||||
await config.createTable()
|
await config.createTable()
|
||||||
await config.createRow()
|
await config.createRow()
|
||||||
await config.createRow()
|
await config.createRow()
|
||||||
|
|
|
@ -28,6 +28,8 @@ const { encrypt } = require("@budibase/backend-core/encryption")
|
||||||
|
|
||||||
const GLOBAL_USER_ID = "us_uuid1"
|
const GLOBAL_USER_ID = "us_uuid1"
|
||||||
const EMAIL = "babs@babs.com"
|
const EMAIL = "babs@babs.com"
|
||||||
|
const FIRSTNAME = "Barbara"
|
||||||
|
const LASTNAME = "Barbington"
|
||||||
const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"
|
const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"
|
||||||
|
|
||||||
class TestConfiguration {
|
class TestConfiguration {
|
||||||
|
@ -59,6 +61,15 @@ class TestConfiguration {
|
||||||
return this.prodAppId
|
return this.prodAppId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUserDetails() {
|
||||||
|
return {
|
||||||
|
globalId: GLOBAL_USER_ID,
|
||||||
|
email: EMAIL,
|
||||||
|
firstName: FIRSTNAME,
|
||||||
|
lastName: LASTNAME,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async doInContext(appId, task) {
|
async doInContext(appId, task) {
|
||||||
if (!appId) {
|
if (!appId) {
|
||||||
appId = this.appId
|
appId = this.appId
|
||||||
|
@ -118,6 +129,8 @@ class TestConfiguration {
|
||||||
// USER / AUTH
|
// USER / AUTH
|
||||||
async globalUser({
|
async globalUser({
|
||||||
id = GLOBAL_USER_ID,
|
id = GLOBAL_USER_ID,
|
||||||
|
firstName = FIRSTNAME,
|
||||||
|
lastName = LASTNAME,
|
||||||
builder = true,
|
builder = true,
|
||||||
admin = false,
|
admin = false,
|
||||||
email = EMAIL,
|
email = EMAIL,
|
||||||
|
@ -135,6 +148,8 @@ class TestConfiguration {
|
||||||
...existing,
|
...existing,
|
||||||
roles: roles || {},
|
roles: roles || {},
|
||||||
tenantId: TENANT_ID,
|
tenantId: TENANT_ID,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
}
|
}
|
||||||
await createASession(id, {
|
await createASession(id, {
|
||||||
sessionId: "sessionid",
|
sessionId: "sessionid",
|
||||||
|
@ -161,6 +176,8 @@ class TestConfiguration {
|
||||||
|
|
||||||
async createUser(
|
async createUser(
|
||||||
id = null,
|
id = null,
|
||||||
|
firstName = FIRSTNAME,
|
||||||
|
lastName = LASTNAME,
|
||||||
email = EMAIL,
|
email = EMAIL,
|
||||||
builder = true,
|
builder = true,
|
||||||
admin = false,
|
admin = false,
|
||||||
|
@ -169,6 +186,8 @@ class TestConfiguration {
|
||||||
const globalId = !id ? `us_${Math.random()}` : `us_${id}`
|
const globalId = !id ? `us_${Math.random()}` : `us_${id}`
|
||||||
const resp = await this.globalUser({
|
const resp = await this.globalUser({
|
||||||
id: globalId,
|
id: globalId,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
email,
|
email,
|
||||||
builder,
|
builder,
|
||||||
admin,
|
admin,
|
||||||
|
@ -520,14 +539,14 @@ class TestConfiguration {
|
||||||
|
|
||||||
// QUERY
|
// QUERY
|
||||||
|
|
||||||
async previewQuery(request, config, datasource, fields) {
|
async previewQuery(request, config, datasource, fields, params, verb) {
|
||||||
return request
|
return request
|
||||||
.post(`/api/queries/preview`)
|
.post(`/api/queries/preview`)
|
||||||
.send({
|
.send({
|
||||||
datasourceId: datasource._id,
|
datasourceId: datasource._id,
|
||||||
parameters: {},
|
parameters: params || {},
|
||||||
fields,
|
fields,
|
||||||
queryVerb: "read",
|
queryVerb: verb || "read",
|
||||||
name: datasource.name,
|
name: datasource.name,
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
|
|
Loading…
Reference in New Issue