WIP - add extractor, generate snippet_data

This commit is contained in:
Stefan Fejes
2019-08-20 15:52:05 +02:00
parent 88084d3d30
commit cc8f1d8a7a
37396 changed files with 4588842 additions and 133 deletions

5
node_modules/gatsby/cache-dir/__tests__/.babelrc generated vendored Normal file
View File

@ -0,0 +1,5 @@
{
"presets": [
["babel-preset-gatsby"]
]
}

View File

@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Dev loader loadPage should be successful when component can be loaded 1`] = `
Object {
"component": "instance",
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/mypage/",
"webpackCompilationHash": "123",
},
}
`;
exports[`Dev loader loadPage should load matchPath pageData if current page returns notFound 1`] = `
Object {
"component": [Function],
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/app/",
"webpackCompilationHash": "123",
},
}
`;
exports[`Dev loader loadPage should load page path first before falling back to matchPath 1`] = `
Object {
"component": [Function],
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/app/login/",
"webpackCompilationHash": "123",
},
}
`;

View File

@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Production loader loadPage should be successful when component can be loaded 1`] = `
Object {
"component": "instance",
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/mypage/",
"webpackCompilationHash": "123",
},
}
`;
exports[`Production loader loadPage should load matchPath pageData if current page returns notFound 1`] = `
Object {
"component": "instance",
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/app/",
"webpackCompilationHash": "123",
},
}
`;
exports[`Production loader loadPage should load page path first before falling back to matchPath 1`] = `
Object {
"component": "instance",
"json": Object {
"pageContext": "something something",
},
"page": Object {
"componentChunkName": "chunk",
"matchPath": undefined,
"path": "/app/login/",
"webpackCompilationHash": "123",
},
}
`;

View File

@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`develop-static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><style> .style3 </style><style> .style2 </style><style> .style1 </style><meta name=\\"note\\" content=\\"environment=development\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
exports[`develop-static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"note\\" content=\\"environment=development\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><div> div3 </div><div> div2 </div><div> div1 </div><script src=\\"/commons.js\\"></script></body></html>"`;
exports[`develop-static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"note\\" content=\\"environment=development\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><div> div3 </div><div> div2 </div><div> div1 </div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
exports[`static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><link as=\\"fetch\\" rel=\\"preload\\" href=\\"/page-data/about/page-data.json\\" crossorigin=\\"anonymous\\"/><style> .style3 </style><style> .style2 </style><style> .style1 </style><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\" id=\\"gatsby-focus-wrapper\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.pagePath=\\"/about/\\";window.webpackCompilationHash=\\"1234567890abcdef1234\\";/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;
exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/><link as=\\"fetch\\" rel=\\"preload\\" href=\\"/page-data/about/page-data.json\\" crossorigin=\\"anonymous\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\" id=\\"gatsby-focus-wrapper\\"></div></div><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.pagePath=\\"/about/\\";window.webpackCompilationHash=\\"1234567890abcdef1234\\";/*]]>*/</script><div> div3 </div><div> div2 </div><div> div1 </div></body></html>"`;
exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/><link as=\\"fetch\\" rel=\\"preload\\" href=\\"/page-data/about/page-data.json\\" crossorigin=\\"anonymous\\"/></head><body><div> div3 </div><div> div2 </div><div> div1 </div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\" id=\\"gatsby-focus-wrapper\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.pagePath=\\"/about/\\";window.webpackCompilationHash=\\"1234567890abcdef1234\\";/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;

612
node_modules/gatsby/cache-dir/__tests__/dev-loader.js generated vendored Normal file
View File

@ -0,0 +1,612 @@
// This is by no means a full test file for loader.js so feel free to add more tests.
import mock from "xhr-mock"
import DevLoader from "../dev-loader"
import emitter from "../emitter"
jest.mock(`../emitter`)
jest.mock(`../socketIo`, () => {
return {
default: jest.fn(),
getPageData: jest.fn(),
}
})
describe(`Dev loader`, () => {
describe(`loadPageDataJson`, () => {
let originalBasePath
let originalPathPrefix
let xhrCount
/**
* @param {string} path
* @param {number} status
* @param {string|Object?} responseText
* @param {boolean?} json
*/
const mockPageData = (path, status, responseText = ``, json = false) => {
mock.get(`/page-data${path}/page-data.json`, (req, res) => {
xhrCount++
if (json) {
res.header(`content-type`, `application/json`)
}
return res
.status(status)
.body(
typeof responseText === `string`
? responseText
: JSON.stringify(responseText)
)
})
}
const defaultPayload = {
path: `/mypage/`,
webpackCompilationHash: `1234`,
}
// replace the real XHR object with the mock XHR object before each test
beforeEach(() => {
originalBasePath = global.__BASE_PATH__
originalPathPrefix = global.__PATH_PREFIX__
global.__BASE_PATH__ = ``
global.__PATH_PREFIX__ = ``
xhrCount = 0
mock.setup()
})
// put the real XHR object back and clear the mocks after each test
afterEach(() => {
global.__BASE_PATH__ = originalBasePath
global.__PATH_PREFIX__ = originalPathPrefix
mock.teardown()
})
it(`should return a pageData json on success`, async () => {
const devLoader = new DevLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload, true)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload: defaultPayload,
}
expect(await devLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(devLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should return a pageData json on success without contentType`, async () => {
const devLoader = new DevLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload: defaultPayload,
}
expect(await devLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(devLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should return a pageData json with an empty compilation hash (gatsby develop)`, async () => {
const devLoader = new DevLoader(null, [])
const payload = { ...defaultPayload, webpackCompilationHash: `` }
mockPageData(`/mypage`, 200, payload)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload,
}
expect(await devLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(devLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should load a 404 page when page-path file is not a gatsby json`, async () => {
const devLoader = new DevLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200, { random: `string` }, true)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await devLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should load a 404 page when page-path file is not a json`, async () => {
const devLoader = new DevLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await devLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should load a 404 page when path returns a 404`, async () => {
const devLoader = new DevLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await devLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should return the dev-404-page when no 404 page can be found`, async () => {
const devLoader = new DevLoader(null, [])
const payload = { ...defaultPayload, path: `/dev-404-page/` }
mockPageData(`/unknown-page`, 404)
mockPageData(`/404.html`, 404)
mockPageData(`/dev-404-page`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/dev-404-page`,
notFound: true,
payload,
}
expect(await devLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/unknown-page`)).toEqual({
notFound: true,
pagePath: `/404.html`,
status: `failure`,
})
expect(xhrCount).toBe(3)
})
it(`should return an error when status is 500`, async () => {
const devLoader = new DevLoader(null, [])
mockPageData(`/error-page`, 500)
const expectation = {
status: `error`,
pagePath: `/error-page`,
}
expect(await devLoader.loadPageDataJson(`/error-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/error-page`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should retry 3 times before returning an error`, async () => {
const devLoader = new DevLoader(null, [])
mockPageData(`/blocked-page`, 0)
const expectation = {
status: `error`,
retries: 3,
pagePath: `/blocked-page`,
}
expect(await devLoader.loadPageDataJson(`/blocked-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/blocked-page`)).toEqual(expectation)
expect(xhrCount).toBe(4)
})
it(`should recover if we get 1 failure`, async () => {
const devLoader = new DevLoader(null, [])
const payload = {
path: `/blocked-page/`,
webpackCompilationHash: `1234`,
}
let xhrCount = 0
mock.get(`/page-data/blocked-page/page-data.json`, (req, res) => {
if (xhrCount++ === 0) {
return res.status(0).body(``)
} else {
res.header(`content-type`, `application/json`)
return res.status(200).body(JSON.stringify(payload))
}
})
const expectation = {
status: `success`,
retries: 1,
pagePath: `/blocked-page`,
payload,
}
expect(await devLoader.loadPageDataJson(`/blocked-page/`)).toEqual(
expectation
)
expect(devLoader.pageDataDb.get(`/blocked-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`shouldn't load pageData multiple times`, async () => {
const devLoader = new DevLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload, true)
const expectation = await devLoader.loadPageDataJson(`/mypage/`)
expect(await devLoader.loadPageDataJson(`/mypage/`)).toBe(expectation)
expect(xhrCount).toBe(1)
})
})
describe(`loadPage`, () => {
const createSyncRequires = components => {
return {
components,
}
}
beforeEach(() => emitter.emit.mockReset())
it(`should be successful when component can be loaded`, async () => {
const syncRequires = createSyncRequires({
chunk: `instance`,
})
const devLoader = new DevLoader(syncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await devLoader.loadPage(`/mypage/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(devLoader.pageDb.get(`/mypage`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation,
pageResources: expectation,
})
})
it(`should load page path first before falling back to matchPath`, async () => {
const syncRequires = createSyncRequires({
chunk: () => `instance`,
})
const prodLoader = new DevLoader(syncRequires, [
{
matchPath: `/app/*`,
path: `/app`,
},
])
const pageData = {
path: `/app/login/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/app/login/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(prodLoader.pageDb.get(`/app/login`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
})
it(`should load matchPath pageData if current page returns notFound`, async () => {
const syncRequires = createSyncRequires({
chunk: () => `instance`,
})
const pageData = {
path: `/app/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
const prodLoader = new DevLoader(syncRequires, [
{
matchPath: `/app/*`,
path: `/app`,
},
])
prodLoader.loadPageDataJson = jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({
notFound: true,
})
)
.mockImplementationOnce(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/app/mypage/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(prodLoader.pageDb.has(`/app/mypage`)).toBe(true)
expect(prodLoader.pageDb.has(`/app`)).toBe(true)
expect(prodLoader.pageDb.get(`/app/mypage`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
expect(prodLoader.loadPageDataJson).toHaveBeenCalledTimes(2)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation,
pageResources: expectation,
})
})
it(`should set not found on finalResult`, async () => {
const syncRequires = createSyncRequires({
chunk: `instance`,
})
const devLoader = new DevLoader(syncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
notFound: true,
})
)
await devLoader.loadPage(`/mypage/`)
const expectation = devLoader.pageDb.get(`/mypage`)
expect(expectation).toHaveProperty(`notFound`, true)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation.payload,
pageResources: expectation.payload,
})
})
it(`should return an error when component cannot be loaded`, async () => {
const syncRequires = createSyncRequires({
chunk: false,
})
const devLoader = new DevLoader(syncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
await devLoader.loadPage(`/mypage/`)
const expectation = devLoader.pageDb.get(`/mypage`)
expect(expectation).toHaveProperty(`status`, `error`)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should return an error pageData contains an error`, async () => {
const syncRequires = createSyncRequires({
chunk: `instance`,
})
const devLoader = new DevLoader(syncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `error`,
})
)
expect(await devLoader.loadPage(`/mypage/`)).toEqual({ status: `error` })
expect(devLoader.pageDb.size).toBe(0)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should throw an error when 404 cannot be fetched`, async () => {
const devLoader = new DevLoader(null, [])
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
status: `failure`,
})
)
try {
await devLoader.loadPage(`/404.html/`)
} catch (err) {
expect(err.message).toEqual(
expect.stringContaining(`404 page could not be found`)
)
}
expect(devLoader.pageDb.size).toBe(0)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should cache the result of loadPage`, async () => {
const syncRequires = createSyncRequires({
chunk: `instance`,
})
const devLoader = new DevLoader(syncRequires, [])
devLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: {
componentChunkName: `chunk`,
},
status: `success`,
})
)
const expectation = await devLoader.loadPage(`/mypage/`)
expect(await devLoader.loadPage(`/mypage/`)).toBe(expectation)
expect(devLoader.loadPageDataJson).toHaveBeenCalledTimes(1)
})
})
describe(`loadPageSync`, () => {
it(`returns page resources when already fetched`, () => {
const devLoader = new DevLoader(null, [])
devLoader.pageDb.set(`/mypage`, { payload: true })
expect(devLoader.loadPageSync(`/mypage/`)).toBe(true)
})
it(`returns page resources when already fetched`, () => {
const devLoader = new DevLoader(null, [])
expect(devLoader.loadPageSync(`/mypage/`)).toBeUndefined()
})
})
describe(`prefetch`, () => {
const flushPromises = () => new Promise(resolve => setImmediate(resolve))
it(`shouldn't prefetch when shouldPrefetch is false`, () => {
const devLoader = new DevLoader(null, [])
devLoader.shouldPrefetch = jest.fn(() => false)
devLoader.doPrefetch = jest.fn()
devLoader.apiRunner = jest.fn()
expect(devLoader.prefetch(`/mypath/`)).toBe(false)
expect(devLoader.shouldPrefetch).toHaveBeenCalledWith(`/mypath/`)
expect(devLoader.apiRunner).not.toHaveBeenCalled()
expect(devLoader.doPrefetch).not.toHaveBeenCalled()
})
it(`should trigger custom prefetch logic when core is disabled`, () => {
const devLoader = new DevLoader(null, [])
devLoader.shouldPrefetch = jest.fn(() => true)
devLoader.doPrefetch = jest.fn()
devLoader.apiRunner = jest.fn()
devLoader.prefetchDisabled = true
expect(devLoader.prefetch(`/mypath/`)).toBe(false)
expect(devLoader.shouldPrefetch).toHaveBeenCalledWith(`/mypath/`)
expect(devLoader.apiRunner).toHaveBeenCalledWith(`onPrefetchPathname`, {
pathname: `/mypath/`,
})
expect(devLoader.doPrefetch).not.toHaveBeenCalled()
})
it(`should prefetch when not yet triggered`, async () => {
jest.useFakeTimers()
const devLoader = new DevLoader(null, [])
devLoader.shouldPrefetch = jest.fn(() => true)
devLoader.apiRunner = jest.fn()
devLoader.doPrefetch = jest.fn(() => Promise.resolve({}))
expect(devLoader.prefetch(`/mypath/`)).toBe(true)
// wait for doPrefetchPromise
await flushPromises()
expect(devLoader.apiRunner).toHaveBeenCalledWith(`onPrefetchPathname`, {
pathname: `/mypath/`,
})
expect(devLoader.apiRunner).toHaveBeenNthCalledWith(
2,
`onPostPrefetchPathname`,
{
pathname: `/mypath/`,
}
)
})
it(`should only run apis once`, async () => {
const devLoader = new DevLoader(null, [])
devLoader.shouldPrefetch = jest.fn(() => true)
devLoader.apiRunner = jest.fn()
devLoader.doPrefetch = jest.fn(() => Promise.resolve({}))
expect(devLoader.prefetch(`/mypath/`)).toBe(true)
expect(devLoader.prefetch(`/mypath/`)).toBe(true)
// wait for doPrefetchPromise
await flushPromises()
expect(devLoader.apiRunner).toHaveBeenCalledTimes(2)
expect(devLoader.apiRunner).toHaveBeenNthCalledWith(
1,
`onPrefetchPathname`,
expect.anything()
)
expect(devLoader.apiRunner).toHaveBeenNthCalledWith(
2,
`onPostPrefetchPathname`,
expect.anything()
)
})
})
})

View File

@ -0,0 +1,59 @@
import "@babel/polyfill"
const {
reportError,
clearError,
errorMap,
} = require(`../error-overlay-handler`)
import * as ErrorOverlay from "react-error-overlay"
jest.mock(`react-error-overlay`, () => {
return {
reportBuildError: jest.fn(),
dismissBuildError: jest.fn(),
startReportingRuntimeErrors: jest.fn(),
setEditorHandler: jest.fn(),
}
})
beforeEach(() => {
ErrorOverlay.reportBuildError.mockClear()
ErrorOverlay.dismissBuildError.mockClear()
})
describe(`errorOverlayHandler`, () => {
describe(`clearError()`, () => {
beforeEach(() => {
reportError(`foo`, `error`)
reportError(`bar`, `error`)
})
afterAll(() => {
clearError(`foo`)
clearError(`bar`)
})
it(`should clear specific error type`, () => {
expect(Object.keys(errorMap)).toHaveLength(2)
clearError(`foo`)
expect(Object.keys(errorMap)).toHaveLength(1)
expect(ErrorOverlay.dismissBuildError).not.toHaveBeenCalled()
})
it(`should call ErrorOverlay to dismiss build errors`, () => {
clearError(`foo`)
clearError(`bar`)
expect(ErrorOverlay.dismissBuildError).toHaveBeenCalled()
})
})
describe(`reportErrorOverlay()`, () => {
it(`should not add error if it's empty and not call ErrorOverlay`, () => {
reportError(`foo`, null)
expect(Object.keys(errorMap)).toHaveLength(0)
expect(ErrorOverlay.reportBuildError).not.toHaveBeenCalled()
})
it(`should add error if it has a truthy value and call ErrorOverlay`, () => {
reportError(`foo`, `bar`)
expect(Object.keys(errorMap)).toHaveLength(1)
expect(ErrorOverlay.reportBuildError).toHaveBeenCalled()
})
})
})

52
node_modules/gatsby/cache-dir/__tests__/find-path.js generated vendored Normal file
View File

@ -0,0 +1,52 @@
import { cleanPath, findMatchPath, setMatchPaths } from "../find-path"
describe(`find-path`, () => {
describe(`cleanPath`, () => {
beforeEach(() => {
global.__BASE_PATH__ = ``
})
it(`should strip out ? & # from a pathname`, () => {
expect(cleanPath(`/mypath#anchor?gatsby=cool`)).toBe(`/mypath`)
})
it(`should convert a /index.html to root dir`, () => {
expect(cleanPath(`/index.html`)).toBe(`/`)
})
it(`strip out a basePrefix`, () => {
global.__BASE_PATH__ = `/blog`
expect(cleanPath(`/blog/mypath`)).toBe(`/mypath`)
})
})
describe(`findMatchPath`, () => {
beforeEach(() => {
// reset matchPaths
setMatchPaths([])
global.__BASE_PATH__ = ``
})
it(`should find a path when matchPath found`, () => {
setMatchPaths([
{
matchPath: `/app/*`,
path: `/app`,
},
])
expect(findMatchPath(`/app/dynamic-page#anchor?gatsby=cool`)).toBe(`/app`)
})
it(`should return null when no matchPathFound`, () => {
setMatchPaths([
{
matchPath: `/app/*`,
path: `/app`,
},
])
expect(findMatchPath(`/notanapp/dynamic-page`)).toBeNull()
})
})
})

627
node_modules/gatsby/cache-dir/__tests__/loader.js generated vendored Normal file
View File

@ -0,0 +1,627 @@
// This is by no means a full test file for loader.js so feel free to add more tests.
import mock from "xhr-mock"
import { ProdLoader } from "../loader"
import emitter from "../emitter"
jest.mock(`../emitter`)
describe(`Production loader`, () => {
describe(`loadPageDataJson`, () => {
let originalBasePath
let originalPathPrefix
let xhrCount
/**
* @param {string} path
* @param {number} status
* @param {string|Object?} responseText
* @param {boolean?} json
*/
const mockPageData = (path, status, responseText = ``, json = false) => {
mock.get(`/page-data${path}/page-data.json`, (req, res) => {
xhrCount++
if (json) {
res.header(`content-type`, `application/json`)
}
return res
.status(status)
.body(
typeof responseText === `string`
? responseText
: JSON.stringify(responseText)
)
})
}
const defaultPayload = {
path: `/mypage/`,
webpackCompilationHash: `1234`,
}
// replace the real XHR object with the mock XHR object before each test
beforeEach(() => {
originalBasePath = global.__BASE_PATH__
originalPathPrefix = global.__PATH_PREFIX__
global.__BASE_PATH__ = ``
global.__PATH_PREFIX__ = ``
xhrCount = 0
mock.setup()
})
// put the real XHR object back and clear the mocks after each test
afterEach(() => {
global.__BASE_PATH__ = originalBasePath
global.__PATH_PREFIX__ = originalPathPrefix
mock.teardown()
})
it(`should return a pageData json on success`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload, true)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload: defaultPayload,
}
expect(await prodLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(prodLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should return a pageData json on success without contentType`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload: defaultPayload,
}
expect(await prodLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(prodLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should return a pageData json with an empty compilation hash (gatsby develop)`, async () => {
const prodLoader = new ProdLoader(null, [])
const payload = { ...defaultPayload, webpackCompilationHash: `` }
mockPageData(`/mypage`, 200, payload)
const expectation = {
status: `success`,
pagePath: `/mypage`,
payload,
}
expect(await prodLoader.loadPageDataJson(`/mypage/`)).toEqual(expectation)
expect(prodLoader.pageDataDb.get(`/mypage`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should load a 404 page when page-path file is not a gatsby json`, async () => {
const prodLoader = new ProdLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200, { random: `string` }, true)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await prodLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should load a 404 page when page-path file is not a json`, async () => {
const prodLoader = new ProdLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await prodLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should load a 404 page when path returns a 404`, async () => {
const prodLoader = new ProdLoader(null, [])
const payload = { ...defaultPayload, path: `/404.html/` }
mockPageData(`/unknown-page`, 200)
mockPageData(`/404.html`, 200, payload, true)
const expectation = {
status: `success`,
pagePath: `/404.html`,
notFound: true,
payload,
}
expect(await prodLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should return a failure when status is 404 and 404 page is fetched`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/unknown-page`, 404)
mockPageData(`/404.html`, 404)
const expectation = {
status: `failure`,
pagePath: `/404.html`,
notFound: true,
}
expect(await prodLoader.loadPageDataJson(`/unknown-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/unknown-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`should return an error when status is 500`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/error-page`, 500)
const expectation = {
status: `error`,
pagePath: `/error-page`,
}
expect(await prodLoader.loadPageDataJson(`/error-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/error-page`)).toEqual(expectation)
expect(xhrCount).toBe(1)
})
it(`should retry 3 times before returning an error`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/blocked-page`, 0)
const expectation = {
status: `error`,
retries: 3,
pagePath: `/blocked-page`,
}
expect(await prodLoader.loadPageDataJson(`/blocked-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/blocked-page`)).toEqual(expectation)
expect(xhrCount).toBe(4)
})
it(`should recover if we get 1 failure`, async () => {
const prodLoader = new ProdLoader(null, [])
const payload = {
path: `/blocked-page/`,
webpackCompilationHash: `1234`,
}
let xhrCount = 0
mock.get(`/page-data/blocked-page/page-data.json`, (req, res) => {
if (xhrCount++ === 0) {
return res.status(0).body(``)
} else {
res.header(`content-type`, `application/json`)
return res.status(200).body(JSON.stringify(payload))
}
})
const expectation = {
status: `success`,
retries: 1,
pagePath: `/blocked-page`,
payload,
}
expect(await prodLoader.loadPageDataJson(`/blocked-page/`)).toEqual(
expectation
)
expect(prodLoader.pageDataDb.get(`/blocked-page`)).toEqual(expectation)
expect(xhrCount).toBe(2)
})
it(`shouldn't load pageData multiple times`, async () => {
const prodLoader = new ProdLoader(null, [])
mockPageData(`/mypage`, 200, defaultPayload, true)
const expectation = await prodLoader.loadPageDataJson(`/mypage/`)
expect(await prodLoader.loadPageDataJson(`/mypage/`)).toBe(expectation)
expect(xhrCount).toBe(1)
})
})
describe(`loadPage`, () => {
const createAsyncRequires = components => {
return {
components,
}
}
beforeEach(() => emitter.emit.mockReset())
it(`should be successful when component can be loaded`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/mypage/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(prodLoader.pageDb.get(`/mypage`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation,
pageResources: expectation,
})
})
it(`should load page path first before falling back to matchPath`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [
{
matchPath: `/app/*`,
path: `/app`,
},
])
const pageData = {
path: `/app/login/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/app/login/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(prodLoader.pageDb.get(`/app/login`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
})
it(`should load matchPath pageData if current page returns notFound`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const pageData = {
path: `/app/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
result: {
pageContext: `something something`,
},
}
const prodLoader = new ProdLoader(asyncRequires, [
{
matchPath: `/app/*`,
path: `/app`,
},
])
prodLoader.loadPageDataJson = jest
.fn()
.mockImplementationOnce(() =>
Promise.resolve({
notFound: true,
})
)
.mockImplementationOnce(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/app/mypage/`)
expect(expectation).toMatchSnapshot()
expect(Object.keys(expectation)).toEqual([`component`, `json`, `page`])
expect(prodLoader.pageDb.has(`/app/mypage`)).toBe(true)
expect(prodLoader.pageDb.has(`/app`)).toBe(true)
expect(prodLoader.pageDb.get(`/app/mypage`)).toEqual(
expect.objectContaining({
payload: expectation,
status: `success`,
})
)
expect(prodLoader.loadPageDataJson).toHaveBeenCalledTimes(2)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation,
pageResources: expectation,
})
})
it(`should set not found on finalResult`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
notFound: true,
})
)
await prodLoader.loadPage(`/mypage/`)
const expectation = prodLoader.pageDb.get(`/mypage`)
expect(expectation).toHaveProperty(`notFound`, true)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation.payload,
pageResources: expectation.payload,
})
})
it(`should return an error when component cannot be loaded`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(false),
})
const prodLoader = new ProdLoader(asyncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `success`,
})
)
await prodLoader.loadPage(`/mypage/`)
const expectation = prodLoader.pageDb.get(`/mypage`)
expect(expectation).toHaveProperty(`status`, `error`)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should return an error pageData contains an error`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [])
const pageData = {
path: `/mypage/`,
componentChunkName: `chunk`,
webpackCompilationHash: `123`,
}
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: pageData,
status: `error`,
})
)
expect(await prodLoader.loadPage(`/mypage/`)).toEqual({ status: `error` })
expect(prodLoader.pageDb.size).toBe(0)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should throw an error when 404 cannot be fetched`, async () => {
const prodLoader = new ProdLoader(null, [])
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
status: `failure`,
})
)
try {
await prodLoader.loadPage(`/404.html/`)
} catch (err) {
expect(err.message).toEqual(
expect.stringContaining(`404 page could not be found`)
)
}
expect(prodLoader.pageDb.size).toBe(0)
expect(emitter.emit).toHaveBeenCalledTimes(0)
})
it(`should cache the result of loadPage`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [])
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: {
componentChunkName: `chunk`,
},
status: `success`,
})
)
const expectation = await prodLoader.loadPage(`/mypage/`)
expect(await prodLoader.loadPage(`/mypage/`)).toBe(expectation)
expect(prodLoader.loadPageDataJson).toHaveBeenCalledTimes(1)
})
it(`should only run 1 network request even when called multiple times`, async () => {
const asyncRequires = createAsyncRequires({
chunk: () => Promise.resolve(`instance`),
})
const prodLoader = new ProdLoader(asyncRequires, [])
prodLoader.loadPageDataJson = jest.fn(() =>
Promise.resolve({
payload: {
componentChunkName: `chunk`,
},
status: `success`,
})
)
const loadPagePromise = prodLoader.loadPage(`/test-page/`)
expect(prodLoader.inFlightDb.size).toBe(1)
expect(prodLoader.loadPage(`/test-page/`)).toBe(loadPagePromise)
expect(prodLoader.inFlightDb.size).toBe(1)
const expectation = await loadPagePromise
expect(prodLoader.inFlightDb.size).toBe(0)
expect(emitter.emit).toHaveBeenCalledTimes(1)
expect(emitter.emit).toHaveBeenCalledWith(`onPostLoadPageResources`, {
page: expectation,
pageResources: expectation,
})
})
})
describe(`loadPageSync`, () => {
it(`returns page resources when already fetched`, () => {
const prodLoader = new ProdLoader(null, [])
prodLoader.pageDb.set(`/mypage`, { payload: true })
expect(prodLoader.loadPageSync(`/mypage/`)).toBe(true)
})
it(`returns page resources when already fetched`, () => {
const prodLoader = new ProdLoader(null, [])
expect(prodLoader.loadPageSync(`/mypage/`)).toBeUndefined()
})
})
describe(`prefetch`, () => {
const flushPromises = () => new Promise(resolve => setImmediate(resolve))
it(`shouldn't prefetch when shouldPrefetch is false`, () => {
const prodLoader = new ProdLoader(null, [])
prodLoader.shouldPrefetch = jest.fn(() => false)
prodLoader.doPrefetch = jest.fn()
prodLoader.apiRunner = jest.fn()
expect(prodLoader.prefetch(`/mypath/`)).toBe(false)
expect(prodLoader.shouldPrefetch).toHaveBeenCalledWith(`/mypath/`)
expect(prodLoader.apiRunner).not.toHaveBeenCalled()
expect(prodLoader.doPrefetch).not.toHaveBeenCalled()
})
it(`should trigger custom prefetch logic when core is disabled`, () => {
const prodLoader = new ProdLoader(null, [])
prodLoader.shouldPrefetch = jest.fn(() => true)
prodLoader.doPrefetch = jest.fn()
prodLoader.apiRunner = jest.fn()
prodLoader.prefetchDisabled = true
expect(prodLoader.prefetch(`/mypath/`)).toBe(false)
expect(prodLoader.shouldPrefetch).toHaveBeenCalledWith(`/mypath/`)
expect(prodLoader.apiRunner).toHaveBeenCalledWith(`onPrefetchPathname`, {
pathname: `/mypath/`,
})
expect(prodLoader.doPrefetch).not.toHaveBeenCalled()
})
it(`should prefetch when not yet triggered`, async () => {
jest.useFakeTimers()
const prodLoader = new ProdLoader(null, [])
prodLoader.shouldPrefetch = jest.fn(() => true)
prodLoader.apiRunner = jest.fn()
prodLoader.doPrefetch = jest.fn(() => Promise.resolve({}))
expect(prodLoader.prefetch(`/mypath/`)).toBe(true)
// wait for doPrefetchPromise
await flushPromises()
expect(prodLoader.apiRunner).toHaveBeenCalledWith(`onPrefetchPathname`, {
pathname: `/mypath/`,
})
expect(prodLoader.apiRunner).toHaveBeenNthCalledWith(
2,
`onPostPrefetchPathname`,
{
pathname: `/mypath/`,
}
)
})
it(`should only run apis once`, async () => {
const prodLoader = new ProdLoader(null, [])
prodLoader.shouldPrefetch = jest.fn(() => true)
prodLoader.apiRunner = jest.fn()
prodLoader.doPrefetch = jest.fn(() => Promise.resolve({}))
expect(prodLoader.prefetch(`/mypath/`)).toBe(true)
expect(prodLoader.prefetch(`/mypath/`)).toBe(true)
// wait for doPrefetchPromise
await flushPromises()
expect(prodLoader.apiRunner).toHaveBeenCalledTimes(2)
expect(prodLoader.apiRunner).toHaveBeenNthCalledWith(
1,
`onPrefetchPathname`,
expect.anything()
)
expect(prodLoader.apiRunner).toHaveBeenNthCalledWith(
2,
`onPostPrefetchPathname`,
expect.anything()
)
})
})
})

View File

@ -0,0 +1,32 @@
const path = require(`path`)
const child = require(`child_process`)
it(`Builds cache-dir with minimal config`, done => {
const args = [
require.resolve(`@babel/cli/bin/babel.js`),
path.join(__dirname, `..`),
`--config-file`,
path.join(__dirname, `.babelrc`),
`--ignore`,
`**/__tests__`,
]
const spawn = child.spawn(process.execPath, args)
let stderr = ``
let stdout = ``
spawn.stderr.on(`data`, function(chunk) {
stderr += chunk
})
spawn.stdout.on(`data`, function(chunk) {
stdout += chunk
})
spawn.on(`close`, function() {
expect(stderr).toEqual(``)
expect(stdout).not.toEqual(``)
done()
})
}, 30000)

330
node_modules/gatsby/cache-dir/__tests__/static-entry.js generated vendored Normal file
View File

@ -0,0 +1,330 @@
import React from "react"
import fs from "fs"
const { join } = require(`path`)
import DevelopStaticEntry from "../develop-static-entry"
jest.mock(`fs`, () => {
const fs = jest.requireActual(`fs`)
return {
...fs,
readFileSync: jest.fn(),
}
})
jest.mock(`gatsby/package.json`, () => {
return {
version: `2.0.0`,
}
})
jest.mock(
`../sync-requires`,
() => {
return {
components: {
"page-component---src-pages-test-js": () => null,
},
}
},
{
virtual: true,
}
)
const MOCK_FILE_INFO = {
[`${process.cwd()}/public/webpack.stats.json`]: `{}`,
[`${process.cwd()}/public/chunk-map.json`]: `{}`,
[join(
process.cwd(),
`/public/page-data/about/page-data.json`
)]: JSON.stringify({
componentChunkName: `page-component---src-pages-test-js`,
path: `/about/`,
webpackCompilationHash: `1234567890abcdef1234`,
}),
}
let StaticEntry
beforeEach(() => {
fs.readFileSync.mockImplementation(file => MOCK_FILE_INFO[file])
StaticEntry = require(`../static-entry`).default
})
const reverseHeadersPlugin = {
plugin: {
onPreRenderHTML: ({ getHeadComponents, replaceHeadComponents }) => {
const headComponents = getHeadComponents()
headComponents.reverse()
replaceHeadComponents(headComponents)
},
},
}
const injectValuePlugin = (hookName, methodName, value) => {
return {
plugin: {
[hookName]: staticEntry => {
const method = staticEntry[methodName]
method(value)
},
},
}
}
const checkSanitized = components => {
expect(components.includes(null)).toBeFalsy()
expect(
components.find(val => Array.isArray(val) && val.length === 0)
).toBeFalsy()
expect(components.find(val => Array.isArray(val))).toBeFalsy()
}
const checkNonEmptyHeadersPlugin = {
plugin: {
onPreRenderHTML: ({
getHeadComponents,
getPreBodyComponents,
getPostBodyComponents,
}) => {
const headComponents = getHeadComponents()
const preBodyComponents = getPreBodyComponents()
const postBodyComponents = getPostBodyComponents()
checkSanitized(headComponents)
checkSanitized(preBodyComponents)
checkSanitized(postBodyComponents)
},
},
}
const fakeStylesPlugin = {
plugin: {
onRenderBody: ({ setHeadComponents }) =>
setHeadComponents([
<style key="style1"> .style1 {} </style>,
<style key="style2"> .style2 {} </style>,
<style key="style3"> .style3 {} </style>,
]),
},
}
const reverseBodyComponentsPluginFactory = type => {
return {
plugin: {
onPreRenderHTML: props => {
const components = props[`get${type}BodyComponents`]()
components.reverse()
props[`replace${type}BodyComponents`](components)
},
},
}
}
const fakeComponentsPluginFactory = type => {
return {
plugin: {
onRenderBody: props => {
props[`set${type}BodyComponents`]([
<div key="div1"> div1 </div>,
<div key="div2"> div2 </div>,
<div key="div3"> div3 </div>,
])
},
},
}
}
describe(`develop-static-entry`, () => {
test(`onPreRenderHTML can be used to replace headComponents`, done => {
global.plugins = [fakeStylesPlugin, reverseHeadersPlugin]
DevelopStaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML can be used to replace postBodyComponents`, done => {
global.plugins = [
fakeComponentsPluginFactory(`Post`),
reverseBodyComponentsPluginFactory(`Post`),
]
DevelopStaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML can be used to replace preBodyComponents`, done => {
global.plugins = [
fakeComponentsPluginFactory(`Pre`),
reverseBodyComponentsPluginFactory(`Pre`),
]
DevelopStaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML adds metatag note for development environment`, done => {
DevelopStaticEntry(`/about/`, (_, html) => {
expect(html).toContain(
`<meta name="note" content="environment=development"/>`
)
done()
})
})
test(`onPreRenderHTML adds metatag note for development environment after replaceHeadComponents`, done => {
global.plugins = [reverseHeadersPlugin]
DevelopStaticEntry(`/about/`, (_, html) => {
expect(html).toContain(
`<meta name="note" content="environment=development"/>`
)
done()
})
})
})
describe(`static-entry sanity checks`, () => {
beforeEach(() => {
global.__PATH_PREFIX__ = ``
global.__BASE_PATH__ = ``
global.__ASSET_PREFIX__ = ``
})
const methodsToCheck = [
`replaceHeadComponents`,
`replacePreBodyComponents`,
`replacePostBodyComponents`,
]
methodsToCheck.forEach(methodName => {
test(`${methodName} can filter out null value`, done => {
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, null)
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
done()
})
})
test(`${methodName} can filter out null values`, done => {
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [
null,
null,
])
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
done()
})
})
test(`${methodName} can filter out empty array`, done => {
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [])
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
done()
})
})
test(`${methodName} can filter out empty arrays`, done => {
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [[], []])
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
done()
})
})
test(`${methodName} can flatten arrays`, done => {
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [
<style key="style1"> .style1 {} </style>,
<style key="style2"> .style2 {} </style>,
<style key="style3"> .style3 {} </style>,
[<style key="style4"> .style3 {} </style>],
])
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
done()
})
})
})
})
describe(`static-entry`, () => {
beforeEach(() => {
global.__PATH_PREFIX__ = ``
global.__BASE_PATH__ = ``
})
test(`onPreRenderHTML can be used to replace headComponents`, done => {
global.plugins = [fakeStylesPlugin, reverseHeadersPlugin]
StaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML can be used to replace postBodyComponents`, done => {
global.plugins = [
fakeComponentsPluginFactory(`Post`),
reverseBodyComponentsPluginFactory(`Post`),
]
StaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML can be used to replace preBodyComponents`, done => {
global.plugins = [
fakeComponentsPluginFactory(`Pre`),
reverseBodyComponentsPluginFactory(`Pre`),
]
StaticEntry(`/about/`, (_, html) => {
expect(html).toMatchSnapshot()
done()
})
})
test(`onPreRenderHTML does not add metatag note for development environment`, done => {
StaticEntry(`/about/`, (_, html) => {
expect(html).not.toContain(
`<meta name="note" content="environment=development"/>`
)
done()
})
})
})
describe(`sanitizeComponents`, () => {
let sanitizeComponents
beforeEach(() => {
fs.readFileSync.mockImplementation(file => MOCK_FILE_INFO[file])
sanitizeComponents = require(`../static-entry`).sanitizeComponents
})
it(`strips assetPrefix for manifest link`, () => {
global.__PATH_PREFIX__ = `https://gatsbyjs.org/blog`
global.__BASE_PATH__ = `/blog`
global.__ASSET_PREFIX__ = `https://gatsbyjs.org`
const sanitizedComponents = sanitizeComponents([
<link
rel="manifest"
href="https://gatsbyjs.org/blog/manifest.webmanifest"
/>,
])
expect(sanitizedComponents[0].props.href).toBe(`/blog/manifest.webmanifest`)
})
})

View File

@ -0,0 +1,23 @@
const stripPrefix = require(`../strip-prefix`).default
describe(`strip-prefix`, () => {
it(`strips a prefix`, () => {
expect(stripPrefix(`/foo/bar/`, `/foo`)).toBe(`/bar/`)
})
it(`strips first instance only`, () => {
expect(stripPrefix(`/foo/foo/bar/`, `/foo`)).toBe(`/foo/bar/`)
})
it(`ignores prefix appearing elsewhere in the string`, () => {
expect(stripPrefix(`/foo/bar/`, `bar`)).toBe(`/foo/bar/`)
})
it(`ignores a non-existent prefix`, () => {
expect(stripPrefix(`/bar`, `/foo`)).toBe(`/bar`)
})
it(`returns input str if no prefix is provided`, () => {
expect(stripPrefix(`/bar`)).toBe(`/bar`)
})
})