Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clear storyStatus when no longer relevant #65

Merged
merged 12 commits into from
Sep 4, 2023
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"typecheck": "tsc --noemit"
},
"dependencies": {
"@storybook/csf-tools": "7.4.0",
"@storybook/csf-tools": "7.5.0-alpha.0",
"@storybook/design-system": "^7.15.15",
"chromatic": "7.1.0-canary.3",
"date-fns": "^2.30.0",
Expand All @@ -71,19 +71,19 @@
"@graphql-codegen/cli": "^4.0.1",
"@graphql-codegen/client-preset": "^4.0.1",
"@graphql-typed-document-node/core": "^3.2.0",
"@storybook/addon-actions": "7.4.0",
"@storybook/addon-essentials": "7.4.0",
"@storybook/addon-interactions": "7.4.0",
"@storybook/addon-mdx-gfm": "7.4.0",
"@storybook/channels": "7.4.0",
"@storybook/client-logger": "7.4.0",
"@storybook/addon-actions": "7.5.0-alpha.0",
"@storybook/addon-essentials": "7.5.0-alpha.0",
"@storybook/addon-interactions": "7.5.0-alpha.0",
"@storybook/addon-mdx-gfm": "7.5.0-alpha.0",
"@storybook/channels": "7.5.0-alpha.0",
"@storybook/client-logger": "7.5.0-alpha.0",
"@storybook/eslint-config-storybook": "^3.1.2",
"@storybook/jest": "^0.2.2",
"@storybook/manager-api": "7.4.0",
"@storybook/react": "7.4.0",
"@storybook/react-vite": "7.4.0",
"@storybook/manager-api": "7.5.0-alpha.0",
"@storybook/react": "7.5.0-alpha.0",
"@storybook/react-vite": "7.5.0-alpha.0",
"@storybook/testing-library": "^0.2.1-next.0",
"@storybook/theming": "7.4.0",
"@storybook/theming": "7.5.0-alpha.0",
"@types/jest": "^29.5.3",
"@types/node": "^18.15.0",
"@types/pluralize": "^0.0.29",
Expand All @@ -109,7 +109,7 @@
"react": "^16.14.0",
"react-dom": "^16.14.0",
"rimraf": "^3.0.2",
"storybook": "7.4.0",
"storybook": "7.5.0-alpha.0",
"@storybook/addon-designs": "^7.0.5",
"ts-jest": "^29.1.1",
"tsup": "^6.6.3",
Expand Down
2 changes: 1 addition & 1 deletion public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* tslint:disable */

/**
* Mock Service Worker (1.2.3).
* Mock Service Worker (1.3.0).
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
* - Please do NOT serve this file on production.
Expand Down
10 changes: 4 additions & 6 deletions src/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Spinner } from "@storybook/design-system";
import type { API } from "@storybook/manager-api";
import { useChannel, useStorybookState } from "@storybook/manager-api";
import React, { useCallback, useState } from "react";
import React, { useCallback } from "react";

import {
ADDON_ID,
Expand All @@ -18,9 +18,9 @@ import { LinkedProject } from "./screens/LinkProject/LinkedProject";
import { LinkingProjectFailed } from "./screens/LinkProject/LinkingProjectFailed";
import { LinkProject } from "./screens/LinkProject/LinkProject";
import { VisualTests } from "./screens/VisualTests/VisualTests";
import { UpdateStatusFunction } from "./types";
import { useAddonState } from "./useAddonState/manager";
import { client, Provider, useAccessToken } from "./utils/graphQLClient";
import { StatusUpdate } from "./utils/testsToStatusUpdate";
import { useProjectId } from "./utils/useProjectId";

interface PanelProps {
Expand All @@ -38,10 +38,8 @@ export const Panel = ({ active, api }: PanelProps) => {
const [runningBuild] = useAddonState<RunningBuildPayload>(RUNNING_BUILD);
const emit = useChannel({});

const updateBuildStatus = useCallback(
(update: StatusUpdate) => {
api.experimental_updateStatus(ADDON_ID, update);
},
const updateBuildStatus = useCallback<UpdateStatusFunction>(
(update) => api.experimental_updateStatus(ADDON_ID, update),
[api]
);
const {
Expand Down
30 changes: 27 additions & 3 deletions src/screens/VisualTests/VisualTests.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from "@storybook/jest";
import type { Meta, StoryObj } from "@storybook/react";
import { findByRole, findByTestId, fireEvent, waitFor } from "@storybook/testing-library";
import { graphql } from "msw";
import React from "react";

import type {
AddonVisualTestsBuildQuery,
Expand Down Expand Up @@ -184,7 +185,7 @@ const meta = {
projectId: "Project:id123",
startDevBuild: action("startDevBuild"),
setAccessToken: action("setAccessToken"),
updateBuildStatus: action("updateBuildStatus"),
updateBuildStatus: action("updateBuildStatus") as any,
},
} satisfies Meta<typeof VisualTests>;

Expand All @@ -208,6 +209,20 @@ export const NoBuild: Story = {
res(ctx.data({ build: null } as AddonVisualTestsBuildQuery))
),
},
render: ({ ...args }) => {
// custom render for mapping `updateBuildStatus` to a function which is mocked, but returns data instead of a function
return (
<VisualTests
{...args}
updateBuildStatus={(fn) => args.updateBuildStatus(typeof fn === "function" ? fn({}) : fn)}
/>
);
},
play: async ({ args }) => {
await waitFor(() => {
expect(args.updateBuildStatus).toHaveBeenCalledWith({});
});
},
};
export const NoBuildStarting: Story = {
...NoBuild,
Expand Down Expand Up @@ -290,8 +305,17 @@ export const Pending: Story = {
"https://www.figma.com/file/GFEbCgCVDtbZhngULbw2gP/Visual-testing-in-Storybook?type=design&node-id=508-304718&t=0rxMQnkxsVpVj1qy-4"
),
},
play: ({ args }) => {
waitFor(() => {
render: ({ ...args }) => {
// custom render for mapping `updateBuildStatus` to a function which is mocked, but returns data instead of a function
return (
<VisualTests
{...args}
updateBuildStatus={(fn) => args.updateBuildStatus(typeof fn === "function" ? fn({}) : fn)}
/>
);
},
play: async ({ args }) => {
await waitFor(() => {
expect(args.updateBuildStatus).toHaveBeenCalledWith({
"button--primary": {
status: "warn",
Expand Down
17 changes: 12 additions & 5 deletions src/screens/VisualTests/VisualTests.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Icons, Loader } from "@storybook/components";
import { Icon, TooltipNote, WithTooltip } from "@storybook/design-system";
// eslint-disable-next-line import/no-unresolved
import { GitInfo } from "chromatic/node";
import type { API_StatusState } from "@storybook/types";
import React, { useCallback, useEffect, useState } from "react";
import { useMutation, useQuery } from "urql";

Expand All @@ -24,7 +23,8 @@ import {
TestResult,
TestStatus,
} from "../../gql/graphql";
import { statusMap, StatusUpdate, testsToStatusUpdate } from "../../utils/testsToStatusUpdate";
import { UpdateStatusFunction } from "../../types";
import { statusMap, testsToStatusUpdate } from "../../utils/testsToStatusUpdate";
import { BuildProgress } from "./BuildProgress";
import { RenderSettings } from "./RenderSettings";
import { SnapshotComparison } from "./SnapshotComparison";
Expand Down Expand Up @@ -214,6 +214,10 @@ const MutationReviewTest = graphql(/* GraphQL */ `
}
`);

const createEmptyStoryStatusUpdate = (state: API_StatusState) => {
return Object.fromEntries(Object.entries(state).map(([id, update]) => [id, null]));
};

interface VisualTestsProps {
projectId: string;
gitInfo: Pick<
Expand All @@ -223,7 +227,7 @@ interface VisualTestsProps {
runningBuild?: RunningBuildPayload;
startDevBuild: () => void;
setAccessToken: (accessToken: string | null) => void;
updateBuildStatus: (update: StatusUpdate) => void;
updateBuildStatus: UpdateStatusFunction;
storyId: string;
}

Expand Down Expand Up @@ -311,7 +315,10 @@ export const VisualTests = ({
testsToStatusUpdate(getFragment(FragmentStatusTestFields, nextBuild.testsForStatus.nodes));

useEffect(() => {
if (buildStatusUpdate) updateBuildStatus(buildStatusUpdate);
updateBuildStatus((state) => ({
...createEmptyStoryStatusUpdate(state),
...buildStatusUpdate,
}));
// We use the stringified version of buildStatusUpdate to do a deep diff
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(buildStatusUpdate), updateBuildStatus]);
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { API } from "@storybook/manager-api";

import { StoryBuildFieldsFragment } from "./gql/graphql";

export type AnnouncedBuild = Extract<StoryBuildFieldsFragment, { __typename: "AnnouncedBuild" }>;
Expand All @@ -6,3 +8,9 @@ export type StartedBuild = Extract<StoryBuildFieldsFragment, { __typename: "Star
export type CompletedBuild = Extract<StoryBuildFieldsFragment, { __typename: "CompletedBuild" }>;

export type BuildWithTests = StartedBuild | CompletedBuild;

export type StoryStatusUpdater = Parameters<API["experimental_updateStatus"]>[1];

export type UpdateStatusFunction = (
update: StoryStatusUpdater
) => ReturnType<API["experimental_updateStatus"]>;
16 changes: 6 additions & 10 deletions src/utils/testsToStatusUpdate.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import type { API } from "@storybook/manager-api";
import type { StoryId } from "@storybook/types";
import type { API_StatusUpdate, API_StatusValue, StoryId } from "@storybook/types";

import { StatusTestFieldsFragment, TestStatus } from "../gql/graphql";

export type StatusUpdate = Parameters<API["experimental_updateStatus"]>[1];
type StoryStatus = StatusUpdate[any]["status"];

export const statusMap: Partial<Record<TestStatus, StoryStatus>> = {
export const statusMap: Partial<Record<TestStatus, API_StatusValue>> = {
[TestStatus.Pending]: "warn",
[TestStatus.Failed]: "error",
[TestStatus.Denied]: "error",
[TestStatus.Broken]: "error",
};

const statusOrder: StoryStatus[] = ["unknown", "pending", "success", "warn", "error"];
function chooseWorseStatus(status: StoryStatus, oldStatus: StoryStatus | null) {
const statusOrder: API_StatusValue[] = ["unknown", "pending", "success", "warn", "error"];
function chooseWorseStatus(status: API_StatusValue, oldStatus: API_StatusValue | null) {
if (!oldStatus) return status;

return statusOrder[Math.max(statusOrder.indexOf(status), statusOrder.indexOf(oldStatus))];
}

export function testsToStatusUpdate<T extends StatusTestFieldsFragment>(
tests: readonly T[]
): StatusUpdate {
const storyIdToStatus: Record<StoryId, StoryStatus> = {};
): API_StatusUpdate {
const storyIdToStatus: Record<StoryId, API_StatusValue> = {};
tests.forEach((test) => {
storyIdToStatus[test.story.storyId] = chooseWorseStatus(
statusMap[test.status],
Expand Down