Skip to content

Commit

Permalink
feat(gatsby): Track static queries by template (#25120)
Browse files Browse the repository at this point in the history
Avoid single char names

Sort at traversal time

Refactor reduce to forEach

Refactor another reduce to forEach

Fix type check
  • Loading branch information
sidharthachatterjee authored Jul 2, 2020
1 parent fae19ac commit 6b39645
Show file tree
Hide file tree
Showing 35 changed files with 785 additions and 8 deletions.
8 changes: 8 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ jobs:
- e2e-test:
test_path: integration-tests/structured-logging

integration_tests_artifacts:
executor: node
steps:
- e2e-test:
test_path: integration-tests/artifacts

e2e_tests_path-prefix:
<<: *e2e-executor
environment:
Expand Down Expand Up @@ -570,6 +576,8 @@ workflows:
<<: *e2e-test-workflow
- integration_tests_structured_logging:
<<: *e2e-test-workflow
- integration_tests_artifacts:
<<: *e2e-test-workflow
- integration_tests_gatsby_cli:
requires:
- bootstrap
Expand Down
21 changes: 21 additions & 0 deletions integration-tests/artifacts/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 gatsbyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 3 additions & 0 deletions integration-tests/artifacts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Artifacts test suite

This integration test suite helps us assert some of the artifacts written out for a Gatsby build. The test suite runs a real Gatsby build and then checks the generated `public` directory for `page-data.json` files. Since we added static query hashes to `page-data.json` files, the tests in this suite assert whether the correct static query hashes are included in every respective page.
173 changes: 173 additions & 0 deletions integration-tests/artifacts/__tests__/static-queries.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
const { spawn } = require(`child_process`)
const path = require(`path`)
const { murmurhash } = require(`babel-plugin-remove-graphql-queries`)
const { readPageData } = require(`gatsby/dist/utils/page-data`)
const { stripIgnoredCharacters } = require(`gatsby/graphql`)

jest.setTimeout(100000)

const publicDir = path.join(process.cwd(), `public`)

const gatsbyBin = path.join(`node_modules`, `.bin`, `gatsby`)

const titleQuery = `
{
site {
siteMetadata {
title
}
}
}
`

const authorQuery = `
{
site {
siteMetadata {
author
}
}
}
`

const githubQuery = `
{
site {
siteMetadata {
github
}
}
}
`

function hashQuery(query) {
const text = stripIgnoredCharacters(query)
const hash = murmurhash(text, `abc`)
return String(hash)
}

const globalQueries = [githubQuery]

describe(`Static Queries`, () => {
beforeAll(async done => {
const gatsbyProcess = spawn(gatsbyBin, [`build`], {
stdio: [`inherit`, `inherit`, `inherit`, `inherit`],
env: {
...process.env,
NODE_ENV: `production`,
},
})

gatsbyProcess.on(`exit`, exitCode => {
done()
})
})

test(`are written correctly when inline`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/inline/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when imported`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/import/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when dynamically imported`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/dynamic/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly in jsx`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/jsx/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly in tsx`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/tsx/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly in typescript`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/typescript/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when nesting imports`, async () => {
const queries = [titleQuery, authorQuery, ...globalQueries]
const pagePath = `/import-import/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when nesting dynamic imports`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/dynamic-dynamic/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when nesting a dynamic import in a regular import`, async () => {
const queries = [titleQuery, authorQuery, ...globalQueries]
const pagePath = `/import-dynamic/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

test(`are written correctly when nesting a regular import in a dynamic import`, async () => {
const queries = [titleQuery, ...globalQueries]
const pagePath = `/dynamic-import/`

const { staticQueryHashes } = await readPageData(publicDir, pagePath)

expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
})

// test(`are written correctly when using wrapRootElement`, async () => {
// const queries = [titleQuery]
// const pagePath = `/dynamic-import/`

// const { staticQueryHashes } = await readPageData(publicDir, pagePath)

// expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
// })

// test(`are written correctly when using wrapPageElement`, async () => {
// const queries = [titleQuery]
// const pagePath = `/dynamic-import/`

// const { staticQueryHashes } = await readPageData(publicDir, pagePath)

// expect(staticQueryHashes.sort()).toEqual(queries.map(hashQuery).sort())
// })
})
9 changes: 9 additions & 0 deletions integration-tests/artifacts/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const React = require(`react`)
const Github = require(`./src/components/github`).default

exports.wrapPageElement = ({ element }) => (
<>
<Github />
{element}
</>
)
9 changes: 9 additions & 0 deletions integration-tests/artifacts/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
siteMetadata: {
title: `Hello world`,
author: `Sid Chatterjee`,
twitter: `chatsidhartha`,
github: `sidharthachatterjee`,
},
plugins: [],
}
Empty file.
3 changes: 3 additions & 0 deletions integration-tests/artifacts/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
testPathIgnorePatterns: [`/node_modules/`, `__tests__/fixtures`, `.cache`],
}
32 changes: 32 additions & 0 deletions integration-tests/artifacts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "artifacts",
"private": true,
"author": "Sid Chatterjee",
"description": "A simplified bare-bones starter for Gatsby",
"version": "0.1.0",
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "jest --config=jest.config.js --runInBand"
},
"dependencies": {
"gatsby": "^2.22.0",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"devDependencies": {
"fs-extra": "^9.0.0",
"jest": "^24.0.0",
"jest-cli": "^24.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-hello-world"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}
15 changes: 15 additions & 0 deletions integration-tests/artifacts/src/components/author.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import { useStaticQuery, graphql } from "gatsby"

export default function Author() {
const { site } = useStaticQuery(graphql`
{
site {
siteMetadata {
author
}
}
}
`)
return <div>{site.siteMetadata.author}</div>
}
15 changes: 15 additions & 0 deletions integration-tests/artifacts/src/components/github.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import { useStaticQuery, graphql } from "gatsby"

export default function Github() {
const { site } = useStaticQuery(graphql`
{
site {
siteMetadata {
github
}
}
}
`)
return <div>{site.siteMetadata.github}</div>
}
7 changes: 7 additions & 0 deletions integration-tests/artifacts/src/components/title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react"
import { useTitle } from "../hooks/use-title"

export default function Title() {
const title = useTitle()
return <div>{title}</div>
}
15 changes: 15 additions & 0 deletions integration-tests/artifacts/src/components/twitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import { useStaticQuery, graphql } from "gatsby"

export default function Twitter() {
const { site } = useStaticQuery(graphql`
{
site {
siteMetadata {
twitter
}
}
}
`)
return <div>{site.siteMetadata.twitter}</div>
}
14 changes: 14 additions & 0 deletions integration-tests/artifacts/src/hooks/use-title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useStaticQuery, graphql } from "gatsby"

export const useTitle = () => {
const { site } = useStaticQuery(graphql`
{
site {
siteMetadata {
title
}
}
}
`)
return site.siteMetadata.title
}
17 changes: 17 additions & 0 deletions integration-tests/artifacts/src/pages/dynamic-dynamic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { Component } from "react"

export default class Dynamic extends Component {
constructor(props) {
super(props)
this.state = { module: null }
}
componentDidMount() {
import(`../pages/dynamic`).then(module =>
this.setState({ module: module.default })
)
}
render() {
const { module: Component } = this.state
return <div>{Component && <Component />}</div>
}
}
17 changes: 17 additions & 0 deletions integration-tests/artifacts/src/pages/dynamic-import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { Component } from "react"

export default class Dynamic extends Component {
constructor(props) {
super(props)
this.state = { module: null }
}
componentDidMount() {
import(`../pages/import`).then(module =>
this.setState({ module: module.default })
)
}
render() {
const { module: Component } = this.state
return <div>{Component && <Component />}</div>
}
}
Loading

0 comments on commit 6b39645

Please sign in to comment.