diff --git a/.travis.yml b/.travis.yml index a87748c1c5ab7..e79c4ef105ca9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,23 @@ jobs: script: - yarn test + - stage: gatsbygram ui tests + language: node_js + node_js: + - '6' + - '8' + cache: + yarn: true + before_install: + - curl -o- -L https://yarnpkg.com/install.sh | bash + - export PATH=$HOME/.yarn/bin:$PATH + - cd examples/gatsbygram + install: + - yarn + script: + - yarn test + + - stage: www graphql docker image build and push if: (NOT type = pull_request) AND branch = master env: diff --git a/examples/gatsbygram/.gitignore b/examples/gatsbygram/.gitignore index 8f5b35a4a9cbc..a57215bb900de 100644 --- a/examples/gatsbygram/.gitignore +++ b/examples/gatsbygram/.gitignore @@ -1,3 +1,4 @@ public .cache node_modules +cypress/videos/ diff --git a/examples/gatsbygram/cypress.json b/examples/gatsbygram/cypress.json new file mode 100644 index 0000000000000..46c5bf7bcf6d3 --- /dev/null +++ b/examples/gatsbygram/cypress.json @@ -0,0 +1,5 @@ +{ + "baseUrl": "http://localhost:8000", + "fixturesFolder": "data", + "projectId": "c9d3r3" +} diff --git a/examples/gatsbygram/cypress/integration/about_page_spec.js b/examples/gatsbygram/cypress/integration/about_page_spec.js new file mode 100644 index 0000000000000..dc9fc7d606993 --- /dev/null +++ b/examples/gatsbygram/cypress/integration/about_page_spec.js @@ -0,0 +1,28 @@ +describe(`About Page`, () => { + it(`successfully loads`, () => { + cy.visit(`/about`) + }) + + it(`contains the title with an SVG icon and text "Gatsbygram"`, () => { + cy.getTestElement(`site-title`).get(`svg`) + cy.getTestElement(`site-title`).contains(`Gatsbygram`) + }) + + it(`clicking on site title takes to home page`, () => { + cy.getTestElement(`site-title`).click() + cy.url().should(`eq`, `${Cypress.config(`baseUrl`)}/`) + + // go back to about page for further testing + cy.visit(`/about`) + }) + + it(`contains a link to about page in nav bar and it works`, () => { + cy.getTestElement(`about-link`).contains(`About`) + cy.getTestElement(`about-link`).click() + cy.url().should(`eq`, `${Cypress.config(`baseUrl`)}/about/`) + }) + + it(`displays title of the page`, () => { + cy.getTestElement(`about-title`).contains(`About Gatsbygram`) + }) +}) diff --git a/examples/gatsbygram/cypress/integration/home_page_spec.js b/examples/gatsbygram/cypress/integration/home_page_spec.js new file mode 100644 index 0000000000000..c2a51dc4ee17e --- /dev/null +++ b/examples/gatsbygram/cypress/integration/home_page_spec.js @@ -0,0 +1,106 @@ + +describe(`The Home Page`, () => { + it(`successfully loads`, () => { + cy.visit(`/`) + }) + + it(`contains the title with an SVG icon and text "Gatsbygram"`, () => { + cy.getTestElement(`site-title`).get(`svg`) + cy.getTestElement(`site-title`).contains(`Gatsbygram`) + }) + + it(`contains a link to about page in nav bar and it works`, () => { + cy.getTestElement(`about-link`).contains(`About`) + cy.getTestElement(`about-link`).click() + cy.url().should(`eq`, `${Cypress.config(`baseUrl`)}/about/`) + // go back to home page + cy.visit(`/`) + }) + + it(`renders user avatar and name`, () => { + cy.getTestElement(`user-avatar`).get(`img`) + cy.getTestElement(`username`).contains(`kyle__mathews`) + }) + + it(`shows user's posts and followers count`, () => { + cy.getTestElement(`user-meta`).contains(`100 posts`) + cy.getTestElement(`user-meta`).contains(`192k followers`) + }) + + it(`shows number of likes when hovered on a post`, () => { + cy.fixture(`posts`).then((postsData) => { + const post = postsData[0] + cy.getTestElement(`post`).first().trigger(`mouseover`) + cy.getTestElement(`likes`).contains(post.likes) + cy.getTestElement(`post`).first().trigger(`mouseout`) + }) + }) + + it(`opens and closes a post`, () => { + cy.fixture(`posts`).then((postsData) => { + const post = postsData[0] + cy.getTestElement(`post`).first().click() + cy.url().should('contain', post.id) + cy.getTestElement(`post-detail-avatar`).should(`have.attr`, `src`, post.avatar) + cy.getTestElement(`post-detail-username`).contains(post.username) + cy.getTestElement(`post-detail-likes`).contains(post.likes) + cy.getTestElement(`post-detail-text`).contains(post.username) + cy.getTestElement(`post-detail-text`).contains(post.text) + cy.getTestElement(`modal-close`).click() + cy.url().should(`eq`, `${Cypress.config(`baseUrl`)}/`) + }) + }) + + it(`goes to next / previous post on clicking arrow icons`, () => { + cy.fixture(`posts`).then((postsData) => { + const post1 = postsData[0] + const post2 = postsData[1] + // open fist post + cy.getTestElement(`post`).first().click() + cy.url().should('contain', post1.id) + // click right arrow icon to go to 2nd post + cy.getTestElement(`next-post`).click() + cy.url().should('contain', post2.id) + // press left arrow to go back to 1st post + cy.getTestElement(`previous-post`).click() + cy.url().should('contain', post1.id) + // close the post + cy.getTestElement(`modal-close`).click() + }) + }) + + it(`goes to next / previous post with keyboard shortcut`, () => { + cy.fixture(`posts`).then((postsData) => { + const post1 = postsData[0] + const post2 = postsData[1] + // open fist post + cy.getTestElement(`post`).first().click() + cy.url().should('contain', post1.id) + // press right arrow to go to 2nd post + cy.get(`body`).type(`{rightarrow}`) + cy.url().should('contain', post2.id) + // press left arrow to go back to 1st post + cy.get(`body`).type(`{leftarrow}`) + cy.url().should('contain', post1.id) + // close the post + cy.getTestElement(`modal-close`).click() + }) + }) + + it(`loads more posts when Load More button is clicked & on scroll`, () => { + // initially loads 12 posts + cy.getTestElement(`post`).should('have.length', 12) + + // loads 12 more posts when Load More button is clicked + cy.getTestElement(`load-more`).click() + cy.getTestElement(`post`).should('have.length', 24) + + // loads 12 more posts when scrolled to bottom + // cy.getTestElement(`home-container`).scrollTo(`0%`, `99%`) + cy.window().scrollTo(`bottom`) + cy.getTestElement(`post`).should('have.length', 36) + + // let's go back to top + cy.window().scrollTo(`top`) + }) +}) diff --git a/examples/gatsbygram/cypress/support/commands.js b/examples/gatsbygram/cypress/support/commands.js new file mode 100644 index 0000000000000..c544c40294bb2 --- /dev/null +++ b/examples/gatsbygram/cypress/support/commands.js @@ -0,0 +1,30 @@ +// *********************************************** +// 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 is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +// copied from here - https://github.com/cypress-io/cypress/issues/1212#issuecomment-360395261 +Cypress.Commands.add("getTestElement", (selector) => { + return cy.get(`[data-testid="${selector}"]`) +}) \ No newline at end of file diff --git a/examples/gatsbygram/cypress/support/index.js b/examples/gatsbygram/cypress/support/index.js new file mode 100644 index 0000000000000..d68db96df2697 --- /dev/null +++ b/examples/gatsbygram/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// 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') diff --git a/examples/gatsbygram/package.json b/examples/gatsbygram/package.json index f1b8ec42b4cd3..23cf1b0bd68e5 100644 --- a/examples/gatsbygram/package.json +++ b/examples/gatsbygram/package.json @@ -5,17 +5,17 @@ "version": "1.0.0", "author": "Kyle Mathews ", "dependencies": { - "gatsby": "^1.9.52", - "gatsby-image": "^1.0.39", - "gatsby-link": "^1.6.20", - "gatsby-plugin-glamor": "^1.6.8", - "gatsby-plugin-google-analytics": "^1.0.8", - "gatsby-plugin-manifest": "^1.0.8", - "gatsby-plugin-offline": "^1.0.9", - "gatsby-plugin-sharp": "^1.6.8", - "gatsby-source-filesystem": "^1.5.2", - "gatsby-transformer-json": "^1.0.8", - "gatsby-transformer-sharp": "^1.6.8", + "gatsby": "latest", + "gatsby-image": "latest", + "gatsby-link": "latest", + "gatsby-plugin-glamor": "latest", + "gatsby-plugin-google-analytics": "latest", + "gatsby-plugin-manifest": "latest", + "gatsby-plugin-offline": "latest", + "gatsby-plugin-sharp": "latest", + "gatsby-source-filesystem": "latest", + "gatsby-transformer-json": "latest", + "gatsby-transformer-sharp": "latest", "instagram-screen-scrape": "^2.0.0", "lodash": "^4.16.4", "mkdirp": "^0.5.1", @@ -38,10 +38,16 @@ "main": "n/a", "scripts": { "lint": "./node_modules/.bin/eslint --ext .js,.jsx --ignore-pattern public .", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "start-server-and-test develop http://localhost:8000 cy:run", "develop": "gatsby develop", "dev": "gatsby develop", "build": "gatsby build", - "deploy": "gatsby build --prefix-paths && gh-pages -d public" + "deploy": "gatsby build --prefix-paths && gh-pages -d public", + "cy:open": "cypress open", + "cy:run": "cypress run" + }, + "devDependencies": { + "cypress": "^2.1.0", + "start-server-and-test": "^1.1.4" } } diff --git a/examples/gatsbygram/src/components/modal.js b/examples/gatsbygram/src/components/modal.js index 4d4795af74328..a9123dc59746f 100644 --- a/examples/gatsbygram/src/components/modal.js +++ b/examples/gatsbygram/src/components/modal.js @@ -123,6 +123,7 @@ class GatsbyGramModal extends React.Component { }} > navigateTo(`/`)} css={{ cursor: `pointer`, diff --git a/examples/gatsbygram/src/components/post-detail.js b/examples/gatsbygram/src/components/post-detail.js index 6613fd6941746..93e8b6c2ca066 100644 --- a/examples/gatsbygram/src/components/post-detail.js +++ b/examples/gatsbygram/src/components/post-detail.js @@ -31,6 +31,7 @@ class PostDetail extends React.Component { }} > {username}
-
+
{username} {text}
diff --git a/examples/gatsbygram/src/components/post.js b/examples/gatsbygram/src/components/post.js index cdf14dd2ab914..ad90dce67e6f6 100644 --- a/examples/gatsbygram/src/components/post.js +++ b/examples/gatsbygram/src/components/post.js @@ -29,6 +29,7 @@ class Post extends React.Component { const { small } = smallImage.childImageSharp return ( (touched = true)} onMouseEnter={() => { @@ -93,6 +94,7 @@ class Post extends React.Component { {/* overlay */} {this.state.hovering && (

-

About Gatsbygram

+

About Gatsbygram

Gatsbygram is an example website built with the JavaScript web framework diff --git a/examples/gatsbygram/src/pages/index.js b/examples/gatsbygram/src/pages/index.js index 1020e3254f396..cd91a3dc98178 100644 --- a/examples/gatsbygram/src/pages/index.js +++ b/examples/gatsbygram/src/pages/index.js @@ -95,6 +95,7 @@ class Index extends React.Component { }} >

{user.username}

-

+

{posts.length} posts 192k followers

@@ -154,6 +156,7 @@ class Index extends React.Component { ))} {!this.state.showingMore && (