Skip to content
This repository has been archived by the owner on Feb 5, 2022. It is now read-only.

Commit

Permalink
Merge pull request #371 from openforge/develop
Browse files Browse the repository at this point in the history
push develop to qa
  • Loading branch information
daftclaud authored Sep 3, 2019
2 parents b0cecdd + 12c6f31 commit 9ce088d
Show file tree
Hide file tree
Showing 207 changed files with 12,622 additions and 4,262 deletions.
542 changes: 542 additions & 0 deletions .firebase/hosting.d3d3.cache

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ Thumbs.db
UserInterfaceState.xcuserstate
.env
linters/sass-lint.html
src/pages/app-blog-post/prerender-blog-data.ts
src/butter-api/butter-api-key.js
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ https://developers.google.com/speed/webp/docs/precompiled
brew install webp
```

#### Make Sure .webp Images are available by running the following commands:
#### Make Sure .webp Images are available by running the following commands inside the root folder:
```
for file in src/assets/*.jpg; do cwebp -q 75 "$file" -o "${file%.jpg}.webp"; done
```
Expand All @@ -54,6 +54,28 @@ for file in src/assets/*.png; do cwebp -q 75 "$file" -o "${file%.png}.webp"; don
for file in src/assets/*.jpeg; do cwebp -q 75 "$file" -o "${file%.jpeg}.webp"; done
```

### Blog Setup
By default, the public version of this project does not contain an API key for the [ButterCMS](https://buttercms.com/) blog content management system. You will need to add your own ButterCMS API key in order to make this project work.

The necessary file for inserting the ButterCMS API key will be auto-generated by running
```
node scripts/get-butter.js
```

After that, use your text editor and open the file:
```
src/butter-api/butter-api-key.ts
```

and enter your Butter API key between the single quotes '':
```
export const BUTTER_API_KEY = '';
```
to
```
export const BUTTER_API_KEY = 'your API token goes here';
```

### Running This Application
```
npm run dev
Expand Down Expand Up @@ -116,12 +138,27 @@ For every commit, it will ensure files are linted and that the code is formatted

If a developer went through providing all the information during a `npm run cz` only to find that there were issues with their commit. They may fix them and instruct commitizen to try the commit again with `npm run cz -- --retry`

## Blog Integration

## Deployment
This project uses [ButterCMS](https://buttercms.com/) as a headless content management system. When a user accesses the deployed site, the blog data will be loaded from the ButterCMS API via AJAX. However, the blog data is also utilized in prerendering the site, to improve SEO. Before any build (dev, prod, prerender), the get-butter.js script is run to retrieve the blog data and stored in pages/blog-post/prerender-blog-data.ts. This file is git-ignored so that the repo is not cluttered with blog content.

The project also utilizes webhooks from [ButterCMS](https://buttercms.com/docs/api/?javascript#webhooks) and [Travis](https://docs.travis-ci.com/user/triggering-builds) to keep the prerendered blog content up to date. Whenever a new blog post is published, Butter's webook invokes the cloud function rebuildMaster, which relays the information to the Travis API, which in turn will trigger a rebuild and redeploy of the master branch. Butter's webhooks are managed in the ButterCMS portal.


The branches develop, qa, staging, and master are all set up for continuous integration and deployment with Travis CI and Firebase. To deploy, create a PR for the appropriate branch, or commit and push directly (avoid this if possible).

If manual deployment is needed, use the following. Only do this on the develop branch, follow the PR request flow for all other branches.

### Featured Post

The featured post is managed in the ButterCMS portal. To make a post featured, it must be given a tag of 'featured'. The actual featured post will be the most recently published post with the featured tag. Currently, this post will also appear in the regular list of posts.


## Deployment
```
npm run prepublish
```
Note that this will synchronously retrieve the blog post data from Butter CMS before building, so that it can be included in the prerender.

_Note: You may have to install firebase-tools via ```npm install -g firebase-tools``` and then authenticate via command line on your local machine to firebase_

Expand Down
36 changes: 36 additions & 0 deletions cypress/integration/app-about.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
describe('About page', function() {
var env = 'http://localhost:3333'
beforeEach(() => {
cy.visit(env + '/about')
})
})

// Moving this here for now -- from the old home page, but some of this will be relevant here

// describe('Perspectives Section', function () {
// it('Should scroll to the perspectives section', function() {
// cy.get('#perspectives').scrollIntoView()
// })
// })
// describe('About Section - App-Members Component', function() {
// it('Should be able to click links within app-members', function() {
// cy.get('#about').scrollIntoView()

// cy.get('#about > div > app-members > div > div').as('members')
// .its('length').should('be.gt', 13)

// cy.get('@members').contains('Software Engineer')
// cy.get('@members').contains('Designer')
// cy.get('@members').contains('Front End')

// cy.get('@members').find('div:nth-child(1)').find('div.col.text-center').within(function() {
// cy.get('a').should('have.attr', 'href')
// cy.get('a').should('have.attr', 'title')
// cy.get('a').should('have.attr', 'style')

// cy.get('a').eq(0).should('have.attr', 'href', 'mailto:jedi@openforge.io').click()
// cy.get('a').eq(1).should('have.attr', 'href', 'https://twitter.com/jedihacks').click()
// cy.get('a').eq(2).should('have.attr', 'href', 'https://github.com/jedihacks').click()
// })
// })
// })
225 changes: 176 additions & 49 deletions cypress/integration/app-contact.spec.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,212 @@
describe('Contact Page', function () {
var env = 'http://localhost:3333';
beforeEach(() => {
cy.visit('localhost:3333/contact')
cy.visit(env + '/contact')
cy.get('button[type=submit]').as('submitBtn')
})

describe('Header', function() {
it('Header should display with appropriate text content within it', function() {
const h2Content = 'Let\'s Work Together'
const pContent = 'Request'
describe('Nav Bar Navigation (Desktop)', function () {
// TODO -> Test suite for the blog link in nav bar.
it('Home on nav bar should redirect to home page', function () {
cy.get('.navbar').contains('Home').click()
cy.url().should('include', '/')
})
describe('Services', function () {
beforeEach(() => {
// Gets Services text
cy.get('.container > #navbarSupportedContent').contains('Services');
// Clicks services dropdown arrow
cy.get('.container > #navbarSupportedContent > .navbar-nav > .nav-item > #navbarDropdown').click();
})
it('Services should drop down to display Development and navigate to developer page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(1) > .nav-link').contains('Development').click()
cy.url().should('include', '/app-developer')
})
it('Services should drop down to display Design and navigate to design page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(2) > .nav-link').contains('Design').click();
cy.url().should('include', '/app-designer');
})
it('Services should drop down to display Consulting and navigate to consulting page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(3) > .nav-link').contains('Consulting').click()
cy.url().should('include', '/startup-consulting')
});
});

cy.get('header')
.should('exist')
.and('be.visible')
cy.get('.hero')
.contains(h2Content)
.and('be.visible')
cy.get('.hero')
.contains(pContent)
.and('be.visible')
describe('About', function () {
it('About should drop down to display Meet the team and navigate to about page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Meet the team').click()
cy.url().should('include', '/about')
cy.contains('We Are Passionate About Technology and Design')
})
it('About should drop down to display Juntoscope Case Study and navigate to juntoscope page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Juntoscope Case Study').click()
cy.url().should('include', '/juntoscope')
cy.contains('Case Study')
})
it('About should drop down to display Toolbox and navigate to Toolbox page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Toolbox').click()
cy.url().should('include', '/toolbox')
cy.contains('Here are some of the tools we use')
})
it('About should drop down to display PWA White Paper and navigate to PWA White Paper page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('PWA White Paper').click()
cy.url().should('include', '/resources/pwa-white-paper')
cy.contains('What is a PWA and is it right for you?')
})
});
})

describe('Nav Bar Navigation (Mobile)', function () {
beforeEach(() => {
cy.viewport(960, 600) // Sets view to large to enable nav menu
cy.get('.navbar-toggler').click() // expands nav menu before each test
})
it('Nav menu should collapse', function () {
cy.wait(2000)
cy.get('.navbar-toggler').click()
})
it('Home on nav Bar should redirect to home page', function () {
cy.get('.navbar').contains('Home').click()
cy.url().should('include', '/')
})

describe('Services', function () {
beforeEach(() => {
cy.get('.container > #navbarSupportedContent').contains('Services');
cy.get('.container > #navbarSupportedContent > .navbar-nav > .nav-item > #navbarDropdown').click();
})
it('Services should drop down to display Development and navigate to developer page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(1) > .nav-link').contains('Development').click()
cy.url().should('include', '/app-developer')
})
it('Services should drop down to display Design and navigate to design page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(2) > .nav-link').contains('Design').click()
cy.url().should('include', '/app-designer')
})
it('Services should drop down to display Consulting and navigate to consulting page', function () {
cy.get('.navbar-nav > .nav-item:nth-child(2) > .dropdown-menu > .hydrated:nth-child(3) > .nav-link').contains('Consulting').click();
cy.url().should('include', '/startup-consulting');
})
});

describe('About', function () {
it('About should drop down to display Meet the team and navigate to about page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Meet the team').click()
cy.url().should('include', '/about')
cy.contains('We Are Passionate About Technology and Design')
})
it('About should drop down to display Juntoscope Case Study and navigate to juntoscope page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Juntoscope Case Study').click()
cy.url().should('include', '/juntoscope')
cy.contains('Case Study')
})
it('About should drop down to display Toolbox and navigate to Toolbox page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('Toolbox').click()
cy.url().should('include', '/toolbox')
cy.contains('Here are some of the tools we use')
})
it('About should drop down to display PWA White Paper and navigate to PWA White Paper page', function () {
cy.get('.navbar').contains('About').click()
cy.get('.navbar').contains('PWA White Paper').click()
cy.url().should('include', '/resources/pwa-white-paper')
cy.contains('What is a PWA and is it right for you?')
})
});
});

describe('Header', function () {
it('Header should display with appropriate text content within it', function () {
const h2Content = 'Let\'s Work Together'
const pContent = 'Request Free Quote'

cy.get('header').should('exist').and('be.visible')
cy.get('.hero').contains(h2Content).and('be.visible')
cy.get('.hero').contains(pContent).and('be.visible')
})

it('Should contain a Request Now button that scrolls to the form on click', function() {
it('Should contain a Request Now button that scrolls to the form on click', function () {
cy.get('header')
.find('.btn')
.should('exist')
.and('be.visible')
.and('contain', 'Request Now')
.and('contain', 'Request Free Quote')
.click()
cy.get('#second-content').click()
})
})

describe('Contact Form', function() {
describe('Contact Form', function () {
let nameField;
let emailField;
let companyField;
let phoneField;
let messageField;
let radioField1;
let radioField2;

describe('Successful form submission', function () {
beforeEach(() => {
nameField = cy.get('input[name=name]')
.type('Test Name')
emailField = cy.get('input[name=email]')
.type('testEmail@gmail.com')
companyField = cy.get('input[name=company]')
.type('Test Company Name')
phoneField = cy.get('input[name=phone]')
.type('1459341234')
messageField = cy.get('input[name=message]')
.type('This is a test message')
radioField1 = cy.get('[type="radio"]')
.check('Web Development')
radioField2 = cy.get('[type="radio"]')
.check('200K')
nameField = cy.get('input[name=name]').type('Testing')
emailField = cy.get('input[name=email]').type('testEmail@gmail.com')
phoneField = cy.get('input[name=phone]').type('1459341234')
messageField = cy.get('input[name=message]').type('This is a test message')
cy.get('@submitBtn').click()
})

it('Should show a success message on submit when all form values have been filled out', function() {
cy.get('div.alert')
.should('exist')
.contains('Thank you')
it('Should show a success message on submit when all form values have been filled out', function () {
cy.wait(2000)
cy.contains('Thank you')
})

it('All fields should be clear after successful form submission', function() {
nameField.should('have.value', '')
emailField.should('have.value', '')
companyField.should('have.value', '')
phoneField.should('have.value', '')
messageField.should('have.value', '')
it('All fields should be clear after successful form submission', function () {
cy.get('input[name=name]').should('have.value', 'Testing')
cy.get('input[name=email]').should('have.value', 'testEmail@gmail.com')
cy.get('input[name=phone]').should('have.value', '1459341234')
cy.get('input[name=message]').should('have.value', 'This is a test message')
})
})
describe('Unsucessful form submission', function() {
describe('Unsucessful form submission', function () {
it('DOM should not show success message when all fields of the form are not filled out', function () {
nameField = cy.get('input[name=name]')
.type('Test Name')
cy.get('@submitBtn').click()
cy.get('div.alert').should('not.exist')
nameField = cy.get('input[name=name]').type('Test Name')
cy.get('@submitBtn').should('be.disabled')
})
})
})

describe('Footer Navigation', function () {
it('Navigate to SLA page', function () {
cy.contains('Read our SLA').click()
cy.url().should('include', '/service-level-agreement')
})
it('Navigate to Developer page', function () {
// cy.contains('I\'m a developer').click()
// cy.url().should('include', '/opportunities/develop')
})
it('Navigate to Design page', function () {
// cy.contains('I\'m a designer').click()
// cy.url().should('include', '/opportunities/design')
})
it('Navigates to StartupJunto Registration Page', function () {
// cy.contains('Register Today!').click()
})
it('Navigates to OpenForge Twitter', function () {
cy.contains('@OpenForge_US').click()
})
it('Navigates to OpenForge Facebook', function () {
cy.contains('OpenForge_US').click()
})
it('Navigates to OpenForge Linkedin', function () {
cy.contains('OpenForge_US').click()
})
it('Navigates to OpenForge Instagram', function () {
cy.contains('@OpenForgeTeam').click()
})
//it('Open native mail to contact Hello@openforge.io', function () {
//cy.contains('hello@openforge.io').click()
//})
})
})
Loading

0 comments on commit 9ce088d

Please sign in to comment.