Back to Repositories

Testing GraphQL Fetch Operations in GatsbyJS WordPress Source

This test suite validates the GraphQL fetching functionality in the Gatsby WordPress source plugin, focusing on error handling and server response scenarios. It ensures robust handling of various HTTP status codes and WPGraphQL connectivity issues.

Test Coverage Overview

The test suite provides comprehensive coverage of error handling scenarios in GraphQL fetching operations.

Key areas tested include:
  • HTTP 500 server error responses
  • Gateway timeout errors (502, 503, 504)
  • WPGraphQL plugin activation status
  • Server overload conditions

Implementation Analysis

The testing approach utilizes Jest’s mocking capabilities to simulate various HTTP response scenarios. The implementation employs async/await patterns with mock implementations of HTTP clients and store management.

Key patterns include:
  • Mock HTTP client responses
  • Global store management with async local storage
  • Error message validation
  • Panic handler integration

Technical Details

Testing tools and configuration:
  • Jest test framework
  • Mock implementations for async-retry
  • Custom store implementation with asyncLocalStorage
  • Chalk for terminal styling
  • Custom reporter for panic messages

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through organized and thorough error handling validation.

Notable practices include:
  • Isolated test cases with clear assertions
  • Proper test setup and teardown
  • Comprehensive error message validation
  • Mock cleanup after test execution
  • Structured describe/test blocks

gatsbyjs/gatsby

packages/gatsby-source-wordpress/__tests__/fetch-graphql.test.js

            
import chalk from "chalk"
import fetchGraphQL, { moduleHelpers } from "../dist/utils/fetch-graphql"
import { getStore, createStore, asyncLocalStorage } from "../dist/store"

const store = {store: createStore(), key: `test`}

const withGlobalStore = (fn) => () =>  asyncLocalStorage.run(store, fn)

jest.mock(`async-retry`, () => {
  return {
    __esModule: true,
    default: jest.fn((tryFunction) => {
      const bail = (e) => {
        throw e
      }

      return tryFunction(bail)
    })
  }
})

describe(`fetchGraphQL helper`, () => {
  let mock
  const panicMessages = []

  beforeAll(withGlobalStore(() => {

    const sharedError = `Request failed with status code`
    try {
      mock = jest.spyOn(moduleHelpers, `getHttp`).mockImplementation(() => {
        return {
          post: (_url, { query }) => {
            if (typeof query === `number`) {
              throw new Error(`${sharedError} ${query}`)
            }

            if (query === `wpgraphql-deactivated`) {
              return Promise.resolve({
                request: {},
                headers: {
                  [`content-type`]: `text/html`,
                },
              })
            }

            return null
          },
        }
      })
    } catch (e) {
      if (!e.message.includes(sharedError)) {
        throw e
      }
    }

    const fakeReporter = {
      panic: ({ context: { sourceMessage } }) => {
        panicMessages.push(sourceMessage)
      },
    }

    getStore().dispatch.gatsbyApi.setState({
      helpers: {
        reporter: fakeReporter,
      },
    })
  }))

  test(`handles 500 errors`, withGlobalStore(async () => {
    await fetchGraphQL({
      query: 500,
      url: `fake url`,
    })

    expect(
      panicMessages[0]
    ).toInclude(`Your WordPress server is either overloaded or encountered a PHP error.`)
  }))

  test(`handles 502, 503, and 504 errors`, withGlobalStore(async () => {
    const errorMessage = `Your WordPress server at ${chalk.bold(
      `fake url`
    )} appears to be overloaded.`

    await fetchGraphQL({
      query: 502,
      url: `fake url`,
    })
    expect(panicMessages[1]).toInclude(errorMessage)

    await fetchGraphQL({
      query: 503,
      url: `fake url`,
    })
    expect(panicMessages[2]).toInclude(errorMessage)

    await fetchGraphQL({
      query: 504,
      url: `fake url`,
    })
    expect(panicMessages[3]).toInclude(errorMessage)
  }))

  test(`errors when WPGraphQL is not active`, withGlobalStore(async () => {
    await fetchGraphQL({
      query: `wpgraphql-deactivated`,
      url: `fake url`,
    })

    expect(
      panicMessages[4]
    ).toInclude(`Unable to connect to WPGraphQL.`)
  }))

  afterAll(withGlobalStore(() => {
    mock.mockRestore()
  }))
})