Skip to content

Commit 7c45c51

Browse files
committed
First commit
1 parent 235047e commit 7c45c51

File tree

12 files changed

+12533
-55
lines changed

12 files changed

+12533
-55
lines changed

package-lock.json

Lines changed: 12177 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,23 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"@testing-library/react": "^9.1.0",
7+
"apollo-cache-inmemory": "^1.6.3",
8+
"apollo-client": "^2.6.4",
9+
"apollo-link": "^1.2.12",
10+
"apollo-link-context": "^1.0.18",
11+
"apollo-link-error": "^1.1.11",
12+
"apollo-link-http": "^1.5.15",
13+
"apollo-link-schema": "^1.2.3",
14+
"deepmerge": "^4.0.0",
15+
"faker": "^4.1.0",
16+
"graphql": "^14.4.2",
17+
"graphql-anywhere": "^4.2.4",
18+
"graphql-tag": "^2.10.1",
19+
"graphql-tools": "^4.0.5",
20+
"graphql.macro": "^1.4.2",
621
"react": "^16.9.0",
22+
"react-apollo": "^3.0.0",
723
"react-dom": "^16.9.0",
824
"react-scripts": "3.1.0"
925
},

src/App.css

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
1-
.App {
2-
text-align: center;
1+
body {
2+
background-color: #f5f5f5;
33
}
44

5-
.App-logo {
6-
animation: App-logo-spin infinite 20s linear;
7-
height: 40vmin;
8-
pointer-events: none;
5+
.c-repository {
6+
margin: 15px;
7+
padding: 10px;
8+
background-color: white;
9+
border: 1px #e5e5e5;
10+
border-style: solid;
11+
max-width: 800px;
912
}
1013

11-
.App-header {
12-
background-color: #282c34;
13-
min-height: 100vh;
14+
.c-repository__row {
15+
padding: 5px;
16+
border: #bbbbbb 1px solid;
17+
}
18+
19+
.c-repository__row + .c-repository__row {
20+
border-top: none;
21+
}
22+
23+
.c-issue {
1424
display: flex;
15-
flex-direction: column;
1625
align-items: center;
17-
justify-content: center;
18-
font-size: calc(10px + 2vmin);
19-
color: white;
2026
}
2127

22-
.App-link {
23-
color: #61dafb;
28+
.c-issue div + div {
29+
margin-left: 5px;
30+
}
31+
32+
.c-issue-icon {
33+
min-width: 5px;
34+
height: 15px;
35+
width: 15px;
36+
background-color: #bbb;
37+
border-radius: 50%;
38+
}
39+
40+
.c-issue-icon--open {
41+
background-color: green;
2442
}
2543

26-
@keyframes App-logo-spin {
27-
from {
28-
transform: rotate(0deg);
29-
}
30-
to {
31-
transform: rotate(360deg);
32-
}
44+
.c-issue-icon--closed {
45+
background-color: red;
3346
}

src/App.js

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,14 @@
1-
import React from 'react';
2-
import logo from './logo.svg';
3-
import './App.css';
1+
import React from "react";
2+
import "./App.css";
3+
import Repository from "./Repository";
4+
import ApolloMockingProvider from "./mocking/ApolloMockingProvider";
45

56
function App() {
67
return (
78
<div className="App">
8-
<header className="App-header">
9-
<img src={logo} className="App-logo" alt="logo" />
10-
<p>
11-
Edit <code>src/App.js</code> and save to reload.
12-
</p>
13-
<a
14-
className="App-link"
15-
href="https://reactjs.org"
16-
target="_blank"
17-
rel="noopener noreferrer"
18-
>
19-
Learn React
20-
</a>
21-
</header>
9+
<ApolloMockingProvider customResolvers={{}}>
10+
<Repository ghId={111} />
11+
</ApolloMockingProvider>
2212
</div>
2313
);
2414
}

src/App.test.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/Repository.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import React from "react";
2+
import gql from "graphql-tag";
3+
import { Query } from "react-apollo";
4+
5+
const gqlQuery = ghId => {
6+
return gql`
7+
{
8+
repositoryByGhId(ghId: ${ghId}) {
9+
ghId
10+
name
11+
description
12+
isPrivate
13+
updatedAt
14+
issues {
15+
number
16+
title
17+
state
18+
}
19+
}
20+
}
21+
`;
22+
};
23+
24+
function Issue({ title, number, state }) {
25+
return (
26+
<div className="c-issue">
27+
<div className={`c-issue-icon c-issue-icon--${state}`} />
28+
<div>#{number}</div>
29+
<div>{title}</div>
30+
</div>
31+
);
32+
}
33+
34+
function Repository({ ghId }) {
35+
return (
36+
<Query query={gqlQuery(ghId)}>
37+
{({ data, error, loading }) => {
38+
if (error) {
39+
console.error("There is an gql error ", error);
40+
}
41+
42+
if (loading) {
43+
return <div>Loading...</div>;
44+
}
45+
46+
const { name, description, isPrivate, updatedAt, issues } = data.repositoryByGhId;
47+
48+
return (
49+
<div className="c-repository">
50+
<h1>Repository {ghId}</h1>
51+
<div className="c-repository__row">
52+
<strong>Name: </strong>
53+
{name}
54+
</div>
55+
<div className="c-repository__row">
56+
<strong>Description: </strong>
57+
{description}
58+
</div>
59+
<div className="c-repository__row">
60+
<strong>Visibility: </strong>
61+
{isPrivate ? "Private" : "Public"}
62+
</div>
63+
<div className="c-repository__row">
64+
<strong>Last modified: </strong>
65+
{updatedAt.toLocaleDateString()}{" "}
66+
</div>
67+
<div className="c-repository__row">
68+
<strong>Issues: </strong>
69+
<ul>
70+
{issues.map(issue => (
71+
<li key={issue.number}>
72+
<Issue {...issue} />
73+
</li>
74+
))}
75+
</ul>
76+
</div>
77+
</div>
78+
);
79+
}}
80+
</Query>
81+
);
82+
}
83+
84+
export default Repository;

src/Repository.test.jsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "react";
2+
import Repository from "./Repository";
3+
import { render } from "./mocking/ApolloMockingProvider";
4+
5+
const zenhubRepo = {
6+
Repository: () => ({
7+
name: 'ZenHubHQ'
8+
})
9+
};
10+
11+
const threeIssues = {
12+
Repository: () => ({
13+
issues: [{ number: 1, title: "Issue 1" }, { number:2, title: "Issue 2" }, { number:3, title: "Issue 3" }]
14+
}),
15+
};
16+
17+
describe("<Repository />", () => {
18+
test("renders repository name", async () => {
19+
const { findByText } = render(<Repository ghId={1} />, zenhubRepo);
20+
21+
await findByText("ZenHubHQ");
22+
});
23+
24+
test("renders a list of issues", async () => {
25+
const { findByText } = render(<Repository ghId={1} />, threeIssues);
26+
27+
await findByText("Issue 1");
28+
await findByText("Issue 2");
29+
await findByText("Issue 3");
30+
});
31+
});

src/logo.svg

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import * as ReactTestingLibrary from "@testing-library/react";
4+
5+
import { loader } from "graphql.macro";
6+
import { makeExecutableSchema, addMockFunctionsToSchema } from "graphql-tools";
7+
8+
import { ApolloClient } from "apollo-client";
9+
import { InMemoryCache } from "apollo-cache-inmemory";
10+
import { ApolloProvider } from "react-apollo";
11+
import { SchemaLink } from "apollo-link-schema";
12+
13+
import generalMocks from "./generalMocks";
14+
import mergeResolvers from "./mergeResolvers";
15+
16+
const ApplicationSchema = loader("./schema.graphql");
17+
18+
// For queries with no variables
19+
const schema = makeExecutableSchema({ typeDefs: ApplicationSchema });
20+
21+
const ApolloMockingProvider = ({ children, customResolvers }) => {
22+
const mocks = mergeResolvers([generalMocks, customResolvers]);
23+
24+
addMockFunctionsToSchema({ schema, mocks });
25+
26+
const client = new ApolloClient({
27+
link: new SchemaLink({ schema }),
28+
cache: new InMemoryCache()
29+
});
30+
31+
return <ApolloProvider client={client}>{children}</ApolloProvider>;
32+
};
33+
34+
ApolloMockingProvider.propTypes = {
35+
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
36+
customResolvers: PropTypes.shape({})
37+
};
38+
39+
ApolloMockingProvider.defaultProps = {
40+
customResolvers: null
41+
};
42+
43+
const render = (comp, customResolvers, options) => {
44+
return ReactTestingLibrary.render(
45+
<ApolloMockingProvider customResolvers={customResolvers || {}}>
46+
{comp}
47+
</ApolloMockingProvider>,
48+
options
49+
);
50+
};
51+
52+
export default ApolloMockingProvider;
53+
export { render };

src/mocking/generalMocks.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import faker from "faker";
2+
3+
// Random data are bad to debug flaky tests
4+
faker.seed(12345);
5+
6+
let idIncrement = 0;
7+
8+
function getNextId() {
9+
idIncrement += 1;
10+
return idIncrement;
11+
}
12+
13+
const formatRepoName = str => {
14+
return (
15+
str
16+
// Replace all weird chars by -
17+
.replace(/-|,|_|\s/g, "-")
18+
// Replace a serie of - by a single one
19+
.replace(/--+/g, "-")
20+
);
21+
};
22+
23+
const jan2019 = new Date(1546510000000);
24+
25+
const resolvers = {
26+
ISO8601DateTime: () => jan2019,
27+
Repository: () => ({
28+
ghId: getNextId,
29+
name: formatRepoName(faker.commerce.productName()),
30+
description: faker.company.catchPhrase()
31+
}),
32+
Issue: () => ({
33+
number: getNextId,
34+
title: () => faker.hacker.phrase(),
35+
state: () => (Math.random() > 0.5 ? "open" : "closed")
36+
})
37+
};
38+
39+
export default resolvers;

0 commit comments

Comments
 (0)