Skip to content

Commit

Permalink
Merge branch 'test-screens' into matt/ap-3260-project-picker-with-chr…
Browse files Browse the repository at this point in the history
…omatic-api-and-token
  • Loading branch information
Matthew Weeks authored Jul 7, 2023
2 parents e07ac8d + dee0733 commit 085edc7
Show file tree
Hide file tree
Showing 19 changed files with 1,417 additions and 473 deletions.
3 changes: 1 addition & 2 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ const config: StorybookConfig = {
{
name: "../dist/index.js",
options: {
projectToken: "00baf09dbbe8",
projectId: "6480e1b0042842f149cfd74c", // Default to the the production project of this addon
projectToken: "chpt_c4206d1157d8947",
},
},
],
Expand Down
13 changes: 4 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Meta } from '@storybook/blocks';
import { VisualTestsIcon } from './components/icons/VisualTestsIcon';

<Meta title="Introduction" />

<VisualTestsIcon />

# Welcome to the Visual Tests addon for Storybook

Catch bugs in UI appearance automatically. Compare image snapshots to detect visual changes.
36 changes: 33 additions & 3 deletions src/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from "react";
import { useAddonState, useChannel, useStorybookState } from "@storybook/manager-api";
import React, { useCallback } from "react";

import { PANEL_ID } from "./constants";
import { ADDON_ID, PANEL_ID, START_BUILD } from "./constants";
import { Authentication } from "./screens/Authentication/Authentication";
import { LinkedProject, LinkProject } from "./screens/LinkProject/LinkProject";
import { VisualTests } from "./screens/VisualTests/VisualTests";
import { AddonState } from "./types";
import { client, Provider, useAccessToken } from "./utils/graphQLClient";
import { useProjectId } from "./utils/useProjectId";

Expand All @@ -14,6 +16,25 @@ interface PanelProps {
export const Panel = ({ active }: PanelProps) => {
const [accessToken, setAccessToken] = useAccessToken();
const [projectId, updateProject, projectIdChanged, clearProjectIdChanged] = useProjectId();
const [state, setAddonState] = useAddonState<AddonState>(ADDON_ID, { isOutdated: true });
const { storyId } = useStorybookState();

const setIsOutdated = useCallback(
(value: boolean) => setAddonState({ ...state, isOutdated: value }),
[state, setAddonState]
);
const setIsRunning = useCallback(
(value: boolean) => setAddonState({ ...state, isRunning: value }),
[state, setAddonState]
);

const emit = useChannel({});

const runDevBuild = useCallback(() => {
if (state.isRunning) return;
setAddonState({ ...state, isRunning: true });
emit(START_BUILD);
}, [emit, state, setAddonState]);

// Render a hidden element when the addon panel is not active.
// Storybook's AddonPanel component does the same but it's not styleable so we don't use it.
Expand All @@ -34,7 +55,16 @@ export const Panel = ({ active }: PanelProps) => {
}
return (
<Provider key={PANEL_ID} value={client}>
<VisualTests setAccessToken={setAccessToken} />
<VisualTests
isOutdated={state.isOutdated}
isRunning={state.isRunning}
lastDevBuildId={state.lastBuildId}
runDevBuild={runDevBuild}
setAccessToken={setAccessToken}
setIsOutdated={setIsOutdated}
setIsRunning={setIsRunning}
storyId={storyId}
/>
</Provider>
);
};
54 changes: 36 additions & 18 deletions src/Tool.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
import { IconButton, Icons } from "@storybook/components";
import { useAddonState, useChannel } from "@storybook/manager-api";
import React, { memo, useCallback, useState } from "react";
import React, { useCallback } from "react";

import { ADDON_ID, BUILD_STARTED, START_BUILD, TOOL_ID } from "./constants";
import { ProgressIcon } from "./components/icons/ProgressIcon";
import { ADDON_ID, BUILD_STARTED, DEV_BUILD_ID_KEY, START_BUILD, TOOL_ID } from "./constants";
import { AddonState } from "./types";

type BuildInfo = { url: string };
const storedBuildId = localStorage.getItem(DEV_BUILD_ID_KEY);

export const Tool = memo(function MyAddonSelector() {
const [running, setRunning] = useState(false);
const [, setAddonState] = useAddonState(ADDON_ID);

const emit = useChannel({
[BUILD_STARTED]: (build: BuildInfo) => {
setAddonState({ build });
},
export const Tool = () => {
const [state, setAddonState] = useAddonState<AddonState>(ADDON_ID, {
isOutdated: true,
lastBuildId: storedBuildId,
});

const onRun = useCallback(async () => {
if (running) return;
const emit = useChannel(
{
[BUILD_STARTED]: (buildId: string) => {
setAddonState({ ...state, lastBuildId: buildId });
localStorage.setItem(DEV_BUILD_ID_KEY, buildId);
},
},
[state, setAddonState]
);

setRunning(true);
const runDevBuild = useCallback(() => {
if (state.isRunning) return;
setAddonState({ ...state, isRunning: true });
emit(START_BUILD);
}, [running, emit]);
}, [emit, state, setAddonState]);

return (
<IconButton key={TOOL_ID} active={running} title="Run visual tests" onClick={onRun}>
<Icons icon="play" /> Run Tests
<IconButton
active={state.isRunning}
disabled={state.isRunning}
key={TOOL_ID}
title="Run visual tests"
onClick={runDevBuild}
>
{state.isRunning ? (
<ProgressIcon onButton />
) : (
<Icons icon="play" style={{ marginRight: 6 }} />
)}
Run tests
</IconButton>
);
});
};
5 changes: 5 additions & 0 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import { css, styled } from "@storybook/theming";
export const Button = styled(BaseButton)<{ link?: boolean; tertiary?: boolean }>(
{
"&&": {
display: "inline-flex",
borderRadius: 4,
fontSize: "13px",
lineHeight: "14px",
padding: "9px 12px",
alignItems: "center",
svg: {
marginRight: 6,
},
},
},
({ link, theme }) =>
Expand Down
61 changes: 46 additions & 15 deletions src/components/SnapshotImage.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,49 @@
import { styled } from "@storybook/theming";

export const SnapshotImage = styled.div({
position: "relative",
display: "flex",
justifyContent: "center",
alignItems: "center",
background: "#fff",
minHeight: 100,
margin: 2,
export const SnapshotImage = styled.div<{ href?: string; target?: string }>(
({ theme }) => ({
position: "relative",
display: "flex",
justifyContent: "center",
alignItems: "center",
background: "transparent",
minHeight: 100,
margin: 2,

img: {
maxWidth: "100%",
},
"img + img": {
position: "absolute",
},
});
img: {
maxWidth: "100%",
transition: "filter 0.1s ease-in-out",
},
"img + img": {
position: "absolute",
},
div: {
color: theme.color.mediumdark,
margin: "30px 15px",
textAlign: "center",
svg: {
width: 28,
height: 28,
},
},
"& > svg": {
position: "absolute",
width: 28,
height: 28,
color: theme.color.lightest,
opacity: 0,
transition: "opacity 0.1s ease-in-out",
},
}),
({ href }) =>
href && {
"&:hover": {
"& > svg": {
opacity: 1,
},
img: {
filter: "brightness(85%)",
},
},
}
);
20 changes: 20 additions & 0 deletions src/components/icons/AlertIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

export const AlertIcon = (props: any) => (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ margin: "3px 6px", verticalAlign: "top" }}
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM5.57143 6.85714C5.57143 7.09384 5.76331 7.28571 6 7.28571C6.23669 7.28571 6.42857 7.09384 6.42857 6.85714L6.42857 3.42857C6.42857 3.19188 6.23669 3 6 3C5.76331 3 5.57143 3.19188 5.57143 3.42857V6.85714ZM5.35714 8.78572C5.35714 8.43067 5.64496 8.14286 6 8.14286C6.35504 8.14286 6.64286 8.43067 6.64286 8.78571C6.64286 9.14075 6.35504 9.42857 6 9.42857C5.64496 9.42857 5.35714 9.14075 5.35714 8.78572Z"
fill="#73828C"
/>
</svg>
);
43 changes: 27 additions & 16 deletions src/components/icons/ProgressIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { animation } from "@storybook/design-system";
import { styled } from "@storybook/theming";
import { css, styled } from "@storybook/theming";

const { rotate360 } = animation;

export const ProgressIcon = styled.div(({ theme }) => ({
width: 12,
height: 12,
margin: "3px 6px",
verticalAlign: "top",
display: "inline-block",
export const ProgressIcon = styled.div<{ onButton?: boolean }>(
({ theme }) => ({
width: 12,
height: 12,
margin: "3px 6px",
verticalAlign: "top",
display: "inline-block",

animation: `${rotate360} 0.7s linear infinite`,
border: "2px solid transparent",
borderLeftColor: theme.base === "dark" ? "#58faf9" : "#00aaff",
borderBottomColor: "#25ccfd",
borderRightColor: theme.base === "dark" ? "#00aaff" : "#58faf9",
borderRadius: "100%",
cursor: "progress",
transform: "translate3d(0, 0, 0)",
}));
animation: `${rotate360} 0.7s linear infinite`,
border: "2px solid transparent",
borderLeftColor: theme.base === "dark" ? "#58faf9" : "#00aaff",
borderBottomColor: "#25ccfd",
borderRightColor: theme.base === "dark" ? "#00aaff" : "#58faf9",
borderRadius: "100%",
cursor: "progress",
transform: "translate3d(0, 0, 0)",
}),
({ onButton }) =>
onButton &&
css({
margin: "0 6px 0 0",
borderWidth: 1,
borderLeftColor: "currentcolor",
borderBottomColor: "currentcolor",
borderRightColor: "currentcolor",
})
);
3 changes: 2 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export const { CHROMATIC_BASE_URL } = process.env;
export const ADDON_ID = "chromaui/storybook-visual-tests";
export const TOOL_ID = `${ADDON_ID}/tool`;
export const PANEL_ID = `${ADDON_ID}/panel`;
export const STORAGE_KEY = `${ADDON_ID}/access-token/${CHROMATIC_BASE_URL}`;
export const ACCESS_TOKEN_KEY = `${ADDON_ID}/access-token/${CHROMATIC_BASE_URL}`;
export const DEV_BUILD_ID_KEY = `${ADDON_ID}/dev-build-id`;

export const PROJECT_PARAM_KEY = "projectId";

Expand Down
Loading

0 comments on commit 085edc7

Please sign in to comment.