Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/integration/playwright/src/utils.ts
12922 views
1
import { expect, Locator, PlaywrightTestOptions } from "@playwright/test";
2
3
export const getUrl = (path: string) => {
4
return `http://127.0.0.1:8080/${path}`;
5
};
6
7
// deno-lint-ignore no-explicit-any
8
export const ojsVal = async (page: any, name: string) => {
9
return await page.evaluate(async (name: string) => {
10
const fieldsExist = (obj, names, timeout = 1000) => {
11
names = names.slice();
12
// deno-lint-ignore no-explicit-any
13
let accept: any, reject: any;
14
const promise = new Promise((a, r) => {
15
accept = a;
16
reject = r;
17
});
18
const delay = 100;
19
if (names.length === 0) {
20
accept(obj);
21
return promise;
22
}
23
let name = names[0];
24
function tick() {
25
if (Object.prototype.hasOwnProperty.call(obj, name)) {
26
names = names.slice(1);
27
if (names.length === 0) {
28
accept(obj);
29
} else {
30
obj = obj[name];
31
name = names[0];
32
//deno-lint-ignore no-window-prefix
33
window.setTimeout(tick, delay);
34
}
35
} else {
36
timeout -= delay;
37
if (timeout < 0) {
38
reject();
39
} else {
40
//deno-lint-ignore no-window-prefix
41
window.setTimeout(tick, delay);
42
}
43
}
44
}
45
tick();
46
return promise;
47
};
48
49
// deno-lint-ignore no-explicit-any
50
await fieldsExist(window, ["_ojs", "runtime"]);
51
// await new Promise((resolve) => setTimeout(resolve, 3000));
52
// deno-lint-ignore no-explicit-any
53
await (window as any)._ojs.runtime.finishInterpreting();
54
// deno-lint-ignore no-explicit-any
55
const val = await (window as any)._ojs.runtime.value(name);
56
return val;
57
}, name);
58
};
59
60
// deno-lint-ignore no-explicit-any
61
export const ojsRuns = async (page: any) => {
62
return await page.evaluate(async () => {
63
const fieldsExist = (obj, names, timeout = 1000) => {
64
names = names.slice();
65
// deno-lint-ignore no-explicit-any
66
let accept: any, reject: any;
67
const promise = new Promise((a, r) => {
68
accept = a;
69
reject = r;
70
});
71
const delay = 100;
72
if (names.length === 0) {
73
accept(obj);
74
return promise;
75
}
76
let name = names[0];
77
function tick() {
78
if (Object.prototype.hasOwnProperty.call(obj, name)) {
79
names = names.slice(1);
80
if (names.length === 0) {
81
accept(obj);
82
} else {
83
obj = obj[name];
84
name = names[0];
85
//deno-lint-ignore no-window-prefix
86
window.setTimeout(tick, delay);
87
}
88
} else {
89
timeout -= delay;
90
if (timeout < 0) {
91
reject();
92
} else {
93
//deno-lint-ignore no-window-prefix
94
window.setTimeout(tick, delay);
95
}
96
}
97
}
98
tick();
99
return promise;
100
};
101
102
// deno-lint-ignore no-explicit-any
103
await fieldsExist(window, ["_ojs", "runtime"]);
104
// await new Promise((resolve) => setTimeout(resolve, 3000));
105
// deno-lint-ignore no-explicit-any
106
await (window as any)._ojs.runtime.finishInterpreting();
107
return true;
108
});
109
};
110
111
export const checkClick = async (page: any, locator: any) => {
112
let error = false;
113
page.on("pageerror", (_e) => {
114
error = true;
115
});
116
try {
117
await locator.click();
118
} catch (_e) {
119
error = true;
120
}
121
return !error;
122
};
123
124
export type RGBColor = {
125
red: number;
126
green: number;
127
blue: number;
128
alpha?: number;
129
};
130
131
export type HexColor = string;
132
133
export function isRGBColor(color: any): color is RGBColor {
134
return (
135
typeof color === 'object' &&
136
'red' in color &&
137
'green' in color &&
138
'blue' in color
139
);
140
}
141
142
export function isHexColor(color: any): color is HexColor {
143
return (
144
typeof color === 'string' &&
145
/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(color)
146
);
147
}
148
149
export async function checkColor(element, cssProperty, color: RGBColor | HexColor) {
150
let colorString: string;
151
// Check if the color is an RGBColor object or a string
152
if (isRGBColor(color)) {
153
colorString = color.alpha !== undefined
154
? `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`
155
: `rgb(${color.red}, ${color.green}, ${color.blue})`;
156
} else if (isHexColor(color)) {
157
colorString = color as string;
158
} else {
159
throw new Error('Invalid color format. Use either RGBColor or HexColor.');
160
}
161
// Check the CSS property
162
await expect(element).toHaveCSS(cssProperty, colorString);
163
}
164
165
export function asRGB(red: number, green: number, blue: number, alpha?: number): RGBColor {
166
return { red, green, blue, alpha };
167
}
168
169
export function hexToRgb(hex: string): RGBColor {
170
// Remove the # if present
171
hex = hex.replace(/^#/, '');
172
173
let r: number, g: number, b: number, a: number | undefined = undefined;
174
175
if (hex.length === 3) {
176
// Handle shorthand #RGB format
177
r = parseInt(hex[0] + hex[0], 16);
178
g = parseInt(hex[1] + hex[1], 16);
179
b = parseInt(hex[2] + hex[2], 16);
180
} else if (hex.length === 6) {
181
// Handle #RRGGBB format
182
r = parseInt(hex.slice(0, 2), 16);
183
g = parseInt(hex.slice(2, 4), 16);
184
b = parseInt(hex.slice(4, 6), 16);
185
} else if (hex.length === 8) {
186
// Handle #RRGGBBAA format
187
r = parseInt(hex.slice(0, 2), 16);
188
g = parseInt(hex.slice(2, 4), 16);
189
b = parseInt(hex.slice(4, 6), 16);
190
a = parseInt(hex.slice(6, 8), 16);
191
} else {
192
throw new Error('Invalid hex color format');
193
}
194
return (asRGB(r, g, b, a));
195
}
196
197
export async function getCSSProperty(loc: Locator, variable: string, asNumber = false): Promise<string | number> {
198
const property = await loc.evaluate((element, variable) =>
199
window.getComputedStyle(element).getPropertyValue(variable),
200
variable
201
);
202
if (asNumber) {
203
return parseFloat(property);
204
} else {
205
return property;
206
}
207
}
208
209
export async function checkCSSproperty(loc1: Locator, loc2: Locator, property: string, asNumber: false | true, checkType: 'identical' | 'similar', factor: number = 1) {
210
let loc1Property = await getCSSProperty(loc1, property, asNumber);
211
let loc2Property = await getCSSProperty(loc2, property, asNumber);
212
if (checkType === 'identical') {
213
await expect(loc2).toHaveCSS(property, loc1Property as string);
214
} else {
215
await expect(loc1Property).toBeCloseTo(loc2Property as number * factor);
216
}
217
}
218
219
export async function checkFontSizeIdentical(loc1: Locator, loc2: Locator) {
220
await checkCSSproperty(loc1, loc2, 'font-size', false, 'identical');
221
}
222
223
export async function checkFontSizeSimilar(loc1: Locator, loc2: Locator, factor: number = 1) {
224
await checkCSSproperty(loc1, loc2, 'font-size', true, 'similar', factor);
225
}
226
227
export async function checkColorIdentical(loc1: Locator, loc2: Locator, property: string) {
228
await checkCSSproperty(loc1, loc2, property, false, 'identical');
229
}
230
231
export async function checkBorderProperties(element: Locator, side: string, color: RGBColor, width: string) {
232
await checkColor(element, `border-${side}-color`, color);
233
await expect(element).toHaveCSS(`border-${side}-width`, width);
234
}
235
236
export async function checkBackgroundColorProperty(element: Locator, color: RGBColor) {
237
await checkColor(element, `background-color`, color);
238
}
239
240
export function useDarkLightMode(mode: 'dark' | 'light'): Partial<PlaywrightTestOptions> {
241
return {
242
colorScheme: mode
243
};
244
}
245