Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apple devices catalog coding challenge submission #17

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
],
"plugins": [
["@babel/plugin-transform-runtime"]
]
}

8 changes: 7 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@ module.exports = {
rootDir: './src',
setupFiles: [
path.resolve('jest/setupEnzyme.js')
]
],
transform: {
"\\.png$": "jest-file-loader",
"\\.jpg$": "jest-file-loader",
"\\.svg$": "jest-file-loader",
"^.+\\.jsx?$": "babel-jest",
},
}
3,296 changes: 2,337 additions & 959 deletions package-lock.json

Large diffs are not rendered by default.

26 changes: 25 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,48 @@
"unit": "jest"
},
"dependencies": {
"@tds/core-a11y-content": "^2.3.3",
"@tds/core-box": "^2.4.3",
"@tds/core-button-link": "^3.3.3",
"@tds/core-card": "^2.6.3",
"@tds/core-colours": "^2.2.4",
"@tds/core-css-reset": "^3.0.4",
"@tds/core-dimple-divider": "^2.1.3",
"@tds/core-flex-grid": "^4.1.3",
"@tds/core-hairline-divider": "^2.1.3",
"@tds/core-heading": "^3.0.8",
"@tds/core-image": "^2.1.3",
"@tds/core-paragraph": "^2.1.3",
"@tds/core-price-lockup": "^2.4.3",
"@tds/core-spinner": "^3.2.3",
"@tds/core-text": "^3.2.3",
"axios": "^0.26.0",
"cors": "^2.8.5",
"enzyme": "^3.11.0",
"express": "^4.17.1",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-router-dom": "^5.2.0"
"react-router-dom": "^5.2.0",
"styled-components": "^5.3.3"
},
"devDependencies": {
"@babel/core": "^7.12.13",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.12.13",
"@babel/preset-react": "^7.12.13",
"@tds/core-breadcrumbs": "^2.3.3",
"@tds/core-link": "^2.3.3",
"@tds/core-notification": "^3.2.5",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"concurrently": "^5.3.0",
"css-loader": "^5.0.2",
"enzyme-adapter-react-16": "^1.15.6",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.0.0",
"jest": "^26.6.3",
"jest-file-loader": "^1.0.2",
"jest-mock-axios": "^4.5.0",
"style-loader": "^2.0.0",
"webpack": "^5.21.2",
"webpack-cli": "^4.5.0",
Expand Down
48 changes: 48 additions & 0 deletions public/images/TELUS_TAGLINE_HORIZONTAL_EN.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 15 additions & 10 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Apple Shopper</title>
</head>
<body>
<div id="root"></div>
</body>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="preload"
as="script"
href="https://polyfill.io/v3/polyfill.min.js?features=es6%2CArray.prototype.includes%2CSet"
/>
<title>Apple Shopper</title>
</head>
<body>
<main id="root"></main>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6%2CArray.prototype.includes%2CSet"></script>
</body>
</html>

4 changes: 4 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var express = require('express');
var app = express();
var cors = require('cors');
var router = express.Router();
var PORT = 8081;

Expand Down Expand Up @@ -47,6 +48,9 @@ router.get('/iphones', function(req, res) {
});
});

// Enable Cross-origin resource sharing
app.use(cors());

app.use('/', router);

app.listen(PORT, () => {
Expand Down
3 changes: 3 additions & 0 deletions src/ui/__mocks__/axios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import mockedAxios from "jest-mock-axios";

export default mockedAxios;
8 changes: 8 additions & 0 deletions src/ui/__mocks__/react-router-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";

const reactRouterDom = require("react-router-dom");
// Mock to avoid colission with MemoryRouter when testing.
// Just render plain div with its children
reactRouterDom.BrowserRouter = ({ children }) => <div>{children}</div>;

module.exports = reactRouterDom;
68 changes: 58 additions & 10 deletions src/ui/__tests__/routes.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,66 @@
import React from 'react';
import {MemoryRouter} from 'react-router-dom';
import {mount, configure} from 'enzyme';
import App from '../components/App';
import Home from '../components/Home';
import NotFound from '../components/NotFound';

describe('Application routes', () => {
it('should render a Home component', () => {
import React from "react";
import { act } from "react-dom/test-utils";
import { MemoryRouter } from "react-router-dom";
import { mount } from "enzyme";
import App from "../components/App";
import Home from "../components/Home";
import IPhones from "../components/IPhones";
import Watches from "../components/Watches";
import NotFound from "../components/NotFound";

// This fixes issue reported in https://github.com/enzymejs/enzyme/issues/2073.
// Mounted wrapper was not wrapped in act(...) warning
const waitForComponentToPaint = async (wrapper) => {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 200));
wrapper.update();
});
};

describe("Application routes", () => {
it("should render a Home component", () => {
const wrapper = mount(
<MemoryRouter initialEntries={['/']}>
<MemoryRouter initialEntries={["/"]}>
<App />
</MemoryRouter>
);

expect(wrapper.find(Home)).toHaveLength(1);
});

it("should render an Iphones component", async () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/iphones"]}>
<App />
</MemoryRouter>
);

expect(wrapper.exists).toBeTruthy();
await waitForComponentToPaint(wrapper);

expect(wrapper.find(IPhones)).toHaveLength(1);
});

it("should render a Watches component", async () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/watches"]}>
<App />
</MemoryRouter>
);

expect(wrapper.exists).toBeTruthy();
await waitForComponentToPaint(wrapper);

expect(wrapper.find(Watches)).toHaveLength(1);
});

it("should render a NotFound component", () => {
const wrapper = mount(
<MemoryRouter initialEntries={["/asd", "/ggggg", "/404"]}>
<App />
</MemoryRouter>
);

expect(wrapper.find(NotFound)).toHaveLength(1);
});
});
33 changes: 33 additions & 0 deletions src/ui/api/hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useEffect, useState } from "react";

/**
* Hook used by components to fetch data
*
* @param {*} fetchFunction
* @param {...any} fetchFunctionParams
* @returns {Array} An array in the form [data, isLoading, isError, error]
*/
export const useFetchData = (fetchFunction, ...fetchFunctionParams) => {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [hasError, setHasError] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
const asyncFunction = async () => {
try {
setIsLoading(true);

const response = await fetchFunction(...fetchFunctionParams);
setData(response.data);
setIsLoading(false);
} catch (error) {
setError(error);
setHasError(true);
}
};
asyncFunction();
}, []);

return [data.data, isLoading, hasError, error];
};
12 changes: 12 additions & 0 deletions src/ui/api/iphone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios from "./utils";

/**
* Gets the list of available iphones
*
* @returns {Promise}
*/
export const getIphones = () => {
return axios.get("/iphones");
};


8 changes: 8 additions & 0 deletions src/ui/api/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import axios from "axios";

export default axios.create({
baseURL: "http://localhost:8081/",
headers: {
"Content-type": "application/json",
},
});
10 changes: 10 additions & 0 deletions src/ui/api/watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import axios from "./utils";

/**
* Gets the list of available watches
*
* @returns {Promise}
*/
export const getWatches = () => {
return axios.get("/watches");
};
49 changes: 38 additions & 11 deletions src/ui/components/App/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
import React from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import Home from '../Home';
import NotFound from '../NotFound';
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import CSSReset from "@tds/core-css-reset";
import FlexGrid from "@tds/core-flex-grid";
import Text from "@tds/core-text";
import Box from "@tds/core-box";
import Home from "../Home";
import NotFound from "../NotFound";
import Watches from "../Watches";
import IPhones from "../IPhones";
import { GlobalFlexMain } from "@tds/core-css-reset";

const App = () => (
<Router>
<Switch>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
<>
<CSSReset />
<GlobalFlexMain />
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path={"/watches"}>
<Watches />
</Route>
<Route exact path="/iphones">
<IPhones />
</Route>
<Route>
<NotFound />
</Route>
</Switch>
</Router>
<FlexGrid>
<FlexGrid.Row horizontalAlign="center">
<Box vertical={8}>
<Text>&#169;{new Date().getFullYear()} TELUS</Text>
</Box>
</FlexGrid.Row>
</FlexGrid>
</>
);

export default App;
3 changes: 3 additions & 0 deletions src/ui/components/Home/__snapshots__/home.spec.jsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Device Catalog renders correctly 1`] = `"<div class=\\"Row__StyledRow-sc-1goz0ht-0 fObXZQ\\"><div class=\\"Col__StyledCol-sc-15yvjc7-0 gBwSfh\\"><div class=\\"sc-bdvvtL cluyzB\\"><img src=\\"../public/images/TELUS_TAGLINE_HORIZONTAL_EN.svg\\" width=\\"150\\" height=\\"50\\" alt=\\"TELUS\\" class=\\"Image__StyledImage-b16p20-0 cNmOoM\\"><hr class=\\"HairlineDivider__StyledHairlineDivider-biamlk-0 BvZCb\\"><h1 data-testid=\\"heading\\" class=\\"Heading__StyledHeading-mpz92r-0 fflItf\\">Device Catalog</h1><p class=\\"Paragraph__StyledParagraph-efl81j-0 jukEfT\\">Revolutionary devices at unbeatable prices.</p><hr class=\\"DimpleDivider__StyledDimpleDivider-quxnvh-0 ibPxnT\\"></div></div></div><div class=\\"Row__StyledRow-sc-1goz0ht-0 fObXZQ\\"><div class=\\"Col__StyledCol-sc-15yvjc7-0 gBwSfh\\"><div class=\\"sc-bdvvtL dGyuLk\\"><div class=\\"sc-bdvvtL YWUYw\\"><div class=\\"sc-bdvvtL cdVIWp sc-eCImPb iUidrU sc-eCImPb iUidrU\\"><a class=\\"sc-jRQBWg cxlYPA\\" href=\\"/iphones\\"><img src=\\"../public/images/iphone.jpg\\" width=\\"150\\" height=\\"250\\" alt=\\"iPhone image\\" class=\\"Image__StyledImage-b16p20-0 cNmOoM\\"><span class=\\"sc-hKwDye jeLaXE\\">iPhones</span></a></div><div class=\\"sc-bdvvtL iQfmHk sc-eCImPb iUidrU sc-eCImPb iUidrU\\"><a class=\\"sc-jRQBWg cxlYPA\\" href=\\"/watches\\"><img src=\\"../public/images/watch.jpg\\" width=\\"150\\" height=\\"250\\" alt=\\"Watch image\\" class=\\"Image__StyledImage-b16p20-0 cNmOoM\\"><span class=\\"sc-hKwDye jeLaXE\\">Watches</span></a></div></div><hr class=\\"HairlineDivider__StyledHairlineDivider-biamlk-0 BvZCb\\"></div></div></div>"`;
22 changes: 22 additions & 0 deletions src/ui/components/Home/home.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import { render } from "enzyme";
import Home from ".";
import { MemoryRouter } from "react-router-dom";

describe("Device Catalog", () => {
it("renders correctly", () => {
const container = render(
<MemoryRouter>
<Home />
</MemoryRouter>
);

expect(container.html()).toMatchSnapshot();
expect(container.find("img").length).toEqual(3);
expect(container.html().includes("Device Catalog")).toEqual(true);
expect(container.html().includes("iPhones")).toEqual(true);
expect(container.find('a[href="/iphones"]').length).toEqual(1);
expect(container.html().includes("Watches")).toEqual(true);
expect(container.find('a[href="/watches"]').length).toEqual(1);
});
});
Loading