Skip to content

Commit 4914cb7

Browse files
joshblackCopilot
andauthored
test: add storybook vrt setup for styled-react (#7297)
Co-authored-by: Copilot <[email protected]>
1 parent 54bc9da commit 4914cb7

File tree

17 files changed

+352
-36
lines changed

17 files changed

+352
-36
lines changed

.github/workflows/vrt-reports.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,25 @@ jobs:
4242
pid=$!
4343
echo "pid=$pid" >> $GITHUB_OUTPUT
4444
sleep 5
45+
- name: Run styled-react storybook
46+
id: styled-react-storybook
47+
run: |
48+
npx serve -l 6007 packages/styled-react/storybook-static &
49+
pid=$!
50+
echo "pid=$pid" >> $GITHUB_OUTPUT
51+
sleep 5
4552
- name: Run VRT
4653
uses: docker://mcr.microsoft.com/playwright:v1.56.1-jammy
4754
env:
4855
STORYBOOK_URL: 'http://172.17.0.1:6006'
56+
STYLED_REACT_STORYBOOK_URL: 'http://172.17.0.1:6007'
4957
with:
5058
args: npx playwright test --grep @vrt --shard="${{ matrix.shard }}/${{ strategy.job-total }}"
5159
- name: Stop storybook
60+
if: ${{ always() }}
5261
run: kill ${{ steps.storybook.outputs.pid }}
62+
- name: Stop styled-react storybook
63+
run: kill ${{ steps.styled-react-storybook.outputs.pid }}
5364
- name: Upload report
5465
if: ${{ always() }}
5566
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4

.github/workflows/vrt.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,32 @@ jobs:
4242
- name: Install dependencies
4343
run: npm ci
4444
- name: Build storybook
45-
run: npx storybook build
46-
working-directory: packages/react
45+
run: npx turbo build:storybook
4746
- name: Run storybook
4847
id: storybook
4948
run: |
5049
npx serve -l 6006 packages/react/storybook-static &
5150
pid=$!
5251
echo "pid=$pid" >> $GITHUB_OUTPUT
5352
sleep 5
53+
- name: Run styled-react storybook
54+
id: styled-react-storybook
55+
run: |
56+
npx serve -l 6007 packages/styled-react/storybook-static &
57+
pid=$!
58+
echo "pid=$pid" >> $GITHUB_OUTPUT
59+
sleep 5
5460
- name: Run VRT
5561
uses: docker://mcr.microsoft.com/playwright:v1.56.1-jammy
5662
env:
5763
STORYBOOK_URL: 'http://172.17.0.1:6006'
64+
STYLED_REACT_STORYBOOK_URL: 'http://172.17.0.1:6007'
5865
with:
5966
args: npx playwright test --grep @vrt --update-snapshots --shard="${{ matrix.shard }}/${{ strategy.job-total }}"
6067
- name: Stop storybook
61-
if: ${{ always() }}
6268
run: kill ${{ steps.storybook.outputs.pid }}
69+
- name: Stop styled-react storybook
70+
run: kill ${{ steps.styled-react-storybook.outputs.pid }}
6371
- name: Create snapshots.zip
6472
run: |
6573
if [[ ! -z $(git ls-files --others --exclude-standard --modified) ]]; then
1.43 KB
Loading
2.82 KB
Loading
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import path from 'node:path'
2+
import {test, expect} from '@playwright/test'
3+
import {getStories, visit} from '../../test-helpers/storybook'
4+
5+
const stories = getStories(path.resolve(__dirname, '../../../packages/styled-react/src/components/Button.stories.tsx'))
6+
7+
test.describe('Button (@primer/styled-react)', () => {
8+
for (const story of stories) {
9+
test.describe(story.title, () => {
10+
test(`default @vrt`, async ({page}) => {
11+
await visit(page, {
12+
id: story.id,
13+
storybook: 'styled-react',
14+
})
15+
16+
// Default state
17+
await expect(page.getByTestId('screenshot')).toHaveScreenshot(`Button.${story.title}.png`)
18+
})
19+
})
20+
}
21+
})

e2e/test-helpers/storybook.ts

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import fs from 'node:fs'
2+
import {parseSync, traverse, types as t} from '@babel/core'
13
import type {Page} from '@playwright/test'
4+
import {kebabCase} from 'change-case'
25
import {waitForImages} from './waitForImages'
36

47
type Value =
@@ -13,14 +16,23 @@ interface Options {
1316
id: string
1417
args?: Record<string, string | boolean>
1518
globals?: Record<string, Value>
19+
storybook?: 'react' | 'styled-react'
1620
}
1721

18-
const {STORYBOOK_URL = 'http://localhost:6006'} = process.env
22+
const {STORYBOOK_URL = 'http://localhost:6006', STYLED_REACT_STORYBOOK_URL = 'http://localhost:6007'} = process.env
1923

20-
export async function visit(page: Page, options: Options) {
24+
function getStorybookUrl(storybook: 'react' | 'styled-react' = 'react'): string {
25+
if (storybook === 'react') {
26+
return STORYBOOK_URL
27+
}
28+
return STYLED_REACT_STORYBOOK_URL
29+
}
30+
31+
async function visit(page: Page, options: Options) {
2132
const {id, args, globals} = options
33+
const storybookURL = getStorybookUrl(options.storybook)
2234
// In CI, the static server strips `.html` extensions
23-
const url = process.env.CI ? new URL(`${STORYBOOK_URL}/iframe`) : new URL(`${STORYBOOK_URL}/iframe.html`)
35+
const url = process.env.CI ? new URL(`${storybookURL}/iframe`) : new URL(`${storybookURL}/iframe.html`)
2436

2537
url.searchParams.set('id', id)
2638
url.searchParams.set('viewMode', 'story')
@@ -77,3 +89,60 @@ function serialize(value: Value): string {
7789

7890
return `${value}`
7991
}
92+
93+
function getStories(filepath: string): Array<{title: string; id: string}> {
94+
const contents = fs.readFileSync(filepath, 'utf-8')
95+
const ast = parseSync(contents, {
96+
sourceType: 'module',
97+
parserOpts: {
98+
plugins: ['typescript', 'jsx'],
99+
},
100+
})
101+
102+
let storyTitle = ''
103+
const exports: Array<string> = []
104+
105+
traverse(ast!, {
106+
ExportDefaultDeclaration(path) {
107+
if (t.isObjectExpression(path.node.declaration)) {
108+
const titleProperty = path.node.declaration.properties.find(prop => {
109+
return t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'title'
110+
})
111+
112+
if (titleProperty && t.isObjectProperty(titleProperty) && t.isStringLiteral(titleProperty.value)) {
113+
storyTitle = titleProperty.value.value
114+
}
115+
}
116+
},
117+
118+
ExportNamedDeclaration(path) {
119+
if (path.node.declaration) {
120+
if (t.isVariableDeclaration(path.node.declaration)) {
121+
for (const declarator of path.node.declaration.declarations) {
122+
if (t.isIdentifier(declarator.id)) {
123+
exports.push(declarator.id.name)
124+
}
125+
}
126+
}
127+
}
128+
},
129+
})
130+
131+
return exports.map(name => {
132+
return {
133+
title: name,
134+
id: getStorybookId(storyTitle, name),
135+
}
136+
})
137+
}
138+
139+
function getStorybookId(title: string, storyName: string): string {
140+
const group = title
141+
.split('/')
142+
.map(part => part.toLowerCase())
143+
.join('-')
144+
const story = kebabCase(storyName)
145+
return `${group}--${story}`
146+
}
147+
148+
export {visit, getStories}

0 commit comments

Comments
 (0)