New Tests (User Roles, Query Level Transformers, Data Sources etc.)

New tests:
-Query Level Transformers
-Table pagination
-User Roles
-Data Sources (correct config, incorrect config, Wizard)

Also:
-New Commands to support
Testing
-Cypress Updated
This commit is contained in:
Mitch-Budibase 2021-11-15 15:25:58 +00:00
parent 969d2f5377
commit 8780010926
11 changed files with 1534 additions and 429 deletions

View File

@ -30,7 +30,6 @@ context("Create a Table", () => {
cy.contains("Save Column").click()
cy.contains("nameupdated ").should("contain", "nameupdated")
})
it("edits a row", () => {
cy.contains("button", "Edit").click({ force: true })
@ -47,6 +46,36 @@ context("Create a Table", () => {
cy.get(".spectrum-Modal").contains("Delete").click()
cy.contains("RoverUpdated").should("not.exist")
})
it("Adds 15 rows and checks pagination", () => {
// 10 rows per page, 15 rows should create 2 pages within table
const totalRows = 16
for (let i = 1; i < totalRows; i++){
cy.addRow([i])
}
cy.wait(1000)
cy.get(".spectrum-Pagination").within(() => {
cy.get(".spectrum-ActionButton").eq(1).click()
})
cy.get(".spectrum-Pagination").within(() => {
cy.get(".spectrum-Body--secondary").contains("Page 2")
})
})
it("Deletes rows and checks pagination", () => {
// Delete rows, removing second page of rows from table
const deleteRows = 5
cy.get(".spectrum-Checkbox-input").check({ force: true })
cy.get(".spectrum-Table-body")
cy.contains("Delete 5 row(s)").click()
cy.get(".spectrum-Modal").contains("Delete").click()
cy.wait(1000)
// Confirm table only has one page
cy.get(".spectrum-Pagination").within(() => {
cy.get(".spectrum-ActionButton").eq(1).should('not.be.enabled')
})
})
it("deletes a column", () => {
cy.get(".title").click()

View File

@ -1,10 +0,0 @@
context("Create a User", () => {
before(() => {
cy.login()
})
it("should create a user", () => {
cy.createUser("bbuser@test.com")
cy.contains("bbuser").should("be.visible")
})
})

View File

@ -0,0 +1,125 @@
context("Create a User and Assign Roles", () => {
before(() => {
cy.login()
})
it("should create a user", () => {
cy.createUser("bbuser@test.com")
cy.contains("bbuser").should("be.visible")
})
it("should confirm there is No Access for a New User", () => {
// Click into the user
cy.contains("bbuser").click()
// Get No Access table - Confirm it has apps in it
cy.get(".spectrum-Table").eq(1).should('not.contain', 'No rows found')
// Get Configure Roles table - Confirm it has no apps
cy.get(".spectrum-Table").eq(0).contains('No rows found')
})
it("should assign role types", () => {
// 3 apps minimum required - to assign an app to each role type
cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`)
.its("body")
.then(val => {
if (val.length < 3) {
for (let i = 1; i < 3; i++) {
const uuid = () => Cypress._.random(0, 1e6)
const name = uuid()
cy.createApp(name)
}
}
})
// Navigate back to the user
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
cy.wait(1000)
cy.get(".spectrum-SideNav").contains("Users").click()
cy.get(".spectrum-Table").contains("bbuser").click()
cy.wait(500)
for (let i = 0; i < 3; i++) {
cy.get(".spectrum-Table-body").eq(1).find('tr').eq(0).click()
cy.get(".spectrum-Dialog-grid").contains("Choose an option").click().then(() => {
cy.wait(500)
if (i == 0) {
cy.get(".spectrum-Popover").contains("Admin").click()
}
if (i == 1) {
cy.get(".spectrum-Popover").contains("Power").click()
}
if (i == 2) {
cy.get(".spectrum-Popover").contains("Basic").click()
}
cy.wait(500)
cy.get(".spectrum-Button").contains("Update role").click({ force: true })
})
}
// Confirm roles exist within Configure roles table
cy.get(".spectrum-Table-body").eq(0).within((assginedRoles) => {
expect(assginedRoles).to.contain("Admin")
expect(assginedRoles).to.contain("Power")
expect(assginedRoles).to.contain("Basic")
})
})
it("should unassign role types", () => {
// Set each app within Configure roles table to 'No Access'
cy.get(".spectrum-Table-body").eq(0).find('tr').its('length').then((len) => {
for (let i = 0; i < len; i ++){
cy.get(".spectrum-Table-body").eq(0).find('tr').eq(0).click().then(() => {
cy.get(".spectrum-Form-item").contains("Role").parent().within(() => {
cy.get(".spectrum-Picker").click({ force: true })
cy.wait(500)
cy.get(".spectrum-Popover").contains("No Access").click()
})
cy.get(".spectrum-Button").contains("Update role").click({ force: true })
cy.wait(1000)
})
}
})
// Confirm Configure roles table no longer has any apps in it
cy.get(".spectrum-Table-body").eq(0).contains('No rows found')
})
it("should enable Developer access", () => {
// Enable Developer access
cy.get(".field").eq(4).within(() => {
cy.get(".spectrum-Form-item").click()
})
// No Access table should now be empty
cy.get(".container").contains("No Access").parent().within(() => {
cy.get(".spectrum-Table").contains("No rows found")
// Each app within Configure roles should have Admin access
cy.get(".spectrum-Table-body").eq(0).find('tr').its('length').then((len) => {
for (let i = 0; i < len; i++) {
cy.get(".spectrum-Table-body").eq(0).find('tr').eq(i).contains("Admin")
cy.wait(500)
}
})
})
})
it("should disable Developer access", () => {
// Disable Developer access
cy.get(".field").eq(4).within(() => {
cy.get(".spectrum-Form-item").click()
})
// Configure roles table should now be empty
cy.get(".container").contains("Configure roles").parent().within(() => {
cy.get(".spectrum-Table").contains("No rows found")
})
})
it("should delete a user", () => {
// Click Delete user button
cy.get(".spectrum-Button").contains("Delete user").click({force: true}).then(() => {
// Confirm deletion within modal
cy.wait(500)
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Delete user").click({force: true})
cy.wait(4000)
})
})
cy.get(".spectrum-Table-body").should("not.have.text", "bbuser")
})
})

View File

@ -80,5 +80,4 @@ xcontext("Custom Theming Properties", () => {
.parent().find(".container.svelte-z3cm5a").click()
.get('[title="Gray 800"]').children().find('[aria-label="Checkmark"]')
}
})

View File

@ -0,0 +1,50 @@
context("Add and Configure External Data Sources", () => {
before(() => {
cy.login()
cy.createTestApp()
})
it("should add and configure a PostgreSQL data source", () => {
// Select PostgreSQL datasource and add config
const datasource = "PostgreSQL"
cy.selectExternalDatasource(datasource)
cy.addSqlDatasourceConfig(datasource)
// Confirm fetch tables was successful
cy.get(".query-list").then(() => {
cy.get(".query-list-item").should('exist')
})
})
it("should add and configure a MySQL data source", () => {
// Select MySQL datasource and add config
const datasource = "MySQL"
cy.selectExternalDatasource(datasource)
cy.addSqlDatasourceConfig(datasource)
// Confirm fetch tables was successful
cy.get(".query-list").then(() => {
cy.get(".query-list-item").should('exist')
})
})
it("should add and configure a REST data source", () => {
// Select REST datasource and add config
const datasource = "REST"
const restUrl = "https://api.openbrewerydb.org/breweries"
cy.selectExternalDatasource(datasource)
cy.addRestDatasourceConfig(restUrl)
// Following config - Click Add Query, then Run Query
cy.get(".spectrum-Button").contains("Add Query").click({ force: true })
cy.wait(500)
cy.get(".viewer-controls").within(() => {
cy.get(".spectrum-Button").contains("Run Query").click({ force: true })
})
// Get the results from running query
cy.get(".viewer").within(() => {
cy.get(".preview").should(
'not.have.value', 'Please run your query to fetch some data.')
})
})
})

View File

@ -0,0 +1,39 @@
context("Datasource Wizard", () => {
before(() => {
cy.login()
cy.createTestApp()
})
it("should navigate in and out of a datasource via wizard", () => {
// Select PostgreSQL and add config (without fetch)
const datasource = "PostgreSQL"
cy.selectExternalDatasource(datasource)
cy.addSqlDatasourceConfig(datasource, true)
// Navigate back within datasource wizard
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Back").click({ force: true })
cy.wait(1000)
})
// Select PostgreSQL datasource again
cy.get(".item-list").contains(datasource).click()
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
})
// Immediately fetch tables after selection
// Previously entered config should not have been saved
// Config is back to default values - Modal will not close (incorrect config)
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Fetch tables from database").click({ force: true })
})
cy.wait(2000)
cy.get(".spectrum-Dialog-grid").should('be.visible')
// Close the modal
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".close-icon").click()
})
})
})

View File

@ -0,0 +1,29 @@
context("Incorrect Datasource Configuration", () => {
before(() => {
cy.login()
cy.createTestApp()
})
it("should add incorrect config for PostgreSQL", () => {
// This test tries to fetch immediately after selecting the datasource
// No config is entered (default values used)
// Select PostgreSQL datasource
cy.selectExternalDatasource("PostgreSQL")
// Attempt to fetch tables without applying config
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains(
"Fetch tables from database").click({ force: true })
})
// Wait 2 seconds then assert Modal has not closed
// Modal will not close if config is incorrect
cy.wait(2000)
cy.get(".spectrum-Dialog-grid").should('be.visible')
// Close the modal
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".close-icon").click()
})
})
})

View File

@ -0,0 +1,124 @@
context("Query Level Transformers", () => {
before(() => {
cy.login()
cy.createTestApp()
})
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.addRestDatasourceConfig(restUrl)
// Add Query
cy.get(".spectrum-Button").contains("Add Query").click({ force: true })
cy.wait(500)
addTransformerQuery()
// Run Query
cy.get(".spectrum-Button").contains("Run Query").click({ force: true })
cy.wait(500)
// Confirm JSON results
cy.get(".preview").should('have.text', '{\n "state": "Indiana",\n "count": 1\n}')
})
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.addRestDatasourceConfig(restUrl)
// Add Query
cy.get(".spectrum-Button").contains("Add Query").click({ force: true })
cy.wait(500)
addTransformerQuery(true)
// Run Query
cy.get(".spectrum-Button").contains("Run Query").click({ force: true })
cy.wait(500)
// Confirm JSON results
cy.get(".preview").should(
'have.text',
'{\n "state": "Indiana",\n "count": 1,\n "flag": "http://flags.ox3.in/svg/us/${stateCode}.svg"\n}')
})
it("should run an invalid query via POST request", () => {
// POST request with transformer as null
cy.request({method: 'POST',
url: 'https://test.budi.live/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')
})
})
it("should run an empty query", () => {
// POST request with Transformer as an empty string
cy.request({method: 'POST',
url: 'https://test.budi.live/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')
})
})
const addTransformerQuery = (addData = false) => {
// Adds query within the Transformer section of Query REST API
cy.get(".CodeMirror textarea")
// Highlight current text within CodeMirror
.type(Cypress.platform === 'darwin' ? '{cmd}a' : '{ctrl}a', { force: true })
// Overwrite current text with function
.type("const breweries = data\n" +
"const totals = {}\n" +
"for (let brewery of breweries) {")
// Delete key in place to remove extra brackets that are added
.type('{del}')
.type("\n const state = brewery.state\n" +
" if (totals[state] == null) {")
.type('{del}')
.type("\n totals[state] = 1\n" +
"} else {")
.type('{del}')
.type("\n totals[state]++\n" +
"}}\n", { parseSpecialCharSequences: false })
if (addData) {
cy.get(".CodeMirror textarea")
.type('const stateCodes = {"texas":"tx",\n' +
'"colorado":"co",\n' +
'"florida":"fl",\n' +
'"iwoa":"ia",\n' +
'"louisiana":"la",\n' +
'"california":"ca",\n' +
'"pennsylvania":"pa",\n' +
'"georgia":"ga",\n' +
'"new hampshire":"nh",\n' +
'"virginia":"va",\n' +
'"michigan":"mi",\n' +
'"maryland":"md",\n' +
'"ohio":"oh"}\n')
.type('const entries = Object.entries(totals)\n' +
"return entries.map(([state, count]) => \n" +
"{ const stateCode = stateCodes[state.toLowerCase()]\n" +
"return {state, count, flag: 'http://flags.ox3.in/svg/us/${stateCode}.svg'",
{ parseSpecialCharSequences: false })
}
else{
cy.get(".CodeMirror textarea")
.type("const entries = Object.entries(totals)\n" +
"return entries.map(([state, count]) => ({state, count}))",
{ parseSpecialCharSequences: false })
}
}
})

View File

@ -35,32 +35,71 @@ Cypress.Commands.add("login", () => {
Cypress.Commands.add("createApp", name => {
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
cy.wait(500)
cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`).its('body').then((body) => {
if( body.length > 0) {
cy.get(".spectrum-Button").contains("Create app").click({ force: true })
}
})
cy.contains(/Start from scratch/).dblclick()
cy.get(".spectrum-Modal").within(() => {
cy.get("input").eq(0).type(name).should("have.value", name).blur()
cy.get(".spectrum-ButtonGroup").contains("Create app").click()
cy.wait(7000)
cy.wait(5000)
})
cy.createTable("Cypress Tests", true)
})
Cypress.Commands.add("deleteApp", () => {
Cypress.Commands.add("deleteApp", name => {
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
cy.wait(1000)
cy.wait(2000)
cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`)
.its("body")
.then(val => {
console.log(val)
if (val.length > 0) {
cy.get(".title > :nth-child(3) > .spectrum-Icon").click()
cy.contains("Delete").click()
cy.get(".spectrum-Button--warning").click()
}
})
.its("body")
.then(val => {
if (val.length > 0) {
cy.searchForApplication(name)
cy.get(".appGrid").children().within(() => {
cy.get(".title").children().within(() => {
cy.get(".spectrum-Icon").click()
})
})
cy.get(".spectrum-Menu").contains("Delete").click()
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get("input").type(name)
})
cy.get(".spectrum-Button--warning").click()
}
else {
return
}
})
})
Cypress.Commands.add("deleteAllApps", () => {
cy.visit(`localhost:${Cypress.env("PORT")}/builder`)
cy.wait(500)
cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`)
.its("body")
.then(val => {
for (let i = 0; i < val.length; i++) {
cy.get(".spectrum-Heading").eq(1).then((app) => {
const name = app.text()
cy.get(".title").children().within(() => {
cy.get(".spectrum-Icon").eq(0).click()
})
cy.get(".spectrum-Menu").contains("Delete").click()
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get("input").type(name)
cy.get(".spectrum-Button--warning").click()
})
cy.reload()
})
}
})
})
Cypress.Commands.add("createTestApp", () => {
const appName = "Cypress Tests"
cy.deleteApp()
cy.deleteApp(appName)
cy.createApp(appName, "This app is used for Cypress testing.")
})
@ -70,10 +109,14 @@ Cypress.Commands.add("createTestTableWithData", () => {
cy.addColumn("dog", "age", "Number")
})
Cypress.Commands.add("createTable", tableName => {
cy.contains("Budibase DB").click()
cy.contains("Create new table").click()
Cypress.Commands.add("createTable", (tableName, initialTable) => {
if (!initialTable) {
cy.get(".add-button").click()
}
cy.wait(7000)
cy.get(".spectrum-Modal").contains("Budibase DB").click().then(() => {
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
})
cy.get(".spectrum-Modal").within(() => {
cy.wait(1000)
cy.get("input").first().type(tableName).blur()
@ -183,6 +226,12 @@ Cypress.Commands.add("navigateToFrontend", () => {
cy.get(".nav-item").contains("Home").click()
})
Cypress.Commands.add("navigateToDataSection", () => {
// Clicks on the Data tab
cy.wait(500)
cy.contains("Data").click()
})
Cypress.Commands.add("createScreen", (screenName, route) => {
cy.get("[aria-label=AddCircle]").click()
cy.get(".spectrum-Modal").within(() => {
@ -226,7 +275,102 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => {
})
Cypress.Commands.add("searchForApplication", appName => {
cy.get(".spectrum-Textfield").within(() => {
cy.get("input").eq(0).type(appName)
cy.wait(1000)
// Searches for the app
cy.get(".filter").then(() => {
cy.get(".spectrum-Textfield").within(() => {
cy.get("input").eq(0).type(appName)
})
})
// Confirms app exists after search
cy.get(".appGrid").contains(appName)
})
Cypress.Commands.add("selectExternalDatasource", datasourceName => {
// Navigates to Data Section
cy.navigateToDataSection()
// Open Data Source modal
cy.get('.nav').within(() => {
cy.get(".add-button").click()
})
// Clicks specified datasource & continue
cy.get(".item-list").contains(datasourceName).click()
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Continue").click({ force: true })
})
})
Cypress.Commands.add("addSqlDatasourceConfig", (sqlType, noFetch) => {
// addExternalDatasource should be called prior to this
// Adds the config for specified SQL datasource & fetches tables
// Host IP Address
cy.wait(500)
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".form-row").contains("Host").parent().children().within(() => {
cy.get(".spectrum-Textfield").within(() => {
cy.get("input").clear().type("3.251.63.170")
})
})
})
// Database Name
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".form-row").contains("Database").parent().children().within(() => {
cy.get(".spectrum-Textfield").within(() => {
if (sqlType == "PostgreSQL") {
cy.get("input").clear().type("test")
}
if (sqlType == "MySQL") {
cy.get("input").clear().type("mysql")
}
})
})
})
// User
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".form-row").contains("User").parent().children().within(() => {
cy.get(".spectrum-Textfield").within(() => {
if (sqlType == "PostgreSQL") {
cy.get("input").clear().type("admin")
}
if (sqlType == "MySQL") {
cy.get("input").clear().type("root")
}
})
})
})
// Password
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".form-row").contains("Password").parent().children().within(() => {
cy.get(".spectrum-Textfield").within(() => {
if (sqlType == "PostgreSQL") {
cy.get("input").clear().type("8cb2b6f4-4b33-4e86-b790-74eee608a4e9")
}
if (sqlType == "MySQL") {
cy.get("input").clear().type("abdc321d-4d21-4fc7-8d20-f40ab9fe6db0")
}
})
})
})
// Click to fetch tables
if (!noFetch){
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Fetch tables from database").click({ force: true })
cy.wait(1000)
})
}
})
Cypress.Commands.add("addRestDatasourceConfig", restUrl => {
// addExternalDatasource should be called prior to this
// Configures REST datasource
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Textfield").within(() => {
cy.get("input").clear().type(restUrl)
})
})
// Click Save and continue to query
cy.get(".spectrum-Dialog-grid").within(() => {
cy.get(".spectrum-Button").contains("Save and continue to query").click({ force: true })
cy.wait(500)
})
})

View File

@ -95,7 +95,7 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/svelte": "^3.0.0",
"babel-jest": "^26.6.3",
"cypress": "^5.1.0",
"cypress": "9.0.0",
"cypress-terminal-report": "^1.4.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",

File diff suppressed because it is too large Load Diff