Add cypress tests for data bindings and component creation

This commit is contained in:
Andrew Kingston 2021-03-05 13:52:26 +00:00
parent 6a6c6338b2
commit c03e361710
9 changed files with 153 additions and 105 deletions

View File

@ -1,8 +1,8 @@
{ {
"baseUrl": "http://localhost:4005/_builder/", "baseUrl": "http://localhost:4001/_builder/",
"video": true, "video": true,
"projectId": "bmbemn", "projectId": "bmbemn",
"env": { "env": {
"PORT": "4005" "PORT": "4001"
} }
} }

View File

@ -1,18 +1,12 @@
context('Create an Application', () => { context("Create an Application", () => {
beforeEach(() => {
cy.server()
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`)
})
beforeEach(() => { it("should create a new application", () => {
cy.server() cy.createApp("My Cool App", "This is a description")
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`) cy.visit(`localhost:${Cypress.env("PORT")}/_builder`)
}) cy.contains("My Cool App").should("exist")
})
// https://on.cypress.io/interacting-with-elements
it('should create a new application', () => {
// https://on.cypress.io/type
cy.createApp('My Cool App', 'This is a description')
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`)
cy.contains('My Cool App').should('exist')
})
}) })

View File

@ -1,18 +1,37 @@
xcontext('Create a Binding', () => { context("Create Bindings", () => {
before(() => { before(() => {
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`) cy.createApp("Cypress Tests", "Cypress test app")
cy.createApp('Binding App', 'Binding App Description') cy.navigateToFrontend()
cy.navigateToFrontend() })
})
it('add an input binding', () => { it("should add a current user binding", () => {
cy.get(".nav-items-container").contains('Home').click() cy.addComponent("Elements", "Paragraph").then(componentId => {
cy.contains("Add").click() addSettingBinding("text", "Current User._id")
cy.get("[data-cy=Input]").click() cy.getComponent(componentId).should(
cy.get("[data-cy=Textfield]").click() "have.text",
cy.contains("Heading").click() `ro_ta_users_us_test@test.com`
cy.get("[data-cy=text-binding-button]").click() )
cy.get("[data-cy=binding-dropdown-modal]").contains('Input 1').click()
cy.get("[data-cy=binding-dropdown-modal] textarea").should('have.value', 'Home{{ Input 1 }}')
}) })
})
it("should add a URL param binding", () => {
const paramName = "foo"
cy.createScreen("Test Param", `/test/:${paramName}`)
cy.addComponent("Elements", "Paragraph").then(componentId => {
addSettingBinding("text", `URL.${paramName}`)
// The builder preview pages don't have a real URL, so all we can do
// is check that we were able to bind to the property, and that the
// component exists on the page
cy.getComponent(componentId).should("have.text", "")
})
})
}) })
const addSettingBinding = (setting, bindingText) => {
cy.get(`[data-cy="setting-${setting}"] [data-cy=text-binding-button]`).click()
cy.get(".drawer").within(() => {
cy.contains(bindingText).click()
cy.get("textarea").should("have.value", `{{ ${bindingText} }}`)
cy.get("button").click()
})
}

View File

@ -1,60 +1,72 @@
xcontext("Create Components", () => { context("Create Components", () => {
let headlineId
before(() => { before(() => {
cy.server() cy.createApp("Cypress Tests", "Cypress test app")
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`) cy.createTable("dog")
// https://on.cypress.io/type cy.addColumn("dog", "name", "string")
cy.createApp("Table App", "Table App Description") cy.addColumn("dog", "age", "number")
cy.createTable("dog", "name", "age") cy.addColumn("dog", "type", "options")
cy.addRow("bob", "15")
})
// https://on.cypress.io/interacting-with-elements
it("should add a container", () => {
cy.navigateToFrontend() cy.navigateToFrontend()
cy.get(".switcher > :nth-child(2)").click()
cy.contains("Container").click()
}) })
it("should add a headline", () => {
cy.addHeadlineComponent("An Amazing headline!")
getIframeBody().contains("An Amazing headline!") it("should add a container", () => {
cy.addComponent(null, "Container").then(componentId => {
cy.getComponent(componentId).should("exist")
})
}) })
it("change the font size of the headline", () => {
it("should add a headline", () => {
cy.addComponent("Elements", "Headline").then(componentId => {
headlineId = componentId
cy.getComponent(headlineId).should("exist")
})
})
it("should change the text of the headline", () => {
const text = "Lorem ipsum dolor sit amet."
cy.get("[data-cy=Settings]").click()
cy.get("[data-cy=setting-text] input")
.type(text)
.blur()
cy.getComponent(headlineId).should("have.text", text)
})
it("should change the size of the headline", () => {
cy.get("[data-cy=Design]").click()
cy.contains("Typography").click() cy.contains("Typography").click()
cy.get("[data-cy=font-size-prop-control]").click() cy.get("[data-cy=font-size-prop-control]").click()
cy.contains("60px").click() cy.contains("60px").click()
cy.contains("Design").click() cy.getComponent(headlineId).should("have.css", "font-size", "60px")
})
getIframeBody() it("should create a form and reset to match schema", () => {
.contains("An Amazing headline!") cy.addComponent("Form", "Form").then(() => {
.should("have.css", "font-size", "60px") cy.get("[data-cy=Settings]").click()
cy.get("[data-cy=setting-datasource]")
.contains("Choose option")
.click()
cy.get(".dropdown")
.contains("dog")
.click()
cy.addComponent("Form", "Field Group").then(fieldGroupId => {
cy.get("[data-cy=Settings]").click()
cy.contains("Update Form Fields").click()
cy.get(".modal")
.get("button.primary")
.click()
cy.getComponent(fieldGroupId).within(() => {
cy.contains("name").should("exist")
cy.contains("age").should("exist")
cy.contains("type").should("exist")
})
cy.getComponent(fieldGroupId)
.find("input")
.should("have.length", 2)
cy.getComponent(fieldGroupId)
.find(".spectrum-Picker")
.should("have.length", 1)
})
})
}) })
}) })
const getIframeDocument = () => {
return (
cy
.get("iframe")
// Cypress yields jQuery element, which has the real
// DOM element under property "0".
// From the real DOM iframe element we can get
// the "document" element, it is stored in "contentDocument" property
// Cypress "its" command can access deep properties using dot notation
// https://on.cypress.io/its
.its("0.contentDocument")
.should("exist")
)
}
const getIframeBody = () => {
// get the document
return (
getIframeDocument()
// automatically retries until body is loaded
.its("body")
.should("not.be.undefined")
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
.then(cy.wrap)
)
}

View File

@ -25,8 +25,9 @@
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Cypress.Commands.add("createApp", name => { Cypress.Commands.add("createApp", name => {
cy.deleteApp(name)
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`)
cy.contains("Create New Web App").click() cy.contains("Create New Web App").click()
cy.get("body") cy.get("body")
.then($body => { .then($body => {
if ($body.find("input[name=apiKey]").length) { if ($body.find("input[name=apiKey]").length) {
@ -41,9 +42,7 @@ Cypress.Commands.add("createApp", name => {
cy.get("input[name=applicationName]") cy.get("input[name=applicationName]")
.type(name) .type(name)
.should("have.value", name) .should("have.value", name)
cy.contains("Next").click() cy.contains("Next").click()
cy.get("input[name=email]") cy.get("input[name=email]")
.click() .click()
.type("test@test.com") .type("test@test.com")
@ -57,6 +56,22 @@ Cypress.Commands.add("createApp", name => {
}) })
}) })
Cypress.Commands.add("deleteApp", name => {
cy.visit(`localhost:${Cypress.env("PORT")}/_builder`)
cy.get("body").then($body => {
cy.wait(1000)
if ($body.find(`[data-cy="app-${name}"]`).length) {
cy.get(`[data-cy="app-${name}"] a`).click()
cy.get("[data-cy=settings-icon]").click()
cy.get(".modal-content").within(() => {
cy.contains("Danger Zone").click()
cy.get("input").type("DELETE")
cy.contains("Delete Entire App").click()
})
}
})
})
Cypress.Commands.add("createTestTableWithData", () => { Cypress.Commands.add("createTestTableWithData", () => {
cy.createTable("dog") cy.createTable("dog")
cy.addColumn("dog", "name", "Text") cy.addColumn("dog", "name", "Text")
@ -87,6 +102,7 @@ Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
cy.get("input") cy.get("input")
.first() .first()
.type(columnName) .type(columnName)
// Unset table display column // Unset table display column
cy.contains("display column").click() cy.contains("display column").click()
cy.get("select").select(type) cy.get("select").select(type)
@ -96,15 +112,12 @@ Cypress.Commands.add("addColumn", (tableName, columnName, type) => {
Cypress.Commands.add("addRow", values => { Cypress.Commands.add("addRow", values => {
cy.contains("Create New Row").click() cy.contains("Create New Row").click()
cy.get(".modal").within(() => { cy.get(".modal").within(() => {
for (let i = 0; i < values.length; i++) { for (let i = 0; i < values.length; i++) {
cy.get("input") cy.get("input")
.eq(i) .eq(i)
.type(values[i]) .type(values[i])
} }
// Save
cy.get(".buttons") cy.get(".buttons")
.contains("Create") .contains("Create")
.click() .click()
@ -114,9 +127,7 @@ Cypress.Commands.add("addRow", values => {
Cypress.Commands.add("createUser", (email, password, role) => { Cypress.Commands.add("createUser", (email, password, role) => {
// Create User // Create User
cy.contains("Users").click() cy.contains("Users").click()
cy.contains("Create New User").click() cy.contains("Create New User").click()
cy.get(".modal").within(() => { cy.get(".modal").within(() => {
cy.get("input") cy.get("input")
.first() .first()
@ -135,20 +146,27 @@ Cypress.Commands.add("createUser", (email, password, role) => {
}) })
}) })
Cypress.Commands.add("addHeadlineComponent", text => { Cypress.Commands.add("addComponent", (category, component) => {
cy.get(".switcher > :nth-child(2)").click() if (category) {
cy.get(`[data-cy="category-${category}"]`).click()
cy.get("[data-cy=Text]").click() }
cy.get("[data-cy=Headline]").click() cy.get(`[data-cy="component-${component}"]`).click()
cy.get(".tabs > :nth-child(2)").click() cy.wait(500)
cy.contains("Settings").click() cy.location().then(loc => {
cy.get('input[name="text"]').type(text) const params = loc.pathname.split("/")
cy.contains("Design").click() return cy.wrap(params[params.length - 1])
})
}) })
Cypress.Commands.add("addButtonComponent", () => {
cy.get(".switcher > :nth-child(2)").click()
cy.get("[data-cy=Button]").click() Cypress.Commands.add("getComponent", componentId => {
return cy
.get("iframe")
.its("0.contentDocument")
.should("exist")
.its("body")
.should("not.be.null")
.then(cy.wrap)
.find(`[data-component-id=${componentId}]`)
}) })
Cypress.Commands.add("navigateToFrontend", () => { Cypress.Commands.add("navigateToFrontend", () => {

View File

@ -57,6 +57,7 @@
<div <div
bind:this={anchors[idx]} bind:this={anchors[idx]}
class="category" class="category"
data-cy={item.isCategory ? `category-${item.name}` : `component-${item.name}`}
on:click={() => onItemChosen(item, idx)} on:click={() => onItemChosen(item, idx)}
class:active={idx === selectedIndex}> class:active={idx === selectedIndex}>
{#if item.icon}<i class={item.icon} />{/if} {#if item.icon}<i class={item.icon} />{/if}
@ -74,6 +75,7 @@
{#each enrichedStructure[selectedIndex].children as item} {#each enrichedStructure[selectedIndex].children as item}
{#if !item.showOnAsset || item.showOnAsset.includes($currentAssetName)} {#if !item.showOnAsset || item.showOnAsset.includes($currentAssetName)}
<DropdownItem <DropdownItem
data-cy={`component-${item.name}`}
icon={item.icon} icon={item.icon}
title={item.name} title={item.name}
on:click={() => onItemChosen(item)} /> on:click={() => onItemChosen(item)} />

View File

@ -69,7 +69,7 @@
} }
</script> </script>
<div class="property-control" bind:this={anchor}> <div class="property-control" bind:this={anchor} data-cy={`setting-${key}`}>
<div class="label">{label}</div> <div class="label">{label}</div>
<div data-cy={`${key}-prop-control`} class="control"> <div data-cy={`${key}-prop-control`} class="control">
<svelte:component <svelte:component

View File

@ -5,7 +5,10 @@
let modal let modal
</script> </script>
<div class="topnavitemright settings" on:click={modal.show}> <div
class="topnavitemright settings"
data-cy="settings-icon"
on:click={modal.show}>
<i class="ri-settings-3-line" /> <i class="ri-settings-3-line" />
</div> </div>
<Modal bind:this={modal} width="600px"> <Modal bind:this={modal} width="600px">

View File

@ -30,7 +30,7 @@
<div class="apps-card"> <div class="apps-card">
<Heading small black>{name}</Heading> <Heading small black>{name}</Heading>
<Spacer medium /> <Spacer medium />
<div class="card-footer"> <div class="card-footer" data-cy={`app-${name}`}>
<TextButton text medium blue href="/_builder/{_id}"> <TextButton text medium blue href="/_builder/{_id}">
Open Open
{name} {name}