Back to Repositories

Testing Font Preload Plugin Implementation in GatsbyJS

A comprehensive test suite for the Gatsby font preloading plugin that validates font asset caching and route handling. The tests ensure proper handling of font requests across different pages and verify the plugin’s core functionality for both local and external font resources.

Test Coverage Overview

The test suite provides thorough coverage of the gatsby-plugin-preload-fonts functionality.

Key areas tested include:
  • Route traversal and page visitation
  • Font request interception and processing
  • Cache management for font assets
  • Handling of both local and external font resources
The tests specifically verify the plugin’s behavior across multiple routes with different font configurations.

Implementation Analysis

The testing approach utilizes Jest’s powerful mocking capabilities to simulate browser behavior and font requests. The implementation employs extensive mocking of external dependencies including Puppeteer, cache operations, and route fetching.

Notable patterns include:
  • Mock browser implementation for request simulation
  • Custom request object creation for font resources
  • Snapshot testing for cache validation

Technical Details

Testing infrastructure includes:
  • Jest as the primary testing framework
  • Puppeteer for browser simulation
  • Custom mock implementations for cache and route handling
  • Progress bar simulation for build process feedback
  • Console output suppression for clean test execution

Best Practices Demonstrated

The test suite exemplifies several testing best practices in modern JavaScript development.

Notable practices include:
  • Comprehensive mocking of external dependencies
  • Isolated test scenarios with clear assertions
  • Snapshot testing for complex object validation
  • Clean separation of concerns in test setup
  • Explicit expectations with assertion counting

gatsbyjs/gatsby

packages/gatsby-plugin-preload-fonts/src/__tests__/index.test.js

            
const { save } = require(`../prepare/cache`)
const fetchRoutes = require(`../prepare/fetch-routes`)
const puppeteer = require(`puppeteer`)
const { main } = require(`../prepare/index`)

jest.mock(`../prepare/cache`, () => {
  return {
    load: jest.fn(() => {
      return {
        timestamp: Date.now(),
        hash: `initial-run`,
        assets: {},
      }
    }),
    save: jest.fn(),
    cacheFile: `/font-preload-cache.json`,
  }
})
jest.mock(`../prepare/fetch-routes`, () => jest.fn())
jest.mock(`puppeteer`, () => {
  return {
    launch: jest.fn(),
  }
})
jest.mock(`progress`, () => {
  function ProgressBar() {
    this.interrupt = jest.fn()
    this.tick = jest.fn()
  }

  return ProgressBar
})
jest.spyOn(console, `log`).mockImplementation(() => {})

const mockPageRequests = requests => {
  const createMockBrowser = () => {
    const prefixLength = `http://localhost:8000`.length
    const listeners = []
    let currentPath

    const page = {
      on: (_event, cb) => listeners.push(cb),
      goto: path => {
        currentPath = path
        const pageRequests = requests[path.substring(prefixLength)]

        if (pageRequests) {
          pageRequests.forEach(req => listeners.forEach(cb => cb(req)))
        }
      },
      url: () => currentPath,
      setCacheEnabled: () => {},
    }

    return { close: jest.fn(), newPage: () => Promise.resolve(page) }
  }

  puppeteer.launch.mockImplementationOnce(() =>
    Promise.resolve(createMockBrowser())
  )
}

const createMockRequest = asset => {
  return {
    url: () => asset,
    method: () => `GET`,
    resourceType: () => `font`,
  }
}

describe(`prepare`, () => {
  it(`visits each provided route`, async () => {
    expect.assertions(1)

    fetchRoutes.mockImplementationOnce(() => [`/foo`, `/bar`, `/baz`])
    mockPageRequests({
      [`/foo`]: [
        createMockRequest(`/path/to/font.otf`),
        createMockRequest(`https://foo.bar/path/to/font.otf`),
      ],
      [`/bar`]: [
        createMockRequest(`/path/to/another.ttf`),
        createMockRequest(`https://foo.bar/path/to/a/font.woff`),
      ],
      [`/baz`]: [
        createMockRequest(`/another/font.woff2`),
        createMockRequest(`/some/external/font.ttf`),
        createMockRequest(`https://foo.bar/another/font.ttf`),
      ],
    })

    await main()

    expect(save.mock.calls[0][0]).toMatchSnapshot({
      timestamp: expect.any(Number),
    })
  })
})