-
Notifications
You must be signed in to change notification settings - Fork 14
/
index.ts
130 lines (109 loc) · 2.97 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { join } from 'path'
import { Page } from 'puppeteer'
import { MatchImageSnapshotOptions } from 'jest-image-snapshot'
import { generateIframeUrl } from '../src/utils/url-generator'
declare const page: Page
const PADDING_AROUND_COMPONENT = 8
interface Dimensions {
x: number
y: number
width: number
height: number
}
interface Options extends MatchImageSnapshotOptions {
delay?: number
waitUntilImagesLoaded?: boolean
effect?: (
page: Page,
makeScreenShot: (options: Options) => void
) => Promise<unknown>
isFullScreen?: boolean
padding?: number
dimensions?: Partial<Dimensions>
selector?: string
}
async function screenshotDOMElement({
isFullScreen,
padding,
dimensions,
selector = '#root .chapter-container'
}: Options) {
if (isFullScreen) {
return page.screenshot()
}
const componentDimensions: Dimensions = await page.evaluate(
componentSelector => {
const component = document.querySelector(componentSelector)
if (!component) {
throw new Error('Rendered story was not found!')
}
const componentRect: ClientRect = component!.getBoundingClientRect()
return {
x: componentRect.left,
y: componentRect.top,
width: componentRect.width,
height: componentRect.height
}
},
selector
)
const clipDimensions = {
...componentDimensions,
...dimensions
}
const clipPadding = padding || PADDING_AROUND_COMPONENT
await page.setViewport({
width: clipDimensions.width,
height: clipDimensions.height
})
return page.screenshot({
clip: {
x: clipDimensions.x - clipPadding,
y: clipDimensions.y - clipPadding,
width: clipDimensions.width + clipPadding * 2,
height: clipDimensions.height + clipPadding * 2
}
})
}
async function matchScreenshot(options: Options) {
const image = await screenshotDOMElement(options)
expect(image).toMatchImageSnapshot(options)
}
// TODO: Make this more universal when we add more components and their variations
export const assertVisuals = function (
kind: string,
type: string,
options: Options = {
delay: 0,
waitUntilImagesLoaded: false,
effect: undefined
}
) {
return async () => {
const {
delay,
waitUntilImagesLoaded,
effect,
customSnapshotIdentifier
} = options
const host = `file:///${join(__dirname, '/../build/storybook/')}`
const url = generateIframeUrl({ host, kind, type })
await page.goto(
url,
waitUntilImagesLoaded ? { waitUntil: 'networkidle0' } : {}
)
await page.waitFor(delay || 0)
await matchScreenshot(options)
if (effect) {
let effectSnapshotId = 0
const makeEffectScreenshot = async (effectOptions: Options) => {
await matchScreenshot({
...options,
...effectOptions,
customSnapshotIdentifier: `${customSnapshotIdentifier}-effect-${++effectSnapshotId}`
})
}
await effect(page, makeEffectScreenshot)
}
}
}