Skip to content

Commit

Permalink
✨ Fetch Contributors using getStaticProps (#828)
Browse files Browse the repository at this point in the history
  • Loading branch information
carloscuesta committed Aug 1, 2021
1 parent 0a253f7 commit 48042f4
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 43 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -26,6 +26,7 @@
"husky": "^7.0.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.0.1",
"jest-fetch-mock": "^3.0.3",
"jsonlint": "^1.6.3",
"lint-staged": "^11.0.0",
"next": "^11.0.0",
Expand Down
16 changes: 15 additions & 1 deletion src/__tests__/__snapshots__/pages.spec.js.snap
Expand Up @@ -469,7 +469,21 @@ exports[`Pages Contributors should render the page 1`] = `
</h1>
<div
className="row center-xs"
/>
>
<article
className="col-xs-3 col-sm-2"
>
<a
href="https://github.com/profile"
target="_blank"
>
<img
className="picture"
src="https://github.com/avatar"
/>
</a>
</article>
</div>
</section>
</main>
`;
Expand Down
26 changes: 24 additions & 2 deletions src/__tests__/pages.spec.js
@@ -1,9 +1,12 @@
import renderer from 'react-test-renderer'
import { enableFetchMocks } from 'jest-fetch-mock'

import App from '../pages/_app'
import Index from '../pages/index'
import About from '../pages/about'
import Contributors from '../pages/contributors'
import Contributors, {
getStaticProps as getContributorsStaticProps,
} from '../pages/contributors'
import RelatedTools from '../pages/related-tools'
import GitmojisApi from '../pages/api/gitmojis'
import gitmojisData from '../data/gitmojis.json'
Expand Down Expand Up @@ -44,8 +47,27 @@ describe('Pages', () => {
})

describe('Contributors', () => {
beforeAll(() => {
enableFetchMocks()
})

it('should fetch contributos from GitHub', async () => {
fetch.mockResponseOnce(JSON.stringify(stubs.contributorsMock))

const props = await getContributorsStaticProps()

expect(props).toEqual({
props: {
contributors: stubs.contributors,
},
revalidate: 3600 * 3,
})
})

it('should render the page', () => {
const wrapper = renderer.create(<Contributors />)
const wrapper = renderer.create(
<Contributors contributors={stubs.contributors} />
)
expect(wrapper).toMatchSnapshot()
})
})
Expand Down
17 changes: 17 additions & 0 deletions src/__tests__/stubs.js
Expand Up @@ -16,3 +16,20 @@ export const response = () => {

return response
}

export const contributors = [
{
url: 'https://github.com/profile',
avatar: 'https://github.com/avatar',
id: 'contributor-id-123',
},
]

export const contributorsMock = [
{
html_url: 'https://github.com/profile',
avatar_url: 'https://github.com/avatar',
id: 'contributor-id-123',
login: 'carloscuesta',
},
]
4 changes: 2 additions & 2 deletions src/components/ContributorsList/Contributor/index.js
Expand Up @@ -3,11 +3,11 @@ import React, { type Element } from 'react'

import styles from './styles.module.css'

type Props = { profile: string, avatar: string }
type Props = { avatar: string, url: string }

const Contributor = (props: Props): Element<'article'> => (
<article className="col-xs-3 col-sm-2">
<a href={props.profile}>
<a href={props.url} target="_blank">
<img className={styles.picture} src={props.avatar} />
</a>
</article>
Expand Down
Expand Up @@ -5,11 +5,10 @@ exports[`ContributorsList Contributor should render the component 1`] = `
className="col-xs-3 col-sm-2"
>
<a
href="https://github.com/profile"
target="_blank"
>
<img
className="picture"
src="https://github.com/avatar"
/>
</a>
</article>
Expand All @@ -18,5 +17,19 @@ exports[`ContributorsList Contributor should render the component 1`] = `
exports[`ContributorsList should render the component 1`] = `
<div
className="row center-xs"
/>
>
<article
className="col-xs-3 col-sm-2"
>
<a
href="https://github.com/profile"
target="_blank"
>
<img
className="picture"
src="https://github.com/avatar"
/>
</a>
</article>
</div>
`;
Expand Up @@ -7,13 +7,15 @@ import * as stubs from './stubs'
describe('ContributorsList', () => {
describe('Contributor', () => {
it('should render the component', () => {
const wrapper = renderer.create(<Contributor {...stubs.props} />)
const wrapper = renderer.create(
<Contributor contributor={stubs.contributor} />
)
expect(wrapper).toMatchSnapshot()
})
})

it('should render the component', () => {
const wrapper = renderer.create(<ContributorsList />)
const wrapper = renderer.create(<ContributorsList {...stubs.props} />)
expect(wrapper).toMatchSnapshot()
})
})
9 changes: 7 additions & 2 deletions src/components/ContributorsList/__tests__/stubs.js
@@ -1,4 +1,9 @@
export const props = {
profile: 'https://github.com/profile',
export const contributor = {
url: 'https://github.com/profile',
avatar: 'https://github.com/avatar',
id: 'contributor-id-123',
}

export const props = {
contributors: [contributor],
}
47 changes: 18 additions & 29 deletions src/components/ContributorsList/index.js
Expand Up @@ -3,35 +3,24 @@ import React, { type Element } from 'react'

import Contributor from './Contributor'

const ContributorsList = (): Element<'div'> => {
const [contributors, setContributors] = React.useState([])

React.useEffect(() => {
const fetchContributors = async () => {
const response = await fetch(
'https://api.github.com/repos/carloscuesta/gitmoji/contributors'
)
const contributors = await response.json()

setContributors(
contributors.filter((contributor) => !contributor.login.includes('bot'))
)
}

fetchContributors()
}, [])

return (
<div className="row center-xs">
{contributors.map((contributor) => (
<Contributor
key={contributor.id}
profile={contributor.html_url}
avatar={contributor.avatar_url}
/>
))}
</div>
)
type Props = {
contributors: Array<{
avatar: string,
id: string,
url: string,
}>,
}

const ContributorsList = (props: Props): Element<'div'> => (
<div className="row center-xs">
{props.contributors.map((contributor) => (
<Contributor
key={contributor.id}
url={contributor.url}
avatar={contributor.avatar}
/>
))}
</div>
)

export default ContributorsList
28 changes: 26 additions & 2 deletions src/pages/contributors.js
Expand Up @@ -4,7 +4,11 @@ import ContributorsList from 'src/components/ContributorsList'
import CarbonAd from 'src/components/CarbonAd'
import SEO from 'src/components/SEO'

const Contributors = () => (
type Props = {
contributors: Array<{ avatar: string, url: string, id: string }>,
}

const Contributors = (props: Props) => (
<>
<SEO pageTitle="Contributors" pageUrl="/contributors" />

Expand All @@ -13,10 +17,30 @@ const Contributors = () => (
<section>
<h1>Contributors</h1>

<ContributorsList />
<ContributorsList contributors={props.contributors} />
</section>
</main>
</>
)

export const getStaticProps = async (): Promise<Props> => {
const response = await fetch(
'https://api.github.com/repos/carloscuesta/gitmoji/contributors'
)
const contributors = await response.json()

return {
props: {
contributors: contributors
.filter((contributor) => !contributor.login.includes('bot'))
.map((contributor) => ({
avatar: contributor.avatar_url,
id: contributor.id,
url: contributor.html_url,
})),
},
revalidate: 3600 * 3,
}
}

export default Contributors
20 changes: 20 additions & 0 deletions yarn.lock
Expand Up @@ -1598,6 +1598,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"

cross-fetch@^3.0.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==
dependencies:
node-fetch "2.6.1"

cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
Expand Down Expand Up @@ -2698,6 +2705,14 @@ jest-environment-node@^27.0.6:
jest-mock "^27.0.6"
jest-util "^27.0.6"

jest-fetch-mock@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b"
integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==
dependencies:
cross-fetch "^3.0.4"
promise-polyfill "^8.1.3"

jest-get-type@^27.0.6:
version "27.0.6"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe"
Expand Down Expand Up @@ -3718,6 +3733,11 @@ process@0.11.10, process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=

promise-polyfill@^8.1.3:
version "8.2.0"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.0.tgz#367394726da7561457aba2133c9ceefbd6267da0"
integrity sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==

prompts@^2.0.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.2.1.tgz#f901dd2a2dfee080359c0e20059b24188d75ad35"
Expand Down

1 comment on commit 48042f4

@vercel
Copy link

@vercel vercel bot commented on 48042f4 Aug 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.