diff --git a/cypress.config.example.js b/cypress.config.example.js new file mode 100644 index 00000000..e1eb8cfa --- /dev/null +++ b/cypress.config.example.js @@ -0,0 +1,5 @@ +module.exports = { + e2e: { + baseUrl: 'https://spokeandchain.nitro/', + }, +}; diff --git a/cypress.example.json b/cypress.example.json deleted file mode 100644 index 5955303d..00000000 --- a/cypress.example.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "env": { - "SITE_URL": "http://spokeandchain.nitro/", - "CP_TRIGGER": "admin", - "CP_LOGIN": "support@craftcms.com", - "CP_PASSWORD": "NewPassword", - "ENABLE_LIGHTHOUSE": true, - "LIGHTHOUSE_OPTIONS": { - "performance": 0, - "accessibility": 90, - "best-practices": 0, - "seo": 0, - "pwa": 0 - }, - "ENABLE_PA11Y": false, - "PA11Y_OPTIONS": { - "runners": ["htmlcs"], - "standard": "WCAG2AA" - } - } -} diff --git a/cypress/e2e/front/a11y/articles.spec.js b/cypress/e2e/front/a11y/articles.spec.js new file mode 100644 index 00000000..4e05b07b --- /dev/null +++ b/cypress/e2e/front/a11y/articles.spec.js @@ -0,0 +1,18 @@ +describe('Articles', () => { + it("should pass the audits", function () { + cy.visit('/articles') + cy.runAudit() + }) +}) + +describe('Articles → Article', () => { + it("should pass the audits", function () { + cy.visit('/articles') + + // Click the first article + cy.get('a.article-card').first() + .click() + + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/a11y/bikes.spec.js b/cypress/e2e/front/a11y/bikes.spec.js new file mode 100644 index 00000000..39d6d31f --- /dev/null +++ b/cypress/e2e/front/a11y/bikes.spec.js @@ -0,0 +1,6 @@ +describe('Bikes', () => { + it("should pass the audits", function () { + cy.visit('/bikes') + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/a11y/cart.spec.js b/cypress/e2e/front/a11y/cart.spec.js new file mode 100644 index 00000000..5ce8b1c8 --- /dev/null +++ b/cypress/e2e/front/a11y/cart.spec.js @@ -0,0 +1,6 @@ +describe('Cart', () => { + it("should pass the audits", function () { + cy.visit('/cart') + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/a11y/contact.spec.js b/cypress/e2e/front/a11y/contact.spec.js new file mode 100644 index 00000000..4309b03e --- /dev/null +++ b/cypress/e2e/front/a11y/contact.spec.js @@ -0,0 +1,6 @@ +describe('Contact', () => { + it("should pass the audits", function () { + cy.visit('/contact') + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/a11y/homepage.spec.js b/cypress/e2e/front/a11y/homepage.spec.js new file mode 100644 index 00000000..f836c1e3 --- /dev/null +++ b/cypress/e2e/front/a11y/homepage.spec.js @@ -0,0 +1,6 @@ +describe('Homepage', () => { + it("should pass the audits", function () { + cy.visit('/') + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/a11y/services.spec.js b/cypress/e2e/front/a11y/services.spec.js new file mode 100644 index 00000000..6f364c9b --- /dev/null +++ b/cypress/e2e/front/a11y/services.spec.js @@ -0,0 +1,6 @@ +describe('Services', () => { + it("should pass the audits", function () { + cy.visit('/services') + cy.runAudit() + }) +}) diff --git a/cypress/e2e/front/account.cy.js b/cypress/e2e/front/account.cy.js new file mode 100644 index 00000000..becf4b32 --- /dev/null +++ b/cypress/e2e/front/account.cy.js @@ -0,0 +1,52 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Account on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + cy.login() + }) + + it(`should contain an Orders section`, function() { + cy.visit('/') + + cy.get('#header .cart-toggle') + .click() + + cy.get('#header .cart-menu a') + .contains('Orders') + .click() + + cy.get('h1') + .contains('Orders') + }) + + it(`should contain an Membership section`, function() { + cy.visit('/') + + cy.get('#header .cart-toggle') + .click() + + cy.get('#header .cart-menu a') + .contains('Membership') + .click() + + cy.get('h1') + .contains('Membership') + }) + + it(`should contain an Settings section`, function() { + cy.visit('/') + + cy.get('#header .cart-toggle') + .click() + + cy.get('#header .cart-menu a') + .contains('Account') + .click() + + cy.get('h1') + .contains('Account') + }) + }) +}) diff --git a/cypress/e2e/front/articles.cy.js b/cypress/e2e/front/articles.cy.js new file mode 100644 index 00000000..f14bda2a --- /dev/null +++ b/cypress/e2e/front/articles.cy.js @@ -0,0 +1,17 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Services on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + }) + + it(`should show two plans`, function () { + cy.visit('/articles') + + cy.get('a.article-card') + .its('length') + .should('be.gt', 0) + }) + }) +}) diff --git a/cypress/e2e/front/cart.cy.js b/cypress/e2e/front/cart.cy.js new file mode 100644 index 00000000..2260dd93 --- /dev/null +++ b/cypress/e2e/front/cart.cy.js @@ -0,0 +1,61 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Cart on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + }) + + it(`should be able to add a product to the cart`, function () { + cy.addProductToCart() + cy.navigateToCart() + + // Make sure that the cart contains at least one item + cy.get('div.line-item') + .its('length') + .should('be.gt', 0) + }) + + it(`should be able to remove a product from the cart`, function () { + cy.addProductToCart() + cy.navigateToCart() + + cy.get('div.line-item').then(($el) => { + // Retrieve line item ID + const lineItemId = $el.attr('id').substr(10) + + // Make sure the the line item exists + cy.get('#line-item-' + lineItemId).should('exist') + + // Remove the line item + cy.get('#remove-trigger-' + lineItemId) + .click({scrollBehavior: 'center'}) + + // Check that the line item has properly been removed + cy.get('#line-item-' + lineItemId).should('not.exist') + }) + }) + + it(`should be able to apply a discount code`, function () { + cy.addProductToCart() + cy.navigateToCart() + + // Click link to enter a coupon + cy.get('form#cart a.coupon-trigger') + .click({scrollBehavior: 'center'}) + + // Use the `15OFF` coupon code + cy.get('form#cart input[name=couponCode]') + .type('15OFF') + + // Apply the coupon + cy.get('form#cart button[type=submit].coupon-apply') + .click({scrollBehavior: 'center'}) + + // Check that the cart contains a discount row + cy.get('form#cart div.discount-row') + .its('length') + .should('be.gt', 0) + }) + }) +}) diff --git a/cypress/e2e/front/checkout.cy.js b/cypress/e2e/front/checkout.cy.js new file mode 100644 index 00000000..d51264b8 --- /dev/null +++ b/cypress/e2e/front/checkout.cy.js @@ -0,0 +1,80 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Checkout on ${size} screen`, () => { + beforeEach(() => { + cy.setViewportSize(size) + + // Define the user fixture + cy.fixture('user').as('user') + }) + + it(`should add a product to the cart and checkout as guest`, function () { + // Add a product to the cart + cy.visit('/product/san-quentin-24') + + cy.get('#buy button[type=submit]') + .click({scrollBehavior: 'center'}); + + // Navigate to the cart + cy.get('button.cart-toggle') + .click(); + + cy.get('div.cart-menu a.button.submit') + .contains('Check Out') + .click(); + + // Checkout as guest + cy.get('#guest-checkout button[type=submit]') + .contains('Continue as Guest'); + + cy.get('#guest-checkout input[type=text]') + .type(this.user.email, {scrollBehavior: 'center'}); + + cy.get('#guest-checkout button[type=submit]') + .click({scrollBehavior: 'center'}); + + // Shipping address + cy.get('form#checkout-address input[name="shippingAddress[firstName]"]') + .type(this.user.address.firstName, {scrollBehavior: 'center'}); + cy.get('form#checkout-address input[name="shippingAddress[lastName]"]') + .type(this.user.address.lastName, {scrollBehavior: 'center'}); + cy.get('form#checkout-address input[name="shippingAddress[addressLine1]"]') + .type(this.user.address.addressLine1, {scrollBehavior: 'center'}); + cy.get('form#checkout-address input[name="shippingAddress[locality]"]') + .type(this.user.address.locality, {scrollBehavior: 'center'}); + cy.get('form#checkout-address input[name="shippingAddress[postalCode]"]') + .type(this.user.address.postalCode, {scrollBehavior: 'center'}); + cy.get('form#checkout-address select[name="shippingAddress[countryCode]"]') + .scrollIntoView({offset: {top: 600, left: 0}}) + .select(this.user.address.countryCode); + cy.get('form#checkout-address button[type=submit]') + .click({scrollBehavior: 'center'}); + + // Use the default shipping method + cy.get('form#checkout-shipping-method input[type=radio][value="freeShipping"]') + .click({scrollBehavior: 'center'}); + + cy.get('form#checkout-shipping-method button[type=submit]') + .click({scrollBehavior: 'center'}); + + // Fill credit card details and pay + cy.get('form#checkout-payment input[name="paymentForm[dummy][firstName]"]') + .type(this.user.card.firstName, {scrollBehavior: 'center'}); + cy.get('form#checkout-payment input[name="paymentForm[dummy][lastName]"]') + .type(this.user.card.lastName, {scrollBehavior: 'center'}); + cy.get('form#checkout-payment input[name="paymentForm[dummy][number]"]') + .type(this.user.card.number, {scrollBehavior: 'center'}); + cy.get('form#checkout-payment input[name="paymentForm[dummy][expiry]"]') + .type(this.user.card.expiry, {scrollBehavior: 'center'}); + cy.get('form#checkout-payment input[name="paymentForm[dummy][cvv]"]') + .type(this.user.card.cvv, {scrollBehavior: 'center'}); + cy.get('form#checkout-payment button[type=submit]') + .click({scrollBehavior: 'center'}); + + // Success + cy.get('h1') + .contains('Success') + }) + }) +}) diff --git a/cypress/e2e/front/homepage.cy.js b/cypress/e2e/front/homepage.cy.js new file mode 100644 index 00000000..e0f698b5 --- /dev/null +++ b/cypress/e2e/front/homepage.cy.js @@ -0,0 +1,24 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Homepage on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + }) + + it(`should show an “All bikes” button`, function () { + cy.visit('/') + + cy.get('.aspect-ratio-hero-home a.button') + .contains("Let's Ride!") + }) + + it(`should show bike categories`, function () { + cy.visit('/') + + cy.get('a.category-card') + .its('length') + .should('be.gt', 0) + }) + }) +}) diff --git a/cypress/e2e/front/nav.cy.js b/cypress/e2e/front/nav.cy.js new file mode 100644 index 00000000..e6f21d02 --- /dev/null +++ b/cypress/e2e/front/nav.cy.js @@ -0,0 +1,37 @@ +const smallScreenSizes = ['iphone-6', [640, 480], [768, 576]]; +const bigScreenSizes = [[1024, 768], [1280, 1024], [1536, 1228]]; + +describe('Navigation', () => { + beforeEach(() => { + cy.visit('/') + }) + + smallScreenSizes.forEach((size) => { + it(`should not be visible on ${size} screen`, function () { + cy.setViewportSize(size) + + cy.get('nav.main').should('not.be.visible') + }) + it(`should show open toggle and hide close toggle when nav is closed on ${size} screen`, function () { + cy.setViewportSize(size) + + cy.get('.toggle-nav .toggle-open').should('be.visible') + cy.get('.toggle-nav .toggle-close').should('not.be.visible') + }) + it(`should hide open toggle and show close toggle when nav is open on ${size} screen`, function () { + cy.setViewportSize(size) + + cy.get('.toggle-nav').click() + + cy.get('.toggle-open').should('not.be.visible') + cy.get('.toggle-close').should('be.visible') + }) + }) + bigScreenSizes.forEach((size) => { + it(`should be visible on ${size} screen`, function () { + cy.setViewportSize(size) + + cy.get('nav.main').should('be.visible') + }) + }) +}) diff --git a/cypress/e2e/front/search.cy.js b/cypress/e2e/front/search.cy.js new file mode 100644 index 00000000..efba9806 --- /dev/null +++ b/cypress/e2e/front/search.cy.js @@ -0,0 +1,38 @@ +const sizes = require('../../viewport-sizes') + +const searchQuery = 'rift zone' + +sizes.forEach((size) => { + describe(`Search on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + }) + + it(`should show search results`, function() { + cy.visit('/') + + let $input, $form + + if (size === 'iphone-6' || (Array.isArray(size) && size[0] < 1024)) { + cy.get('#header button.toggle-nav') + .click() + $input = cy.get('.search-form input#search-input') + $form = cy.get('form.search-form') + } else { + cy.get('#header button.search-toggle') + .click() + $input = cy.get('#search-form input#search-input') + $form = cy.get('form#search-form'); + } + + $input.type(searchQuery) + $form.submit() + + cy.get('h1').contains(`Search results for “${searchQuery}”`) + + cy.get('a.product-card') + .its('length') + .should('be.gt', 0) + }) + }) +}) diff --git a/cypress/e2e/front/services.cy.js b/cypress/e2e/front/services.cy.js new file mode 100644 index 00000000..45f30e11 --- /dev/null +++ b/cypress/e2e/front/services.cy.js @@ -0,0 +1,17 @@ +const sizes = require('../../viewport-sizes') + +sizes.forEach((size) => { + describe(`Services on ${size} screen`, () => { + beforeEach(function() { + cy.setViewportSize(size) + }) + + it(`should show two plans`, function () { + cy.visit('/services') + + cy.get('div.services-plan') + .its('length') + .should('be.eq', 2) + }) + }) +}) diff --git a/cypress/e2e/index.js b/cypress/e2e/index.js new file mode 100644 index 00000000..eafc3d44 --- /dev/null +++ b/cypress/e2e/index.js @@ -0,0 +1,5 @@ +import './commands' +Cypress.on('uncaught:exception', (err, runnable) => { + // returning false here prevents Cypress from failing the test + return false +}) \ No newline at end of file diff --git a/cypress/e2e/new/checkPages.cy.js b/cypress/e2e/new/checkPages.cy.js new file mode 100644 index 00000000..338f578e --- /dev/null +++ b/cypress/e2e/new/checkPages.cy.js @@ -0,0 +1,7 @@ +const urls = ['/', '/bikes', '/services', '/articles', '/contact'] + +urls.forEach((url) => { + it(`should render correctly`, function () { + cy.visit(url) + }) +}) \ No newline at end of file diff --git a/cypress/e2e/new/searchForm.cy.js b/cypress/e2e/new/searchForm.cy.js new file mode 100644 index 00000000..6f60a714 --- /dev/null +++ b/cypress/e2e/new/searchForm.cy.js @@ -0,0 +1,7 @@ +it(`search form should work correctly`, function () { + cy.visit('/search-test') + cy.get('#searchText').type('Welcome') + cy.get('#submit').click() + cy.get('.result-link').contains('Welcome Courtney Duncan') + cy.get('.result-link').contains('Adventure Journal on the Pine Mountain 2').should('not.exist') +}) \ No newline at end of file