diff --git a/src/components/BrowserSelector.stories.ts b/src/components/BrowserSelector.stories.ts new file mode 100644 index 00000000..b691a96b --- /dev/null +++ b/src/components/BrowserSelector.stories.ts @@ -0,0 +1,110 @@ +import { action } from "@storybook/addon-actions"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Browser, ComparisonResult } from "../gql/graphql"; +import { BrowserSelector } from "./BrowserSelector"; + +const meta = { + component: BrowserSelector, + args: { + onSelectBrowser: action("onSelectBrowser"), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const browserChrome = { + id: "_chrome", + key: Browser.Chrome, + name: "Chrome", +}; +const browserSafari = { + id: "_safari", + key: Browser.Safari, + name: "Safari", +}; + +export const WithSingleBrowserChanged: Story = { + args: { + selectedBrowser: browserChrome, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.Changed, + }, + ], + }, +}; + +export const WithSingleBrowserEqual: Story = { + args: { + selectedBrowser: browserChrome, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.Equal, + }, + ], + }, +}; + +export const WithSingleBrowserError: Story = { + args: { + selectedBrowser: browserChrome, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.CaptureError, + }, + ], + }, +}; + +export const WithManyBrowsersEqual: Story = { + args: { + selectedBrowser: browserChrome, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.Equal, + }, + { + browser: browserSafari, + result: ComparisonResult.Equal, + }, + ], + }, +}; + +export const WithManyBrowsersSecondSelected: Story = { + args: { + selectedBrowser: browserSafari, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.Equal, + }, + { + browser: browserSafari, + result: ComparisonResult.Equal, + }, + ], + }, +}; + +export const WithManyBrowsersVaried: Story = { + args: { + selectedBrowser: browserChrome, + browserResults: [ + { + browser: browserChrome, + result: ComparisonResult.Changed, + }, + { + browser: browserSafari, + result: ComparisonResult.Equal, + }, + ], + }, +}; diff --git a/src/components/BrowserSelector.tsx b/src/components/BrowserSelector.tsx index f6a53592..29b72c44 100644 --- a/src/components/BrowserSelector.tsx +++ b/src/components/BrowserSelector.tsx @@ -20,27 +20,22 @@ const browserIcons = { type BrowserData = Pick; interface BrowserSelectorProps { + selectedBrowser: BrowserData; browserResults: { browser: BrowserData; result: ComparisonResult }[]; onSelectBrowser: (browser: BrowserData) => void; } -export const BrowserSelector = ({ browserResults, onSelectBrowser }: BrowserSelectorProps) => { - const [selected, setSelected] = React.useState(browserResults[0].browser); - - const handleSelect = React.useCallback( - (browser: BrowserData) => { - setSelected(browser); - onSelectBrowser(browser); - }, - [onSelectBrowser] - ); - +export const BrowserSelector = ({ + selectedBrowser, + browserResults, + onSelectBrowser, +}: BrowserSelectorProps) => { const links = browserResults .filter(({ browser }) => browser.key in browserIcons) .map(({ browser, result }) => ({ - active: selected === browser, + active: selectedBrowser === browser, id: browser.id, - onClick: () => handleSelect(browser), + onClick: () => onSelectBrowser(browser), right: result !== ComparisonResult.Equal && , title: browser.name, })); @@ -48,7 +43,7 @@ export const BrowserSelector = ({ browserResults, onSelectBrowser }: BrowserSele const aggregate = aggregateResult(browserResults.map(({ result }) => result)); if (!aggregate) return null; - const icon = browserIcons[selected.key]; + const icon = browserIcons[selectedBrowser.key]; return ( {aggregate === ComparisonResult.Equal ? ( diff --git a/src/components/ViewportSelector.stories.ts b/src/components/ViewportSelector.stories.ts new file mode 100644 index 00000000..0ceecd23 --- /dev/null +++ b/src/components/ViewportSelector.stories.ts @@ -0,0 +1,108 @@ +import { action } from "@storybook/addon-actions"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { ComparisonResult } from "../gql/graphql"; +import { ViewportSelector } from "./ViewportSelector"; + +const viewport800Px = { + id: "_800", + name: "800px", +}; +const viewport1200Px = { + id: "_1200", + name: "1200px", +}; + +const meta = { + component: ViewportSelector, + args: { + onSelectViewport: action("onSelectViewport"), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const WithSingleViewportChanged: Story = { + args: { + selectedViewport: viewport1200Px, + viewportResults: [ + { + viewport: viewport1200Px, + result: ComparisonResult.Changed, + }, + ], + }, +}; + +export const WithSingleViewportEqual: Story = { + args: { + selectedViewport: viewport1200Px, + viewportResults: [ + { + viewport: viewport1200Px, + result: ComparisonResult.Equal, + }, + ], + }, +}; + +export const WithSingleViewportError: Story = { + args: { + selectedViewport: viewport1200Px, + viewportResults: [ + { + viewport: viewport1200Px, + result: ComparisonResult.CaptureError, + }, + ], + }, +}; + +export const WithManyViewportsEqual: Story = { + args: { + selectedViewport: viewport800Px, + viewportResults: [ + { + viewport: viewport800Px, + result: ComparisonResult.Equal, + }, + { + viewport: viewport1200Px, + result: ComparisonResult.Equal, + }, + ], + }, +}; + +export const WithManyViewportsSecondSelected: Story = { + args: { + selectedViewport: viewport1200Px, + viewportResults: [ + { + viewport: viewport800Px, + result: ComparisonResult.Equal, + }, + { + viewport: viewport1200Px, + result: ComparisonResult.Changed, + }, + ], + }, +}; + +export const WithManyViewportsVaried: Story = { + args: { + selectedViewport: viewport800Px, + viewportResults: [ + { + viewport: viewport800Px, + result: ComparisonResult.Equal, + }, + { + viewport: viewport1200Px, + result: ComparisonResult.Changed, + }, + ], + }, +}; diff --git a/src/components/ViewportSelector.tsx b/src/components/ViewportSelector.tsx index 3a759596..8e363581 100644 --- a/src/components/ViewportSelector.tsx +++ b/src/components/ViewportSelector.tsx @@ -10,21 +10,16 @@ import { TooltipMenu } from "./TooltipMenu"; type ViewportData = Pick; interface ViewportSelectorProps { - viewportResults: { viewport: ViewportData; result: ComparisonResult }[]; + selectedViewport: ViewportData; onSelectViewport: (viewport: ViewportData) => void; + viewportResults: { viewport: ViewportData; result: ComparisonResult }[]; } -export const ViewportSelector = ({ viewportResults, onSelectViewport }: ViewportSelectorProps) => { - const [selected, setSelected] = React.useState(viewportResults[0].viewport); - - const handleSelect = React.useCallback( - (viewport: ViewportData) => { - setSelected(viewport); - onSelectViewport(viewport); - }, - [onSelectViewport] - ); - +export const ViewportSelector = ({ + selectedViewport, + viewportResults, + onSelectViewport, +}: ViewportSelectorProps) => { const aggregate = aggregateResult(viewportResults.map(({ result }) => result)); if (!aggregate) return null; @@ -35,8 +30,8 @@ export const ViewportSelector = ({ viewportResults, onSelectViewport }: Viewport id: viewport.id, title: viewport.name, right: result !== ComparisonResult.Equal && , - onClick: () => handleSelect(viewport), - active: selected === viewport, + onClick: () => onSelectViewport(viewport), + active: selectedViewport === viewport, }))} > {aggregate === ComparisonResult.Equal ? ( @@ -46,7 +41,7 @@ export const ViewportSelector = ({ viewportResults, onSelectViewport }: Viewport )} - {selected.name} + {selectedViewport.name} ); diff --git a/src/gql/gql.ts b/src/gql/gql.ts index 0ba820ce..ffd66f92 100644 --- a/src/gql/gql.ts +++ b/src/gql/gql.ts @@ -16,7 +16,7 @@ const documents = { "\n query SelectProjectsQuery {\n viewer {\n accounts {\n id\n name\n avatarUrl\n projects {\n id\n name\n webUrl\n projectToken\n lastBuild {\n branch\n number\n }\n }\n }\n }\n }\n": types.SelectProjectsQueryDocument, "\n query ProjectQuery($projectId: ID!) {\n project(id: $projectId) {\n id\n name\n webUrl\n lastBuild {\n branch\n number\n }\n }\n }\n": types.ProjectQueryDocument, "\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n name\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n": types.BuildDocument, - "\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n": types.BuildFieldsFragmentDoc, + "\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n": types.BuildFieldsFragmentDoc, "\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n": types.TestFieldsFragmentDoc, "\n mutation ReviewTest($input: ReviewTestInput!) {\n reviewTest(input: $input) {\n updatedTests {\n id\n status\n }\n userErrors {\n ... on UserError {\n __typename\n message\n }\n ... on BuildSupersededError {\n build {\n id\n }\n }\n ... on TestUnreviewableError {\n test {\n id\n }\n }\n }\n }\n }\n": types.ReviewTestDocument, }; @@ -50,7 +50,7 @@ export function graphql(source: "\n query Build($hasBuildId: Boolean!, $buildId /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n"): (typeof documents)["\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n"]; +export function graphql(source: "\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n"): (typeof documents)["\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n brokenCount: testCount(results: [CAPTURE_ERROR])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/src/gql/graphql.ts b/src/gql/graphql.ts index 5f9d5ccd..524a94ba 100644 --- a/src/gql/graphql.ts +++ b/src/gql/graphql.ts @@ -1273,7 +1273,7 @@ export type BuildQuery = { __typename?: 'Query', build?: ( type BuildFields_AnnouncedBuild_Fragment = { __typename: 'AnnouncedBuild', id: string, number: number, branch: string, commit: string, status: BuildStatus, browsers: Array<{ __typename?: 'BrowserInfo', id: string, key: Browser, name: string }> } & { ' $fragmentName'?: 'BuildFields_AnnouncedBuild_Fragment' }; -type BuildFields_CompletedBuild_Fragment = { __typename: 'CompletedBuild', result: BuildResult, startedAt: any, id: string, number: number, branch: string, commit: string, status: BuildStatus, changeCount: number, tests?: { __typename?: 'CompletedBuildTestConnection', nodes: Array<( +type BuildFields_CompletedBuild_Fragment = { __typename: 'CompletedBuild', result: BuildResult, startedAt: any, id: string, number: number, branch: string, commit: string, status: BuildStatus, changeCount: number, brokenCount: number, tests?: { __typename?: 'CompletedBuildTestConnection', nodes: Array<( { __typename?: 'Test' } & { ' $fragmentRefs'?: { 'TestFieldsFragment': TestFieldsFragment } } )> } | null, browsers: Array<{ __typename?: 'BrowserInfo', id: string, key: Browser, name: string }> } & { ' $fragmentName'?: 'BuildFields_CompletedBuild_Fragment' }; @@ -1282,7 +1282,7 @@ type BuildFields_PreparedBuild_Fragment = { __typename: 'PreparedBuild', id: str type BuildFields_PublishedBuild_Fragment = { __typename: 'PublishedBuild', id: string, number: number, branch: string, commit: string, status: BuildStatus, browsers: Array<{ __typename?: 'BrowserInfo', id: string, key: Browser, name: string }> } & { ' $fragmentName'?: 'BuildFields_PublishedBuild_Fragment' }; -type BuildFields_StartedBuild_Fragment = { __typename: 'StartedBuild', startedAt: any, id: string, number: number, branch: string, commit: string, status: BuildStatus, changeCount: number, tests?: { __typename?: 'StartedBuildTestConnection', nodes: Array<( +type BuildFields_StartedBuild_Fragment = { __typename: 'StartedBuild', startedAt: any, id: string, number: number, branch: string, commit: string, status: BuildStatus, changeCount: number, brokenCount: number, tests?: { __typename?: 'StartedBuildTestConnection', nodes: Array<( { __typename?: 'Test' } & { ' $fragmentRefs'?: { 'TestFieldsFragment': TestFieldsFragment } } )> } | null, browsers: Array<{ __typename?: 'BrowserInfo', id: string, key: Browser, name: string }> } & { ' $fragmentName'?: 'BuildFields_StartedBuild_Fragment' }; @@ -1299,8 +1299,8 @@ export type ReviewTestMutationVariables = Exact<{ export type ReviewTestMutation = { __typename?: 'Mutation', reviewTest?: { __typename?: 'ReviewTestPayload', updatedTests?: Array<{ __typename?: 'Test', id: string, status: TestStatus }> | null, userErrors: Array<{ __typename: 'BuildSupersededError', message: string, build: { __typename?: 'AnnouncedBuild', id: string } | { __typename?: 'CompletedBuild', id: string } | { __typename?: 'PreparedBuild', id: string } | { __typename?: 'PublishedBuild', id: string } | { __typename?: 'StartedBuild', id: string } } | { __typename: 'TestNotFoundError', message: string } | { __typename: 'TestUnreviewableError', message: string, test: { __typename?: 'Test', id: string } }> } | null }; export const TestFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Test"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"comparisons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"browser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}},{"kind":"Field","name":{"kind":"Name","value":"captureDiff"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"diffImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"headCapture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"captureImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"parameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"story"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storyId"}}]}}]}}]} as unknown as DocumentNode; -export const BuildFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BuildFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Build"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"commit"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"browsers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StartedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CompletedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Test"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"comparisons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"browser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}},{"kind":"Field","name":{"kind":"Name","value":"captureDiff"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"diffImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"headCapture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"captureImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"parameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"story"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storyId"}}]}}]}}]} as unknown as DocumentNode; +export const BuildFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BuildFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Build"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"commit"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"browsers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StartedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","alias":{"kind":"Name","value":"brokenCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"CAPTURE_ERROR"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CompletedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","alias":{"kind":"Name","value":"brokenCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"CAPTURE_ERROR"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Test"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"comparisons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"browser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}},{"kind":"Field","name":{"kind":"Name","value":"captureDiff"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"diffImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"headCapture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"captureImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"parameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"story"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storyId"}}]}}]}}]} as unknown as DocumentNode; export const SelectProjectsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectProjectsQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"projects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"projectToken"}},{"kind":"Field","name":{"kind":"Name","value":"lastBuild"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"number"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ProjectQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"lastBuild"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"number"}}]}}]}}]}}]} as unknown as DocumentNode; -export const BuildDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Build"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"buildId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"branch"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"build"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"buildId"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BuildFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"skip"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"lastBuild"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"branches"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"branch"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BuildFields"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Test"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"comparisons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"browser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}},{"kind":"Field","name":{"kind":"Name","value":"captureDiff"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"diffImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"headCapture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"captureImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"parameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"story"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storyId"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BuildFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Build"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"commit"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"browsers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StartedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CompletedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const BuildDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Build"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"buildId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"branch"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"build"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"buildId"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BuildFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"skip"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasBuildId"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"lastBuild"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"branches"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"branch"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BuildFields"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Test"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"webUrl"}},{"kind":"Field","name":{"kind":"Name","value":"comparisons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","name":{"kind":"Name","value":"browser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}},{"kind":"Field","name":{"kind":"Name","value":"captureDiff"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"diffImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"headCapture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"captureImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"parameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewport"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"story"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storyId"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BuildFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Build"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"branch"}},{"kind":"Field","name":{"kind":"Name","value":"commit"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"browsers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StartedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","alias":{"kind":"Name","value":"brokenCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"CAPTURE_ERROR"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CompletedBuild"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"result"}},{"kind":"Field","alias":{"kind":"Name","value":"changeCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ADDED"},{"kind":"EnumValue","value":"CHANGED"},{"kind":"EnumValue","value":"FIXED"}]}}]},{"kind":"Field","alias":{"kind":"Name","value":"brokenCount"},"name":{"kind":"Name","value":"testCount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"results"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"CAPTURE_ERROR"}]}}]},{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"tests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestFields"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ReviewTestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ReviewTest"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewTestInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviewTest"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updatedTests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"userErrors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BuildSupersededError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"build"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TestUnreviewableError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"test"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/src/screens/VisualTests/BuildInfo.stories.ts b/src/screens/VisualTests/BuildInfo.stories.ts new file mode 100644 index 00000000..8565b5fe --- /dev/null +++ b/src/screens/VisualTests/BuildInfo.stories.ts @@ -0,0 +1,135 @@ +import { action } from "@storybook/addon-actions"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Browser, BuildStatus } from "../../gql/graphql"; +import { makeBrowserInfo } from "../../utils/storyData"; +import { BuildInfo } from "./BuildInfo"; + +const meta = { + component: BuildInfo, + args: { + isOutdated: false, + runDevBuild: action("runDevBuild"), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const InProgressUnstarted: Story = { + args: { + build: { + status: BuildStatus.InProgress, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + }, +}; + +export const InProgress: Story = { + args: { + build: { + status: BuildStatus.InProgress, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 0, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + }, +}; + +export const Pending: Story = { + args: { + build: { + status: BuildStatus.Pending, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 10, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + }, +}; + +export const Passed: Story = { + args: { + build: { + status: BuildStatus.Passed, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 0, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + }, +}; + +export const PassedOutdated: Story = { + args: { + build: { + status: BuildStatus.Passed, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 0, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + isOutdated: true, + }, +}; +export const Accepted: Story = { + args: { + build: { + status: BuildStatus.Accepted, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 10, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 1, + }, +}; + +export const PendingManyViewportsAndBrowsers: Story = { + args: { + build: { + status: BuildStatus.Pending, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 10, + brokenCount: 0, + browsers: [ + makeBrowserInfo(Browser.Chrome), + makeBrowserInfo(Browser.Firefox), + makeBrowserInfo(Browser.Safari), + ], + }, + viewportCount: 2, + }, +}; + +export const Broken: Story = { + args: { + build: { + status: BuildStatus.Broken, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 0, + brokenCount: 10, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 0, + }, +}; + +export const Failed: Story = { + args: { + build: { + status: BuildStatus.Failed, + startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago + changeCount: 0, + brokenCount: 0, + browsers: [makeBrowserInfo(Browser.Chrome)], + }, + viewportCount: 0, + }, +}; diff --git a/src/screens/VisualTests/BuildInfo.tsx b/src/screens/VisualTests/BuildInfo.tsx index c2145206..fc89c3d9 100644 --- a/src/screens/VisualTests/BuildInfo.tsx +++ b/src/screens/VisualTests/BuildInfo.tsx @@ -8,40 +8,40 @@ import { AlertIcon } from "../../components/icons/AlertIcon"; import { ProgressIcon } from "../../components/icons/ProgressIcon"; import { StatusIcon } from "../../components/icons/StatusIcon"; import { Col, Row, Text } from "../../components/layout"; -import { BuildStatus } from "../../gql/graphql"; +import { BuildFieldsFragment, BuildStatus } from "../../gql/graphql"; interface BuildInfoSectionProps { - status: BuildStatus; - startedAt: string; - brokenCount: number; - browserCount: number; - changeCount: number; + build: + | Pick + | Pick< + Extract, + "status" | "browsers" | "startedAt" | "brokenCount" | "changeCount" + >; viewportCount: number; - isInProgress: boolean; isOutdated: boolean; - isPending: boolean; - isRunning: boolean; runDevBuild: () => void; } export const BuildInfo = ({ - status, - startedAt, - brokenCount, - browserCount, - changeCount, + build, viewportCount, - isInProgress, isOutdated, - isPending, - isRunning, runDevBuild, }: BuildInfoSectionProps) => { + const { status, browsers } = build; const startedAgo = - startedAt && formatDistance(new Date(startedAt), new Date(), { addSuffix: true }); + "startedAt" in build && + formatDistance(new Date(build.startedAt), new Date(), { addSuffix: true }); + const browserCount = browsers.length; + const inProgress = [ + BuildStatus.InProgress, + BuildStatus.Announced, + BuildStatus.Prepared, + BuildStatus.Published, + ].includes(status); let statusText; - if (status === BuildStatus.InProgress) { + if (inProgress) { statusText = ( <> Running tests... @@ -56,6 +56,8 @@ export const BuildInfo = ({ ); } else { + if (!("startedAt" in build)) throw new Error(`No startedAt field on started build`); + statusText = isOutdated ? ( <> Snapshots outdated @@ -64,11 +66,15 @@ export const BuildInfo = ({ ) : ( <> - {changeCount ? pluralize("change", changeCount, true) : "No changes"} - {brokenCount ? `, ${pluralize("error", brokenCount, true)}` : null} + {build.changeCount ? pluralize("change", build.changeCount, true) : "No changes"} + {build.brokenCount ? `, ${pluralize("error", build.brokenCount, true)}` : null} - {/* eslint-disable-next-line no-nested-ternary */} - + ); } @@ -93,9 +99,9 @@ export const BuildInfo = ({ {pluralize("browser", browserCount, true)} {" • "} - {isInProgress && Test in progress...} - {!isInProgress && startedAt && ( - {startedAgo} + {inProgress && Test in progress...} + {!inProgress && "startedAt" in build && ( + {startedAgo} )} ); @@ -113,8 +119,8 @@ export const BuildInfo = ({ {isOutdated && ( - )} - {status === BuildStatus.Failed && ( + {BuildStatus.Failed === status && ( - diff --git a/src/screens/VisualTests/SnapshotComparison.stories.tsx b/src/screens/VisualTests/SnapshotComparison.stories.tsx new file mode 100644 index 00000000..042a26e4 --- /dev/null +++ b/src/screens/VisualTests/SnapshotComparison.stories.tsx @@ -0,0 +1,141 @@ +import { action } from "@storybook/addon-actions"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Browser, ComparisonResult, TestResult, TestStatus } from "../../gql/graphql"; +import { makeComparison, makeTest } from "../../utils/storyData"; +import { SnapshotComparison } from "./SnapshotComparison"; + +const browsers = [Browser.Chrome, Browser.Safari]; +const tests = [ + makeTest({ + id: "11", + status: TestStatus.Pending, + result: TestResult.Changed, + comparisons: [ + makeComparison({ + id: "112", + browser: Browser.Chrome, + viewport: 800, + result: ComparisonResult.Changed, + }), + makeComparison({ + id: "112", + browser: Browser.Safari, + viewport: 800, + result: ComparisonResult.Equal, + }), + ], + viewport: 800, + storyId: "button--primary", + }), + makeTest({ + id: "12", + status: TestStatus.Passed, + result: TestResult.Equal, + browsers, + viewport: 1200, + storyId: "button--primary", + }), + makeTest({ + id: "13", + status: TestStatus.Passed, + result: TestResult.Equal, + browsers, + viewport: 400, + storyId: "button--primary", + }), +]; + +const meta = { + component: SnapshotComparison, + args: { + tests, + isAccepting: false, + onAccept: action("onAccept"), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const InProgress: Story = { + args: { + tests: tests.map((test) => ({ + ...test, + status: TestStatus.InProgress, + result: null, + comparisons: test.comparisons.map((comparison) => ({ + ...comparison, + result: null, + headCapture: null, + captureDiff: null, + })), + })), + }, +}; + +export const WithMultipleTests: Story = {}; + +/** + * Sort of confusing situation where the only comparison with changes (1200px/Saf) is on the + * "opposite" side of the current comparison (800px/Chrome) + */ +export const WithMultipleTestsFirstPassed: Story = { + args: { + tests: [ + makeTest({ + id: "11", + status: TestStatus.Passed, + result: TestResult.Equal, + browsers, + viewport: 800, + storyId: "button--primary", + }), + makeTest({ + id: "12", + status: TestStatus.Pending, + result: TestResult.Changed, + comparisons: [ + makeComparison({ + id: "112", + browser: Browser.Chrome, + viewport: 1200, + result: ComparisonResult.Equal, + }), + makeComparison({ + id: "112", + browser: Browser.Safari, + viewport: 1200, + result: ComparisonResult.Changed, + }), + ], + viewport: 1200, + storyId: "button--primary", + }), + ], + }, +}; + +export const WithSingleTest: Story = { + args: { + tests: [tests[0]], + }, +}; + +export const WithSingleTestAccepting: Story = { + args: { + isAccepting: true, + tests: [tests[0]], + }, +}; + +export const WithSingleTestAccepted: Story = { + args: { + tests: [ + { + ...tests[0], + status: TestStatus.Accepted, + }, + ], + }, +}; diff --git a/src/screens/VisualTests/SnapshotComparison.tsx b/src/screens/VisualTests/SnapshotComparison.tsx index e8f9ea27..2af809bd 100644 --- a/src/screens/VisualTests/SnapshotComparison.tsx +++ b/src/screens/VisualTests/SnapshotComparison.tsx @@ -1,6 +1,6 @@ import { Icons, Loader } from "@storybook/components"; import { styled } from "@storybook/theming"; -import React, { ComponentProps, useState } from "react"; +import React, { useState } from "react"; import { BrowserSelector } from "../../components/BrowserSelector"; import { IconButton } from "../../components/IconButton"; @@ -10,7 +10,13 @@ import { Placeholder } from "../../components/Placeholder"; import { SnapshotImage } from "../../components/SnapshotImage"; import { TooltipMenu } from "../../components/TooltipMenu"; import { ViewportSelector } from "../../components/ViewportSelector"; -import { ComparisonResult, ReviewTestBatch, TestFieldsFragment } from "../../gql/graphql"; +import { + ComparisonResult, + ReviewTestBatch, + TestFieldsFragment, + TestStatus, +} from "../../gql/graphql"; +import { useTests } from "../../utils/useTests"; const Divider = styled.div(({ theme }) => ({ backgroundColor: theme.appBorderColor, @@ -19,30 +25,24 @@ const Divider = styled.div(({ theme }) => ({ })); interface SnapshotSectionProps { - test?: TestFieldsFragment; - changeCount: number; + tests: TestFieldsFragment[]; isAccepting: boolean; - isInProgress: boolean; - browserResults: ComponentProps["browserResults"]; - viewportResults: ComponentProps["viewportResults"]; onAccept: (testId: TestFieldsFragment["id"], batch?: ReviewTestBatch) => void; } -export const SnapshotComparison = ({ - test, - changeCount, - isAccepting, - isInProgress, - browserResults, - viewportResults, - onAccept, -}: SnapshotSectionProps) => { +export const SnapshotComparison = ({ tests, isAccepting, onAccept }: SnapshotSectionProps) => { + const { + selectedTest, + selectedComparison, + isInProgress, + changeCount, + browserResults, + onSelectBrowser, + viewportResults, + onSelectViewport, + } = useTests(tests); const [diffVisible, setDiffVisible] = useState(true); - const comparison = - test?.comparisons.find(({ result }) => result === ComparisonResult.Changed) || - test?.comparisons[0]; - return ( <> {isInProgress ? ( @@ -54,7 +54,7 @@ export const SnapshotComparison = ({ ) : ( - {comparison?.result === ComparisonResult.Changed && ( + {selectedComparison?.result === ComparisonResult.Changed && ( setDiffVisible(!diffVisible)}> @@ -64,25 +64,25 @@ export const SnapshotComparison = ({ {viewportResults.length > 0 && ( )} {browserResults.length > 0 && ( )} - {changeCount > 0 && ( + {changeCount > 0 && selectedTest.status !== TestStatus.Accepted && ( <> - onAccept(test.id)}> + onAccept(selectedTest.id)}> Accept @@ -94,7 +94,7 @@ export const SnapshotComparison = ({ id: "logout", title: "Accept all viewports", center: "Accept all unreviewed changes to this story", - onClick: () => onAccept(test.id, ReviewTestBatch.Spec), + onClick: () => onAccept(selectedTest.id, ReviewTestBatch.Spec), disabled: isAccepting, loading: isAccepting, }, @@ -102,7 +102,7 @@ export const SnapshotComparison = ({ id: "learn", title: "Accept this component", center: "Accept all unreviewed changes for this component", - onClick: () => onAccept(test.id, ReviewTestBatch.Component), + onClick: () => onAccept(selectedTest.id, ReviewTestBatch.Component), disabled: isAccepting, loading: isAccepting, }, @@ -127,18 +127,18 @@ export const SnapshotComparison = ({ {isInProgress && } - {!isInProgress && comparison && ( - - {comparison.headCapture?.captureImage && ( - + {!isInProgress && selectedComparison && ( + + {selectedComparison.headCapture?.captureImage && ( + )} {diffVisible && - comparison.result === ComparisonResult.Changed && - comparison.captureDiff?.diffImage && ( - + selectedComparison.result === ComparisonResult.Changed && + selectedComparison.captureDiff?.diffImage && ( + )} - {comparison.result === ComparisonResult.CaptureError && - !comparison.headCapture?.captureImage && ( + {selectedComparison.result === ComparisonResult.CaptureError && + !selectedComparison.headCapture?.captureImage && (

diff --git a/src/screens/VisualTests/VisualTests.stories.tsx b/src/screens/VisualTests/VisualTests.stories.tsx index 7c9bebc5..bbbbc88d 100644 --- a/src/screens/VisualTests/VisualTests.stories.tsx +++ b/src/screens/VisualTests/VisualTests.stories.tsx @@ -8,132 +8,23 @@ import { Browser, BuildStatus, ComparisonResult, TestResult, TestStatus } from " import { AnnouncedBuild, CompletedBuild, PublishedBuild, StartedBuild } from "../../types"; import { storyWrapper } from "../../utils/graphQLClient"; import { playAll } from "../../utils/playAll"; +import { headCapture, makeBrowserInfo, makeTest, makeViewportInfo } from "../../utils/storyData"; import { withFigmaDesign } from "../../utils/withFigmaDesign"; +import * as SnapshotComparisonStories from "./SnapshotComparison.stories"; import { VisualTests } from "./VisualTests"; -const browser = (key: Browser) => ({ - id: key, - key, - name: key.slice(0, 1) + key.slice(1).toLowerCase(), - version: "", -}); -const viewport = (width: number) => ({ - id: `_${width}`, - name: `${width}px`, - width, - isDefault: width === 1200, -}); - -const headCapture = { - captureImage: { - imageUrl: "/B.png", - }, -}; -const captureDiff = { - diffImage: { - imageUrl: "/B-comparison.png", - }, -}; - +const { tests: primaryTests } = SnapshotComparisonStories.default.args; +const browsers = [Browser.Chrome, Browser.Safari]; const tests = [ - { - id: "11", - status: TestStatus.Passed, - result: TestResult.Equal, - webUrl: "https://www.chromatic.com/test?appId=123&id=11", - comparisons: [ - { - id: "111", - browser: browser(Browser.Chrome), - viewport: viewport(1200), - result: ComparisonResult.Equal, - headCapture, - }, - { - id: "112", - browser: browser(Browser.Safari), - viewport: viewport(1200), - result: ComparisonResult.Equal, - headCapture, - }, - ], - parameters: { viewport: viewport(1200) }, - story: { storyId: "button--primary" }, - }, - { - id: "12", - status: TestStatus.Pending, - result: TestResult.Changed, - webUrl: "https://www.chromatic.com/test?appId=123&id=12", - comparisons: [ - { - id: "121", - browser: browser(Browser.Chrome), - viewport: viewport(800), - result: ComparisonResult.Equal, - headCapture, - }, - { - id: "122", - browser: browser(Browser.Safari), - viewport: viewport(800), - result: ComparisonResult.Changed, - headCapture, - captureDiff, - }, - ], - parameters: { viewport: viewport(800) }, - story: { storyId: "button--primary" }, - }, - { - id: "13", - status: TestStatus.Passed, - result: TestResult.Equal, - webUrl: "https://www.chromatic.com/test?appId=123&id=13", - comparisons: [ - { - id: "131", - browser: browser(Browser.Chrome), - viewport: viewport(400), - result: ComparisonResult.Equal, - headCapture, - }, - { - id: "132", - browser: browser(Browser.Safari), - viewport: viewport(400), - result: ComparisonResult.Equal, - headCapture, - }, - ], - parameters: { viewport: viewport(400) }, - story: { storyId: "button--primary" }, - }, - - { + ...primaryTests, + makeTest({ id: "21", status: TestStatus.Passed, result: TestResult.Equal, - webUrl: "https://www.chromatic.com/test?appId=123&id=21", - comparisons: [ - { - id: "211", - browser: browser(Browser.Chrome), - viewport: viewport(1200), - result: ComparisonResult.Equal, - headCapture, - }, - { - id: "212", - browser: browser(Browser.Safari), - viewport: viewport(1200), - result: ComparisonResult.Equal, - headCapture, - }, - ], - parameters: { viewport: viewport(1200) }, - story: { storyId: "button--secondary" }, - }, + browsers, + viewport: 1200, + storyId: "button--secondary", + }), ]; const paginated = (nodes: TestFieldsFragment[]) => ({ @@ -154,7 +45,7 @@ const announcedBuild: AnnouncedBuild = { number: 1, branch: "feature-branch", commit: "1234567", - browsers: [browser(Browser.Chrome), browser(Browser.Safari)], + browsers: [makeBrowserInfo(Browser.Chrome), makeBrowserInfo(Browser.Safari)], status: BuildStatus.Announced, }; @@ -170,14 +61,7 @@ const inProgressBuild: StartedBuild = { startedAt: new Date(Date.now() - 1000 * 60 * 2), // 2 minutes ago status: BuildStatus.InProgress, changeCount: null, - tests: paginated( - tests.map((test) => ({ - ...test, - status: TestStatus.InProgress, - result: null, - comparisons: [], - })) - ), + tests: paginated(SnapshotComparisonStories.InProgress.args.tests), }; const passedBuild: CompletedBuild = { @@ -218,7 +102,8 @@ const acceptedBuild: CompletedBuild = { const brokenBuild: CompletedBuild = { ...(inProgressBuild as any), status: BuildStatus.Broken, - changeCount: 3, + changeCount: 0, + brokenCount: 3, tests: paginated( tests.map((test) => ({ ...test, @@ -306,16 +191,17 @@ export const Outdated: Story = { }, }; -export const OutdatedRunning: Story = { - args: { - ...Outdated.args, - isRunning: true, - }, - argTypes: { updateBuildStatus: { action: "updateBuildStatus" } }, - parameters: { - ...Outdated.parameters, - }, -}; +// This story doesn't really make sense because if the build is running it should be `IN_PROGRESS` or similar +// export const OutdatedRunning: Story = { +// args: { +// ...Outdated.args, +// isRunning: true, +// }, +// argTypes: { updateBuildStatus: { action: "updateBuildStatus" } }, +// parameters: { +// ...Outdated.parameters, +// }, +// }; export const Announced: Story = { parameters: { diff --git a/src/screens/VisualTests/VisualTests.tsx b/src/screens/VisualTests/VisualTests.tsx index fbdb90e4..d80e9778 100644 --- a/src/screens/VisualTests/VisualTests.tsx +++ b/src/screens/VisualTests/VisualTests.tsx @@ -12,19 +12,13 @@ import { BuildQueryVariables, ReviewTestBatch, ReviewTestInputStatus, - TestFieldsFragment, - TestResult, - TestStatus, } from "../../gql/graphql"; -import { aggregateResult } from "../../utils/aggregateResult"; import { StatusUpdate, testsToStatusUpdate } from "../../utils/testsToStatusUpdate"; import { BuildInfo } from "./BuildInfo"; import { RenderSettings } from "./RenderSettings"; import { SnapshotComparison } from "./SnapshotComparison"; import { Warnings } from "./Warnings"; -type ComparisonResult = any; - const QueryBuild = graphql(/* GraphQL */ ` query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) { build(id: $buildId) @include(if: $hasBuildId) { @@ -54,6 +48,7 @@ const FragmentBuildFields = graphql(/* GraphQL */ ` } ... on StartedBuild { changeCount: testCount(results: [ADDED, CHANGED, FIXED]) + brokenCount: testCount(results: [CAPTURE_ERROR]) startedAt tests { nodes { @@ -64,6 +59,7 @@ const FragmentBuildFields = graphql(/* GraphQL */ ` ... on CompletedBuild { result changeCount: testCount(results: [ADDED, CHANGED, FIXED]) + brokenCount: testCount(results: [CAPTURE_ERROR]) startedAt tests { nodes { @@ -73,6 +69,7 @@ const FragmentBuildFields = graphql(/* GraphQL */ ` } } `); + const FragmentTestFields = graphql(/* GraphQL */ ` fragment TestFields on Test { id @@ -175,7 +172,6 @@ export const VisualTests = ({ slug, storyId, }: VisualTestsProps) => { - // TODO: Replace hardcoded projectId with useProjectId hook and parameters const [{ data, fetching, error }, rerun] = useQuery({ query: QueryBuild, variables: { @@ -290,88 +286,16 @@ export const VisualTests = ({ const allTests = getFragment(FragmentTestFields, "tests" in build ? build.tests.nodes : []); const tests = allTests.filter((test) => test.story?.storyId === storyId); - const { changeCount, brokenCount, resultsByBrowser, resultsByViewport, viewportInfoById } = - tests.reduce( - (acc, test) => { - if (test.result === TestResult.Changed) { - acc.changeCount += 1; - } - if (test.result === TestResult.CaptureError || test.result === TestResult.SystemError) { - acc.brokenCount += 1; - } - test.comparisons?.forEach(({ browser, result }) => { - acc.resultsByBrowser[browser.id] = aggregateResult([ - result, - acc.resultsByBrowser[browser.id], - ]); - }); - test.comparisons?.forEach(({ viewport, result }) => { - acc.resultsByViewport[viewport.id] = aggregateResult([ - result, - acc.resultsByViewport[viewport.id], - ]); - }); - acc.viewportInfoById[test.parameters.viewport.id] = test.parameters.viewport; - return acc; - }, - { - changeCount: 0, - brokenCount: 0, - resultsByBrowser: {} as Record, - resultsByViewport: {} as Record, - viewportInfoById: {} as Record, - } - ); - - const test = tests.find(({ result }) => result === TestResult.Changed) || tests[0]; - const isPending = test?.status === TestStatus.Pending; - const isInProgress = tests.some(({ status }) => status === TestStatus.InProgress); - - const browserCount = build.browsers.length; - const viewportCount = Object.keys(viewportInfoById).length; - - const browserInfoById = Object.fromEntries( - build.browsers.map((browser) => [browser.id, browser]) - ); - const browserResults = Object.entries(resultsByBrowser).map(([id, result]) => ({ - browser: browserInfoById[id], - result, - })); - const viewportResults = Object.entries(resultsByViewport).map(([id, result]) => ({ - viewport: viewportInfoById[id], - result, - })); + const viewportCount = new Set(allTests.map((t) => t.parameters.viewport.id)).size; return (