mirror of
https://github.com/penpot/penpot.git
synced 2025-04-16 08:51:32 -05:00
🔥 Remove cypress directory and related files
This commit is contained in:
parent
3246c196d1
commit
89a7a6a414
43 changed files with 0 additions and 3907 deletions
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"watchForFileChanges": false,
|
||||
"video": false
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
Binary file not shown.
Before Width: | Height: | Size: 86 KiB |
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"email": "validuser@penpot.app",
|
||||
"password": "password",
|
||||
"team": "test team"
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
// Welcome to Cypress!
|
||||
//
|
||||
// This spec file contains a variety of sample tests
|
||||
// for a todo list app that are designed to demonstrate
|
||||
// the power of writing tests in Cypress.
|
||||
//
|
||||
// To learn more about how Cypress works and
|
||||
// what makes it such an awesome testing tool,
|
||||
// please read our getting started guide:
|
||||
// https://on.cypress.io/introduction-to-cypress
|
||||
|
||||
describe('example to-do app', () => {
|
||||
beforeEach(() => {
|
||||
// Cypress starts out with a blank slate for each test
|
||||
// so we must tell it to visit our website with the `cy.visit()` command.
|
||||
// Since we want to visit the same URL at the start of all our tests,
|
||||
// we include it in our beforeEach function so that it runs before each test
|
||||
cy.visit('https://example.cypress.io/todo')
|
||||
})
|
||||
|
||||
it('displays two todo items by default', () => {
|
||||
// We use the `cy.get()` command to get all elements that match the selector.
|
||||
// Then, we use `should` to assert that there are two matched items,
|
||||
// which are the two default items.
|
||||
cy.get('.todo-list li').should('have.length', 2)
|
||||
|
||||
// We can go even further and check that the default todos each contain
|
||||
// the correct text. We use the `first` and `last` functions
|
||||
// to get just the first and last matched elements individually,
|
||||
// and then perform an assertion with `should`.
|
||||
cy.get('.todo-list li').first().should('have.text', 'Pay electric bill')
|
||||
cy.get('.todo-list li').last().should('have.text', 'Walk the dog')
|
||||
})
|
||||
|
||||
it('can add new todo items', () => {
|
||||
// We'll store our item text in a variable so we can reuse it
|
||||
const newItem = 'Feed the cat'
|
||||
|
||||
// Let's get the input element and use the `type` command to
|
||||
// input our new list item. After typing the content of our item,
|
||||
// we need to type the enter key as well in order to submit the input.
|
||||
// This input has a data-test attribute so we'll use that to select the
|
||||
// element in accordance with best practices:
|
||||
// https://on.cypress.io/selecting-elements
|
||||
cy.get('[data-test=new-todo]').type(`${newItem}{enter}`)
|
||||
|
||||
// Now that we've typed our new item, let's check that it actually was added to the list.
|
||||
// Since it's the newest item, it should exist as the last element in the list.
|
||||
// In addition, with the two default items, we should have a total of 3 elements in the list.
|
||||
// Since assertions yield the element that was asserted on,
|
||||
// we can chain both of these assertions together into a single statement.
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 3)
|
||||
.last()
|
||||
.should('have.text', newItem)
|
||||
})
|
||||
|
||||
it('can check off an item as completed', () => {
|
||||
// In addition to using the `get` command to get an element by selector,
|
||||
// we can also use the `contains` command to get an element by its contents.
|
||||
// However, this will yield the <label>, which is lowest-level element that contains the text.
|
||||
// In order to check the item, we'll find the <input> element for this <label>
|
||||
// by traversing up the dom to the parent element. From there, we can `find`
|
||||
// the child checkbox <input> element and use the `check` command to check it.
|
||||
cy.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check()
|
||||
|
||||
// Now that we've checked the button, we can go ahead and make sure
|
||||
// that the list element is now marked as completed.
|
||||
// Again we'll use `contains` to find the <label> element and then use the `parents` command
|
||||
// to traverse multiple levels up the dom until we find the corresponding <li> element.
|
||||
// Once we get that element, we can assert that it has the completed class.
|
||||
cy.contains('Pay electric bill')
|
||||
.parents('li')
|
||||
.should('have.class', 'completed')
|
||||
})
|
||||
|
||||
context('with a checked task', () => {
|
||||
beforeEach(() => {
|
||||
// We'll take the command we used above to check off an element
|
||||
// Since we want to perform multiple tests that start with checking
|
||||
// one element, we put it in the beforeEach hook
|
||||
// so that it runs at the start of every test.
|
||||
cy.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check()
|
||||
})
|
||||
|
||||
it('can filter for uncompleted tasks', () => {
|
||||
// We'll click on the "active" button in order to
|
||||
// display only incomplete items
|
||||
cy.contains('Active').click()
|
||||
|
||||
// After filtering, we can assert that there is only the one
|
||||
// incomplete item in the list.
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Walk the dog')
|
||||
|
||||
// For good measure, let's also assert that the task we checked off
|
||||
// does not exist on the page.
|
||||
cy.contains('Pay electric bill').should('not.exist')
|
||||
})
|
||||
|
||||
it('can filter for completed tasks', () => {
|
||||
// We can perform similar steps as the test above to ensure
|
||||
// that only completed tasks are shown
|
||||
cy.contains('Completed').click()
|
||||
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Pay electric bill')
|
||||
|
||||
cy.contains('Walk the dog').should('not.exist')
|
||||
})
|
||||
|
||||
it('can delete all completed tasks', () => {
|
||||
// First, let's click the "Clear completed" button
|
||||
// `contains` is actually serving two purposes here.
|
||||
// First, it's ensuring that the button exists within the dom.
|
||||
// This button only appears when at least one task is checked
|
||||
// so this command is implicitly verifying that it does exist.
|
||||
// Second, it selects the button so we can click it.
|
||||
cy.contains('Clear completed').click()
|
||||
|
||||
// Then we can make sure that there is only one element
|
||||
// in the list and our element does not exist
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.should('not.have.text', 'Pay electric bill')
|
||||
|
||||
// Finally, make sure that the clear button no longer exists.
|
||||
cy.contains('Clear completed').should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,299 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Actions', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/actions')
|
||||
})
|
||||
|
||||
// https://on.cypress.io/interacting-with-elements
|
||||
|
||||
it('.type() - type into a DOM element', () => {
|
||||
// https://on.cypress.io/type
|
||||
cy.get('.action-email')
|
||||
.type('fake@email.com').should('have.value', 'fake@email.com')
|
||||
|
||||
// .type() with special character sequences
|
||||
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
|
||||
.type('{del}{selectall}{backspace}')
|
||||
|
||||
// .type() with key modifiers
|
||||
.type('{alt}{option}') //these are equivalent
|
||||
.type('{ctrl}{control}') //these are equivalent
|
||||
.type('{meta}{command}{cmd}') //these are equivalent
|
||||
.type('{shift}')
|
||||
|
||||
// Delay each keypress by 0.1 sec
|
||||
.type('slow.typing@email.com', { delay: 100 })
|
||||
.should('have.value', 'slow.typing@email.com')
|
||||
|
||||
cy.get('.action-disabled')
|
||||
// Ignore error checking prior to type
|
||||
// like whether the input is visible or disabled
|
||||
.type('disabled error checking', { force: true })
|
||||
.should('have.value', 'disabled error checking')
|
||||
})
|
||||
|
||||
it('.focus() - focus on a DOM element', () => {
|
||||
// https://on.cypress.io/focus
|
||||
cy.get('.action-focus').focus()
|
||||
.should('have.class', 'focus')
|
||||
.prev().should('have.attr', 'style', 'color: orange;')
|
||||
})
|
||||
|
||||
it('.blur() - blur off a DOM element', () => {
|
||||
// https://on.cypress.io/blur
|
||||
cy.get('.action-blur').type('About to blur').blur()
|
||||
.should('have.class', 'error')
|
||||
.prev().should('have.attr', 'style', 'color: red;')
|
||||
})
|
||||
|
||||
it('.clear() - clears an input or textarea element', () => {
|
||||
// https://on.cypress.io/clear
|
||||
cy.get('.action-clear').type('Clear this text')
|
||||
.should('have.value', 'Clear this text')
|
||||
.clear()
|
||||
.should('have.value', '')
|
||||
})
|
||||
|
||||
it('.submit() - submit a form', () => {
|
||||
// https://on.cypress.io/submit
|
||||
cy.get('.action-form')
|
||||
.find('[type="text"]').type('HALFOFF')
|
||||
|
||||
cy.get('.action-form').submit()
|
||||
.next().should('contain', 'Your form has been submitted!')
|
||||
})
|
||||
|
||||
it('.click() - click on a DOM element', () => {
|
||||
// https://on.cypress.io/click
|
||||
cy.get('.action-btn').click()
|
||||
|
||||
// You can click on 9 specific positions of an element:
|
||||
// -----------------------------------
|
||||
// | topLeft top topRight |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | left center right |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | bottomLeft bottom bottomRight |
|
||||
// -----------------------------------
|
||||
|
||||
// clicking in the center of the element is the default
|
||||
cy.get('#action-canvas').click()
|
||||
|
||||
cy.get('#action-canvas').click('topLeft')
|
||||
cy.get('#action-canvas').click('top')
|
||||
cy.get('#action-canvas').click('topRight')
|
||||
cy.get('#action-canvas').click('left')
|
||||
cy.get('#action-canvas').click('right')
|
||||
cy.get('#action-canvas').click('bottomLeft')
|
||||
cy.get('#action-canvas').click('bottom')
|
||||
cy.get('#action-canvas').click('bottomRight')
|
||||
|
||||
// .click() accepts an x and y coordinate
|
||||
// that controls where the click occurs :)
|
||||
|
||||
cy.get('#action-canvas')
|
||||
.click(80, 75) // click 80px on x coord and 75px on y coord
|
||||
.click(170, 75)
|
||||
.click(80, 165)
|
||||
.click(100, 185)
|
||||
.click(125, 190)
|
||||
.click(150, 185)
|
||||
.click(170, 165)
|
||||
|
||||
// click multiple elements by passing multiple: true
|
||||
cy.get('.action-labels>.label').click({ multiple: true })
|
||||
|
||||
// Ignore error checking prior to clicking
|
||||
cy.get('.action-opacity>.btn').click({ force: true })
|
||||
})
|
||||
|
||||
it('.dblclick() - double click on a DOM element', () => {
|
||||
// https://on.cypress.io/dblclick
|
||||
|
||||
// Our app has a listener on 'dblclick' event in our 'scripts.js'
|
||||
// that hides the div and shows an input on double click
|
||||
cy.get('.action-div').dblclick().should('not.be.visible')
|
||||
cy.get('.action-input-hidden').should('be.visible')
|
||||
})
|
||||
|
||||
it('.rightclick() - right click on a DOM element', () => {
|
||||
// https://on.cypress.io/rightclick
|
||||
|
||||
// Our app has a listener on 'contextmenu' event in our 'scripts.js'
|
||||
// that hides the div and shows an input on right click
|
||||
cy.get('.rightclick-action-div').rightclick().should('not.be.visible')
|
||||
cy.get('.rightclick-action-input-hidden').should('be.visible')
|
||||
})
|
||||
|
||||
it('.check() - check a checkbox or radio element', () => {
|
||||
// https://on.cypress.io/check
|
||||
|
||||
// By default, .check() will check all
|
||||
// matching checkbox or radio elements in succession, one after another
|
||||
cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]')
|
||||
.check().should('be.checked')
|
||||
|
||||
cy.get('.action-radios [type="radio"]').not('[disabled]')
|
||||
.check().should('be.checked')
|
||||
|
||||
// .check() accepts a value argument
|
||||
cy.get('.action-radios [type="radio"]')
|
||||
.check('radio1').should('be.checked')
|
||||
|
||||
// .check() accepts an array of values
|
||||
cy.get('.action-multiple-checkboxes [type="checkbox"]')
|
||||
.check(['checkbox1', 'checkbox2']).should('be.checked')
|
||||
|
||||
// Ignore error checking prior to checking
|
||||
cy.get('.action-checkboxes [disabled]')
|
||||
.check({ force: true }).should('be.checked')
|
||||
|
||||
cy.get('.action-radios [type="radio"]')
|
||||
.check('radio3', { force: true }).should('be.checked')
|
||||
})
|
||||
|
||||
it('.uncheck() - uncheck a checkbox element', () => {
|
||||
// https://on.cypress.io/uncheck
|
||||
|
||||
// By default, .uncheck() will uncheck all matching
|
||||
// checkbox elements in succession, one after another
|
||||
cy.get('.action-check [type="checkbox"]')
|
||||
.not('[disabled]')
|
||||
.uncheck().should('not.be.checked')
|
||||
|
||||
// .uncheck() accepts a value argument
|
||||
cy.get('.action-check [type="checkbox"]')
|
||||
.check('checkbox1')
|
||||
.uncheck('checkbox1').should('not.be.checked')
|
||||
|
||||
// .uncheck() accepts an array of values
|
||||
cy.get('.action-check [type="checkbox"]')
|
||||
.check(['checkbox1', 'checkbox3'])
|
||||
.uncheck(['checkbox1', 'checkbox3']).should('not.be.checked')
|
||||
|
||||
// Ignore error checking prior to unchecking
|
||||
cy.get('.action-check [disabled]')
|
||||
.uncheck({ force: true }).should('not.be.checked')
|
||||
})
|
||||
|
||||
it('.select() - select an option in a <select> element', () => {
|
||||
// https://on.cypress.io/select
|
||||
|
||||
// at first, no option should be selected
|
||||
cy.get('.action-select')
|
||||
.should('have.value', '--Select a fruit--')
|
||||
|
||||
// Select option(s) with matching text content
|
||||
cy.get('.action-select').select('apples')
|
||||
// confirm the apples were selected
|
||||
// note that each value starts with "fr-" in our HTML
|
||||
cy.get('.action-select').should('have.value', 'fr-apples')
|
||||
|
||||
cy.get('.action-select-multiple')
|
||||
.select(['apples', 'oranges', 'bananas'])
|
||||
// when getting multiple values, invoke "val" method first
|
||||
.invoke('val')
|
||||
.should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas'])
|
||||
|
||||
// Select option(s) with matching value
|
||||
cy.get('.action-select').select('fr-bananas')
|
||||
// can attach an assertion right away to the element
|
||||
.should('have.value', 'fr-bananas')
|
||||
|
||||
cy.get('.action-select-multiple')
|
||||
.select(['fr-apples', 'fr-oranges', 'fr-bananas'])
|
||||
.invoke('val')
|
||||
.should('deep.equal', ['fr-apples', 'fr-oranges', 'fr-bananas'])
|
||||
|
||||
// assert the selected values include oranges
|
||||
cy.get('.action-select-multiple')
|
||||
.invoke('val').should('include', 'fr-oranges')
|
||||
})
|
||||
|
||||
it('.scrollIntoView() - scroll an element into view', () => {
|
||||
// https://on.cypress.io/scrollintoview
|
||||
|
||||
// normally all of these buttons are hidden,
|
||||
// because they're not within
|
||||
// the viewable area of their parent
|
||||
// (we need to scroll to see them)
|
||||
cy.get('#scroll-horizontal button')
|
||||
.should('not.be.visible')
|
||||
|
||||
// scroll the button into view, as if the user had scrolled
|
||||
cy.get('#scroll-horizontal button').scrollIntoView()
|
||||
.should('be.visible')
|
||||
|
||||
cy.get('#scroll-vertical button')
|
||||
.should('not.be.visible')
|
||||
|
||||
// Cypress handles the scroll direction needed
|
||||
cy.get('#scroll-vertical button').scrollIntoView()
|
||||
.should('be.visible')
|
||||
|
||||
cy.get('#scroll-both button')
|
||||
.should('not.be.visible')
|
||||
|
||||
// Cypress knows to scroll to the right and down
|
||||
cy.get('#scroll-both button').scrollIntoView()
|
||||
.should('be.visible')
|
||||
})
|
||||
|
||||
it('.trigger() - trigger an event on a DOM element', () => {
|
||||
// https://on.cypress.io/trigger
|
||||
|
||||
// To interact with a range input (slider)
|
||||
// we need to set its value & trigger the
|
||||
// event to signal it changed
|
||||
|
||||
// Here, we invoke jQuery's val() method to set
|
||||
// the value and trigger the 'change' event
|
||||
cy.get('.trigger-input-range')
|
||||
.invoke('val', 25)
|
||||
.trigger('change')
|
||||
.get('input[type=range]').siblings('p')
|
||||
.should('have.text', '25')
|
||||
})
|
||||
|
||||
it('cy.scrollTo() - scroll the window or element to a position', () => {
|
||||
// https://on.cypress.io/scrollto
|
||||
|
||||
// You can scroll to 9 specific positions of an element:
|
||||
// -----------------------------------
|
||||
// | topLeft top topRight |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | left center right |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// | bottomLeft bottom bottomRight |
|
||||
// -----------------------------------
|
||||
|
||||
// if you chain .scrollTo() off of cy, we will
|
||||
// scroll the entire window
|
||||
cy.scrollTo('bottom')
|
||||
|
||||
cy.get('#scrollable-horizontal').scrollTo('right')
|
||||
|
||||
// or you can scroll to a specific coordinate:
|
||||
// (x axis, y axis) in pixels
|
||||
cy.get('#scrollable-vertical').scrollTo(250, 250)
|
||||
|
||||
// or you can scroll to a specific percentage
|
||||
// of the (width, height) of the element
|
||||
cy.get('#scrollable-both').scrollTo('75%', '25%')
|
||||
|
||||
// control the easing of the scroll (default is 'swing')
|
||||
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' })
|
||||
|
||||
// control the duration of the scroll (in ms)
|
||||
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 })
|
||||
})
|
||||
})
|
|
@ -1,39 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Aliasing', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/aliasing')
|
||||
})
|
||||
|
||||
it('.as() - alias a DOM element for later use', () => {
|
||||
// https://on.cypress.io/as
|
||||
|
||||
// Alias a DOM element for use later
|
||||
// We don't have to traverse to the element
|
||||
// later in our code, we reference it with @
|
||||
|
||||
cy.get('.as-table').find('tbody>tr')
|
||||
.first().find('td').first()
|
||||
.find('button').as('firstBtn')
|
||||
|
||||
// when we reference the alias, we place an
|
||||
// @ in front of its name
|
||||
cy.get('@firstBtn').click()
|
||||
|
||||
cy.get('@firstBtn')
|
||||
.should('have.class', 'btn-success')
|
||||
.and('contain', 'Changed')
|
||||
})
|
||||
|
||||
it('.as() - alias a route for later use', () => {
|
||||
// Alias the route to wait for its response
|
||||
cy.intercept('GET', '**/comments/*').as('getComment')
|
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-btn').click()
|
||||
|
||||
// https://on.cypress.io/wait
|
||||
cy.wait('@getComment').its('response.statusCode').should('eq', 200)
|
||||
})
|
||||
})
|
|
@ -1,177 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Assertions', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/assertions')
|
||||
})
|
||||
|
||||
describe('Implicit Assertions', () => {
|
||||
it('.should() - make an assertion about the current subject', () => {
|
||||
// https://on.cypress.io/should
|
||||
cy.get('.assertion-table')
|
||||
.find('tbody tr:last')
|
||||
.should('have.class', 'success')
|
||||
.find('td')
|
||||
.first()
|
||||
// checking the text of the <td> element in various ways
|
||||
.should('have.text', 'Column content')
|
||||
.should('contain', 'Column content')
|
||||
.should('have.html', 'Column content')
|
||||
// chai-jquery uses "is()" to check if element matches selector
|
||||
.should('match', 'td')
|
||||
// to match text content against a regular expression
|
||||
// first need to invoke jQuery method text()
|
||||
// and then match using regular expression
|
||||
.invoke('text')
|
||||
.should('match', /column content/i)
|
||||
|
||||
// a better way to check element's text content against a regular expression
|
||||
// is to use "cy.contains"
|
||||
// https://on.cypress.io/contains
|
||||
cy.get('.assertion-table')
|
||||
.find('tbody tr:last')
|
||||
// finds first <td> element with text content matching regular expression
|
||||
.contains('td', /column content/i)
|
||||
.should('be.visible')
|
||||
|
||||
// for more information about asserting element's text
|
||||
// see https://on.cypress.io/using-cypress-faq#How-do-I-get-an-element’s-text-contents
|
||||
})
|
||||
|
||||
it('.and() - chain multiple assertions together', () => {
|
||||
// https://on.cypress.io/and
|
||||
cy.get('.assertions-link')
|
||||
.should('have.class', 'active')
|
||||
.and('have.attr', 'href')
|
||||
.and('include', 'cypress.io')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Explicit Assertions', () => {
|
||||
// https://on.cypress.io/assertions
|
||||
it('expect - make an assertion about a specified subject', () => {
|
||||
// We can use Chai's BDD style assertions
|
||||
expect(true).to.be.true
|
||||
const o = { foo: 'bar' }
|
||||
|
||||
expect(o).to.equal(o)
|
||||
expect(o).to.deep.equal({ foo: 'bar' })
|
||||
// matching text using regular expression
|
||||
expect('FooBar').to.match(/bar$/i)
|
||||
})
|
||||
|
||||
it('pass your own callback function to should()', () => {
|
||||
// Pass a function to should that can have any number
|
||||
// of explicit assertions within it.
|
||||
// The ".should(cb)" function will be retried
|
||||
// automatically until it passes all your explicit assertions or times out.
|
||||
cy.get('.assertions-p')
|
||||
.find('p')
|
||||
.should(($p) => {
|
||||
// https://on.cypress.io/$
|
||||
// return an array of texts from all of the p's
|
||||
// @ts-ignore TS6133 unused variable
|
||||
const texts = $p.map((i, el) => Cypress.$(el).text())
|
||||
|
||||
// jquery map returns jquery object
|
||||
// and .get() convert this to simple array
|
||||
const paragraphs = texts.get()
|
||||
|
||||
// array should have length of 3
|
||||
expect(paragraphs, 'has 3 paragraphs').to.have.length(3)
|
||||
|
||||
// use second argument to expect(...) to provide clear
|
||||
// message with each assertion
|
||||
expect(paragraphs, 'has expected text in each paragraph').to.deep.eq([
|
||||
'Some text from first p',
|
||||
'More text from second p',
|
||||
'And even more text from third p',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
it('finds element by class name regex', () => {
|
||||
cy.get('.docs-header')
|
||||
.find('div')
|
||||
// .should(cb) callback function will be retried
|
||||
.should(($div) => {
|
||||
expect($div).to.have.length(1)
|
||||
|
||||
const className = $div[0].className
|
||||
|
||||
expect(className).to.match(/heading-/)
|
||||
})
|
||||
// .then(cb) callback is not retried,
|
||||
// it either passes or fails
|
||||
.then(($div) => {
|
||||
expect($div, 'text content').to.have.text('Introduction')
|
||||
})
|
||||
})
|
||||
|
||||
it('can throw any error', () => {
|
||||
cy.get('.docs-header')
|
||||
.find('div')
|
||||
.should(($div) => {
|
||||
if ($div.length !== 1) {
|
||||
// you can throw your own errors
|
||||
throw new Error('Did not find 1 element')
|
||||
}
|
||||
|
||||
const className = $div[0].className
|
||||
|
||||
if (!className.match(/heading-/)) {
|
||||
throw new Error(`Could not find class "heading-" in ${className}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('matches unknown text between two elements', () => {
|
||||
/**
|
||||
* Text from the first element.
|
||||
* @type {string}
|
||||
*/
|
||||
let text
|
||||
|
||||
/**
|
||||
* Normalizes passed text,
|
||||
* useful before comparing text with spaces and different capitalization.
|
||||
* @param {string} s Text to normalize
|
||||
*/
|
||||
const normalizeText = (s) => s.replace(/\s/g, '').toLowerCase()
|
||||
|
||||
cy.get('.two-elements')
|
||||
.find('.first')
|
||||
.then(($first) => {
|
||||
// save text from the first element
|
||||
text = normalizeText($first.text())
|
||||
})
|
||||
|
||||
cy.get('.two-elements')
|
||||
.find('.second')
|
||||
.should(($div) => {
|
||||
// we can massage text before comparing
|
||||
const secondText = normalizeText($div.text())
|
||||
|
||||
expect(secondText, 'second text').to.equal(text)
|
||||
})
|
||||
})
|
||||
|
||||
it('assert - assert shape of an object', () => {
|
||||
const person = {
|
||||
name: 'Joe',
|
||||
age: 20,
|
||||
}
|
||||
|
||||
assert.isObject(person, 'value is object')
|
||||
})
|
||||
|
||||
it('retries the should callback until assertions pass', () => {
|
||||
cy.get('#random-number')
|
||||
.should(($div) => {
|
||||
const n = parseFloat($div.text())
|
||||
|
||||
expect(n).to.be.gte(1).and.be.lte(10)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,97 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Connectors', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/connectors')
|
||||
})
|
||||
|
||||
it('.each() - iterate over an array of elements', () => {
|
||||
// https://on.cypress.io/each
|
||||
cy.get('.connectors-each-ul>li')
|
||||
.each(($el, index, $list) => {
|
||||
console.log($el, index, $list)
|
||||
})
|
||||
})
|
||||
|
||||
it('.its() - get properties on the current subject', () => {
|
||||
// https://on.cypress.io/its
|
||||
cy.get('.connectors-its-ul>li')
|
||||
// calls the 'length' property yielding that value
|
||||
.its('length')
|
||||
.should('be.gt', 2)
|
||||
})
|
||||
|
||||
it('.invoke() - invoke a function on the current subject', () => {
|
||||
// our div is hidden in our script.js
|
||||
// $('.connectors-div').hide()
|
||||
|
||||
// https://on.cypress.io/invoke
|
||||
cy.get('.connectors-div').should('be.hidden')
|
||||
// call the jquery method 'show' on the 'div.container'
|
||||
.invoke('show')
|
||||
.should('be.visible')
|
||||
})
|
||||
|
||||
it('.spread() - spread an array as individual args to callback function', () => {
|
||||
// https://on.cypress.io/spread
|
||||
const arr = ['foo', 'bar', 'baz']
|
||||
|
||||
cy.wrap(arr).spread((foo, bar, baz) => {
|
||||
expect(foo).to.eq('foo')
|
||||
expect(bar).to.eq('bar')
|
||||
expect(baz).to.eq('baz')
|
||||
})
|
||||
})
|
||||
|
||||
describe('.then()', () => {
|
||||
it('invokes a callback function with the current subject', () => {
|
||||
// https://on.cypress.io/then
|
||||
cy.get('.connectors-list > li')
|
||||
.then(($lis) => {
|
||||
expect($lis, '3 items').to.have.length(3)
|
||||
expect($lis.eq(0), 'first item').to.contain('Walk the dog')
|
||||
expect($lis.eq(1), 'second item').to.contain('Feed the cat')
|
||||
expect($lis.eq(2), 'third item').to.contain('Write JavaScript')
|
||||
})
|
||||
})
|
||||
|
||||
it('yields the returned value to the next command', () => {
|
||||
cy.wrap(1)
|
||||
.then((num) => {
|
||||
expect(num).to.equal(1)
|
||||
|
||||
return 2
|
||||
})
|
||||
.then((num) => {
|
||||
expect(num).to.equal(2)
|
||||
})
|
||||
})
|
||||
|
||||
it('yields the original subject without return', () => {
|
||||
cy.wrap(1)
|
||||
.then((num) => {
|
||||
expect(num).to.equal(1)
|
||||
// note that nothing is returned from this callback
|
||||
})
|
||||
.then((num) => {
|
||||
// this callback receives the original unchanged value 1
|
||||
expect(num).to.equal(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('yields the value yielded by the last Cypress command inside', () => {
|
||||
cy.wrap(1)
|
||||
.then((num) => {
|
||||
expect(num).to.equal(1)
|
||||
// note how we run a Cypress command
|
||||
// the result yielded by this Cypress command
|
||||
// will be passed to the second ".then"
|
||||
cy.wrap(2)
|
||||
})
|
||||
.then((num) => {
|
||||
// this callback receives the value yielded by "cy.wrap(2)"
|
||||
expect(num).to.equal(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,77 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Cookies', () => {
|
||||
beforeEach(() => {
|
||||
Cypress.Cookies.debug(true)
|
||||
|
||||
cy.visit('https://example.cypress.io/commands/cookies')
|
||||
|
||||
// clear cookies again after visiting to remove
|
||||
// any 3rd party cookies picked up such as cloudflare
|
||||
cy.clearCookies()
|
||||
})
|
||||
|
||||
it('cy.getCookie() - get a browser cookie', () => {
|
||||
// https://on.cypress.io/getcookie
|
||||
cy.get('#getCookie .set-a-cookie').click()
|
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie('token').should('have.property', 'value', '123ABC')
|
||||
})
|
||||
|
||||
it('cy.getCookies() - get browser cookies', () => {
|
||||
// https://on.cypress.io/getcookies
|
||||
cy.getCookies().should('be.empty')
|
||||
|
||||
cy.get('#getCookies .set-a-cookie').click()
|
||||
|
||||
// cy.getCookies() yields an array of cookies
|
||||
cy.getCookies().should('have.length', 1).should((cookies) => {
|
||||
// each cookie has these properties
|
||||
expect(cookies[0]).to.have.property('name', 'token')
|
||||
expect(cookies[0]).to.have.property('value', '123ABC')
|
||||
expect(cookies[0]).to.have.property('httpOnly', false)
|
||||
expect(cookies[0]).to.have.property('secure', false)
|
||||
expect(cookies[0]).to.have.property('domain')
|
||||
expect(cookies[0]).to.have.property('path')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.setCookie() - set a browser cookie', () => {
|
||||
// https://on.cypress.io/setcookie
|
||||
cy.getCookies().should('be.empty')
|
||||
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
// cy.getCookie() yields a cookie object
|
||||
cy.getCookie('foo').should('have.property', 'value', 'bar')
|
||||
})
|
||||
|
||||
it('cy.clearCookie() - clear a browser cookie', () => {
|
||||
// https://on.cypress.io/clearcookie
|
||||
cy.getCookie('token').should('be.null')
|
||||
|
||||
cy.get('#clearCookie .set-a-cookie').click()
|
||||
|
||||
cy.getCookie('token').should('have.property', 'value', '123ABC')
|
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookie('token').should('be.null')
|
||||
|
||||
cy.getCookie('token').should('be.null')
|
||||
})
|
||||
|
||||
it('cy.clearCookies() - clear browser cookies', () => {
|
||||
// https://on.cypress.io/clearcookies
|
||||
cy.getCookies().should('be.empty')
|
||||
|
||||
cy.get('#clearCookies .set-a-cookie').click()
|
||||
|
||||
cy.getCookies().should('have.length', 1)
|
||||
|
||||
// cy.clearCookies() yields null
|
||||
cy.clearCookies()
|
||||
|
||||
cy.getCookies().should('be.empty')
|
||||
})
|
||||
})
|
|
@ -1,202 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Cypress.Commands', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
// https://on.cypress.io/custom-commands
|
||||
|
||||
it('.add() - create a custom command', () => {
|
||||
Cypress.Commands.add('console', {
|
||||
prevSubject: true,
|
||||
}, (subject, method) => {
|
||||
// the previous subject is automatically received
|
||||
// and the commands arguments are shifted
|
||||
|
||||
// allow us to change the console method used
|
||||
method = method || 'log'
|
||||
|
||||
// log the subject to the console
|
||||
// @ts-ignore TS7017
|
||||
console[method]('The subject is', subject)
|
||||
|
||||
// whatever we return becomes the new subject
|
||||
// we don't want to change the subject so
|
||||
// we return whatever was passed in
|
||||
return subject
|
||||
})
|
||||
|
||||
// @ts-ignore TS2339
|
||||
cy.get('button').console('info').then(($button) => {
|
||||
// subject is still $button
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.Cookies', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
// https://on.cypress.io/cookies
|
||||
it('.debug() - enable or disable debugging', () => {
|
||||
Cypress.Cookies.debug(true)
|
||||
|
||||
// Cypress will now log in the console when
|
||||
// cookies are set or cleared
|
||||
cy.setCookie('fakeCookie', '123ABC')
|
||||
cy.clearCookie('fakeCookie')
|
||||
cy.setCookie('fakeCookie', '123ABC')
|
||||
cy.clearCookie('fakeCookie')
|
||||
cy.setCookie('fakeCookie', '123ABC')
|
||||
})
|
||||
|
||||
it('.preserveOnce() - preserve cookies by key', () => {
|
||||
// normally cookies are reset after each test
|
||||
cy.getCookie('fakeCookie').should('not.be.ok')
|
||||
|
||||
// preserving a cookie will not clear it when
|
||||
// the next test starts
|
||||
cy.setCookie('lastCookie', '789XYZ')
|
||||
Cypress.Cookies.preserveOnce('lastCookie')
|
||||
})
|
||||
|
||||
it('.defaults() - set defaults for all cookies', () => {
|
||||
// now any cookie with the name 'session_id' will
|
||||
// not be cleared before each new test runs
|
||||
Cypress.Cookies.defaults({
|
||||
preserve: 'session_id',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.arch', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Get CPU architecture name of underlying OS', () => {
|
||||
// https://on.cypress.io/arch
|
||||
expect(Cypress.arch).to.exist
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.config()', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Get and set configuration options', () => {
|
||||
// https://on.cypress.io/config
|
||||
let myConfig = Cypress.config()
|
||||
|
||||
expect(myConfig).to.have.property('animationDistanceThreshold', 5)
|
||||
expect(myConfig).to.have.property('baseUrl', null)
|
||||
expect(myConfig).to.have.property('defaultCommandTimeout', 4000)
|
||||
expect(myConfig).to.have.property('requestTimeout', 5000)
|
||||
expect(myConfig).to.have.property('responseTimeout', 30000)
|
||||
expect(myConfig).to.have.property('viewportHeight', 660)
|
||||
expect(myConfig).to.have.property('viewportWidth', 1000)
|
||||
expect(myConfig).to.have.property('pageLoadTimeout', 60000)
|
||||
expect(myConfig).to.have.property('waitForAnimations', true)
|
||||
|
||||
expect(Cypress.config('pageLoadTimeout')).to.eq(60000)
|
||||
|
||||
// this will change the config for the rest of your tests!
|
||||
Cypress.config('pageLoadTimeout', 20000)
|
||||
|
||||
expect(Cypress.config('pageLoadTimeout')).to.eq(20000)
|
||||
|
||||
Cypress.config('pageLoadTimeout', 60000)
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.dom', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
// https://on.cypress.io/dom
|
||||
it('.isHidden() - determine if a DOM element is hidden', () => {
|
||||
let hiddenP = Cypress.$('.dom-p p.hidden').get(0)
|
||||
let visibleP = Cypress.$('.dom-p p.visible').get(0)
|
||||
|
||||
// our first paragraph has css class 'hidden'
|
||||
expect(Cypress.dom.isHidden(hiddenP)).to.be.true
|
||||
expect(Cypress.dom.isHidden(visibleP)).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.env()', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
// We can set environment variables for highly dynamic values
|
||||
|
||||
// https://on.cypress.io/environment-variables
|
||||
it('Get environment variables', () => {
|
||||
// https://on.cypress.io/env
|
||||
// set multiple environment variables
|
||||
Cypress.env({
|
||||
host: 'veronica.dev.local',
|
||||
api_server: 'http://localhost:8888/v1/',
|
||||
})
|
||||
|
||||
// get environment variable
|
||||
expect(Cypress.env('host')).to.eq('veronica.dev.local')
|
||||
|
||||
// set environment variable
|
||||
Cypress.env('api_server', 'http://localhost:8888/v2/')
|
||||
expect(Cypress.env('api_server')).to.eq('http://localhost:8888/v2/')
|
||||
|
||||
// get all environment variable
|
||||
expect(Cypress.env()).to.have.property('host', 'veronica.dev.local')
|
||||
expect(Cypress.env()).to.have.property('api_server', 'http://localhost:8888/v2/')
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.log', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Control what is printed to the Command Log', () => {
|
||||
// https://on.cypress.io/cypress-log
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.platform', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Get underlying OS name', () => {
|
||||
// https://on.cypress.io/platform
|
||||
expect(Cypress.platform).to.be.exist
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.version', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Get current version of Cypress being run', () => {
|
||||
// https://on.cypress.io/version
|
||||
expect(Cypress.version).to.be.exist
|
||||
})
|
||||
})
|
||||
|
||||
context('Cypress.spec', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/cypress-api')
|
||||
})
|
||||
|
||||
it('Get current spec information', () => {
|
||||
// https://on.cypress.io/spec
|
||||
// wrap the object so we can inspect it easily by clicking in the command log
|
||||
cy.wrap(Cypress.spec).should('include.keys', ['name', 'relative', 'absolute'])
|
||||
})
|
||||
})
|
|
@ -1,88 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
/// JSON fixture file can be loaded directly using
|
||||
// the built-in JavaScript bundler
|
||||
// @ts-ignore
|
||||
const requiredExample = require('../../fixtures/example')
|
||||
|
||||
context('Files', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/files')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// load example.json fixture file and store
|
||||
// in the test context object
|
||||
cy.fixture('example.json').as('example')
|
||||
})
|
||||
|
||||
it('cy.fixture() - load a fixture', () => {
|
||||
// https://on.cypress.io/fixture
|
||||
|
||||
// Instead of writing a response inline you can
|
||||
// use a fixture file's content.
|
||||
|
||||
// when application makes an Ajax request matching "GET **/comments/*"
|
||||
// Cypress will intercept it and reply with the object in `example.json` fixture
|
||||
cy.intercept('GET', '**/comments/*', { fixture: 'example.json' }).as('getComment')
|
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.fixture-btn').click()
|
||||
|
||||
cy.wait('@getComment').its('response.body')
|
||||
.should('have.property', 'name')
|
||||
.and('include', 'Using fixtures to represent data')
|
||||
})
|
||||
|
||||
it('cy.fixture() or require - load a fixture', function () {
|
||||
// we are inside the "function () { ... }"
|
||||
// callback and can use test context object "this"
|
||||
// "this.example" was loaded in "beforeEach" function callback
|
||||
expect(this.example, 'fixture in the test context')
|
||||
.to.deep.equal(requiredExample)
|
||||
|
||||
// or use "cy.wrap" and "should('deep.equal', ...)" assertion
|
||||
cy.wrap(this.example)
|
||||
.should('deep.equal', requiredExample)
|
||||
})
|
||||
|
||||
it('cy.readFile() - read file contents', () => {
|
||||
// https://on.cypress.io/readfile
|
||||
|
||||
// You can read a file and yield its contents
|
||||
// The filePath is relative to your project's root.
|
||||
cy.readFile('cypress.json').then((json) => {
|
||||
expect(json).to.be.an('object')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.writeFile() - write to a file', () => {
|
||||
// https://on.cypress.io/writefile
|
||||
|
||||
// You can write to a file
|
||||
|
||||
// Use a response from a request to automatically
|
||||
// generate a fixture file for use later
|
||||
cy.request('https://jsonplaceholder.cypress.io/users')
|
||||
.then((response) => {
|
||||
cy.writeFile('cypress/fixtures/users.json', response.body)
|
||||
})
|
||||
|
||||
cy.fixture('users').should((users) => {
|
||||
expect(users[0].name).to.exist
|
||||
})
|
||||
|
||||
// JavaScript arrays and objects are stringified
|
||||
// and formatted into text.
|
||||
cy.writeFile('cypress/fixtures/profile.json', {
|
||||
id: 8739,
|
||||
name: 'Jane',
|
||||
email: 'jane@example.com',
|
||||
})
|
||||
|
||||
cy.fixture('profile').should((profile) => {
|
||||
expect(profile.name).to.eq('Jane')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,52 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Local Storage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/local-storage')
|
||||
})
|
||||
// Although local storage is automatically cleared
|
||||
// in between tests to maintain a clean state
|
||||
// sometimes we need to clear the local storage manually
|
||||
|
||||
it('cy.clearLocalStorage() - clear all data in local storage', () => {
|
||||
// https://on.cypress.io/clearlocalstorage
|
||||
cy.get('.ls-btn').click().should(() => {
|
||||
expect(localStorage.getItem('prop1')).to.eq('red')
|
||||
expect(localStorage.getItem('prop2')).to.eq('blue')
|
||||
expect(localStorage.getItem('prop3')).to.eq('magenta')
|
||||
})
|
||||
|
||||
// clearLocalStorage() yields the localStorage object
|
||||
cy.clearLocalStorage().should((ls) => {
|
||||
expect(ls.getItem('prop1')).to.be.null
|
||||
expect(ls.getItem('prop2')).to.be.null
|
||||
expect(ls.getItem('prop3')).to.be.null
|
||||
})
|
||||
|
||||
cy.get('.ls-btn').click().should(() => {
|
||||
expect(localStorage.getItem('prop1')).to.eq('red')
|
||||
expect(localStorage.getItem('prop2')).to.eq('blue')
|
||||
expect(localStorage.getItem('prop3')).to.eq('magenta')
|
||||
})
|
||||
|
||||
// Clear key matching string in Local Storage
|
||||
cy.clearLocalStorage('prop1').should((ls) => {
|
||||
expect(ls.getItem('prop1')).to.be.null
|
||||
expect(ls.getItem('prop2')).to.eq('blue')
|
||||
expect(ls.getItem('prop3')).to.eq('magenta')
|
||||
})
|
||||
|
||||
cy.get('.ls-btn').click().should(() => {
|
||||
expect(localStorage.getItem('prop1')).to.eq('red')
|
||||
expect(localStorage.getItem('prop2')).to.eq('blue')
|
||||
expect(localStorage.getItem('prop3')).to.eq('magenta')
|
||||
})
|
||||
|
||||
// Clear keys matching regex in Local Storage
|
||||
cy.clearLocalStorage(/prop1|2/).should((ls) => {
|
||||
expect(ls.getItem('prop1')).to.be.null
|
||||
expect(ls.getItem('prop2')).to.be.null
|
||||
expect(ls.getItem('prop3')).to.eq('magenta')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,32 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Location', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/location')
|
||||
})
|
||||
|
||||
it('cy.hash() - get the current URL hash', () => {
|
||||
// https://on.cypress.io/hash
|
||||
cy.hash().should('be.empty')
|
||||
})
|
||||
|
||||
it('cy.location() - get window.location', () => {
|
||||
// https://on.cypress.io/location
|
||||
cy.location().should((location) => {
|
||||
expect(location.hash).to.be.empty
|
||||
expect(location.href).to.eq('https://example.cypress.io/commands/location')
|
||||
expect(location.host).to.eq('example.cypress.io')
|
||||
expect(location.hostname).to.eq('example.cypress.io')
|
||||
expect(location.origin).to.eq('https://example.cypress.io')
|
||||
expect(location.pathname).to.eq('/commands/location')
|
||||
expect(location.port).to.eq('')
|
||||
expect(location.protocol).to.eq('https:')
|
||||
expect(location.search).to.be.empty
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.url() - get the current URL', () => {
|
||||
// https://on.cypress.io/url
|
||||
cy.url().should('eq', 'https://example.cypress.io/commands/location')
|
||||
})
|
||||
})
|
|
@ -1,104 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Misc', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/misc')
|
||||
})
|
||||
|
||||
it('.end() - end the command chain', () => {
|
||||
// https://on.cypress.io/end
|
||||
|
||||
// cy.end is useful when you want to end a chain of commands
|
||||
// and force Cypress to re-query from the root element
|
||||
cy.get('.misc-table').within(() => {
|
||||
// ends the current chain and yields null
|
||||
cy.contains('Cheryl').click().end()
|
||||
|
||||
// queries the entire table again
|
||||
cy.contains('Charles').click()
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.exec() - execute a system command', () => {
|
||||
// execute a system command.
|
||||
// so you can take actions necessary for
|
||||
// your test outside the scope of Cypress.
|
||||
// https://on.cypress.io/exec
|
||||
|
||||
// we can use Cypress.platform string to
|
||||
// select appropriate command
|
||||
// https://on.cypress/io/platform
|
||||
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`)
|
||||
|
||||
// on CircleCI Windows build machines we have a failure to run bash shell
|
||||
// https://github.com/cypress-io/cypress/issues/5169
|
||||
// so skip some of the tests by passing flag "--env circle=true"
|
||||
const isCircleOnWindows = Cypress.platform === 'win32' && Cypress.env('circle')
|
||||
|
||||
if (isCircleOnWindows) {
|
||||
cy.log('Skipping test on CircleCI')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// cy.exec problem on Shippable CI
|
||||
// https://github.com/cypress-io/cypress/issues/6718
|
||||
const isShippable = Cypress.platform === 'linux' && Cypress.env('shippable')
|
||||
|
||||
if (isShippable) {
|
||||
cy.log('Skipping test on ShippableCI')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cy.exec('echo Jane Lane')
|
||||
.its('stdout').should('contain', 'Jane Lane')
|
||||
|
||||
if (Cypress.platform === 'win32') {
|
||||
cy.exec('print cypress.json')
|
||||
.its('stderr').should('be.empty')
|
||||
} else {
|
||||
cy.exec('cat cypress.json')
|
||||
.its('stderr').should('be.empty')
|
||||
|
||||
cy.exec('pwd')
|
||||
.its('code').should('eq', 0)
|
||||
}
|
||||
})
|
||||
|
||||
it('cy.focused() - get the DOM element that has focus', () => {
|
||||
// https://on.cypress.io/focused
|
||||
cy.get('.misc-form').find('#name').click()
|
||||
cy.focused().should('have.id', 'name')
|
||||
|
||||
cy.get('.misc-form').find('#description').click()
|
||||
cy.focused().should('have.id', 'description')
|
||||
})
|
||||
|
||||
context('Cypress.Screenshot', function () {
|
||||
it('cy.screenshot() - take a screenshot', () => {
|
||||
// https://on.cypress.io/screenshot
|
||||
cy.screenshot('my-image')
|
||||
})
|
||||
|
||||
it('Cypress.Screenshot.defaults() - change default config of screenshots', function () {
|
||||
Cypress.Screenshot.defaults({
|
||||
blackout: ['.foo'],
|
||||
capture: 'viewport',
|
||||
clip: { x: 0, y: 0, width: 200, height: 200 },
|
||||
scale: false,
|
||||
disableTimersAndAnimations: true,
|
||||
screenshotOnRunFailure: true,
|
||||
onBeforeScreenshot () { },
|
||||
onAfterScreenshot () { },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.wrap() - wrap an object', () => {
|
||||
// https://on.cypress.io/wrap
|
||||
cy.wrap({ foo: 'bar' })
|
||||
.should('have.property', 'foo')
|
||||
.and('include', 'bar')
|
||||
})
|
||||
})
|
|
@ -1,56 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Navigation', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io')
|
||||
cy.get('.navbar-nav').contains('Commands').click()
|
||||
cy.get('.dropdown-menu').contains('Navigation').click()
|
||||
})
|
||||
|
||||
it('cy.go() - go back or forward in the browser\'s history', () => {
|
||||
// https://on.cypress.io/go
|
||||
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
|
||||
cy.go('back')
|
||||
cy.location('pathname').should('not.include', 'navigation')
|
||||
|
||||
cy.go('forward')
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
|
||||
// clicking back
|
||||
cy.go(-1)
|
||||
cy.location('pathname').should('not.include', 'navigation')
|
||||
|
||||
// clicking forward
|
||||
cy.go(1)
|
||||
cy.location('pathname').should('include', 'navigation')
|
||||
})
|
||||
|
||||
it('cy.reload() - reload the page', () => {
|
||||
// https://on.cypress.io/reload
|
||||
cy.reload()
|
||||
|
||||
// reload the page without using the cache
|
||||
cy.reload(true)
|
||||
})
|
||||
|
||||
it('cy.visit() - visit a remote url', () => {
|
||||
// https://on.cypress.io/visit
|
||||
|
||||
// Visit any sub-domain of your current domain
|
||||
|
||||
// Pass options to the visit
|
||||
cy.visit('https://example.cypress.io/commands/navigation', {
|
||||
timeout: 50000, // increase total time for the visit to resolve
|
||||
onBeforeLoad (contentWindow) {
|
||||
// contentWindow is the remote page's window object
|
||||
expect(typeof contentWindow === 'object').to.be.true
|
||||
},
|
||||
onLoad (contentWindow) {
|
||||
// contentWindow is the remote page's window object
|
||||
expect(typeof contentWindow === 'object').to.be.true
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,163 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Network Requests', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/network-requests')
|
||||
})
|
||||
|
||||
// Manage HTTP requests in your app
|
||||
|
||||
it('cy.request() - make an XHR request', () => {
|
||||
// https://on.cypress.io/request
|
||||
cy.request('https://jsonplaceholder.cypress.io/comments')
|
||||
.should((response) => {
|
||||
expect(response.status).to.eq(200)
|
||||
// the server sometimes gets an extra comment posted from another machine
|
||||
// which gets returned as 1 extra object
|
||||
expect(response.body).to.have.property('length').and.be.oneOf([500, 501])
|
||||
expect(response).to.have.property('headers')
|
||||
expect(response).to.have.property('duration')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.request() - verify response using BDD syntax', () => {
|
||||
cy.request('https://jsonplaceholder.cypress.io/comments')
|
||||
.then((response) => {
|
||||
// https://on.cypress.io/assertions
|
||||
expect(response).property('status').to.equal(200)
|
||||
expect(response).property('body').to.have.property('length').and.be.oneOf([500, 501])
|
||||
expect(response).to.include.keys('headers', 'duration')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.request() with query parameters', () => {
|
||||
// will execute request
|
||||
// https://jsonplaceholder.cypress.io/comments?postId=1&id=3
|
||||
cy.request({
|
||||
url: 'https://jsonplaceholder.cypress.io/comments',
|
||||
qs: {
|
||||
postId: 1,
|
||||
id: 3,
|
||||
},
|
||||
})
|
||||
.its('body')
|
||||
.should('be.an', 'array')
|
||||
.and('have.length', 1)
|
||||
.its('0') // yields first element of the array
|
||||
.should('contain', {
|
||||
postId: 1,
|
||||
id: 3,
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.request() - pass result to the second request', () => {
|
||||
// first, let's find out the userId of the first user we have
|
||||
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
|
||||
.its('body') // yields the response object
|
||||
.its('0') // yields the first element of the returned list
|
||||
// the above two commands its('body').its('0')
|
||||
// can be written as its('body.0')
|
||||
// if you do not care about TypeScript checks
|
||||
.then((user) => {
|
||||
expect(user).property('id').to.be.a('number')
|
||||
// make a new post on behalf of the user
|
||||
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
|
||||
userId: user.id,
|
||||
title: 'Cypress Test Runner',
|
||||
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
|
||||
})
|
||||
})
|
||||
// note that the value here is the returned value of the 2nd request
|
||||
// which is the new post object
|
||||
.then((response) => {
|
||||
expect(response).property('status').to.equal(201) // new entity created
|
||||
expect(response).property('body').to.contain({
|
||||
title: 'Cypress Test Runner',
|
||||
})
|
||||
|
||||
// we don't know the exact post id - only that it will be > 100
|
||||
// since JSONPlaceholder has built-in 100 posts
|
||||
expect(response.body).property('id').to.be.a('number')
|
||||
.and.to.be.gt(100)
|
||||
|
||||
// we don't know the user id here - since it was in above closure
|
||||
// so in this test just confirm that the property is there
|
||||
expect(response.body).property('userId').to.be.a('number')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.request() - save response in the shared test context', () => {
|
||||
// https://on.cypress.io/variables-and-aliases
|
||||
cy.request('https://jsonplaceholder.cypress.io/users?_limit=1')
|
||||
.its('body').its('0') // yields the first element of the returned list
|
||||
.as('user') // saves the object in the test context
|
||||
.then(function () {
|
||||
// NOTE 👀
|
||||
// By the time this callback runs the "as('user')" command
|
||||
// has saved the user object in the test context.
|
||||
// To access the test context we need to use
|
||||
// the "function () { ... }" callback form,
|
||||
// otherwise "this" points at a wrong or undefined object!
|
||||
cy.request('POST', 'https://jsonplaceholder.cypress.io/posts', {
|
||||
userId: this.user.id,
|
||||
title: 'Cypress Test Runner',
|
||||
body: 'Fast, easy and reliable testing for anything that runs in a browser.',
|
||||
})
|
||||
.its('body').as('post') // save the new post from the response
|
||||
})
|
||||
.then(function () {
|
||||
// When this callback runs, both "cy.request" API commands have finished
|
||||
// and the test context has "user" and "post" objects set.
|
||||
// Let's verify them.
|
||||
expect(this.post, 'post has the right user id').property('userId').to.equal(this.user.id)
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.intercept() - route responses to matching requests', () => {
|
||||
// https://on.cypress.io/intercept
|
||||
|
||||
let message = 'whoa, this comment does not exist'
|
||||
|
||||
// Listen to GET to comments/1
|
||||
cy.intercept('GET', '**/comments/*').as('getComment')
|
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-btn').click()
|
||||
|
||||
// https://on.cypress.io/wait
|
||||
cy.wait('@getComment').its('response.statusCode').should('be.oneOf', [200, 304])
|
||||
|
||||
// Listen to POST to comments
|
||||
cy.intercept('POST', '**/comments').as('postComment')
|
||||
|
||||
// we have code that posts a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-post').click()
|
||||
cy.wait('@postComment').should(({ request, response }) => {
|
||||
expect(request.body).to.include('email')
|
||||
expect(request.headers).to.have.property('content-type')
|
||||
expect(response && response.body).to.have.property('name', 'Using POST in cy.intercept()')
|
||||
})
|
||||
|
||||
// Stub a response to PUT comments/ ****
|
||||
cy.intercept({
|
||||
method: 'PUT',
|
||||
url: '**/comments/*',
|
||||
}, {
|
||||
statusCode: 404,
|
||||
body: { error: message },
|
||||
headers: { 'access-control-allow-origin': '*' },
|
||||
delayMs: 500,
|
||||
}).as('putComment')
|
||||
|
||||
// we have code that puts a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-put').click()
|
||||
|
||||
cy.wait('@putComment')
|
||||
|
||||
// our 404 statusCode logic in scripts.js executed
|
||||
cy.get('.network-put-comment').should('contain', message)
|
||||
})
|
||||
})
|
|
@ -1,114 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Querying', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/querying')
|
||||
})
|
||||
|
||||
// The most commonly used query is 'cy.get()', you can
|
||||
// think of this like the '$' in jQuery
|
||||
|
||||
it('cy.get() - query DOM elements', () => {
|
||||
// https://on.cypress.io/get
|
||||
|
||||
cy.get('#query-btn').should('contain', 'Button')
|
||||
|
||||
cy.get('.query-btn').should('contain', 'Button')
|
||||
|
||||
cy.get('#querying .well>button:first').should('contain', 'Button')
|
||||
// ↲
|
||||
// Use CSS selectors just like jQuery
|
||||
|
||||
cy.get('[data-test-id="test-example"]').should('have.class', 'example')
|
||||
|
||||
// 'cy.get()' yields jQuery object, you can get its attribute
|
||||
// by invoking `.attr()` method
|
||||
cy.get('[data-test-id="test-example"]')
|
||||
.invoke('attr', 'data-test-id')
|
||||
.should('equal', 'test-example')
|
||||
|
||||
// or you can get element's CSS property
|
||||
cy.get('[data-test-id="test-example"]')
|
||||
.invoke('css', 'position')
|
||||
.should('equal', 'static')
|
||||
|
||||
// or use assertions directly during 'cy.get()'
|
||||
// https://on.cypress.io/assertions
|
||||
cy.get('[data-test-id="test-example"]')
|
||||
.should('have.attr', 'data-test-id', 'test-example')
|
||||
.and('have.css', 'position', 'static')
|
||||
})
|
||||
|
||||
it('cy.contains() - query DOM elements with matching content', () => {
|
||||
// https://on.cypress.io/contains
|
||||
cy.get('.query-list')
|
||||
.contains('bananas')
|
||||
.should('have.class', 'third')
|
||||
|
||||
// we can pass a regexp to `.contains()`
|
||||
cy.get('.query-list')
|
||||
.contains(/^b\w+/)
|
||||
.should('have.class', 'third')
|
||||
|
||||
cy.get('.query-list')
|
||||
.contains('apples')
|
||||
.should('have.class', 'first')
|
||||
|
||||
// passing a selector to contains will
|
||||
// yield the selector containing the text
|
||||
cy.get('#querying')
|
||||
.contains('ul', 'oranges')
|
||||
.should('have.class', 'query-list')
|
||||
|
||||
cy.get('.query-button')
|
||||
.contains('Save Form')
|
||||
.should('have.class', 'btn')
|
||||
})
|
||||
|
||||
it('.within() - query DOM elements within a specific element', () => {
|
||||
// https://on.cypress.io/within
|
||||
cy.get('.query-form').within(() => {
|
||||
cy.get('input:first').should('have.attr', 'placeholder', 'Email')
|
||||
cy.get('input:last').should('have.attr', 'placeholder', 'Password')
|
||||
})
|
||||
})
|
||||
|
||||
it('cy.root() - query the root DOM element', () => {
|
||||
// https://on.cypress.io/root
|
||||
|
||||
// By default, root is the document
|
||||
cy.root().should('match', 'html')
|
||||
|
||||
cy.get('.query-ul').within(() => {
|
||||
// In this within, the root is now the ul DOM element
|
||||
cy.root().should('have.class', 'query-ul')
|
||||
})
|
||||
})
|
||||
|
||||
it('best practices - selecting elements', () => {
|
||||
// https://on.cypress.io/best-practices#Selecting-Elements
|
||||
cy.get('[data-cy=best-practices-selecting-elements]').within(() => {
|
||||
// Worst - too generic, no context
|
||||
cy.get('button').click()
|
||||
|
||||
// Bad. Coupled to styling. Highly subject to change.
|
||||
cy.get('.btn.btn-large').click()
|
||||
|
||||
// Average. Coupled to the `name` attribute which has HTML semantics.
|
||||
cy.get('[name=submission]').click()
|
||||
|
||||
// Better. But still coupled to styling or JS event listeners.
|
||||
cy.get('#main').click()
|
||||
|
||||
// Slightly better. Uses an ID but also ensures the element
|
||||
// has an ARIA role attribute
|
||||
cy.get('#main[role=button]').click()
|
||||
|
||||
// Much better. But still coupled to text content that may change.
|
||||
cy.contains('Submit').click()
|
||||
|
||||
// Best. Insulated from all changes.
|
||||
cy.get('[data-cy=submit]').click()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,205 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
// remove no check once Cypress.sinon is typed
|
||||
// https://github.com/cypress-io/cypress/issues/6720
|
||||
|
||||
context('Spies, Stubs, and Clock', () => {
|
||||
it('cy.spy() - wrap a method in a spy', () => {
|
||||
// https://on.cypress.io/spy
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
|
||||
const obj = {
|
||||
foo () {},
|
||||
}
|
||||
|
||||
const spy = cy.spy(obj, 'foo').as('anyArgs')
|
||||
|
||||
obj.foo()
|
||||
|
||||
expect(spy).to.be.called
|
||||
})
|
||||
|
||||
it('cy.spy() retries until assertions pass', () => {
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
|
||||
const obj = {
|
||||
/**
|
||||
* Prints the argument passed
|
||||
* @param x {any}
|
||||
*/
|
||||
foo (x) {
|
||||
console.log('obj.foo called with', x)
|
||||
},
|
||||
}
|
||||
|
||||
cy.spy(obj, 'foo').as('foo')
|
||||
|
||||
setTimeout(() => {
|
||||
obj.foo('first')
|
||||
}, 500)
|
||||
|
||||
setTimeout(() => {
|
||||
obj.foo('second')
|
||||
}, 2500)
|
||||
|
||||
cy.get('@foo').should('have.been.calledTwice')
|
||||
})
|
||||
|
||||
it('cy.stub() - create a stub and/or replace a function with stub', () => {
|
||||
// https://on.cypress.io/stub
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
|
||||
const obj = {
|
||||
/**
|
||||
* prints both arguments to the console
|
||||
* @param a {string}
|
||||
* @param b {string}
|
||||
*/
|
||||
foo (a, b) {
|
||||
console.log('a', a, 'b', b)
|
||||
},
|
||||
}
|
||||
|
||||
const stub = cy.stub(obj, 'foo').as('foo')
|
||||
|
||||
obj.foo('foo', 'bar')
|
||||
|
||||
expect(stub).to.be.called
|
||||
})
|
||||
|
||||
it('cy.clock() - control time in the browser', () => {
|
||||
// https://on.cypress.io/clock
|
||||
|
||||
// create the date in UTC so its always the same
|
||||
// no matter what local timezone the browser is running in
|
||||
const now = new Date(Date.UTC(2017, 2, 14)).getTime()
|
||||
|
||||
cy.clock(now)
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
cy.get('#clock-div').click()
|
||||
.should('have.text', '1489449600')
|
||||
})
|
||||
|
||||
it('cy.tick() - move time in the browser', () => {
|
||||
// https://on.cypress.io/tick
|
||||
|
||||
// create the date in UTC so its always the same
|
||||
// no matter what local timezone the browser is running in
|
||||
const now = new Date(Date.UTC(2017, 2, 14)).getTime()
|
||||
|
||||
cy.clock(now)
|
||||
cy.visit('https://example.cypress.io/commands/spies-stubs-clocks')
|
||||
cy.get('#tick-div').click()
|
||||
.should('have.text', '1489449600')
|
||||
|
||||
cy.tick(10000) // 10 seconds passed
|
||||
cy.get('#tick-div').click()
|
||||
.should('have.text', '1489449610')
|
||||
})
|
||||
|
||||
it('cy.stub() matches depending on arguments', () => {
|
||||
// see all possible matchers at
|
||||
// https://sinonjs.org/releases/latest/matchers/
|
||||
const greeter = {
|
||||
/**
|
||||
* Greets a person
|
||||
* @param {string} name
|
||||
*/
|
||||
greet (name) {
|
||||
return `Hello, ${name}!`
|
||||
},
|
||||
}
|
||||
|
||||
cy.stub(greeter, 'greet')
|
||||
.callThrough() // if you want non-matched calls to call the real method
|
||||
.withArgs(Cypress.sinon.match.string).returns('Hi')
|
||||
.withArgs(Cypress.sinon.match.number).throws(new Error('Invalid name'))
|
||||
|
||||
expect(greeter.greet('World')).to.equal('Hi')
|
||||
// @ts-ignore
|
||||
expect(() => greeter.greet(42)).to.throw('Invalid name')
|
||||
expect(greeter.greet).to.have.been.calledTwice
|
||||
|
||||
// non-matched calls goes the actual method
|
||||
// @ts-ignore
|
||||
expect(greeter.greet()).to.equal('Hello, undefined!')
|
||||
})
|
||||
|
||||
it('matches call arguments using Sinon matchers', () => {
|
||||
// see all possible matchers at
|
||||
// https://sinonjs.org/releases/latest/matchers/
|
||||
const calculator = {
|
||||
/**
|
||||
* returns the sum of two arguments
|
||||
* @param a {number}
|
||||
* @param b {number}
|
||||
*/
|
||||
add (a, b) {
|
||||
return a + b
|
||||
},
|
||||
}
|
||||
|
||||
const spy = cy.spy(calculator, 'add').as('add')
|
||||
|
||||
expect(calculator.add(2, 3)).to.equal(5)
|
||||
|
||||
// if we want to assert the exact values used during the call
|
||||
expect(spy).to.be.calledWith(2, 3)
|
||||
|
||||
// let's confirm "add" method was called with two numbers
|
||||
expect(spy).to.be.calledWith(Cypress.sinon.match.number, Cypress.sinon.match.number)
|
||||
|
||||
// alternatively, provide the value to match
|
||||
expect(spy).to.be.calledWith(Cypress.sinon.match(2), Cypress.sinon.match(3))
|
||||
|
||||
// match any value
|
||||
expect(spy).to.be.calledWith(Cypress.sinon.match.any, 3)
|
||||
|
||||
// match any value from a list
|
||||
expect(spy).to.be.calledWith(Cypress.sinon.match.in([1, 2, 3]), 3)
|
||||
|
||||
/**
|
||||
* Returns true if the given number is event
|
||||
* @param {number} x
|
||||
*/
|
||||
const isEven = (x) => x % 2 === 0
|
||||
|
||||
// expect the value to pass a custom predicate function
|
||||
// the second argument to "sinon.match(predicate, message)" is
|
||||
// shown if the predicate does not pass and assertion fails
|
||||
expect(spy).to.be.calledWith(Cypress.sinon.match(isEven, 'isEven'), 3)
|
||||
|
||||
/**
|
||||
* Returns a function that checks if a given number is larger than the limit
|
||||
* @param {number} limit
|
||||
* @returns {(x: number) => boolean}
|
||||
*/
|
||||
const isGreaterThan = (limit) => (x) => x > limit
|
||||
|
||||
/**
|
||||
* Returns a function that checks if a given number is less than the limit
|
||||
* @param {number} limit
|
||||
* @returns {(x: number) => boolean}
|
||||
*/
|
||||
const isLessThan = (limit) => (x) => x < limit
|
||||
|
||||
// you can combine several matchers using "and", "or"
|
||||
expect(spy).to.be.calledWith(
|
||||
Cypress.sinon.match.number,
|
||||
Cypress.sinon.match(isGreaterThan(2), '> 2').and(Cypress.sinon.match(isLessThan(4), '< 4')),
|
||||
)
|
||||
|
||||
expect(spy).to.be.calledWith(
|
||||
Cypress.sinon.match.number,
|
||||
Cypress.sinon.match(isGreaterThan(200), '> 200').or(Cypress.sinon.match(3)),
|
||||
)
|
||||
|
||||
// matchers can be used from BDD assertions
|
||||
cy.get('@add').should('have.been.calledWith',
|
||||
Cypress.sinon.match.number, Cypress.sinon.match(3))
|
||||
|
||||
// you can alias matchers for shorter test code
|
||||
const { match: M } = Cypress.sinon
|
||||
|
||||
cy.get('@add').should('have.been.calledWith', M.number, M(3))
|
||||
})
|
||||
})
|
|
@ -1,121 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Traversal', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/traversal')
|
||||
})
|
||||
|
||||
it('.children() - get child DOM elements', () => {
|
||||
// https://on.cypress.io/children
|
||||
cy.get('.traversal-breadcrumb')
|
||||
.children('.active')
|
||||
.should('contain', 'Data')
|
||||
})
|
||||
|
||||
it('.closest() - get closest ancestor DOM element', () => {
|
||||
// https://on.cypress.io/closest
|
||||
cy.get('.traversal-badge')
|
||||
.closest('ul')
|
||||
.should('have.class', 'list-group')
|
||||
})
|
||||
|
||||
it('.eq() - get a DOM element at a specific index', () => {
|
||||
// https://on.cypress.io/eq
|
||||
cy.get('.traversal-list>li')
|
||||
.eq(1).should('contain', 'siamese')
|
||||
})
|
||||
|
||||
it('.filter() - get DOM elements that match the selector', () => {
|
||||
// https://on.cypress.io/filter
|
||||
cy.get('.traversal-nav>li')
|
||||
.filter('.active').should('contain', 'About')
|
||||
})
|
||||
|
||||
it('.find() - get descendant DOM elements of the selector', () => {
|
||||
// https://on.cypress.io/find
|
||||
cy.get('.traversal-pagination')
|
||||
.find('li').find('a')
|
||||
.should('have.length', 7)
|
||||
})
|
||||
|
||||
it('.first() - get first DOM element', () => {
|
||||
// https://on.cypress.io/first
|
||||
cy.get('.traversal-table td')
|
||||
.first().should('contain', '1')
|
||||
})
|
||||
|
||||
it('.last() - get last DOM element', () => {
|
||||
// https://on.cypress.io/last
|
||||
cy.get('.traversal-buttons .btn')
|
||||
.last().should('contain', 'Submit')
|
||||
})
|
||||
|
||||
it('.next() - get next sibling DOM element', () => {
|
||||
// https://on.cypress.io/next
|
||||
cy.get('.traversal-ul')
|
||||
.contains('apples').next().should('contain', 'oranges')
|
||||
})
|
||||
|
||||
it('.nextAll() - get all next sibling DOM elements', () => {
|
||||
// https://on.cypress.io/nextall
|
||||
cy.get('.traversal-next-all')
|
||||
.contains('oranges')
|
||||
.nextAll().should('have.length', 3)
|
||||
})
|
||||
|
||||
it('.nextUntil() - get next sibling DOM elements until next el', () => {
|
||||
// https://on.cypress.io/nextuntil
|
||||
cy.get('#veggies')
|
||||
.nextUntil('#nuts').should('have.length', 3)
|
||||
})
|
||||
|
||||
it('.not() - remove DOM elements from set of DOM elements', () => {
|
||||
// https://on.cypress.io/not
|
||||
cy.get('.traversal-disabled .btn')
|
||||
.not('[disabled]').should('not.contain', 'Disabled')
|
||||
})
|
||||
|
||||
it('.parent() - get parent DOM element from DOM elements', () => {
|
||||
// https://on.cypress.io/parent
|
||||
cy.get('.traversal-mark')
|
||||
.parent().should('contain', 'Morbi leo risus')
|
||||
})
|
||||
|
||||
it('.parents() - get parent DOM elements from DOM elements', () => {
|
||||
// https://on.cypress.io/parents
|
||||
cy.get('.traversal-cite')
|
||||
.parents().should('match', 'blockquote')
|
||||
})
|
||||
|
||||
it('.parentsUntil() - get parent DOM elements from DOM elements until el', () => {
|
||||
// https://on.cypress.io/parentsuntil
|
||||
cy.get('.clothes-nav')
|
||||
.find('.active')
|
||||
.parentsUntil('.clothes-nav')
|
||||
.should('have.length', 2)
|
||||
})
|
||||
|
||||
it('.prev() - get previous sibling DOM element', () => {
|
||||
// https://on.cypress.io/prev
|
||||
cy.get('.birds').find('.active')
|
||||
.prev().should('contain', 'Lorikeets')
|
||||
})
|
||||
|
||||
it('.prevAll() - get all previous sibling DOM elements', () => {
|
||||
// https://on.cypress.io/prevall
|
||||
cy.get('.fruits-list').find('.third')
|
||||
.prevAll().should('have.length', 2)
|
||||
})
|
||||
|
||||
it('.prevUntil() - get all previous sibling DOM elements until el', () => {
|
||||
// https://on.cypress.io/prevuntil
|
||||
cy.get('.foods-list').find('#nuts')
|
||||
.prevUntil('#veggies').should('have.length', 3)
|
||||
})
|
||||
|
||||
it('.siblings() - get all sibling DOM elements', () => {
|
||||
// https://on.cypress.io/siblings
|
||||
cy.get('.traversal-pills .active')
|
||||
.siblings().should('have.length', 2)
|
||||
})
|
||||
})
|
|
@ -1,110 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Utilities', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/utilities')
|
||||
})
|
||||
|
||||
it('Cypress._ - call a lodash method', () => {
|
||||
// https://on.cypress.io/_
|
||||
cy.request('https://jsonplaceholder.cypress.io/users')
|
||||
.then((response) => {
|
||||
let ids = Cypress._.chain(response.body).map('id').take(3).value()
|
||||
|
||||
expect(ids).to.deep.eq([1, 2, 3])
|
||||
})
|
||||
})
|
||||
|
||||
it('Cypress.$ - call a jQuery method', () => {
|
||||
// https://on.cypress.io/$
|
||||
let $li = Cypress.$('.utility-jquery li:first')
|
||||
|
||||
cy.wrap($li)
|
||||
.should('not.have.class', 'active')
|
||||
.click()
|
||||
.should('have.class', 'active')
|
||||
})
|
||||
|
||||
it('Cypress.Blob - blob utilities and base64 string conversion', () => {
|
||||
// https://on.cypress.io/blob
|
||||
cy.get('.utility-blob').then(($div) => {
|
||||
// https://github.com/nolanlawson/blob-util#imgSrcToDataURL
|
||||
// get the dataUrl string for the javascript-logo
|
||||
return Cypress.Blob.imgSrcToDataURL('https://example.cypress.io/assets/img/javascript-logo.png', undefined, 'anonymous')
|
||||
.then((dataUrl) => {
|
||||
// create an <img> element and set its src to the dataUrl
|
||||
let img = Cypress.$('<img />', { src: dataUrl })
|
||||
|
||||
// need to explicitly return cy here since we are initially returning
|
||||
// the Cypress.Blob.imgSrcToDataURL promise to our test
|
||||
// append the image
|
||||
$div.append(img)
|
||||
|
||||
cy.get('.utility-blob img').click()
|
||||
.should('have.attr', 'src', dataUrl)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('Cypress.minimatch - test out glob patterns against strings', () => {
|
||||
// https://on.cypress.io/minimatch
|
||||
let matching = Cypress.minimatch('/users/1/comments', '/users/*/comments', {
|
||||
matchBase: true,
|
||||
})
|
||||
|
||||
expect(matching, 'matching wildcard').to.be.true
|
||||
|
||||
matching = Cypress.minimatch('/users/1/comments/2', '/users/*/comments', {
|
||||
matchBase: true,
|
||||
})
|
||||
|
||||
expect(matching, 'comments').to.be.false
|
||||
|
||||
// ** matches against all downstream path segments
|
||||
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/**', {
|
||||
matchBase: true,
|
||||
})
|
||||
|
||||
expect(matching, 'comments').to.be.true
|
||||
|
||||
// whereas * matches only the next path segment
|
||||
|
||||
matching = Cypress.minimatch('/foo/bar/baz/123/quux?a=b&c=2', '/foo/*', {
|
||||
matchBase: false,
|
||||
})
|
||||
|
||||
expect(matching, 'comments').to.be.false
|
||||
})
|
||||
|
||||
it('Cypress.Promise - instantiate a bluebird promise', () => {
|
||||
// https://on.cypress.io/promise
|
||||
let waited = false
|
||||
|
||||
/**
|
||||
* @return Bluebird<string>
|
||||
*/
|
||||
function waitOneSecond () {
|
||||
// return a promise that resolves after 1 second
|
||||
// @ts-ignore TS2351 (new Cypress.Promise)
|
||||
return new Cypress.Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
// set waited to true
|
||||
waited = true
|
||||
|
||||
// resolve with 'foo' string
|
||||
resolve('foo')
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
cy.then(() => {
|
||||
// return a promise to cy.then() that
|
||||
// is awaited until it resolves
|
||||
// @ts-ignore TS7006
|
||||
return waitOneSecond().then((str) => {
|
||||
expect(str).to.eq('foo')
|
||||
expect(waited).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,59 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Viewport', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/viewport')
|
||||
})
|
||||
|
||||
it('cy.viewport() - set the viewport size and dimension', () => {
|
||||
// https://on.cypress.io/viewport
|
||||
|
||||
cy.get('#navbar').should('be.visible')
|
||||
cy.viewport(320, 480)
|
||||
|
||||
// the navbar should have collapse since our screen is smaller
|
||||
cy.get('#navbar').should('not.be.visible')
|
||||
cy.get('.navbar-toggle').should('be.visible').click()
|
||||
cy.get('.nav').find('a').should('be.visible')
|
||||
|
||||
// lets see what our app looks like on a super large screen
|
||||
cy.viewport(2999, 2999)
|
||||
|
||||
// cy.viewport() accepts a set of preset sizes
|
||||
// to easily set the screen to a device's width and height
|
||||
|
||||
// We added a cy.wait() between each viewport change so you can see
|
||||
// the change otherwise it is a little too fast to see :)
|
||||
|
||||
cy.viewport('macbook-15')
|
||||
cy.wait(200)
|
||||
cy.viewport('macbook-13')
|
||||
cy.wait(200)
|
||||
cy.viewport('macbook-11')
|
||||
cy.wait(200)
|
||||
cy.viewport('ipad-2')
|
||||
cy.wait(200)
|
||||
cy.viewport('ipad-mini')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-6+')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-6')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-5')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-4')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-3')
|
||||
cy.wait(200)
|
||||
|
||||
// cy.viewport() accepts an orientation for all presets
|
||||
// the default orientation is 'portrait'
|
||||
cy.viewport('ipad-2', 'portrait')
|
||||
cy.wait(200)
|
||||
cy.viewport('iphone-4', 'landscape')
|
||||
cy.wait(200)
|
||||
|
||||
// The viewport will be reset back to the default dimensions
|
||||
// in between tests (the default can be set in cypress.json)
|
||||
})
|
||||
})
|
|
@ -1,31 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Waiting', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/waiting')
|
||||
})
|
||||
// BE CAREFUL of adding unnecessary wait times.
|
||||
// https://on.cypress.io/best-practices#Unnecessary-Waiting
|
||||
|
||||
// https://on.cypress.io/wait
|
||||
it('cy.wait() - wait for a specific amount of time', () => {
|
||||
cy.get('.wait-input1').type('Wait 1000ms after typing')
|
||||
cy.wait(1000)
|
||||
cy.get('.wait-input2').type('Wait 1000ms after typing')
|
||||
cy.wait(1000)
|
||||
cy.get('.wait-input3').type('Wait 1000ms after typing')
|
||||
cy.wait(1000)
|
||||
})
|
||||
|
||||
it('cy.wait() - wait for a specific route', () => {
|
||||
// Listen to GET to comments/1
|
||||
cy.intercept('GET', '**/comments/*').as('getComment')
|
||||
|
||||
// we have code that gets a comment when
|
||||
// the button is clicked in scripts.js
|
||||
cy.get('.network-btn').click()
|
||||
|
||||
// wait for GET comments/1
|
||||
cy.wait('@getComment').its('response.statusCode').should('be.oneOf', [200, 304])
|
||||
})
|
||||
})
|
|
@ -1,22 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
context('Window', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('https://example.cypress.io/commands/window')
|
||||
})
|
||||
|
||||
it('cy.window() - get the global window object', () => {
|
||||
// https://on.cypress.io/window
|
||||
cy.window().should('have.property', 'top')
|
||||
})
|
||||
|
||||
it('cy.document() - get the document object', () => {
|
||||
// https://on.cypress.io/document
|
||||
cy.document().should('have.property', 'charset').and('eq', 'UTF-8')
|
||||
})
|
||||
|
||||
it('cy.title() - get the title', () => {
|
||||
// https://on.cypress.io/title
|
||||
cy.title().should('include', 'Kitchen Sink')
|
||||
})
|
||||
})
|
|
@ -1,50 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("account creation", () => {
|
||||
let validUser;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
validUser = user;
|
||||
});
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
cy.getBySel("register-submit").click();
|
||||
});
|
||||
|
||||
it("displays the account creation form", () => {
|
||||
cy.getBySel("register-form-submit").should("exist");
|
||||
});
|
||||
|
||||
it("create an account", () => {
|
||||
let email = "mail" + Date.now() +"@mail.com";
|
||||
cy.get("#email").type(email);
|
||||
cy.get("#password").type("anewpassword");
|
||||
cy.get("input[type=submit]").click();
|
||||
cy.getBySel("register-title").should("exist");
|
||||
cy.get("#fullname").type("Test user")
|
||||
cy.get("input[type=submit]").click();
|
||||
cy.get(".dashboard-layout").should("exist");
|
||||
});
|
||||
|
||||
it("create an account of an existent email fails", () => {
|
||||
cy.get("#email").type(validUser.email);
|
||||
cy.get("#password").type("anewpassword");
|
||||
cy.getBySel("register-form-submit").click();
|
||||
cy.getBySel("email-input-error").should("exist");
|
||||
});
|
||||
|
||||
it("can go back", () => {
|
||||
cy.getBySel("login-here-link").click();
|
||||
cy.getBySel("login-title").should("exist");
|
||||
cy.get("#email").should("exist");
|
||||
cy.get("#password").should("exist");
|
||||
});
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("demo account", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
});
|
||||
|
||||
it("create demo account", () => {
|
||||
cy.getBySel("demo-account-link").should("exist");
|
||||
cy.getBySel("demo-account-link").click();
|
||||
cy.get(".profile").contains("Demo User");
|
||||
});
|
||||
});
|
|
@ -1,38 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("login", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
});
|
||||
|
||||
it("displays the login form", () => {
|
||||
cy.getBySel("login-title").should("exist");
|
||||
cy.get("#email").should("exist");
|
||||
cy.get("#password").should("exist");
|
||||
});
|
||||
|
||||
it("can't login with an invalid user", () => {
|
||||
cy.get("#email").type("bad@mail.com");
|
||||
cy.get("#password").type("badpassword");
|
||||
cy.getBySel("login-submit").click();
|
||||
cy.getBySel("login-banner").should("exist");
|
||||
});
|
||||
|
||||
it("can login with a valid user", () => {
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.get("#email").type(user.email);
|
||||
cy.get("#password").type(user.password);
|
||||
});
|
||||
|
||||
cy.getBySel("login-submit").click();
|
||||
cy.get(".dashboard-layout").should("exist");
|
||||
});
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("recover password", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
cy.getBySel("forgot-password").click();
|
||||
});
|
||||
|
||||
it("displays the recover form", () => {
|
||||
cy.getBySel("recovery-resquest-submit").should("exist");
|
||||
});
|
||||
|
||||
it("recover password with wrong mail works", () => {
|
||||
cy.get("#email").type("bad@mail.com");
|
||||
cy.getBySel("recovery-resquest-submit").click();
|
||||
cy.get(".info").should("exist");
|
||||
});
|
||||
|
||||
it("recover password with good mail works", () => {
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.get("#email").type(user.email);
|
||||
});
|
||||
cy.getBySel("recovery-resquest-submit").click();
|
||||
cy.get(".info").should("exist");
|
||||
});
|
||||
|
||||
it("can go back", () => {
|
||||
cy.getBySel("go-back-link").click();
|
||||
cy.getBySel("login-title").should("exist");
|
||||
cy.get("#email").should("exist");
|
||||
cy.get("#password").should("exist");
|
||||
});
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("onboarding options solo or team", () => {
|
||||
beforeEach(() => {
|
||||
cy.demoLogin();
|
||||
cy.get(".modal-right button").click();
|
||||
cy.get(".onboarding button").click();
|
||||
cy.get(".onboarding .skip").click();
|
||||
});
|
||||
|
||||
it("choose solo option", () => {
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
cy.getBySel("fly-solo-op").click();
|
||||
cy.getBySel("empty-placeholder").should("exist");
|
||||
});
|
||||
|
||||
it("choose team option and cancel", () => {
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
cy.getBySel("team-up-button").click();
|
||||
cy.getBySel("onboarding-choice-team-up").should("exist");
|
||||
cy.get("button").click();
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
});
|
||||
|
||||
it("choose team option, set team name and cancel", () => {
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
cy.getBySel("team-up-button").click();
|
||||
cy.getBySel("onboarding-choice-team-up").should("exist");
|
||||
cy.get("#name").type("test team");
|
||||
cy.get("input[type=submit]").first().click();
|
||||
cy.get("#email").should("exist");
|
||||
cy.get("button").click();
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
});
|
||||
|
||||
it("choose team option, set team name and skip", () => {
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
cy.getBySel("team-up-button").click();
|
||||
cy.getBySel("onboarding-choice-team-up").should("exist");
|
||||
cy.get("#name").type("test team");
|
||||
cy.get("input[type=submit]").first().click();
|
||||
cy.get("#email").should("exist");
|
||||
cy.get(".skip-action").click();
|
||||
cy.getBySel("empty-placeholder").should("exist");
|
||||
});
|
||||
|
||||
it("choose team option, set team name and invite", () => {
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
cy.getBySel("team-up-button").click();
|
||||
cy.getBySel("onboarding-choice-team-up").should("exist");
|
||||
cy.get("#name").type("test team");
|
||||
cy.get("input[type=submit]").first().click();
|
||||
cy.get("#email").should("exist");
|
||||
cy.get("#email").type("test@test.com");
|
||||
cy.get("input[type=submit]").first().click();
|
||||
cy.getBySel("empty-placeholder").should("exist");
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
import {
|
||||
checkOnboardingSlide,
|
||||
goToSlideByNumber,
|
||||
} from "../../support/utils.js";
|
||||
|
||||
describe("onboarding slides", () => {
|
||||
beforeEach(() => {
|
||||
cy.demoLogin();
|
||||
});
|
||||
|
||||
it("go through all the onboarding slides", () => {
|
||||
cy.getBySel("onboarding-welcome").should("exist");
|
||||
cy.getBySel("onboarding-next-btn").should("exist");
|
||||
cy.getBySel("onboarding-next-btn").click();
|
||||
|
||||
cy.getBySel("opsource-next-btn").should("exist");
|
||||
cy.getBySel("skip-btn").should("not.exist");
|
||||
cy.getBySel("opsource-next-btn").click();
|
||||
|
||||
var genArr = Array.from(Array(3).keys());
|
||||
cy.wrap(genArr).each((index) => {
|
||||
checkOnboardingSlide(index, true);
|
||||
});
|
||||
checkOnboardingSlide("3", false);
|
||||
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
});
|
||||
|
||||
it("go to specific onboarding slides", () => {
|
||||
cy.getBySel("onboarding-next-btn").click();
|
||||
cy.getBySel(`opsource-next-btn`).click();
|
||||
|
||||
var genArr = Array.from(Array(4).keys());
|
||||
cy.wrap(genArr).each((index) => {
|
||||
goToSlideByNumber(4 - index);
|
||||
});
|
||||
});
|
||||
|
||||
it("skip onboarding slides", () => {
|
||||
cy.getBySel("onboarding-next-btn").click();
|
||||
cy.getBySel("opsource-next-btn").click();
|
||||
cy.getBySel("skip-btn").click();
|
||||
cy.getBySel("fly-solo-op").click();
|
||||
cy.getBySel("onboarding-welcome-title").should("exist");
|
||||
});
|
||||
});
|
|
@ -1,489 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
|
||||
createProject,
|
||||
deleteFirstProject,
|
||||
deleteFirstFile,
|
||||
createFile
|
||||
|
||||
} from '../../support/utils.js';
|
||||
|
||||
|
||||
|
||||
describe("files", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
createProject("test project" + Date.now());
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
//cleanup
|
||||
deleteFirstProject();
|
||||
});
|
||||
|
||||
|
||||
it("can create a new file", () => {
|
||||
cy.get(".grid-item").then((files) => {
|
||||
cy.get('.project').first().find("[data-test=project-new-file]").click();
|
||||
cy.get("#workspace").should("exist");
|
||||
cy.get(".project-tree").should("contain", "New File");
|
||||
|
||||
//Go back
|
||||
cy.get(".main-icon a").click();
|
||||
cy.get(".grid-item").should('have.length', files.length + 1);
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it("can create a new file inside a project", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
cy.get(".grid-item").should('have.length', 0);
|
||||
createFile();
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can create a new file inside a project with shortcut", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
cy.get(".grid-item").should('have.length', 0);
|
||||
cy.get("body").type("+");
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can delete a file inside a project", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-delete").click();
|
||||
cy.get('.accept-button').click();
|
||||
cy.get(".grid-item").should('have.length', 0);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can cancel a file deletion inside a project", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-delete").click();
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can delete a file outside a project", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
|
||||
cy.get(".grid-item").then((files) => {
|
||||
cy.get('.menu')
|
||||
.first()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-delete").click();
|
||||
cy.get('.accept-button').click();
|
||||
cy.get(".grid-item").should('have.length', files.length-1);
|
||||
});
|
||||
})
|
||||
|
||||
it("can cancel a file deletion outside a project", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
|
||||
cy.get(".grid-item").then((files) => {
|
||||
cy.get('.menu')
|
||||
.first()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-delete").click();
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get(".grid-item").should('have.length', files.length);
|
||||
});
|
||||
})
|
||||
|
||||
it("can rename a file", () => {
|
||||
const fileName = "test file " + Date.now();
|
||||
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-rename").click();
|
||||
cy.get(".edit-wrapper").should("exist");
|
||||
cy.get(".edit-wrapper").type(fileName + "{enter}");
|
||||
|
||||
cy.get(".grid-item").first().should("contain", fileName);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can duplicate a file", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-duplicate").click();
|
||||
cy.get(".grid-item").should('have.length', 2);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can move a file to another project", () => {
|
||||
const projectToMoveName = "test project to move " + Date.now();
|
||||
const fileName = "test file " + Date.now();
|
||||
|
||||
createProject(projectToMoveName);
|
||||
cy.get(".project").eq(1).find("h2").click();
|
||||
createFile(fileName);
|
||||
|
||||
//TODO: Bug workaround. When a file is selected, it doesn't open context menu
|
||||
cy.get(".dashboard-grid").click();
|
||||
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.wait(500);
|
||||
cy.getBySel("file-move-to").click();
|
||||
|
||||
cy.get('a').contains(projectToMoveName).click();
|
||||
|
||||
cy.getBySel("project-title").should("contain", projectToMoveName);
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
cy.get(".grid-item").first().should("contain", fileName);
|
||||
|
||||
|
||||
//Go back and cleanup: delete project
|
||||
cy.get(".recent-projects").click();
|
||||
deleteFirstProject();
|
||||
});
|
||||
|
||||
|
||||
it("can move a file to another team", () => {
|
||||
const fileName = "test file " + Date.now();
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile(fileName);
|
||||
|
||||
//TODO: Bug workaround. When a file is selected, it doesn't open context menu
|
||||
cy.get(".dashboard-grid").click();
|
||||
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.wait(500);
|
||||
cy.getBySel("file-move-to").click();
|
||||
|
||||
cy.getBySel("move-to-other-team").click();
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.get('a').contains(user.team).click();
|
||||
cy.get('a').contains("Drafts").click();
|
||||
cy.get(".current-team").should("contain", user.team);
|
||||
cy.get(".dashboard-title").should("contain", "Drafts");
|
||||
cy.get(".grid-item").first().should("contain", fileName);
|
||||
});
|
||||
|
||||
|
||||
//cleanup
|
||||
deleteFirstFile();
|
||||
cy.get(".current-team").click();
|
||||
cy.get(".team-name").contains("Your Penpot").click();
|
||||
});
|
||||
|
||||
|
||||
it("can make a file a shared library", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get(".icon-library").should('have.length', 0);
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-add-shared").click();
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".icon-library").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can cancel make a file a shared library", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get(".icon-library").should('have.length', 0);
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-add-shared").click();
|
||||
cy.get(".modal-close-button").click();
|
||||
cy.get(".icon-library").should('have.length', 0);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can remove a file as shared library", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-add-shared").click();
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".icon-library").should('have.length', 1);
|
||||
|
||||
//TODO: Bug workaround. When a file is selected, it doesn't open context menu
|
||||
cy.get(".dashboard-grid").click();
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-del-shared").click();
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".icon-library").should('have.length', 0);
|
||||
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can cancel remove a file as shared library", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-add-shared").click();
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".icon-library").should('have.length', 1);
|
||||
|
||||
//TODO: Bug workaround. When a file is selected, it doesn't open context menu
|
||||
cy.get(".dashboard-grid").click();
|
||||
|
||||
cy.get('.menu')
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-del-shared").click();
|
||||
cy.get(".modal-close-button").click();
|
||||
cy.get(".icon-library").should('have.length', 1);
|
||||
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can search for a file", () => {
|
||||
const fileName = "test file " + Date.now();
|
||||
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile(fileName);
|
||||
|
||||
cy.get("#search-input").type("bad name");
|
||||
cy.get(".grid-item").should('have.length', 0);
|
||||
|
||||
cy.get("#search-input").clear().type(fileName);
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can multiselect files", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
createFile();
|
||||
createFile();
|
||||
|
||||
cy.get(".selected").should('have.length', 0);
|
||||
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".selected").should('have.length', 1);
|
||||
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
cy.get(".selected").should('have.length', 2);
|
||||
|
||||
cy.get(".grid-item").eq(1).click({shiftKey: true});
|
||||
cy.get(".selected").should('have.length', 3);
|
||||
|
||||
cy.get(".grid-item").eq(1).click({shiftKey: true});
|
||||
cy.get(".selected").should('have.length', 2);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can delete multiselected files", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
createFile();
|
||||
createFile();
|
||||
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
|
||||
cy.get(".grid-item").should('have.length', 3);
|
||||
cy.get(".grid-item").eq(0).rightclick();
|
||||
cy.getBySel("delete-multi-files").should("contain", "Delete 2 files");
|
||||
cy.getBySel("delete-multi-files").click();
|
||||
cy.get('.accept-button').click();
|
||||
cy.get(".grid-item").should('have.length', 1);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can cancel delete multiselected files", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
createFile();
|
||||
createFile();
|
||||
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
|
||||
cy.get(".grid-item").should('have.length', 3);
|
||||
cy.get(".grid-item").eq(0).rightclick();
|
||||
cy.getBySel("delete-multi-files").should("contain", "Delete 2 files");
|
||||
cy.getBySel("delete-multi-files").click();
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get(".grid-item").should('have.length', 3);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
|
||||
it("can duplicate multiselected files", () => {
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile();
|
||||
createFile();
|
||||
createFile();
|
||||
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
|
||||
cy.get(".grid-item").should('have.length', 3);
|
||||
cy.get(".grid-item").eq(0).rightclick();
|
||||
cy.getBySel("duplicate-multi").should("contain", "Duplicate 2 files");
|
||||
cy.getBySel("duplicate-multi").click();
|
||||
cy.get(".grid-item").should('have.length', 5);
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
})
|
||||
|
||||
it("can move multiselected files to another project", () => {
|
||||
const projectToMoveName = "test project to move " + Date.now();
|
||||
createProject(projectToMoveName);
|
||||
|
||||
cy.get(".project").eq(1).find("h2").click();
|
||||
createFile();
|
||||
createFile();
|
||||
createFile();
|
||||
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
|
||||
|
||||
cy.get(".grid-item").eq(0).rightclick();
|
||||
cy.getBySel("move-to-multi").should("contain", "Move 2 files to");
|
||||
cy.getBySel("move-to-multi").click();
|
||||
cy.get('a').contains(projectToMoveName).click();
|
||||
|
||||
cy.getBySel("project-title").should("contain", projectToMoveName);
|
||||
cy.get(".grid-item").should('have.length', 2);
|
||||
|
||||
|
||||
//Go back
|
||||
cy.get(".recent-projects").click();
|
||||
deleteFirstProject();
|
||||
})
|
||||
|
||||
|
||||
it("can move multiselected files to another team", () => {
|
||||
const fileName1 = "test file " + Date.now();
|
||||
const fileName2 = "test file " + Date.now();
|
||||
const fileName3 = "test file " + Date.now();
|
||||
|
||||
cy.get(".project").first().find("h2").click();
|
||||
createFile(fileName1)
|
||||
createFile(fileName2)
|
||||
createFile(fileName3)
|
||||
|
||||
|
||||
//multiselect first and third file
|
||||
cy.get(".grid-item").eq(0).click({shiftKey: true});
|
||||
cy.get(".grid-item").eq(2).click({shiftKey: true});
|
||||
|
||||
|
||||
cy.get(".grid-item").eq(0).rightclick();
|
||||
cy.getBySel("move-to-multi").should("contain", "Move 2 files to");
|
||||
cy.getBySel("move-to-multi").click();
|
||||
cy.getBySel("move-to-other-team").click();
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.get('a').contains(user.team).click();
|
||||
cy.get('a').contains("Drafts").click();
|
||||
cy.get(".current-team").should("contain", user.team);
|
||||
cy.get(".dashboard-title").should("contain", "Drafts");
|
||||
cy.get(".grid-item").eq(0).should("contain", fileName1);
|
||||
cy.get(".grid-item").eq(1).should("contain", fileName2);
|
||||
});
|
||||
|
||||
|
||||
//cleanup
|
||||
deleteFirstFile()
|
||||
deleteFirstFile()
|
||||
cy.get(".current-team").click();
|
||||
cy.get(".team-name").contains("Your Penpot").click();
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
|
||||
deleteFirstFile,
|
||||
deleteFirstFont
|
||||
|
||||
} from '../../support/utils.js';
|
||||
|
||||
|
||||
|
||||
describe("comments", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("can open and close comments popup", () => {
|
||||
cy.get(".comments-section").should("not.exist");
|
||||
cy.getBySel("open-comments").click();
|
||||
cy.get(".comments-section").should("exist");
|
||||
cy.getBySel("open-comments").click();
|
||||
cy.get(".comments-section").should("not.exist");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("import and export", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
});
|
||||
|
||||
it("can export a file", () => {
|
||||
cy.get('.menu')
|
||||
.first()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-export").click();
|
||||
cy.get('.icon-tick').should("exist");
|
||||
});
|
||||
|
||||
it("can import a file", () => {
|
||||
cy.get(".grid-item").then((files) => {
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.getBySel("file-import").click();
|
||||
|
||||
cy.uploadBinaryFile("input[type=file]", "test-file-import.penpot");
|
||||
|
||||
cy.get(".accept-button").should('not.be.disabled');
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".accept-button").should('not.be.disabled');
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".grid-item").should('have.length', files.length+1);
|
||||
});
|
||||
|
||||
//cleanup
|
||||
deleteFirstFile() ;
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe("release notes", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
});
|
||||
|
||||
it("can show release notes", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.get(".onboarding").should("not.exist");
|
||||
cy.getBySel("release-notes").click();
|
||||
cy.get(".onboarding").should("exist");
|
||||
});
|
||||
});
|
||||
|
||||
describe("fonts", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
});
|
||||
|
||||
it("can upload a font file", () => {
|
||||
cy.getBySel("fonts").click();
|
||||
cy.get(".font-item").should('have.length', 0);
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/Viafont.otf");
|
||||
cy.get(".upload-button").click();
|
||||
cy.get(".font-item").should('have.length', 1);
|
||||
|
||||
//cleanup
|
||||
deleteFirstFont();
|
||||
|
||||
});
|
||||
|
||||
it("can upload multiple font files", () => {
|
||||
cy.getBySel("fonts").click();
|
||||
cy.get(".font-item").should('have.length', 0);
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/Viafont.otf");
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/blkchcry.ttf");
|
||||
cy.getBySel("upload-all").click();
|
||||
cy.get(".font-item").should('have.length', 2);
|
||||
|
||||
//cleanup
|
||||
deleteFirstFont();
|
||||
deleteFirstFont();
|
||||
});
|
||||
|
||||
it("can dismiss multiple font files", () => {
|
||||
cy.getBySel("fonts").click();
|
||||
cy.get(".font-item").should('have.length', 0);
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/Viafont.otf");
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/blkchcry.ttf");
|
||||
cy.getBySel("dismiss-all").click();
|
||||
cy.get(".font-item").should('have.length', 0);
|
||||
});
|
||||
|
||||
it("can rename a font", () => {
|
||||
const fontName = "test font " + Date.now();
|
||||
|
||||
//Upload a font
|
||||
cy.getBySel("fonts").click();
|
||||
cy.uploadBinaryFile("#font-upload", "fonts/Viafont.otf");
|
||||
cy.get(".upload-button").click();
|
||||
cy.get(".font-item").should('have.length', 1);
|
||||
|
||||
//Rename font
|
||||
cy.get(".font-item .options").first().click();
|
||||
cy.getBySel("font-edit").click();
|
||||
cy.get(".dashboard-installed-fonts input[value=Viafont]").type(fontName+"{enter}");
|
||||
cy.get(".dashboard-installed-fonts").should("contain", fontName);
|
||||
|
||||
//cleanup
|
||||
deleteFirstFont();
|
||||
|
||||
});
|
||||
});
|
|
@ -1,153 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
|
||||
createProject,
|
||||
deleteFirstProject
|
||||
|
||||
} from '../../support/utils.js';
|
||||
|
||||
|
||||
|
||||
describe("projects", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("displays the projects page", () => {
|
||||
cy.get(".dashboard-title").should("contain", "Projects");
|
||||
});
|
||||
|
||||
it("can create a new project", () => {
|
||||
let projectName = "test project " + Date.now();
|
||||
cy.get(".project").then((projects) => {
|
||||
cy.getBySel("new-project-button").click();
|
||||
cy.get('.project').should('have.length', projects.length + 1);
|
||||
cy.get('.project').first().find(".edit-wrapper").type(projectName + "{enter}")
|
||||
cy.get('.project').first().find("h2").should("contain", projectName);
|
||||
|
||||
//cleanup: delete project
|
||||
deleteFirstProject();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
it("can rename a project", () => {
|
||||
let projectName = "test project " + Date.now();
|
||||
let projectName2 = "renamed project " + Date.now();
|
||||
|
||||
createProject(projectName);
|
||||
|
||||
cy.get('.project').first().find("h2").should("contain", projectName);
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.get('.project').first().find("[data-test=project-rename]").click();
|
||||
cy.get('.project').first().find(".edit-wrapper").type(projectName2 + "{enter}")
|
||||
cy.get('.project').first().find("h2").should("contain", projectName2)
|
||||
|
||||
//cleanup: delete project
|
||||
deleteFirstProject();
|
||||
});
|
||||
|
||||
it("can delete a project", () => {
|
||||
createProject();
|
||||
cy.get(".project").then((projects) => {
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.wait(500);
|
||||
cy.getBySel("project-delete").click();
|
||||
cy.wait(500);
|
||||
cy.get('.accept-button').click();
|
||||
cy.wait(500);
|
||||
|
||||
cy.get('.project').should('have.length', projects.length - 1);
|
||||
})
|
||||
});
|
||||
|
||||
it("can cancel the deletion of a project", () => {
|
||||
createProject();
|
||||
cy.get(".project").then((projects) => {
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.wait(500);
|
||||
cy.getBySel("project-delete").click();
|
||||
cy.wait(500);
|
||||
cy.get('.cancel-button').click();
|
||||
cy.wait(500);
|
||||
|
||||
cy.get('.project').should('have.length', projects.length);
|
||||
|
||||
|
||||
//cleanup: delete project
|
||||
deleteFirstProject();
|
||||
})
|
||||
});
|
||||
|
||||
it("can duplicate a project", () => {
|
||||
let projectName = "test project " + Date.now();
|
||||
createProject(projectName);
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.wait(500);
|
||||
cy.getBySel("project-duplicate").click();
|
||||
cy.getBySel("project-title").should("exist");
|
||||
cy.getBySel("project-title").should("contain", projectName+" (");
|
||||
|
||||
|
||||
//cleanup: delete project
|
||||
cy.get(".recent-projects").click();
|
||||
deleteFirstProject();
|
||||
deleteFirstProject();
|
||||
});
|
||||
|
||||
|
||||
it("can move a project to a team", () => {
|
||||
let projectName = "test project " + Date.now();
|
||||
createProject(projectName);
|
||||
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.get('.project').first().find("[data-test=project-move-to]").click();
|
||||
cy.get('a').contains(user.team).click();
|
||||
|
||||
cy.get(".current-team").should("contain", user.team);
|
||||
cy.get(".project").first().should("contain", projectName);
|
||||
|
||||
|
||||
//cleanup: delete project
|
||||
deleteFirstProject();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("pin and unpin project to sidebar", () => {
|
||||
let projectName = "test project " + Date.now();
|
||||
createProject(projectName);
|
||||
|
||||
cy.get(".project").first().find(".icon-pin-fill").should("exist");
|
||||
cy.getBySel("pinned-projects").should("contain", projectName);
|
||||
|
||||
//unpin
|
||||
cy.get(".project").first().find(".pin-icon").click();
|
||||
cy.get(".project").first().find(".icon-pin-fill").should("not.exist");
|
||||
cy.getBySel("pinned-projects").should("not.contain", projectName);
|
||||
|
||||
//pin
|
||||
cy.get(".project").first().find(".pin-icon").click();
|
||||
cy.get(".project").first().find(".icon-pin-fill").should("exist");
|
||||
cy.getBySel("pinned-projects").should("contain", projectName);
|
||||
|
||||
//cleanup: delete project
|
||||
deleteFirstProject();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
|
||||
createTeam,
|
||||
deleteCurrentTeam
|
||||
|
||||
} from '../../support/utils.js';
|
||||
|
||||
|
||||
describe("teams", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("can create a new team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
cy.get(".current-team").click();
|
||||
cy.getBySel("create-new-team").click();
|
||||
cy.get("#name").type(teamName);
|
||||
cy.get("input[type=submit]").click();
|
||||
|
||||
cy.get(".current-team").should("contain", teamName);
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
|
||||
})
|
||||
|
||||
it("can cancel create a new team", () => {
|
||||
cy.get(".current-team").click();
|
||||
cy.getBySel("create-new-team").click();
|
||||
cy.get(".modal-close-button").click();
|
||||
|
||||
cy.get(".current-team").should("contain", "Your Penpot");
|
||||
})
|
||||
|
||||
it("can delete a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("delete-team").click();
|
||||
cy.get(".accept-button").click();
|
||||
cy.get(".current-team").should("contain", "Your Penpot");
|
||||
})
|
||||
|
||||
it("can cancel the deletion of a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("delete-team").click();
|
||||
cy.get(".cancel-button").click();
|
||||
cy.get(".current-team").should("contain", teamName);
|
||||
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
it("can see the members page of a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("team-members").click();
|
||||
|
||||
cy.get(".dashboard-title").should("contain", "Members");
|
||||
cy.fixture('validuser.json').then((user) => {
|
||||
cy.get(".dashboard-table").should("contain", user.email);
|
||||
});
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
it("can invite someone to a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("team-members").click();
|
||||
|
||||
cy.getBySel("invite-member").click();
|
||||
cy.get("#email").type("mail@mail.com");
|
||||
cy.get(".custom-select select").select("admin");
|
||||
cy.get("input[type=submit]").click();
|
||||
|
||||
cy.get(".success").should("exist");
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
it("can see the settings page of a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("team-settings").click();
|
||||
|
||||
cy.get(".dashboard-title").should("contain", "Settings");
|
||||
|
||||
cy.get(".team-settings .name").should("contain", teamName);
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
it("can rename team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
const newTeamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("rename-team").click();
|
||||
cy.get("#name").type(newTeamName);
|
||||
cy.get("input[type=submit]").click();
|
||||
|
||||
cy.get(".current-team").should("contain", newTeamName);
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
it("can cancel the rename of a team", () => {
|
||||
const teamName = "test team " + Date.now();
|
||||
createTeam(teamName);
|
||||
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("rename-team").click();
|
||||
cy.get(".modal-close-button").click();
|
||||
|
||||
cy.get(".current-team").should("contain", teamName);
|
||||
|
||||
//cleanup
|
||||
deleteCurrentTeam();
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
|
@ -1,155 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
describe("profile", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
});
|
||||
});
|
||||
|
||||
it("open profile section", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").should("exist");
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("account-title").should("exist");
|
||||
});
|
||||
|
||||
it("change profile name", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.get("#fullname").should("exist");
|
||||
cy.get("#fullname").clear().type("New name").type("{enter}");
|
||||
cy.get(".banner.success").should("exist");
|
||||
});
|
||||
|
||||
it("change profile image with png", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("profile-image-input").should("exist");
|
||||
|
||||
cy.get(".profile img").then((oldImg) => {
|
||||
cy.getBySel("profile-image-input").attachFile("test-image-png.png");
|
||||
cy.get(".profile img")
|
||||
.invoke("attr", "src")
|
||||
.should("not.eq", oldImg[0].src);
|
||||
});
|
||||
});
|
||||
|
||||
it("change profile image with jpg", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("profile-image-input").should("exist");
|
||||
|
||||
cy.get(".profile img").then((oldImg) => {
|
||||
cy.getBySel("profile-image-input").attachFile("test-image-jpg.jpg");
|
||||
cy.get(".profile img")
|
||||
.invoke("attr", "src")
|
||||
.should("not.eq", oldImg[0].src);
|
||||
});
|
||||
});
|
||||
|
||||
it("change profile email", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.get(".change-email").should("exist");
|
||||
cy.get(".change-email").click();
|
||||
cy.getBySel("change-email-title").should("exist");
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.get("#email-1").type(user.email);
|
||||
cy.get("#email-2").type(user.email);
|
||||
});
|
||||
cy.getBySel("change-email-submit").click();
|
||||
cy.get(".banner.info").should("exist");
|
||||
});
|
||||
|
||||
it("type wrong email while trying to update should throw an error", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.get(".change-email").click();
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.get("#email-1").type(user.email);
|
||||
});
|
||||
cy.get("#email-2").type("bad@email.com");
|
||||
cy.getBySel("change-email-submit").click();
|
||||
cy.get(".error").should("exist");
|
||||
});
|
||||
|
||||
it("open password section", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("password-profile-opt").click();
|
||||
cy.get(".password-form").should("exist");
|
||||
});
|
||||
|
||||
it("type old password wrong should throw an error", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("password-profile-opt").click();
|
||||
cy.get("#password-old").type("badpassword");
|
||||
cy.get("#password-1").type("pretty-new-password");
|
||||
cy.get("#password-2").type("pretty-new-password");
|
||||
cy.getBySel("submit-password").click();
|
||||
cy.get(".error").should("exist");
|
||||
});
|
||||
|
||||
it("type same old password should work", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("password-profile-opt").click();
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.get("#password-old").type(user.password);
|
||||
cy.get("#password-1").type(user.password);
|
||||
cy.get("#password-2").type(user.password);
|
||||
});
|
||||
cy.getBySel("submit-password").click();
|
||||
cy.get(".banner.success").should("exist");
|
||||
});
|
||||
|
||||
it("open settings section", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("settings-profile").should("exist");
|
||||
});
|
||||
|
||||
it("set lang to Spanish and back to english", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("settings-profile").click();
|
||||
cy.getBySel("setting-lang").should("exist");
|
||||
cy.getBySel("setting-lang").select("es");
|
||||
cy.getBySel("submit-lang-change").should("exist");
|
||||
cy.getBySel("submit-lang-change").click();
|
||||
cy.contains("Tu cuenta").should("exist");
|
||||
cy.getBySel("setting-lang").select("en");
|
||||
cy.getBySel("submit-lang-change").click();
|
||||
cy.contains("Your account").should("exist");
|
||||
});
|
||||
|
||||
it("log out from app", () => {
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("logout-profile-opt").should("exist");
|
||||
cy.getBySel("logout-profile-opt").click();
|
||||
cy.getBySel("login-title").should("exist");
|
||||
});
|
||||
});
|
||||
|
||||
describe("remove account", () => {
|
||||
it("create demo account and delete it", () => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
cy.getBySel("demo-account-link").click();
|
||||
cy.getBySel("onboarding-next-btn").click();
|
||||
cy.getBySel("opsource-next-btn").click();
|
||||
cy.getBySel("skip-btn").click();
|
||||
cy.getBySel("fly-solo-op").click();
|
||||
cy.getBySel("close-templates-btn").click();
|
||||
cy.get(".profile").click();
|
||||
cy.getBySel("profile-profile-opt").click();
|
||||
cy.getBySel("remove-acount-btn").click();
|
||||
cy.getBySel("delete-account-btn").click();
|
||||
cy.getBySel("login-title").should("exist");
|
||||
});
|
||||
});
|
|
@ -1,93 +0,0 @@
|
|||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright (c) KALEIDOS INC
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
describe("draw shapes", () => {
|
||||
beforeEach(() => {
|
||||
cy.fixture("validuser.json").then((user) => {
|
||||
cy.login(user.email, user.password);
|
||||
cy.get(".project-th").first().dblclick();
|
||||
cy.clearViewport();
|
||||
});
|
||||
});
|
||||
|
||||
it("draw an artboard", () => {
|
||||
cy.get(".render-shapes rect").should("not.exist");
|
||||
cy.getBySel("artboard-btn").click();
|
||||
cy.drawInViewport(300, 300, 400, 450);
|
||||
cy.get(".render-shapes rect").first().as("artboard");
|
||||
cy.get("@artboard").should("exist");
|
||||
cy.get("@artboard").invoke("attr", "width").should("eq", "100");
|
||||
cy.get("@artboard").invoke("attr", "height").should("eq", "150");
|
||||
});
|
||||
|
||||
it("draw a square", () => {
|
||||
cy.get(".render-shapes rect").should("not.exist");
|
||||
cy.getBySel("rect-btn").click();
|
||||
cy.drawInViewport(300, 300, 400, 450);
|
||||
cy.get(".render-shapes rect").should("exist");
|
||||
cy.get(".render-shapes rect")
|
||||
.invoke("attr", "width")
|
||||
.should("eq", "100");
|
||||
cy.get(".render-shapes rect")
|
||||
.invoke("attr", "height")
|
||||
.should("eq", "150");
|
||||
});
|
||||
|
||||
it("draw an ellipse", () => {
|
||||
cy.get(".render-shapes ellipse").should("not.exist");
|
||||
cy.getBySel("ellipse-btn").click();
|
||||
cy.drawInViewport(300, 300, 400, 450);
|
||||
cy.get(".render-shapes ellipse").as("ellipse");
|
||||
cy.get("@ellipse").should("exist");
|
||||
cy.get("@ellipse").invoke("attr", "rx").should("eq", "50");
|
||||
cy.get("@ellipse").invoke("attr", "ry").should("eq", "75");
|
||||
});
|
||||
|
||||
it("draw a curve", () => {
|
||||
cy.get(".render-shapes path").should("not.exist");
|
||||
cy.getBySel("curve-btn").click();
|
||||
cy.drawMultiInViewport([
|
||||
{ x: 300, y: 300 },
|
||||
{ x: 350, y: 300 },
|
||||
{ x: 300, y: 350 },
|
||||
{ x: 400, y: 450 },
|
||||
]);
|
||||
cy.get(".render-shapes path").as("curve");
|
||||
cy.get("@curve").should("exist");
|
||||
cy.get("@curve")
|
||||
.invoke("attr", "d")
|
||||
.should("eq", "M300,300L350,300L300,350L400,450");
|
||||
});
|
||||
|
||||
it("draw a path", () => {
|
||||
cy.get(".render-shapes path").should("not.exist");
|
||||
cy.getBySel("path-btn").click();
|
||||
cy.clickMultiInViewport([
|
||||
{ x: 300, y: 300 },
|
||||
{ x: 350, y: 300 },
|
||||
]);
|
||||
cy.drawMultiInViewport(
|
||||
[
|
||||
{ x: 400, y: 450 },
|
||||
{ x: 450, y: 450 },
|
||||
],
|
||||
true
|
||||
);
|
||||
cy.clickMultiInViewport([{ x: 300, y: 300 }]);
|
||||
cy.get(".render-shapes path").as("curve");
|
||||
cy.get("@curve").should("exist");
|
||||
cy.get("@curve")
|
||||
.invoke("attr", "d")
|
||||
.should(
|
||||
"eq",
|
||||
"M300,300L350,300C350,300,350,450,400,450C450,450,300,300,300,300Z"
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,22 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
import 'cypress-file-upload';
|
||||
|
||||
Cypress.Commands.add('login', (email, password) => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
cy.get("#email").type(email);
|
||||
cy.get("#password").type(password);
|
||||
cy.getBySel("login-submit").click();
|
||||
})
|
||||
|
||||
Cypress.Commands.add('demoLogin', () => {
|
||||
cy.visit("http://localhost:3449/#/auth/login");
|
||||
cy.getBySel("demo-account-link").click()
|
||||
})
|
||||
|
||||
Cypress.Commands.add('drawInViewport', (x1, y1, x2, y2) => {
|
||||
cy.get(".viewport-controls")
|
||||
.trigger('mousemove', { x: x1, y: y1 })
|
||||
.trigger('mousedown', {
|
||||
x: x1,
|
||||
y: y1,
|
||||
which: 1
|
||||
})
|
||||
.trigger('mousemove', { x: x2, y: y2 })
|
||||
.trigger('mouseup', { x: x2, y: y2, which: 1 });
|
||||
})
|
||||
|
||||
Cypress.Commands.add('drawMultiInViewport', (coords, force=false) => {
|
||||
cy.get(".viewport-controls")
|
||||
.trigger('mousemove', { x: coords[0].x, y: coords[0].y, force: force})
|
||||
.trigger('mousedown', {
|
||||
x: coords[0].x,
|
||||
y: coords[0].y,
|
||||
which: 1,
|
||||
force: force
|
||||
});
|
||||
|
||||
for (var i=1; i<coords.length; i++){
|
||||
cy.get(".viewport-controls").trigger('mousemove', { x: coords[i].x, y: coords[i].y, force: force })
|
||||
}
|
||||
|
||||
cy.get(".viewport-controls").trigger('mouseup', {
|
||||
x: coords[coords.length-1].x,
|
||||
y: coords[coords.length-1].y,
|
||||
which: 1,
|
||||
force: force });
|
||||
})
|
||||
|
||||
|
||||
function click(x, y) {
|
||||
cy.get(".viewport-controls")
|
||||
.trigger('mousemove', { x: x, y: y })
|
||||
.trigger('mousedown', {x: x, y: y, which: 1})
|
||||
.trigger('mouseup', {x: x, y: y, which: 1});
|
||||
|
||||
}
|
||||
|
||||
Cypress.Commands.add('clickMultiInViewport', (coords) => {
|
||||
for (var i=0; i<coords.length; i++){
|
||||
click(coords[i].x, coords[i].y);
|
||||
}
|
||||
})
|
||||
|
||||
Cypress.Commands.add('clearViewport', () => {
|
||||
cy.get(".viewport-controls").type('{ctrl}a');
|
||||
cy.get(".viewport-controls").type('{del}');
|
||||
cy.window().its("debug").invoke('reset_viewport');
|
||||
})
|
||||
|
||||
Cypress.Commands.add('getBySel', (selector, ...args) => {
|
||||
return cy.get(`[data-test=${selector}]`, ...args)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('getBySelLike', (selector, ...args) => {
|
||||
return cy.get(`[data-test*=${selector}]`, ...args)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('uploadBinaryFile', (fileInputSelector, fileName) => {
|
||||
cy.fixture(fileName, "binary")
|
||||
.then(Cypress.Blob.binaryStringToBlob)
|
||||
.then(fileContent => {
|
||||
cy.get(fileInputSelector).attachFile({
|
||||
fileContent,
|
||||
filePath: fileName,
|
||||
encoding: 'utf-8',
|
||||
lastModified: new Date().getTime()
|
||||
});
|
||||
});
|
||||
})
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
|
@ -1,75 +0,0 @@
|
|||
export const checkOnboardingSlide = (number, checkSkip) => {
|
||||
cy.getBySel(`slide-${number}-title`).should("exist");
|
||||
if(checkSkip){cy.getBySel("skip-btn").should("exist");}
|
||||
cy.get(".onboarding .step-dots").should("exist");
|
||||
cy.getBySel(`slide-${number}-btn`).should("exist");
|
||||
cy.getBySel(`slide-${number}-btn`).click();
|
||||
};
|
||||
export const deleteFirstProject = () => {
|
||||
cy.get('.project').first().find("[data-test=project-options]").click();
|
||||
cy.wait(500);
|
||||
cy.get('.project').first().find("[data-test=project-delete]").click();
|
||||
cy.wait(500);
|
||||
cy.get('.accept-button').click();
|
||||
}
|
||||
|
||||
export const createProject = (projectName="") => {
|
||||
cy.getBySel("new-project-button").click();
|
||||
cy.wait(500);
|
||||
cy.get('.project').first().find(".edit-wrapper").type(projectName + "{enter}");
|
||||
cy.wait(500);
|
||||
}
|
||||
|
||||
|
||||
export const deleteFirstFile = () => {
|
||||
cy.get('.menu')
|
||||
.first()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-delete").click();
|
||||
cy.get('.accept-button').click();
|
||||
}
|
||||
|
||||
|
||||
export const createFile = (fileName="", projectNum=0) => {
|
||||
cy.getBySel("new-file").click();
|
||||
cy.wait(500);
|
||||
if (fileName !=""){
|
||||
cy.get('.menu')
|
||||
.first()
|
||||
.trigger('mouseover')
|
||||
.click();
|
||||
cy.getBySel("file-rename").click();
|
||||
cy.get(".edit-wrapper").type(fileName + "{enter}");
|
||||
//TODO: Bug workaround. When a file is selected, it doesn't open context menu
|
||||
cy.get(".dashboard-grid").click();
|
||||
}
|
||||
}
|
||||
|
||||
export const createTeam = (teamName) => {
|
||||
cy.get(".current-team").click();
|
||||
cy.getBySel("create-new-team").click();
|
||||
cy.get("#name").type(teamName);
|
||||
cy.get("input[type=submit]").click();
|
||||
cy.wait(500);
|
||||
}
|
||||
|
||||
export const deleteCurrentTeam = () => {
|
||||
cy.get(".icon-actions").first().click();
|
||||
cy.getBySel("delete-team").click();
|
||||
cy.get(".accept-button").click();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const goToSlideByNumber = (number) => {
|
||||
cy.get(`.step-dots li:nth-child(${number})`).click();
|
||||
cy.getBySel(`slide-${number -1}-btn`).should("exist");
|
||||
};
|
||||
|
||||
export const deleteFirstFont = () => {
|
||||
cy.get(".font-item .options").first().click();
|
||||
cy.getBySel("font-delete").click();
|
||||
cy.get(".accept-button").click();
|
||||
};
|
Loading…
Add table
Reference in a new issue