refactor, more tests (#444)

* async/await refactor, more testing

* add funding docs

* test fix

* dependency updates
This commit is contained in:
Matthias Kretschmann 2024-04-08 12:09:48 +01:00 committed by GitHub
parent 83e2ae1daa
commit a036be8087
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1624 additions and 1479 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
github: kremalicious
patreon: kremalicious
custom: ['https://kremalicious.com/thanks']

View File

@ -24,6 +24,7 @@ By combining this plugin with [gatsby-plugin-meta-redirect](https://github.com/g
- [Documentation](#documentation)
- [Plugin Development](#plugin-development)
- [Changelog](#changelog)
- [Sponsorship](#sponsorship)
- [License](#license)
---
@ -92,6 +93,12 @@ npm run release
See [CHANGELOG.md](CHANGELOG.md).
## Sponsorship
[![](https://img.shields.io/static/v1?label=Say%20Thanks%20With%20Web3&labelColor=%2343a699&message=%E2%9D%A4&logo=Ethereum&color=%23fe8e86&style=for-the-badge)](https://kremalicious.com/thanks)
[![](https://img.shields.io/static/v1?label=Say%20Thanks%20With%20GitHub&labelColor=%2343a699&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86&style=for-the-badge)](https://github.com/sponsors/kremalicious)
## License
The MIT License
@ -107,9 +114,3 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
---
Made with ♥ by [Matthias Kretschmann](https://matthiaskretschmann.com) ([@kremalicious](https://github.com/kremalicious))
Say thanks with BTC:
`35UUssHexVK48jbiSgTxa4QihEoCqrwCTG`
Say thanks with ETH:
`0x04354F554536DA108726829207958d3E277f0210`

2847
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,18 +20,17 @@
"maintained node versions"
],
"devDependencies": {
"@babel/cli": "^7.23.0",
"@babel/core": "^7.23.0",
"@babel/preset-env": "^7.22.20",
"@babel/cli": "^7.24.1",
"@babel/core": "^7.24.4",
"@babel/preset-env": "^7.24.4",
"auto-changelog": "^2.4.0",
"chalk": "^5.3.0",
"cross-env": "^7.0.3",
"eslint": "^8.50.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-prettier": "^9.1.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.0.3",
"release-it": "^16.2.1"
"prettier": "^3.2.5",
"release-it": "^17.1.1"
},
"peerDependencies": {
"gatsby": "^4.0.0 || ^5.0.0",

View File

@ -1,68 +1,100 @@
import chalk from 'chalk'
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
export function createPages({ graphql, actions }, pluginOptions) {
// Define the type definitions for the `MarkdownRemark` node
const typeDefs = `
type MarkdownRemark implements Node {
fields: MarkdownRemarkFields
frontmatter: MarkdownRemarkFrontmatter
}
type MarkdownRemarkFields {
slug: String
}
type MarkdownRemarkFrontmatter {
slug: String
}
`
// Create the type definitions
createTypes(typeDefs)
}
export async function createPages({ graphql, actions }, pluginOptions) {
const { createRedirect } = actions
const markdownQuery = pluginOptions.query || 'allMarkdownRemark'
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
q: ${markdownQuery}(
filter: { frontmatter: { redirect_from: { ne: null } } }
) {
edges {
node {
fields {
slug
}
frontmatter {
redirect_from
}
}
try {
const { data } = await graphql(`
{
q: ${markdownQuery}(filter: { frontmatter: { redirect_from: { ne: null } } }) {
edges {
node {
fields {
slug
}
frontmatter {
slug
redirect_from
}
}
}
`
).then((result) => {
if (result.errors) {
console.log(result.errors) // eslint-disable-line no-console
reject(result.errors)
return
}
}
`)
const allPosts = result.data.q.edges
const allPosts = data?.q?.edges
const redirects = []
if (!allPosts || allPosts.length === 0) {
console.log(
'%c %s %c %s',
'color:orange',
'warning',
'color:none',
'no posts with redirect_from found'
)
return
}
// For all posts with redirect_from frontmatter,
// extract all values and push to redirects array
allPosts.forEach((post) => {
redirects.push({
from: post.node.frontmatter.redirect_from,
to: post.node.fields.slug
})
})
const redirects = []
// Create redirects from the just constructed array
redirects.forEach(({ from, to }) => {
// iterate through all `from` array items
from.forEach((from) => {
createRedirect({
fromPath: from,
toPath: to,
isPermanent: true,
redirectInBrowser: true
})
})
})
resolve(
console.log(`${chalk.green('success')} create redirects`) // eslint-disable-line no-console
allPosts.forEach(({ node }) => {
let _slug
const { redirect_from, slug } = node.frontmatter
if (!slug) _slug = node.fields?.slug
if (!_slug) {
console.log(
'%c %s %c %s',
'color:orange',
'warning',
'color:none',
'no slug found in frontmatter or fields'
)
return
}
redirect_from.forEach((from) => {
redirects.push({ from, to: _slug })
})
})
redirects.forEach(({ from, to }) => {
createRedirect({
fromPath: from,
toPath: to,
isPermanent: true,
redirectInBrowser: true
})
})
console.log(
'%c %s %c %s',
'color:green',
'success',
'color:none',
`created ${redirects.length} redirects`
)
})
} catch (error) {
console.error(error.message)
}
}

View File

@ -14,6 +14,22 @@ describe('createPages', () => {
let actions
let consoleLogSpy
const markdownQuery = 'allMarkdownRemark'
const edges = [
{
node: {
fields: { slug: '/post-1' },
frontmatter: { redirect_from: ['/old-url-1', '/old-url-2'] }
}
},
{
node: {
fields: { slug: '/post-2' },
frontmatter: { redirect_from: ['/old-url-3'] }
}
}
]
beforeEach(() => {
actions = { createRedirect: jest.fn() }
pluginOptions = { query: 'allMarkdownRemark' }
@ -25,39 +41,34 @@ describe('createPages', () => {
consoleLogSpy.mockRestore()
})
it('should create redirects correctly', async () => {
graphql.mockReturnValueOnce(
Promise.resolve({
data: {
q: {
edges: [
{
node: {
fields: { slug: '/post-1/' },
frontmatter: { redirect_from: ['/old-url-1', '/old-url-2'] }
}
}
]
}
}
})
)
it('should create redirects for each post with a redirect_from field', async () => {
const data = { q: { edges } }
graphql.mockReturnValueOnce(Promise.resolve({ data }))
const createRedirectSpy = jest.spyOn(actions, 'createRedirect')
await createPages({ graphql, actions }, pluginOptions)
await createPages({ graphql, actions }, { query: markdownQuery })
expect(actions.createRedirect).toHaveBeenCalledTimes(2)
expect(actions.createRedirect).toHaveBeenCalledWith({
expect(createRedirectSpy).toHaveBeenCalledTimes(3)
expect(createRedirectSpy).toHaveBeenCalledWith({
fromPath: '/old-url-1',
toPath: '/post-1/',
toPath: '/post-1',
isPermanent: true,
redirectInBrowser: true
})
expect(actions.createRedirect).toHaveBeenCalledWith({
expect(createRedirectSpy).toHaveBeenCalledWith({
fromPath: '/old-url-2',
toPath: '/post-1/',
toPath: '/post-1',
isPermanent: true,
redirectInBrowser: true
})
expect(createRedirectSpy).toHaveBeenCalledWith({
fromPath: '/old-url-3',
toPath: '/post-2',
isPermanent: true,
redirectInBrowser: true
})
createRedirectSpy.mockRestore()
})
it('should use pluginOptions.query when defined', async () => {
@ -83,16 +94,37 @@ describe('createPages', () => {
await createPages({ graphql, actions }, pluginOptions)
})
it('should log and reject errors when the GraphQL query fails', async () => {
graphql.mockReturnValueOnce(
Promise.resolve({ errors: [{ message: 'GraphQL error' }] })
it('should log a success message when redirects are created', async () => {
const data = { q: { edges } }
graphql.mockReturnValueOnce(Promise.resolve({ data }))
const createRedirectSpy = jest.spyOn(actions, 'createRedirect')
await createPages({ graphql, actions }, { query: markdownQuery })
expect(createRedirectSpy).toHaveBeenCalledTimes(3)
expect(console.log).toHaveBeenCalledWith(
'%c %s %c %s',
'color:green',
'success',
'color:none',
'created 3 redirects'
)
})
it('should log an error message when an error occurs', async () => {
const error = new Error('GraphQL query failed')
graphql.mockImplementationOnce(() => {
throw error
})
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
try {
await createPages({ graphql, actions }, pluginOptions)
} catch (error) {
expect(console.log).toHaveBeenCalledWith([{ message: 'GraphQL error' }])
expect(error).toEqual([{ message: 'GraphQL error' }])
expect(console.error).toHaveBeenCalledWith('GraphQL query failed')
}
consoleSpy.mockRestore()
})
})

View File

@ -1,5 +1,4 @@
{
"rootDir": "../",
"coverageDirectory": "<rootDir>/coverage/",
"transformIgnorePatterns": ["node_modules/(?!chalk/.*)"]
"coverageDirectory": "<rootDir>/coverage/"
}