Skip to content

Push Tests

A PushTest tests an aspect of a push at a point in time. Most push tests test the Project returned by the push: that is, the state of the repository after the push. However push tests can also look at the push itself: for example, considering the branch or commit message.

Push tests are a central part of the Atomist API, being combined in push rules to determine how to handle pushes and drive delivery. Push tests are often reused, so it is good practice to extract them into constants. Many extension packs export push test constants.


Examples include:

A push test maps from a PushListenerInvocation to a Promise<boolean>. It decides whether this push is relevant (true) or not relevant (false), returning a Promise so that it can invoke asynchronous operations.

To help your test make a decision, the PushListenerInvocation provides

  • push: context around the push itself, such as the before and after commits, who made it, the repository name, and more.
  • project: access to the code, through the Project interface
  • the inherited RepoContext fields common to all SDM events

Creating push tests

When you only need the project, use the predicatePushTest function:

import { predicatePushTest } from "@atomist/sdm";
export const IsMkdocsProject = predicatePushTest(
    project => project.hasFile("mkdocs.yml"));

For maximum flexibility, construct a push test with a name and a mapping function. This provides access to both the push and project. The previous example would look like this:

import { pushTest } from "@atomist/sdm";
export const IsMkdocsProject = pushTest(
    (pli: PushListenerInvocation): Promise<boolean> => {
        return pli.project.hasFile("mkdocs.yml");

This allows us to check the push itself. For example:

import { pushTest } from "@atomist/sdm";
export const ToDefaultBranch = pushTest(
    async pu => pu.push.branch === pu.repo.defaultBranch);

Testing push tests

As with the rest of the SDM API, we can write unit tests for push tests. This helps ensure that the decisions made in our delivery flows are solid.

The following example uses Mocha and construct in memory projects and verify the behavior of the above push tests.

describe("IsMkdocsProject", () => {

    it("should not find MkDocs in empty repo", async () => {
        const project = InMemoryProject.of();
        // We need to cast as we want to ignore properties other than project of the invocation
        const r = await IsMkdocsProject.mapping({ project } as any as PushListenerInvocation);

    it("should find Mkdocs in repo with mkdocs file", async () => {
        const project = InMemoryProject.of({ path: "mkdocs.yml", content: "here: yes" });
        const r = await IsMkdocsProject.mapping({ project } as any as PushListenerInvocation);