Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

DEVPROD-940: Surface repotracker error on Project Health page #2150

Merged
merged 7 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions cypress/integration/projectHealth/banners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
describe("banners", () => {
const projectWithRepotrackerError = "/commits/mongodb-mongo-test";

describe("repotracker banner", () => {
beforeEach(() => {
cy.visit(projectWithRepotrackerError);
});

it("should error if revision is incomplete", () => {
cy.dataCy("repotracker-error-banner").should("be.visible");
cy.dataCy("repotracker-error-trigger").should("be.visible");
cy.dataCy("repotracker-error-trigger").click();
cy.dataCy("repotracker-error-modal").should("be.visible");
cy.getInputByLabel("Base Revision").type("1234");
cy.contains("button", "Confirm").should(
"have.attr",
"aria-disabled",
"false"
);
cy.contains("button", "Confirm").click();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the following test rely on the save? If so, the tests should be combined

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh nope they should be independent!

cy.validateToast("error");
cy.dataCy("repotracker-error-banner").should("be.visible");
});

it("should be able to clear the repotracker error", () => {
cy.dataCy("repotracker-error-banner").should("be.visible");
cy.dataCy("repotracker-error-trigger").should("be.visible");
cy.dataCy("repotracker-error-trigger").click();
cy.dataCy("repotracker-error-modal").should("be.visible");
cy.getInputByLabel("Base Revision").type(
"7ad0f0571691fa5063b757762a5b103999290fa8"
);
cy.contains("button", "Confirm").should(
"have.attr",
"aria-disabled",
"false"
);
cy.contains("button", "Confirm").click();
cy.validateToast("success", "Successfully updated merge base revision");
cy.dataCy("repotracker-error-banner").should("not.exist");
});
});
});
226 changes: 226 additions & 0 deletions src/components/Banners/RepotrackerBanner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import { MockedProvider } from "@apollo/client/testing";
import { RepotrackerBanner } from "components/Banners";
import { RenderFakeToastContext } from "context/toast/__mocks__";
import {
UserProjectSettingsPermissionsQuery,
UserProjectSettingsPermissionsQueryVariables,
RepotrackerErrorQuery,
RepotrackerErrorQueryVariables,
SetLastRevisionMutation,
SetLastRevisionMutationVariables,
} from "gql/generated/types";
import { SET_LAST_REVISION } from "gql/mutations";
import {
USER_PROJECT_SETTINGS_PERMISSIONS,
REPOTRACKER_ERROR,
} from "gql/queries";
import { render, screen, userEvent, waitFor } from "test_utils";
import { ApolloMock } from "types/gql";

describe("repotracker banner", () => {
describe("repotracker error does not exist", () => {
it("does not render banner", async () => {
const { Component } = RenderFakeToastContext(
<MockedProvider mocks={[projectNoError]}>
<RepotrackerBanner projectIdentifier="evergreen" />
</MockedProvider>
);
render(<Component />);
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-banner")).toBeNull();
});
});
});

describe("repotracker error exists", () => {
it("renders a banner", async () => {
const { Component } = RenderFakeToastContext(
<MockedProvider mocks={[projectWithError, adminUser]}>
<RepotrackerBanner projectIdentifier="evergreen" />
</MockedProvider>
);
render(<Component />);
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-banner")).toBeVisible();
});
});

it("does not render modal trigger if user is not admin", async () => {
const { Component } = RenderFakeToastContext(
<MockedProvider mocks={[projectWithError, basicUser]}>
<RepotrackerBanner projectIdentifier="evergreen" />
</MockedProvider>
);
render(<Component />);
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-banner")).toBeVisible();
});
expect(screen.queryByDataCy("repotracker-error-trigger")).toBeNull();
});

it("renders modal trigger if user is admin", async () => {
const { Component } = RenderFakeToastContext(
<MockedProvider mocks={[projectWithError, adminUser]}>
<RepotrackerBanner projectIdentifier="evergreen" />
</MockedProvider>
);
render(<Component />);
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-banner")).toBeVisible();
});
expect(screen.queryByDataCy("repotracker-error-trigger")).toBeVisible();
});

it("can submit new base revision via modal", async () => {
const user = userEvent.setup();
const { Component, dispatchToast } = RenderFakeToastContext(
<MockedProvider mocks={[projectWithError, adminUser, setLastRevision]}>
<RepotrackerBanner projectIdentifier="evergreen" />
</MockedProvider>
);
render(<Component />);
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-banner")).toBeVisible();
});
expect(screen.queryByDataCy("repotracker-error-trigger")).toBeVisible();

// Open modal.
await user.click(screen.queryByDataCy("repotracker-error-trigger"));
await waitFor(() => {
expect(screen.queryByDataCy("repotracker-error-modal")).toBeVisible();
});

// Submit new base revision.
const confirmButton = screen.getByRole("button", { name: "Confirm" });
expect(confirmButton).toHaveAttribute("aria-disabled", "true");
await user.type(
screen.getByLabelText("Base Revision"),
"new_base_revision"
);
expect(confirmButton).toHaveAttribute("aria-disabled", "false");
await user.click(confirmButton);
expect(dispatchToast.success).toHaveBeenCalledTimes(1);
});
});
});

const projectNoError: ApolloMock<
RepotrackerErrorQuery,
RepotrackerErrorQueryVariables
> = {
request: {
query: REPOTRACKER_ERROR,
variables: {
projectIdentifier: "evergreen",
},
},
result: {
data: {
project: {
__typename: "Project",
id: "evergreen",
branch: "",
repotrackerError: null,
},
},
},
};

const projectWithError: ApolloMock<
RepotrackerErrorQuery,
RepotrackerErrorQueryVariables
> = {
request: {
query: REPOTRACKER_ERROR,
variables: {
projectIdentifier: "evergreen",
},
},
result: {
data: {
project: {
__typename: "Project",
id: "evergreen",
branch: "main",
repotrackerError: {
__typename: "RepotrackerError",
exists: true,
invalidRevision: "invalid_revision",
},
},
},
},
};

const adminUser: ApolloMock<
UserProjectSettingsPermissionsQuery,
UserProjectSettingsPermissionsQueryVariables
> = {
request: {
query: USER_PROJECT_SETTINGS_PERMISSIONS,
variables: { projectIdentifier: "evergreen" },
},
result: {
data: {
user: {
__typename: "User",
userId: "admin",
permissions: {
__typename: "Permissions",
canCreateProject: true,
projectPermissions: {
__typename: "ProjectPermissions",
admin: true,
},
},
},
},
},
};

const basicUser: ApolloMock<
UserProjectSettingsPermissionsQuery,
UserProjectSettingsPermissionsQueryVariables
> = {
request: {
query: USER_PROJECT_SETTINGS_PERMISSIONS,
variables: { projectIdentifier: "evergreen" },
},
result: {
data: {
user: {
__typename: "User",
userId: "basic",
permissions: {
__typename: "Permissions",
canCreateProject: false,
projectPermissions: {
__typename: "ProjectPermissions",
admin: false,
},
},
},
},
},
};

const setLastRevision: ApolloMock<
SetLastRevisionMutation,
SetLastRevisionMutationVariables
> = {
request: {
query: SET_LAST_REVISION,
variables: {
projectIdentifier: "evergreen",
revision: "new_base_revision",
},
},
result: {
data: {
setLastRevision: {
__typename: "SetLastRevisionPayload",
mergeBaseRevision: "new_base_revision",
},
},
},
};
Loading