Skip to content

Commit

Permalink
initial scaffolding
Browse files Browse the repository at this point in the history
  • Loading branch information
funador committed Oct 29, 2019
1 parent fdfcc84 commit e71c4b4
Show file tree
Hide file tree
Showing 32 changed files with 11,049 additions and 0 deletions.
1 change: 1 addition & 0 deletions __mocks__/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'test-file-stub';
3 changes: 3 additions & 0 deletions __mocks__/shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global.requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};
1 change: 1 addition & 0 deletions __mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
30 changes: 30 additions & 0 deletions configs/jest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"rootDir": "..",
"coverageDirectory": "<rootDir>/tests/__coverage__/",
"setupFiles": [
"<rootDir>/tests/__mocks__/shim.js"
],
"roots": [
"<rootDir>/src/",
"<rootDir>/tests/"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tests/__mocks__/fileMock.js",
"\\.(css|scss|less)$": "<rootDir>/tests/__mocks__/styleMock.js"
},
"moduleFileExtensions": ["ts", "tsx", "js", "jsx"],
"transform": {
"^.+\\.(ts|tsx)$": "<rootDir>/configs/jest.preprocessor.js"
},
"transformIgnorePatterns": [
"/node_modules/"
],
"testRegex": "/tests/.*\\.(ts|tsx)$",
"moduleDirectories": [
"node_modules"
],
"globals": {
"DEVELOPMENT": false,
"FAKE_SERVER": false
}
}
22 changes: 22 additions & 0 deletions configs/jest.preprocessor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const tsc = require('typescript');
const tsConfig = require('./../tsconfig.json');

module.exports = {
process(src, path) {
const isTs = path.endsWith('.ts');
const isTsx = path.endsWith('.tsx');
const isTypescriptFile = (isTs || isTsx);

if ( isTypescriptFile ) {
return tsc.transpileModule(
src,
{
compilerOptions: tsConfig.compilerOptions,
fileName: path
}
).outputText;
}

return src;
},
};
51 changes: 51 additions & 0 deletions configs/webpack/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// shared config (dev and prod)
const { resolve } = require('path')
const { CheckerPlugin } = require('awesome-typescript-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
context: resolve(__dirname, '../../src'),
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader', 'source-map-loader'],
exclude: /node_modules/,
},
{
test: /\.tsx?$/,
use: ['babel-loader', 'awesome-typescript-loader'],
},
{
test: /\.css$/,
use: ['style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }],
},
{
test: /\.(scss|sass)$/,
loaders: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
'sass-loader',
],
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file-loader?hash=sha512&digest=hex&name=img/[hash].[ext]',
'image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false',
],
},
],
},
plugins: [new CheckerPlugin(), new HtmlWebpackPlugin({ template: 'index.html' })],
externals: {
react: 'React',
'react-dom': 'ReactDOM',
},
performance: {
hints: false,
},
}
22 changes: 22 additions & 0 deletions configs/webpack/dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// development config
const merge = require('webpack-merge')
const webpack = require('webpack')
const commonConfig = require('./common')

module.exports = merge(commonConfig, {
mode: 'development',
entry: [
'react-hot-loader/patch', // activate HMR for React
'webpack-dev-server/client?http://localhost:8080', // bundle the client for webpack-dev-server and connect to the provided endpoint
'webpack/hot/only-dev-server', // bundle the client for hot reloading, only- means to only hot reload for successful updates
'./index.tsx', // the entry point of our app
],
devServer: {
hot: true, // enable HMR on the server
},
devtool: 'cheap-module-eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(), // enable HMR globally
new webpack.NamedModulesPlugin(), // prints more readable module names in the browser console on HMR updates
],
})
5 changes: 5 additions & 0 deletions enzyme.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Enzyme from 'enzyme'

import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })
13 changes: 13 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
clearMocks: true,
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less|scss)$': '<rootDir>/__mocks__/styleMock.js',
},
setupTestFrameworkScriptFile: 'jest-enzyme',
testEnvironment: 'enzyme',
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
}
61 changes: 61 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "extend-react-challenge",
"version": "0.0.1",
"description": "A coding challenge for extend front end candidates",
"author": "Extend",
"license": "MIT",
"repository": {
"type": "git",
"url": ""
},
"scripts": {
"lint": "tslint './src/**/*.ts*' --format stylish --project . --force",
"start": "yarn run start-dev",
"start-dev": "webpack-dev-server --config=configs/webpack/dev.js",
"test": "jest --watch --coverage --config=jest.config.js"
},
"devDependencies": {
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"@types/jest": "^24.0.18",
"@types/node": "^12.7.12",
"@types/react": "^16.9.5",
"@types/react-dom": "^16.9.1",
"awesome-typescript-loader": "^5.2.1",
"babel-loader": "^8.0.6",
"css-loader": "^3.2.0",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
"file-loader": "^4.2.0",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^6.0.0",
"jest": "^24.9.0",
"jest-environment-enzyme": "^7.1.1",
"jest-enzyme": "^7.1.1",
"node-sass": "^4.12.0",
"react": "^16.10.2",
"react-dom": "^16.10.2",
"rimraf": "^3.0.0",
"sass-loader": "^8.0.0",
"source-map-loader": "^0.2.4",
"style-loader": "^1.0.0",
"ts-jest": "^24.1.0",
"tslint": "^5.20.0",
"typescript": "^3.6.4",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.1",
"webpack-cli": "^3.3.9",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.8.2",
"webpack-merge": "^4.2.2"
},
"dependencies": {
"@emotion/core": "^10.0.22",
"@emotion/styled": "^10.0.22",
"react-hot-loader": "^4.12.15",
"react-redux": "^7.1.1",
"redux": "^4.0.4"
}
}
15 changes: 15 additions & 0 deletions src/assets/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Color names provided by colorhexa.com
const colors = {
black: '#000000',
darkLimeGreen: '#64A364',
lightGrayishLimeGreen: '#e9f9ea',
mostlyWhiteGrey: '#f7f7f7',
softRed: '#ee4957',
veryLightGray: '#e5e5e5',
veryDarkGrayishBlue: '#44484c',
veryPaleRed: '#ffe4e4',
vividRed: '#f20505',
white: '#ffffff',
}

export { colors }
Binary file added src/assets/icons/arrow-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const arrowIcon = require('./arrow-icon.png')
const redHeartIcon = require('./red-heart-icon.png')
const searchIcon = require('./search-icon.png')
const whiteHeartIcon = require('./white-heart-icon.png')

const icons = {
arrowIcon,
redHeartIcon,
searchIcon,
whiteHeartIcon,
}

export { icons }
Binary file added src/assets/icons/red-heart-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/search-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/white-heart-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { colors } from './colors'
import { icons } from './icons'

export { colors, icons }
7 changes: 7 additions & 0 deletions src/components/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react'
import { shallow } from 'enzyme'
import App from './App'

it('renders without crashing', () => {
shallow(<App />)
})
22 changes: 22 additions & 0 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { FC } from 'react'
import { hot } from 'react-hot-loader/root'
import styled from '@emotion/styled'
import Header from './Header'

const App: FC = () => {
return (
<Container>
<Header />
{/* Happy coding! */}
</Container>
)
}

const Container = styled.div({
margin: '0 auto',
height: '100%',
width: '560px',
paddingTop: '60px',
})

export default hot(App)
7 changes: 7 additions & 0 deletions src/components/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react'
import { shallow } from 'enzyme'
import Header from './Header'

it('renders without crashing', () => {
shallow(<Header />)
})
25 changes: 25 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { FC } from 'react'
import styled from '@emotion/styled'
import Heart from './Heart'

const Header: FC = () => {
return (
<Container>
<Title>Dog Breeds</Title>
<Heart icon="redHeartIcon" alt="red heart icon" />
</Container>
)
}

const Container = styled.div({
display: 'flex',
justifyContent: 'space-between',
})

const Title = styled.h1({
fontWeight: 'bold',
fontSize: '24px',
lineHeight: '33px',
})

export default Header
19 changes: 19 additions & 0 deletions src/components/Heart.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from 'react'
import { shallow } from 'enzyme'
import Heart from './Heart'

describe('<Heart />', () => {
const mockProps = {
icon: 'redHeartIcon',
alt: 'My fake alt text',
}

it('renders without crashing', () => {
shallow(<Heart {...mockProps} />)
})

it('renders the correct icon', () => {
const wrapper = shallow(<Heart {...mockProps} />)
expect(wrapper.prop('alt')).toBe(mockProps.alt)
})
})
20 changes: 20 additions & 0 deletions src/components/Heart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { FC } from 'react'
import styled from '@emotion/styled'
import { icons } from '../assets'

interface Props {
icon: string
alt: string
}

const Heart: FC<Props> = ({ icon, alt }) => {
return <HeartIcon src={icons[icon]} alt={alt} />
}

const HeartIcon = styled.img({
width: '17px',
height: '15px',
alignSelf: 'center',
})

export default Heart
22 changes: 22 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Extend Front End Challenge</title>
<link
href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,700,800"
rel="stylesheet"
/>
</head>
<body>
<noscript>For the best experience, please enable JavaScript</noscript>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.development.js" integrity="sha256-Fy0+oh76u+dih9imNzr0Ka1RHbVKV8o4nR+p8s6wTXE=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.development.js" integrity="sha256-ZMB3rvxm3yr+lN12NcNAJbw6JQWFah3Qx3s3XH1Z0P8=" crossorigin="anonymous"></script>
</body>
</html>
13 changes: 13 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import store from './redux/store'
import App from './components/App'
import './reset.scss'

render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
)
Empty file added src/redux/actions.ts
Empty file.
Loading

0 comments on commit e71c4b4

Please sign in to comment.