Back to Repositories

Testing Automated Issue Labeling System in Gatsby Repository

This test suite validates the automatic issue labeling functionality in Gatsby’s repository using Jest. It ensures proper label assignment based on issue titles and handles existing labels while maintaining error logging capabilities.

Test Coverage Overview

The test suite provides comprehensive coverage of the issue labeling system with multiple test cases:
  • Question-based issues detection
  • Handling of existing labels
  • Documentation-related issues identification
  • Error handling scenarios
  • Edge cases with unrecognized patterns

Implementation Analysis

The testing approach utilizes Jest’s mocking capabilities to simulate the Danger.js environment and GitHub API interactions. It implements async/await patterns for promise-based testing and uses Jest’s spyOn for monitoring function calls.
  • Mock implementation of Danger.js context
  • Spy functionality for error logging
  • Promise-based test assertions

Technical Details

Testing infrastructure includes:
  • Jest as the primary testing framework
  • Mock implementations of GitHub API calls
  • beforeEach hooks for test state reset
  • Custom error logging validation
  • TypeScript type definitions

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Isolated test cases with proper setup/teardown
  • Comprehensive error handling coverage
  • Clear test case descriptions
  • Modular test organization
  • Consistent testing patterns across scenarios

gatsbyjs/gatsby

peril/tests/labeler.test.ts

            
jest.mock("danger", () => jest.fn())
import * as danger from "danger"
const dm = danger as any

import * as l from "../rules/labeler"
jest.spyOn(l, `logApiError`)

let apiError: any

beforeEach(() => {
  dm.danger = {
    github: {
      repository: {
        name: "gatsby",
        owner: {
          login: "gatsbyjs",
        },
      },
      issue: {
        labels: [],
        number: 100,
      },
      api: {
        issues: {
          addLabels: jest.fn(),
        },
      },
    },
  }
})

describe("a new issue", () => {
  it("with question mark in a title", () => {
    dm.danger.github.issue.title =
      "Help - Has anyone hosted a gatsby.js site on Platform.sh?"
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).toBeCalledWith({
        repo: "gatsby",
        owner: "gatsbyjs",
        number: 100,
        labels: ["type: question or discussion"],
      })
    })
  })

  it("with existing labels", () => {
    dm.danger.github.issue.title = "How are labels handled?"
    dm.danger.github.issue.labels = [{ name: "good first issue" }]
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).toBeCalledWith({
        repo: "gatsby",
        owner: "gatsbyjs",
        number: 100,
        labels: ["good first issue", "type: question or discussion"],
      })
    })
  })

  it("starting with how", () => {
    dm.danger.github.issue.title =
      "How do you justify Gatsby’s bundle size to clients"
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).toBeCalledWith({
        repo: "gatsby",
        owner: "gatsbyjs",
        number: 100,
        labels: ["type: question or discussion"],
      })
    })
  })

  it("including tutorial", () => {
    dm.danger.github.issue.title = "Tutorial template + gold standard example"
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).toBeCalledWith({
        repo: "gatsby",
        owner: "gatsbyjs",
        number: 100,
        labels: ["type: documentation"],
      })
    })
  })

  it("including readme", () => {
    dm.danger.github.issue.title = "[v2] default starter: update README"
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).toBeCalledWith({
        repo: "gatsby",
        owner: "gatsbyjs",
        number: 100,
        labels: ["type: documentation"],
      })
    })
  })

  it("not recognised", () => {
    dm.danger.github.issue.title = "Supporting HSTS and how to HSTS preloading"
    return l.labeler().then(() => {
      expect(dm.danger.github.api.issues.addLabels).not.toBeCalled()
    })
  })

  describe("error logging", () => {
    beforeEach(() => {
      apiError = new Error("Mocked error")
      dm.danger.github.issue.title =
        "Help - Has anyone hosted a gatsby.js site on Platform.sh?"
      dm.danger.github.api.issues.addLabels = () => Promise.reject(apiError)
    })

    it("log error", () => {
      return l.labeler().then(() => {
        expect(l.logApiError).toHaveBeenCalledWith({
          action: "issues.addLabel",
          error: apiError,
          opts: {
            labels: ["type: question or discussion"],
            number: 100,
            owner: "gatsbyjs",
            repo: "gatsby",
          },
        })
      })
    })
  })
})