5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {expect, test} from '@playwright/test';
8
+import {expect, test, type Page} from '@playwright/test';
9
import {encodeStore, type Store} from '../../lib/stores';
10
+import {defaultConfig} from '../../lib/defaultStore';
11
import {format} from 'prettier';
12
13
function isMonacoLoaded(): boolean {
21
return format(data.join(''), {parser: 'babel'});
22
}
23
24
+async function expandConfigs(page: Page): Promise<void> {
25
+ const expandButton = page.locator('[title="Expand config editor"]');
26
+ expandButton.click();
27
+}
28
+
29
+const TEST_SOURCE = `export default function TestComponent({ x }) {
30
+ return <Button>{x}</Button>;
31
+}`;
32
+
33
const TEST_CASE_INPUTS = [
34
{
35
name: 'module-scope-use-memo',
131
132
test('editor should compile from hash successfully', async ({page}) => {
133
const store: Store = {
124
- source: `export default function TestComponent({ x }) {
125
- return <Button>{x}</Button>;
126
- }
127
- `,
134
+ source: TEST_SOURCE,
135
+ config: defaultConfig,
136
+ showInternals: false,
137
};
138
const hash = encodeStore(store);
139
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
145
path: 'test-results/01-compiles-from-hash.png',
146
});
147
const text =
139
- (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? [];
148
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
149
const output = await formatPrint(text);
150
151
expect(output).not.toEqual('');
154
155
test('reset button works', async ({page}) => {
156
const store: Store = {
148
- source: `export default function TestComponent({ x }) {
149
- return <Button>{x}</Button>;
150
- }
151
- `,
157
+ source: TEST_SOURCE,
158
+ config: defaultConfig,
159
+ showInternals: false,
160
};
161
const hash = encodeStore(store);
162
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
165
// Reset button works
166
page.on('dialog', dialog => dialog.accept());
167
await page.getByRole('button', {name: 'Reset'}).click();
168
+ await expandConfigs(page);
169
+
170
await page.screenshot({
171
fullPage: true,
172
path: 'test-results/02-reset-button-works.png',
173
});
174
const text =
165
- (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? [];
175
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
176
const output = await formatPrint(text);
177
178
+ const configText =
179
+ (await page.locator('.monaco-editor-config').allInnerTexts()) ?? [];
180
+ const configOutput = configText.join('');
181
+
182
expect(output).not.toEqual('');
183
expect(output).toMatchSnapshot('02-default-output.txt');
184
+ expect(configOutput).not.toEqual('');
185
+ expect(configOutput).toMatchSnapshot('default-config.txt');
186
+});
187
+
188
+test('defaults load when only source is in Store', async ({page}) => {
189
+ // Test for backwards compatibility
190
+ const partial = {
191
+ source: TEST_SOURCE,
192
+ };
193
+ const hash = encodeStore(partial as Store);
194
+ await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
195
+ await page.waitForFunction(isMonacoLoaded);
196
+ await expandConfigs(page);
197
+
198
+ await page.screenshot({
199
+ fullPage: true,
200
+ path: 'test-results/03-missing-defaults.png',
201
+ });
202
+
203
+ // Config editor has default config
204
+ const configText =
205
+ (await page.locator('.monaco-editor-config').allInnerTexts()) ?? [];
206
+ const configOutput = configText.join('');
207
+
208
+ expect(configOutput).not.toEqual('');
209
+ expect(configOutput).toMatchSnapshot('default-config.txt');
210
+
211
+ const checkbox = page.locator('label.show-internals');
212
+ await expect(checkbox).not.toBeChecked();
213
+ const ssaTab = page.locator('text=SSA');
214
+ await expect(ssaTab).not.toBeVisible();
215
+});
216
+
217
+test('show internals button toggles correctly', async ({page}) => {
218
+ await page.goto(`/`, {waitUntil: 'networkidle'});
219
+ await page.waitForFunction(isMonacoLoaded);
220
+
221
+ // show internals should be off
222
+ const checkbox = page.locator('label.show-internals');
223
+ await checkbox.click();
224
+
225
+ await page.screenshot({
226
+ fullPage: true,
227
+ path: 'test-results/04-show-internals-on.png',
228
+ });
229
+
230
+ await expect(checkbox).toBeChecked();
231
+
232
+ const ssaTab = page.locator('text=SSA');
233
+ await expect(ssaTab).toBeVisible();
234
+});
235
+
236
+test('error is displayed when config has syntax error', async ({page}) => {
237
+ const store: Store = {
238
+ source: TEST_SOURCE,
239
+ config: `compilationMode: `,
240
+ showInternals: false,
241
+ };
242
+ const hash = encodeStore(store);
243
+ await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
244
+ await page.waitForFunction(isMonacoLoaded);
245
+ await expandConfigs(page);
246
+ await page.screenshot({
247
+ fullPage: true,
248
+ path: 'test-results/05-config-syntax-error.png',
249
+ });
250
+
251
+ const text =
252
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
253
+ const output = text.join('');
254
+
255
+ // Remove hidden chars
256
+ expect(output.replace(/\s+/g, ' ')).toContain('Invalid override format');
257
+});
258
+
259
+test('error is displayed when config has validation error', async ({page}) => {
260
+ const store: Store = {
261
+ source: TEST_SOURCE,
262
+ config: `import type { PluginOptions } from 'babel-plugin-react-compiler/dist';
263
+
264
+({
265
+ compilationMode: "123"
266
+} satisfies Partial<PluginOptions>);`,
267
+ showInternals: false,
268
+ };
269
+ const hash = encodeStore(store);
270
+ await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
271
+ await page.waitForFunction(isMonacoLoaded);
272
+ await expandConfigs(page);
273
+ await page.screenshot({
274
+ fullPage: true,
275
+ path: 'test-results/06-config-validation-error.png',
276
+ });
277
+
278
+ const text =
279
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
280
+ const output = text.join('');
281
+
282
+ expect(output.replace(/\s+/g, ' ')).toContain('Unexpected compilationMode');
283
+});
284
+
285
+test('disableMemoizationForDebugging flag works as expected', async ({
286
+ page,
287
+}) => {
288
+ const store: Store = {
289
+ source: TEST_SOURCE,
290
+ config: `import type { PluginOptions } from 'babel-plugin-react-compiler/dist';
291
+
292
+({
293
+ environment: {
294
+ disableMemoizationForDebugging: true
295
+ }
296
+} satisfies Partial<PluginOptions>);`,
297
+ showInternals: false,
298
+ };
299
+ const hash = encodeStore(store);
300
+ await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
301
+ await page.waitForFunction(isMonacoLoaded);
302
+ await expandConfigs(page);
303
+ await page.screenshot({
304
+ fullPage: true,
305
+ path: 'test-results/07-config-disableMemoizationForDebugging-flag.png',
306
+ });
307
+
308
+ const text =
309
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
310
+ const output = await formatPrint(text);
311
+
312
+ expect(output).not.toEqual('');
313
+ expect(output).toMatchSnapshot('disableMemoizationForDebugging-output.txt');
314
});
315
316
TEST_CASE_INPUTS.forEach((t, idx) =>
317
test(`playground compiles: ${t.name}`, async ({page}) => {
318
const store: Store = {
319
source: t.input,
320
+ config: defaultConfig,
321
+ showInternals: false,
322
};
323
const hash = encodeStore(store);
324
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
325
await page.waitForFunction(isMonacoLoaded);
326
await page.screenshot({
327
fullPage: true,
182
- path: `test-results/03-0${idx}-${t.name}.png`,
328
+ path: `test-results/08-0${idx}-${t.name}.png`,
329
});
330
331
const text =
186
- (await page.locator('.monaco-editor').nth(3).allInnerTexts()) ?? [];
332
+ (await page.locator('.monaco-editor-output').allInnerTexts()) ?? [];
333
let output: string;
334
if (t.noFormat) {
335
output = text.join('');