forked from vitejs/vite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
testUtils.ts
162 lines (143 loc) · 4.53 KB
/
testUtils.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// test utils used in e2e tests for playgrounds.
// this can be directly imported in any playground tests as 'testUtils', e.g.
// `import { getColor } from 'testUtils'`
import fs from 'fs'
import path from 'path'
import slash from 'slash'
import colors from 'css-color-names'
import { ElementHandle } from 'playwright-chromium'
export const isBuild = !!process.env.VITE_TEST_BUILD
const testPath = expect.getState().testPath
const testName = slash(testPath).match(/playground\/([\w-]+)\//)?.[1]
export const testDir = path.resolve(__dirname, '../../temp', testName)
const hexToNameMap: Record<string, string> = {}
Object.keys(colors).forEach((color) => {
hexToNameMap[colors[color]] = color
})
function componentToHex(c: number): string {
var hex = c.toString(16)
return hex.length == 1 ? '0' + hex : hex
}
function rgbToHex(rgb: string): string {
const match = rgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/)
if (match) {
const [_, rs, gs, bs] = match
return (
'#' +
componentToHex(parseInt(rs, 10)) +
componentToHex(parseInt(gs, 10)) +
componentToHex(parseInt(bs, 10))
)
} else {
return '#000000'
}
}
const timeout = (n: number) => new Promise((r) => setTimeout(r, n))
async function toEl(el: string | ElementHandle): Promise<ElementHandle> {
if (typeof el === 'string') {
return await page.$(el)
}
return el
}
export async function getColor(el: string | ElementHandle) {
el = await toEl(el)
const rgb = await el.evaluate((el) => getComputedStyle(el as Element).color)
return hexToNameMap[rgbToHex(rgb)] || rgb
}
export async function getBg(el: string | ElementHandle) {
el = await toEl(el)
return el.evaluate((el) => getComputedStyle(el as Element).backgroundImage)
}
export function editFile(filename: string, replacer: (str: string) => string) {
if (isBuild) return
filename = path.resolve(testDir, filename)
const content = fs.readFileSync(filename, 'utf-8')
const modified = replacer(content)
fs.writeFileSync(filename, modified)
}
export function addFile(filename: string, content: string) {
fs.writeFileSync(path.resolve(testDir, filename), content)
}
export function removeFile(filename: string) {
fs.unlinkSync(path.resolve(testDir, filename))
}
export function listAssets(base = '') {
const assetsDir = path.join(testDir, 'dist', base, 'assets')
return fs.readdirSync(assetsDir)
}
export function findAssetFile(match: string | RegExp, base = '') {
const assetsDir = path.join(testDir, 'dist', base, 'assets')
const files = fs.readdirSync(assetsDir)
const file = files.find((file) => {
return file.match(match)
})
return file ? fs.readFileSync(path.resolve(assetsDir, file), 'utf-8') : ''
}
export function readManifest(base = '') {
return JSON.parse(
fs.readFileSync(path.join(testDir, 'dist', base, 'manifest.json'), 'utf-8')
)
}
/**
* Poll a getter until the value it returns includes the expected value.
*/
export async function untilUpdated(
poll: () => string | Promise<string>,
expected: string
) {
if (isBuild) return
const maxTries = process.env.CI ? 100 : 50
for (let tries = 0; tries < maxTries; tries++) {
const actual = (await poll()) || ''
if (actual.indexOf(expected) > -1 || tries === maxTries - 1) {
expect(actual).toMatch(expected)
break
} else {
await timeout(50)
}
}
}
/**
* Sort an object by key, { c: 1, b: 3, a: 2, e: 4 } => { a: 2, b: 3, c: 1, e: 4 }
* @param target
*/
export function sortObjectDeep<T extends object = object>(target: T): T {
if (!target || typeof target !== 'object') return target
return Object.keys(target)
.sort()
.reduce<T>(
(acc, item) => ({
...acc,
[item]:
typeof target[item] === 'object'
? sortObjectDeep(target[item])
: target[item]
}),
{} as T
)
}
export function stringifyObjectWithSort(
value: any,
replacer?: (this: any, key: string, value: any) => any,
space?: string | number
): string
export function stringifyObjectWithSort(
value: any,
replacer?: (number | string)[] | null,
space?: string | number
): string
export function stringifyObjectWithSort(
value: any,
replacer?:
| ((this: any, key: string, value: any) => any)
| (number | string)[]
| null,
space?: string | number
): string {
const finalValue = typeof value === 'object' ? sortObjectDeep(value) : value
// Must check to fix overload of JSON.stringify
if (typeof replacer === 'function') {
return JSON.stringify(finalValue, replacer, space)
}
return JSON.stringify(finalValue, replacer, space)
}