Back to Repositories

Testing WordPress Media Item Fetching Integration in GatsbyJS

This test suite validates the functionality of fetching and handling media items in the Gatsby WordPress source plugin. It focuses on testing the retrieval of media items both by source URL and by ID, ensuring proper pagination and data handling.

Test Coverage Overview

The test suite provides comprehensive coverage of media item fetching functionality in Gatsby’s WordPress integration.

  • Tests fetching media items by source URL with multiple pages
  • Validates single-page media item retrieval
  • Tests fetching media items by ID with pagination
  • Verifies proper handling of null responses and edge cases

Implementation Analysis

The tests utilize Jest’s mocking capabilities to simulate GraphQL responses and API interactions. The implementation follows a modular approach with separate test blocks for URL-based and ID-based fetching.

Key patterns include:
  • Mock store implementation using asyncLocalStorage
  • GraphQL response simulation
  • Pagination handling verification
  • Node creation and management testing

Technical Details

  • Testing Framework: Jest
  • Mocked Services: GraphQL fetching, node management
  • Store Management: Custom store implementation with asyncLocalStorage
  • Configuration: Configurable per-page limits and schema options
  • Helper Utilities: Base64 encoding, content digest creation

Best Practices Demonstrated

The test suite exemplifies strong testing practices through isolation of concerns and thorough coverage.

  • Proper test setup and teardown with beforeAll and afterEach hooks
  • Isolated test cases with clear assertions
  • Comprehensive mock implementations
  • Structured test organization with nested describe blocks
  • Effective error handling validation

gatsbyjs/gatsby

packages/gatsby-source-wordpress/__tests__/fetch-referenced-media-items.test.js

            
jest.mock(`../dist/utils/fetch-graphql`, () => jest.fn())

import fetchGraphql from "../dist/utils/fetch-graphql"
import { fetchMediaItemsBySourceUrl, fetchMediaItemsById } from "../dist/steps/source-nodes/fetch-nodes/fetch-referenced-media-items"
import { createContentDigest } from "gatsby-core-utils"
import { getStore, createStore, asyncLocalStorage } from "../dist/store"

const fakeReporter = {
  panic: msg => {
    console.error(msg)
  },
  info: msg => {
    console.log(msg)
  },
}

const getNodeMock = jest.fn()

const btoa = (input) => Buffer.from(input).toString(`base64`)

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

const runWithGlobalStore = async (fn) => {
  asyncLocalStorage.run(store, fn)
}

const withGlobalStore = (fn) => () => {
     runWithGlobalStore(fn)
  }
describe(`fetch-referenced-media-items`, () => {
  beforeAll(withGlobalStore(() => {
    getStore().dispatch.gatsbyApi.setState({
      pluginOptions: {
        schema: {
          perPage: 2,
        },
      },
    })
  }))

  afterEach(() => {
    jest.resetAllMocks()
  })

  describe(`fetchMediaItemsBySourceUrl`, () => {

const createApi = () => {
  return {
    actions: {
      createTypes: jest.fn(),
      createNode: jest.fn(),
      deleteNode: jest.fn(),
    },
    reporter: fakeReporter,
    createNodeId: jest.fn(),
    async getNode(id) {
      return {
        localFile: {
          id: id,
        },
      }
    },
  }
}

    it(`should properly download multiple pages`, withGlobalStore(async () => {
      fetchGraphql
        .mockResolvedValueOnce({
          data: {
            mediaItem__index_0: null,
            mediaItem__index_1: null,
          },
        })
        .mockResolvedValueOnce({
          data: {
            mediaItem__index_2: {
              id: 2,
              mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
            },
            mediaItem__index_3: {
              id: 3,
              mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
            },
          },
        })
        .mockResolvedValueOnce({
          data: {
            mediaItem__index_4: null,
            mediaItem__index_5: null,
          },
        })
        .mockResolvedValueOnce({
          data: {
            mediaItem__index_6: null,
            mediaItem__index_7: null,
          },
        })
      const result = await fetchMediaItemsBySourceUrl({
        mediaItemUrls: [
          `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3?_=7`,
          `https://wordpress.host/wp-content/uploads/2018/05/file2.mp3?_=7`,
          `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
          `https://wordpress.host/wp-content/uploads/2018/05/file2.mp3`,
        ],
        createContentDigest,
        helpers: createApi(),
      })
      expect(result).toHaveLength(2)
    }))


    it(`should properly download a single page if there is only 1`, withGlobalStore(async () => {
      getStore().dispatch.gatsbyApi.setState({
        pluginOptions: {
          schema: {
            perPage: 5,
          },
        },
      })

      fetchGraphql
        .mockResolvedValueOnce({
          data: {
            mediaItem__index_0: {
              id: 0,
              mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/single-page-file1.mp3`,
            },
            mediaItem__index_1: {
              id: 1,
              mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/single-page-file1.mp3`,
            },
          },
        })

      const result = await fetchMediaItemsBySourceUrl({
        mediaItemUrls: [
          `https://wordpress.host/wp-content/uploads/2018/05/single-page-file1.mp3`,
          `https://wordpress.host/wp-content/uploads/2018/05/single-page-file2.mp3`,
        ],
        selectionSet: `id\nmediaItemUrl`,
        createContentDigest,
        helpers: createApi(),
      })
      expect(result).toHaveLength(2)
    }))
  })


  describe(`fetchMediaItemsById`, () => {

    const createApi = () => {
      return {
        actions: {
          createTypes: jest.fn(),
          createNode: jest.fn(),
          deleteNode: jest.fn(),
        },
        reporter: fakeReporter,
        createNodeId: jest.fn(),
        getNode: getNodeMock
      }
    }

    it(`should properly download multiple pages of ids`, withGlobalStore(async () => {
      getNodeMock
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce({
        localFile: {
          id: 0,
        }})
        .mockReturnValueOnce({
          localFile: {
            id: 1,
          }})
          .mockReturnValueOnce({
            localFile: {
              id: 2,
            }})
            .mockReturnValueOnce({
              localFile: {
                id: 3,
              }})
      getStore().dispatch.gatsbyApi.setState({
        pluginOptions: {
          schema: {
            perPage: 2,
          },
        },
      })


      fetchGraphql
        .mockResolvedValueOnce({
          data: {
            mediaItems: {
              nodes: [{
                id: 0,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
              },{
                id: 1,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
              },]
            }
          },
        })
        .mockResolvedValueOnce({
          data: {
            mediaItems: {
              nodes: [{
                id: 2,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file2.mp3`,
              },{
                id: 3,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file3.mp3`,
              },]
            }
          },
        })
      const result = await fetchMediaItemsById({
        mediaItemIds: [
          btoa(`attachment:1`),
          btoa(`attachment:2`),
          btoa(`attachment:3`),
          btoa(`attachment:4`),
        ],
        settings: {
          limit: 5
        },
        typeInfo: {
          pluralName: `mediaItems`,
          nodesTypeName: `MediaItem`
        },

        createContentDigest,
        helpers: createApi(),
      })
      expect(result).toHaveLength(4)
    }))


    it(`should properly download a single page of ids if there is only 1`, withGlobalStore(async () => {
      getNodeMock
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce(undefined)
      .mockReturnValueOnce({
        localFile: {
          id: 0,
        }})
        .mockReturnValueOnce({
          localFile: {
            id: 1,
          }})

      getStore().dispatch.gatsbyApi.setState({
        pluginOptions: {
          schema: {
            perPage: 5,
          },
        },
      })

      fetchGraphql
        .mockResolvedValueOnce({
          data: {
            mediaItems: {
              nodes: [{
                id: 0,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
              },{
                id: 1,
                mediaItemUrl: `https://wordpress.host/wp-content/uploads/2018/05/file1.mp3`,
              },]
            }
          },
        })

      const result = await fetchMediaItemsById({
        mediaItemIds: [
          btoa(`attachment:1`), btoa(`attachment:2`)
        ],
        settings: {
          limit: 5
        },
        typeInfo: {
          pluralName: `mediaItems`,
          nodesTypeName: `MediaItem`
        },

        selectionSet: `id\nmediaItemUrl`,
        createContentDigest,
        helpers: createApi(),
      })
      expect(result).toHaveLength(2)
    }))
  })
})