Cypress test fixes and refactoring around the create app workflows

This commit is contained in:
Dean 2022-03-28 23:21:38 +01:00
parent c353adf151
commit f512441f11
13 changed files with 361 additions and 146 deletions

View File

@ -6,9 +6,13 @@ filterTests(['all'], () => {
cy.login()
})
after(() => {
cy.deleteAllApps()
})
it("should change the icon and colour for an application", () => {
// Search for test application
cy.searchForApplication("Cypress Tests")
cy.applicationInAppTable("Cypress Tests")
cy.get(".appTable")
.within(() => {
cy.get(".spectrum-Icon").eq(1).click()

View File

@ -2,11 +2,146 @@ import filterTests from '../support/filterTests'
filterTests(['smoke', 'all'], () => {
context("Create an Application", () => {
it("should create a new application", () => {
beforeEach(() => {
cy.login()
cy.createTestApp()
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.contains("Cypress Tests").should("exist")
})
it("should show the new user UI/UX", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').should("exist")
cy.get(`[data-cy="import-app-btn"]`).should("exist")
cy.get(".template-category-filters").should("exist")
cy.get(".template-categories").should("exist")
cy.get(".appTable").should("not.exist")
})
it("should provide filterable templates", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.get(".template-category-filters").should("exist")
cy.get(".template-categories").should("exist")
cy.get(".template-category").its('length').should('be.gt', 1)
cy.get(".template-category-filters .spectrum-ActionButton").its('length').should('be.gt', 2)
cy.get(".template-category-filters .spectrum-ActionButton").eq(1).click()
cy.get(".template-category").should('have.length', 1)
cy.get(".template-category-filters .spectrum-ActionButton").eq(0).click()
cy.get(".template-category").its('length').should('be.gt', 1)
})
it("should enforce a valid url before submission", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
const appName = "A New App"
cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').click({force: true})
cy.get(".spectrum-Modal").within(() => {
//Auto fill
cy.get("input").eq(0).type(appName).should("have.value", appName).blur()
cy.get("input").eq(1).should("have.value", "/a-new-app")
cy.get(".spectrum-ButtonGroup").contains("Create app").should('not.be.disabled')
//Empty the app url - disabled create
cy.get("input").eq(1).clear().blur()
cy.get(".spectrum-ButtonGroup").contains("Create app").should('be.disabled')
//Invalid url
cy.get("input").eq(1).type("/new app-url").blur()
cy.get(".spectrum-ButtonGroup").contains("Create app").should('be.disabled')
//Specifically alter the url
cy.get("input").eq(1).clear()
cy.get("input").eq(1).type("another-app-name").blur()
cy.get("input").eq(1).should("have.value", "/another-app-name")
cy.get("input").eq(0).should("have.value", appName)
cy.get(".spectrum-ButtonGroup").contains("Create app").should('not.be.disabled')
})
})
it("should create the first application from scratch", () => {
const appName = "Cypress Tests"
cy.deleteApp(appName)
cy.createApp(appName, "This app is used for Cypress testing.")
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(1000)
cy.applicationInAppTable(appName)
cy.deleteApp(appName)
})
it("should generate the first application from a template", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.get(".template-category-filters").should("exist")
cy.get(".template-categories").should("exist")
//### Select nth template and choose to create?
cy.get('.template-category').eq(0).within(() => {
const card = cy.get('.template-card').eq(0).should("exist");
const cardOverlay = card.get('.template-thumbnail-action-overlay').should("exist")
cardOverlay.invoke("show")
cardOverlay.get("button").contains("Use template").should("exist").click({force: true})
})
//### CMD Create app from theme card
cy.get(".spectrum-Modal").should('be.visible')
const templateName = cy.get(".spectrum-Modal .template-thumbnail-text")
templateName.invoke('text')
.then(templateNameText => {
const templateNameParsed = "/"+templateNameText.toLowerCase().replace(/\s+/g, "-")
cy.get(".spectrum-Modal input").eq(0).should("have.value", templateNameText)
cy.get(".spectrum-Modal input").eq(1).should("have.value", templateNameParsed)
cy.get(".spectrum-Modal .spectrum-ButtonGroup").contains("Create app").click()
cy.wait(5000)
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(1000)
cy.applicationInAppTable(templateNameText)
cy.deleteAllApps()
});
})
it("should display a second application and app filtering", () => {
const appName = "Cypress Tests"
cy.deleteApp(appName)
cy.createApp(appName, "This app is used for Cypress testing.")
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
const secondAppName = "Second App Demo"
cy.deleteApp(secondAppName)
cy.get(`[data-cy="create-app-btn"]`).contains('Create new app').click({force: true})
cy.wait(500)
cy.url().should('include', '/builder/portal/apps/create')
cy.createAppFromScratch(secondAppName)
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
//Both applications should exist and be searchable
cy.searchForApplication(appName)
cy.searchForApplication(secondAppName)
cy.deleteAllApps()
})
})
})

View File

@ -7,6 +7,10 @@ filterTests(["smoke", "all"], () => {
cy.createTestApp()
})
after(() => {
cy.deleteAllApps()
})
it("should create a new Table", () => {
cy.createTable("dog")
cy.wait(1000)

View File

@ -4,9 +4,14 @@ filterTests(["smoke", "all"], () => {
context("Create a User and Assign Roles", () => {
before(() => {
cy.login()
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.createAppFromScratch("Initial App")
})
it("should create a user", () => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(1000)
cy.createUser("bbuser@test.com")
cy.get(".spectrum-Table").should("contain", "bbuser")
})
@ -30,7 +35,14 @@ filterTests(["smoke", "all"], () => {
for (let i = 1; i < 3; i++) {
const uuid = () => Cypress._.random(0, 1e6)
const name = uuid()
if(i < 1){
cy.createApp(name)
} else {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.get(`[data-cy="create-app-btn"]`).click({ force: true })
cy.createAppFromScratch(name)
}
}
}
})

View File

@ -4,6 +4,8 @@ filterTests(['smoke', 'all'], () => {
context("Create a View", () => {
before(() => {
cy.login()
cy.deleteAllApps()
cy.createTestApp()
cy.createTable("data")
cy.addColumn("data", "group", "Text")

View File

@ -4,6 +4,7 @@ filterTests(["smoke", "all"], () => {
context("REST Datasource Testing", () => {
before(() => {
cy.login()
cy.deleteAllApps()
cy.createTestApp()
})
@ -23,7 +24,7 @@ filterTests(["smoke", "all"], () => {
cy.wait("@queryError")
cy.get("@queryError")
.its("response.body")
.should("have.property", "message", "Invalid URL: http://random text?")
.should("have.property", "message", "Invalid URL")
cy.get("@queryError")
.its("response.body")
.should("have.property", "status", 400)

View File

@ -4,7 +4,7 @@ filterTests(["smoke", "all"], () => {
context("Query Level Transformers", () => {
before(() => {
cy.login()
cy.deleteApp("Cypress Tests")
cy.deleteAllApps()
cy.createApp("Cypress Tests")
})

View File

@ -15,8 +15,8 @@ filterTests(['all'], () => {
renameApp(appName, appRename)
cy.reload()
cy.wait(1000)
cy.searchForApplication(appRename)
cy.get(".appTable").find(".title").should("have.length", 1)
cy.applicationInAppTable(appRename)
// Set app name back to Cypress Tests
cy.reload()
cy.wait(1000)
@ -29,17 +29,17 @@ filterTests(['all'], () => {
const appRename = "Cypress Renamed"
// Publish the app
cy.get(".toprightnav")
cy.get(".spectrum-Button").contains("Publish").click({force: true})
cy.get(".spectrum-Button").contains("Publish").click({ force: true })
cy.get(".spectrum-Dialog-grid")
.within(() => {
// Click publish again within the modal
cy.get(".spectrum-Button").contains("Publish").click({force: true})
cy.get(".spectrum-Button").contains("Publish").click({ force: true })
})
// Rename app, Search for app, Confirm name was changed
cy.get(".home-logo").click()
renameApp(appName, appRename, true)
cy.searchForApplication(appRename)
cy.get(".appTable").find(".wrapper").should("have.length", 1)
cy.applicationInAppTable(appRename)
})
it("Should try to rename an application to have no name", () => {
@ -51,7 +51,7 @@ filterTests(['all'], () => {
cy.get(".spectrum-Dialog-grid").contains("Cancel").click()
cy.reload()
cy.wait(1000)
cy.searchForApplication(appName)
cy.applicationInAppTable(appName)
cy.get(".appTable").find(".title").should("have.length", 1)
})
@ -61,12 +61,12 @@ filterTests(['all'], () => {
const appName = "Cypress Tests"
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.get(".spectrum-Button").contains("Create app").click({force: true})
cy.get(".spectrum-Button").contains("Create app").click({ force: true })
cy.contains(/Start from scratch/).click()
cy.get(".spectrum-Modal")
.within(() => {
cy.get("input").eq(0).type(appName)
cy.get(".spectrum-ButtonGroup").contains("Create app").click({force: true})
cy.get(".spectrum-ButtonGroup").contains("Create app").click({ force: true })
cy.get(".error").should("have.text", "Another app with the same name already exists")
})
})
@ -81,7 +81,7 @@ filterTests(['all'], () => {
renameApp(appName, numberName)
cy.reload()
cy.wait(1000)
cy.searchForApplication(numberName)
cy.applicationInAppTable(numberName)
cy.get(".appTable").find(".title").should("have.length", 1)
cy.reload()
cy.wait(1000)
@ -94,7 +94,7 @@ filterTests(['all'], () => {
})
const renameApp = (originalName, changedName, published, noName) => {
cy.searchForApplication(originalName)
cy.applicationInAppTable(originalName)
cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`)
.its("body")
.then(val => {
@ -104,7 +104,7 @@ filterTests(['all'], () => {
cy.get(".spectrum-Icon").eq(1).click()
})
// Check for when an app is published
if (published == true){
if (published == true) {
// Should not have Edit as option, will unpublish app
cy.should("not.have.value", "Edit")
cy.get(".spectrum-Menu").contains("Unpublish").click()
@ -114,7 +114,7 @@ filterTests(['all'], () => {
cy.contains("Edit").click()
cy.get(".spectrum-Modal")
.within(() => {
if (noName == true){
if (noName == true) {
cy.get("input").clear()
cy.get(".spectrum-Dialog-grid").click()
.contains("App name must be letters, numbers and spaces only")
@ -122,7 +122,7 @@ filterTests(['all'], () => {
}
cy.get("input").clear()
cy.get("input").eq(0).type(changedName).should("have.value", changedName).blur()
cy.get(".spectrum-ButtonGroup").contains("Save").click({force: true})
cy.get(".spectrum-ButtonGroup").contains("Save").click({ force: true })
cy.wait(500)
})
}

View File

@ -35,7 +35,9 @@ Cypress.Commands.add("login", () => {
Cypress.Commands.add("createApp", name => {
cy.visit(`${Cypress.config().baseUrl}/builder`)
cy.wait(500)
cy.get(".spectrum-Button").contains("Create app").click({ force: true })
cy.get(`[data-cy="create-app-btn"]`).click({ force: true })
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()
@ -51,10 +53,23 @@ Cypress.Commands.add("deleteApp", name => {
.its("body")
.then(val => {
if (val.length > 0) {
cy.searchForApplication(name)
cy.get(".appTable").within(() => {
cy.get(".spectrum-Icon").eq(1).click()
const appId = val.reduce((acc, app) => {
if (name === app.name) {
acc = app.appId
}
return acc
}, "")
if (appId == "") {
return
}
const appIdParsed = appId.split("_").pop()
const actionEleId = `[data-cy=row_actions_${appIdParsed}]`
cy.get(actionEleId).within(() => {
cy.get(".spectrum-Icon").eq(0).click()
})
cy.get(".spectrum-Menu").then($menu => {
if ($menu.text().includes("Unpublish")) {
cy.get(".spectrum-Menu").contains("Unpublish").click()
@ -80,22 +95,18 @@ Cypress.Commands.add("deleteAllApps", () => {
.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(() => {
const appIdParsed = val[i].appId.split("_").pop()
const actionEleId = `[data-cy=row_actions_${appIdParsed}]`
cy.get(actionEleId).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("input").type(val[i].name)
cy.get(".spectrum-Button--warning").click()
})
cy.reload()
})
}
})
})
@ -190,9 +201,11 @@ Cypress.Commands.add("addRowMultiValue", values => {
Cypress.Commands.add("createUser", email => {
// quick hacky recorded way to create a user
cy.contains("Users").click()
cy.get(".spectrum-Button--primary").click()
cy.get(`[data-cy="add-user"]`).click()
cy.get(".spectrum-Picker-label").click()
cy.get(".spectrum-Menu-item:nth-child(2) > .spectrum-Menu-itemLabel").click()
//Onboarding type selector
cy.get(
":nth-child(2) > .spectrum-Form-itemField > .spectrum-Textfield > .spectrum-Textfield-input"
)
@ -312,16 +325,37 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => {
})
})
//Filters visible with 1 or more
Cypress.Commands.add("searchForApplication", appName => {
cy.wait(1000)
// Searches for the app
cy.get(".filter").then(() => {
cy.get(".spectrum-Textfield").within(() => {
cy.get("input").eq(0).clear()
cy.get("input").eq(0).type(appName)
})
})
// Confirms app exists after search
cy.get(".appTable").contains(appName)
cy.applicationInAppTable(appName)
})
//Assumes there are no others
Cypress.Commands.add("applicationInAppTable", appName => {
cy.get(".appTable").within(() => {
cy.get(".title").contains(appName).should("exist")
})
})
Cypress.Commands.add("createAppFromScratch", appName => {
cy.get(`[data-cy="create-app-btn"]`)
.contains("Start from scratch")
.click({ force: true })
cy.get(".spectrum-Modal").within(() => {
cy.get("input").eq(0).type(appName).should("have.value", appName).blur()
cy.get(".spectrum-ButtonGroup").contains("Create app").click()
cy.wait(10000)
})
cy.createTable("Cypress Tests", true)
})
Cypress.Commands.add("selectExternalDatasource", datasourceName => {

View File

@ -69,6 +69,7 @@
</ActionButton>
{#each templateCategories as templateCategoryKey}
<ActionButton
dataCy={templateCategoryKey}
selected={templateCategoryKey == selectedTemplateCategory}
on:click={() => {
selectedTemplateCategory = templateCategoryKey
@ -85,7 +86,7 @@
<div class="template-categories">
<Layout gap="XL" noPadding>
{#each filteredTemplateCategories as templateCategoryKey}
<div class="template-category">
<div class="template-category" data-cy={templateCategoryKey}>
<Detail size="M">{templateCategoryKey}</Detail>
<div class="template-grid">
{#each filteredTemplates[templateCategoryKey] as templateEntry}

View File

@ -61,7 +61,7 @@
{#if app.deployed}Published{:else}Unpublished{/if}
</StatusLight>
</div>
<div>
<div data-cy={`row_actions_${app.appId}`}>
<Button
size="S"
disabled={app.lockedOther}

View File

@ -42,11 +42,31 @@
}
}
// auto add slash to url
$: {
if ($values.url && !$values.url.startsWith("/")) {
$values.url = `/${$values.url}`
const resolveAppUrl = (template, name) => {
let parsedName
const resolvedName = resolveAppName(null, name)
parsedName = resolvedName ? resolvedName.toLowerCase() : ""
const parsedUrl = parsedName ? parsedName.replace(/\s+/g, "-") : ""
return encodeURI(parsedUrl)
}
const resolveAppName = (template, name) => {
if (template && !name) {
return template.name
}
return name ? name.trim() : null
}
const tidyUrl = url => {
if (url && !url.startsWith("/")) {
url = `/${url}`
}
$values.url = url === "" ? null : url
}
const nameToUrl = appName => {
let resolvedUrl = resolveAppUrl(null, appName)
tidyUrl(resolvedUrl)
}
</script>
@ -61,15 +81,17 @@
bind:value={$values.name}
error={$validation.touched.name && $validation.errors.name}
on:blur={() => ($validation.touched.name = true)}
on:change={nameToUrl($values.name)}
label="Name"
/>
<Input
bind:value={$values.url}
error={$validation.touched.url && $validation.errors.url}
on:blur={() => ($validation.touched.url = true)}
on:change={tidyUrl($values.url)}
label="URL"
placeholder={$values.name
? "/" + encodeURIComponent($values.name).toLowerCase()
: "/"}
placeholder={$values.url
? $values.url
: `/${resolveAppUrl(null, $values.name)}`}
/>
</ModalContent>

View File

@ -71,7 +71,7 @@
<Heading size="S">Users</Heading>
<ButtonGroup>
<Button disabled secondary>Import users</Button>
<Button primary on:click={createUserModal.show}>Add user</Button>
<Button primary dataCy="add-user" on:click={createUserModal.show}>Add user</Button>
</ButtonGroup>
</div>
<div class="field">