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

Commit

Permalink
Tests (#12)
Browse files Browse the repository at this point in the history
* Create basic redux actions unit tests

* Update jest collect coverage settings

* Write basic reducer integration test

* Remove redux actions unit tests

- we are testing action in our reducer integration test

* Add react-testing-library and jest-styled-components dependencies

* Create basic button component unit test

* Create basic button component snapshot

* Create test case for disabled button

- just to show how coverage works and why button was not 100 % covered

* Create failing test for not found page

* Create successful test for not found page

- create render with router helper
- create basic test case

* Create basic products list snapshot test

* Create basic products list snapshot test when products loaded

* Fix react-testing-library react-hooks errors

* Add jest-mock dependency

* Added CartItem product id into array

* Getting rid of classes

* Adding number of products per size selector

* Refactored getting url params in product list

* Mock Fetch requests

- add fetch-mock dev dependency
- mock GET /api/skus
- mock POST /oauth/token

* ramdify

* Create basic tests for product detail page

* Create basic tests for cart page

- initialize redux store with mock data
- update cart item component so that we can differentiate between loaded and not loaded state

* Use routes constants instead of hard-coded routes

* Create basic test for not-logged-in user on account page

* Create basic test user account page

* Create basic signup page test

* Write advanced tests for signup page

- test unsuccessful submit
- test successful submit

* Replace hard-coded user data with constant mock user data

* Write tests for sign in page

* Update products list snapshot

* Fix typo

* Polish source code

* Make store mock nicer

* Detect account page by page-id

* Fix snapshot tests

* Install cypress

* Initialize cypress

* Add eslint-plugin-cypress

* Fix cypress base url

* Write basic cypress test

* Fix cypress test

* Resolve tasks from code review

- fix naming in reducer test
- rename test files from index.test.js to [testee].test.js
- replace some snapshots with normal jest expectations

* Run tests before every commit

* Add cross-env

* Revert "Add cross-env"

This reverts commit 0ceeb98

* Revert "Run tests before every commit"

This reverts commit c6635c0

* Recover README files 💣
  • Loading branch information
developer239 authored and dannytce committed Apr 26, 2019
1 parent af41308 commit 9502fdc
Show file tree
Hide file tree
Showing 38 changed files with 1,766 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
'prettier',
'prettier/react',
],
plugins: ['react-hooks'],
plugins: ['react-hooks', 'cypress'],
root: true,
env: {
browser: true,
Expand Down
3 changes: 3 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"baseUrl": "http://localhost:3000"
}
1 change: 1 addition & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
18 changes: 18 additions & 0 deletions cypress/integration/add-to-cart.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
describe('home page', () => {
it('should display home page', () => {
cy.visit('/products')
// Find first Add To Cart button
cy.get('button')
.eq(0)
.click() // put the product into shopping cart
// Find second Add To Cart button
cy.get('button')
.eq(1)
.click() // put the product into shopping cart
.click() // put the product into shopping cart
// Navigate to shopping cart
cy.contains('My Cart').click()
// Expect to have 2 different products in shopping cart
cy.get('li').should('have.length', 2)
})
})
17 changes: 17 additions & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ***********************************************************
// 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)

module.exports = () => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
25 changes: 25 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ***********************************************
// 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) => { ... })
20 changes: 20 additions & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -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')
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@
"eject": "react-scripts eject",
"format": "prettier --write '*/**/*.{js,css,md,json}'",
"lint:js": "eslint . --ignore-path .gitignore --fix",
"lint:css": "stylelint 'src/**/*.js'"
"lint:css": "stylelint 'src/**/*.js'",
"cypress:open": "cypress open"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}",
"!/node_modules/",
"!src/index.js",
"!src/serviceWorker.js",
"!src/store/index.js"
]
},
"lint-staged": {
"*.js": [
Expand Down Expand Up @@ -55,11 +65,16 @@
"devDependencies": {
"@strv/eslint-config-react": "^1.0.1",
"@strv/stylelint-config-styled-components": "^1.0.0",
"cypress": "^3.2.0",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-cypress": "^2.2.1",
"eslint-plugin-react-hooks": "^1.6.0",
"fetch-mock": "^7.3.1",
"husky": "^1.3.1",
"jest-styled-components": "^6.3.1",
"lint-staged": "^8.1.5",
"prettier": "^1.16.4",
"react-testing-library": "^6.1.2",
"stylelint": "^9.10.1",
"stylelint-config-prettier": "^5.0.0"
}
Expand Down
6 changes: 3 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import { getCustomer } from './utils/customer'
import { configureStore } from './store'
import * as routes from './routes'

const store = configureStore({
const defaultStore = configureStore({
customer: getCustomer(),
})

const App = () => (
<Provider store={store}>
const App = ({ store }) => (
<Provider store={store || defaultStore}>
<React.Fragment>
<GlobalStyles />
<ToastContainer position={toast.POSITION.BOTTOM_RIGHT} />
Expand Down
20 changes: 20 additions & 0 deletions src/components/Button/test/Button.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import { render } from 'react-testing-library'
import 'jest-styled-components'

import Button from '../index'

// This is just an example how to test components
describe('[components] Button', () => {
it('should render correctly', () => {
const renderer = render(<Button>My Button</Button>)
expect(renderer.container).toMatchSnapshot()
})

describe('when disabled', () => {
it('should render correctly', () => {
const renderer = render(<Button disabled>My Button</Button>)
expect(renderer.container).toMatchSnapshot()
})
})
})
42 changes: 42 additions & 0 deletions src/components/Button/test/__snapshots__/Button.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`[components] Button should render correctly 1`] = `
.c0 {
background: #ef0d33;
cursor: pointer;
padding: 1rem;
margin-top: 0.5rem;
border: none;
border-radius: 5px;
color: #fff;
}
<div>
<button
class="c0"
>
My Button
</button>
</div>
`;

exports[`[components] Button when disabled should render correctly 1`] = `
.c0 {
background: #e5e5e5;
cursor: default;
padding: 1rem;
margin-top: 0.5rem;
border: none;
border-radius: 5px;
color: #fff;
}
<div>
<button
class="c0"
disabled=""
>
My Button
</button>
</div>
`;
4 changes: 2 additions & 2 deletions src/components/Layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as routes from '../../routes'

import { Wrapper, Header, HeaderSection, HeaderLink } from './styled'

const Layout = ({ isAuthenticated, children }) => (
const Layout = ({ isAuthenticated, children, dataTestId }) => (
<Fragment>
<Header>
<HeaderSection>
Expand All @@ -26,7 +26,7 @@ const Layout = ({ isAuthenticated, children }) => (
)}
</HeaderSection>
</Header>
<Wrapper>{children}</Wrapper>
<Wrapper data-testid={dataTestId}>{children}</Wrapper>
</Fragment>
)

Expand Down
2 changes: 1 addition & 1 deletion src/components/Loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { LoaderWrap, StyledLoader, Circular, Path } from './styled'

const Loader = props => (
<LoaderWrap {...props}>
<LoaderWrap data-testid="loader" {...props}>
<StyledLoader>
<Circular viewBox="25 25 50 50">
<Path
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Account/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Layout from '../../components/Layout'
import { H1 } from '../../components/Typography'

const AccountPage = ({ customer }) => (
<Layout>
<Layout dataTestId="account-page">
<H1>Welcome {customer.attributes.metadata.firstName}</H1>
</Layout>
)
Expand Down
36 changes: 36 additions & 0 deletions src/pages/Account/test/Account.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import 'jest-styled-components'

import { App } from '../../../App'
import * as routes from '../../../routes'
import { renderWithRouter } from '../../../utilsTest/render'
import { configureStore } from '../../../store'
import { USER } from '../../../utilsTest/mockData'

describe('[pages] Account', () => {
describe('when not logged in', () => {
it('should redirect to login page', () => {
const renderer = renderWithRouter(<App />, routes.ACCOUNT)
const HTMLDivElement = renderer.getByTestId('login-page')
expect(HTMLDivElement).toBeTruthy()
})
})

describe('when logged in', () => {
it('should render private user account page', () => {
const store = configureStore({
customer: {
attributes: {
metadata: {
firstName: USER.firstName,
},
},
},
})

const renderer = renderWithRouter(<App store={store} />, routes.ACCOUNT)
const H1HtmlElement = renderer.getByTestId('account-page')
expect(H1HtmlElement).toBeTruthy()
})
})
})
18 changes: 11 additions & 7 deletions src/pages/Cart/CartItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ const CartItem = ({ productId, quantity, removeProduct }) => {
return (
<li key={productId}>
{isLoading && <Loader small />}
<p>
{/* and finally here we try to get name from downloaded product */}
{getName(product)} - {quantity}
</p>
<Button type="button" onClick={() => removeProduct(productId)}>
Remove
</Button>
{!isLoading && (
<div data-testid="product-in-cart">
<p>
{/* and finally here we try to get name from downloaded product */}
{getName(product)} - {quantity}
</p>
<Button type="button" onClick={() => removeProduct(productId)}>
Remove
</Button>
</div>
)}
</li>
)
}
Expand Down
37 changes: 37 additions & 0 deletions src/pages/Cart/test/CartItem.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react'
import { waitForElement } from 'react-testing-library'
import 'jest-styled-components'

import { App } from '../../../App'
import * as routes from '../../../routes'
import { renderWithRouter } from '../../../utilsTest/render'
import { mockFetchProduct } from '../../../utilsTest/mockHelpers'
import { configureStore } from '../../../store'
import { getCustomer } from '../../../utils/customer'

describe('[pages] Cart', () => {
describe('when loading', () => {
it('should render correctly', () => {
const renderer = renderWithRouter(<App />, routes.CART)
expect(renderer.container).toMatchSnapshot()
})
})

describe('when products loaded', () => {
mockFetchProduct()

it('should render correctly', async () => {
const productId = 1
const store = configureStore({
customer: getCustomer(),
cart: {
[productId]: productId,
},
})

const renderer = renderWithRouter(<App store={store} />, routes.CART)
await waitForElement(() => renderer.getByTestId('product-in-cart'))
expect(renderer.getAllByTestId('product-in-cart').length).toEqual(1)
})
})
})
Loading

0 comments on commit 9502fdc

Please sign in to comment.