[playground] Fix broken tests (#31573)
Our e2e setup with monaco is kinda brittle since it relies on the dom. It seems like longish text gets truncated so let's just simpify all these test cases. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31573). * __->__ #31573 * #31572
lauren committed
Nov 18, 2024 at 19:18 UTC
c866d7506086140aaa79a015f4a7b2cf20c51905
15 files changed
+143
-343
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/01-user-output.txt
+13
-13
@@ -1,13 +1,13 @@
1
-function TestComponent(t0) {
2
- const $ = _c(2);
3
- const { x } = t0;
4
- let t1;
5
- if ($[0] !== x) {
6
- t1 = <Button>{x}</Button>;
7
- $[0] = x;
8
- $[1] = t1;
9
- } else {
10
- t1 = $[1];
11
- }
12
- return t1;
13
-}
\ No newline at end of file
1
+function TestComponent(t0) {
2
+ const $ = _c(2);
3
+ const { x } = t0;
4
+ let t1;
5
+ if ($[0] !== x) {
6
+ t1 = <Button>{x}</Button>;
7
+ $[0] = x;
8
+ $[1] = t1;
9
+ } else {
10
+ t1 = $[1];
11
+ }
12
+ return t1;
13
+}
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/02-default-output.txt
+11
-11
@@ -1,11 +1,11 @@
1
-function MyApp() {
2
- const $ = _c(1);
3
- let t0;
4
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
5
- t0 = <div>Hello World</div>;
6
- $[0] = t0;
7
- } else {
8
- t0 = $[0];
9
- }
10
- return t0;
11
-}
\ No newline at end of file
1
+function MyApp() {
2
+ const $ = _c(1);
3
+ let t0;
4
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
5
+ t0 = <div>Hello World</div>;
6
+ $[0] = t0;
7
+ } else {
8
+ t0 = $[0];
9
+ }
10
+ return t0;
11
+}
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-beats-module-scope-output.txt
new
+14
@@ -0,0 +1,14 @@
1
+function TestComponent(t0) {
2
+ "use memo";
3
+ const $ = _c(2);
4
+ const { x } = t0;
5
+ let t1;
6
+ if ($[0] !== x) {
7
+ t1 = <Button>{x}</Button>;
8
+ $[0] = x;
9
+ $[1] = t1;
10
+ } else {
11
+ t1 = $[1];
12
+ }
13
+ return t1;
14
+}
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-no-directive-arrow-function-expression-output.txt
deleted
-20
@@ -1,20 +0,0 @@
1
-function anonymous_1() {
2
- "use no memo";
3
- const Avatar = () => {
4
- return <div>Avatar Content</div>;
5
- };
6
- const MemoizedAvatar = React.memo(Avatar);
7
- const Bio = () => {
8
- const handleBioUpdate = () => {
9
- console.log("Bio updated");
10
- };
11
- return <div onClick={handleBioUpdate}>Bio Content</div>;
12
- };
13
- const MemoizedBio = React.memo(Bio);
14
- return (
15
- <div>
16
- <MemoizedAvatar />
17
- <MemoizedBio />
18
- </div>
19
- );
20
-}
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-use-memo-arrow-function-expression-output.txt
deleted
-32
@@ -1,32 +0,0 @@
1
-function anonymous_1() {
2
- "use memo";
3
- const $ = _c(3);
4
- const Chart = _temp2;
5
- let t0;
6
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
7
- t0 = React.memo(Chart);
8
- $[0] = t0;
9
- } else {
10
- t0 = $[0];
11
- }
12
- const MemoizedChart = t0;
13
- const Graph = _temp3;
14
- let t1;
15
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
16
- t1 = React.memo(Graph);
17
- $[1] = t1;
18
- } else {
19
- t1 = $[1];
20
- }
21
- const MemoizedGraph = t1;
22
- let t2;
23
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
24
- t2 = (
25
- <div>
26
- <MemoizedChart />
27
- <MemoizedGraph />
28
- </div>
29
- );
30
- $[2] = t2;
31
- } else {
32
- t2 = $[2];
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-use-memo-function-declaration-output.txt
deleted
-32
@@ -1,32 +0,0 @@
1
-function App() {
2
- "use memo";
3
- const $ = _c(3);
4
- let t0;
5
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6
- const Sidebar = function Sidebar() {
7
- const handleToggle = _temp;
8
- return <aside onClick={handleToggle}>Sidebar Content</
9
- aside>;
10
- };
11
- t0 = React.memo(Sidebar);
12
- $[0] = t0;
13
- } else {
14
- t0 = $[0];
15
- }
16
- const MemoizedSidebar = t0;
17
- let t1;
18
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
19
- const Content = function Content() {
20
- return <main>Main Content</main>;
21
- };
22
- t1 = React.memo(Content);
23
- $[1] = t1;
24
- } else {
25
- t1 = $[1];
26
- }
27
- const MemoizedContent = t1;
28
- let t2;
29
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
30
- t2 = (
31
- <div>
32
- <MemoizedSidebar />
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-use-no-memo-function-declaration-output.txt
deleted
-32
@@ -1,32 +0,0 @@
1
-function Settings() {
2
- "use memo";
3
- const $ = _c(3);
4
- let t0;
5
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6
- t0 = function Preferences() {
7
- const handleSave = _temp;
8
- return <div onClick={handleSave}>Preferences Content</
9
- div>;
10
- };
11
- $[0] = t0;
12
- } else {
13
- t0 = $[0];
14
- }
15
- const Preferences = t0;
16
- let t1;
17
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
18
- t1 = function Notifications() {
19
- return <div>Notifications Settings</div>;
20
- };
21
- $[1] = t1;
22
- } else {
23
- t1 = $[1];
24
- }
25
- const Notifications = t1;
26
- let t2;
27
- if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
28
- t2 = (
29
- <div>
30
- <Preferences />
31
- <Notifications />
32
- </div>
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/function-scope-use-no-memo-function-expression-output.txt
deleted
-18
@@ -1,18 +0,0 @@
1
-function anonymous_1() {
2
- "use no memo";
3
- const Widget = function () {
4
- const handleExpand = () => {
5
- console.log("Widget expanded");
6
- };
7
- return <div onClick={handleExpand}>Widget Content</div>;
8
- };
9
- const Panel = function () {
10
- return <section>Panel Information</section>;
11
- };
12
- return (
13
- <div>
14
- <Widget />
15
- <Panel />
16
- </div>
17
- );
18
-}
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/module-scope-use-memo-output.txt
+12
-14
@@ -1,15 +1,13 @@
1
-function anonymous_1() {
2
- const $ = _c(1);
3
- const handleClick = _temp;
4
- let t0;
5
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
6
- t0 = <h1 onClick={handleClick}>Welcome to the App!</h1>;
7
- $[0] = t0;
8
- } else {
9
- t0 = $[0];
10
- }
11
- return t0;
1
+function TestComponent(t0) {
2
+ const $ = _c(2);
3
+ const { x } = t0;
4
+ let t1;
5
+ if ($[0] !== x) {
6
+ t1 = <Button>{x}</Button>;
7
+ $[0] = x;
8
+ $[1] = t1;
9
+ } else {
10
+ t1 = $[1];
11
+ }
12
+ return t1;
13
}
13
-function _temp() {
14
- console.log("Header clicked");
15
-}
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/module-scope-use-no-memo-function-expression-output.txt
deleted
-3
@@ -1,3 +0,0 @@
1
-function anonymous_1() {
2
- return <aside>Sidebar Information</aside>;
3
-}
\ No newline at end of file
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/module-scope-use-no-memo-output.txt
+3
-7
@@ -1,7 +1,3 @@
1
-function anonymous_1() {
2
- const handleMouseOver = () => {
3
- console.log("Footer hovered");
4
- };
5
- return <footer onMouseOver={handleMouseOver}>Footer
6
- Information</footer>;
7
-}
\ No newline at end of file
1
+function TestComponent({ x }) {
2
+ return <Button>{x}</Button>;
3
+}
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/use-memo-output.txt
new
+28
@@ -0,0 +1,28 @@
1
+function TestComponent(t0) {
2
+ "use memo";
3
+ const $ = _c(2);
4
+ const { x } = t0;
5
+ let t1;
6
+ if ($[0] !== x) {
7
+ t1 = <Button>{x}</Button>;
8
+ $[0] = x;
9
+ $[1] = t1;
10
+ } else {
11
+ t1 = $[1];
12
+ }
13
+ return t1;
14
+}
15
+function anonymous_1(t0) {
16
+ "use memo";
17
+ const $ = _c(2);
18
+ const { x } = t0;
19
+ let t1;
20
+ if ($[0] !== x) {
21
+ t1 = <Button>{x}</Button>;
22
+ $[0] = x;
23
+ $[1] = t1;
24
+ } else {
25
+ t1 = $[1];
26
+ }
27
+ return t1;
28
+}
compiler/apps/playground/__tests__/e2e/__snapshots__/page.spec.ts/use-no-memo-output.txt
new
+8
@@ -0,0 +1,8 @@
1
+function anonymous_1() {
2
+ "use no memo";
3
+ return <Button>{x}</Button>;
4
+}
5
+function anonymous_3({ x }) {
6
+ "use no memo";
7
+ return <Button>{x}</Button>;
8
+}
compiler/apps/playground/__tests__/e2e/page.spec.ts
+52
-161
@@ -7,185 +7,64 @@
7
8
import {expect, test} from '@playwright/test';
9
import {encodeStore, type Store} from '../../lib/stores';
10
+import {format} from 'prettier';
11
11
-test.describe.configure({mode: 'parallel'});
12
-
13
-function concat(data: Array<string>): string {
14
- return data.join('');
12
+function print(data: Array<string>): Promise<string> {
13
+ return format(data.join(''), {parser: 'babel'});
14
}
15
+
16
const DIRECTIVE_TEST_CASES = [
17
{
18
name: 'module-scope-use-memo',
19
- input: `'use memo';
20
-
21
-const Header = () => {
22
- const handleClick = () => {
23
- console.log('Header clicked');
24
- };
25
-
26
- return <h1 onClick={handleClick}>Welcome to the App!</h1>;
27
-};`,
19
+ input: `
20
+'use memo';
21
+export default function TestComponent({ x }) {
22
+ return <Button>{x}</Button>;
23
+}`,
24
},
25
{
26
name: 'module-scope-use-no-memo',
31
- input: `'use no memo';
32
-
33
-const Footer = () => {
34
- const handleMouseOver = () => {
35
- console.log('Footer hovered');
36
- };
37
-
38
- return <footer onMouseOver={handleMouseOver}>Footer Information</footer>;
39
-};
40
-`,
41
- },
42
- {
43
- name: 'function-scope-use-memo-function-declaration',
44
- input: `function App() {
45
- 'use memo';
46
-
47
- function Sidebar() {
48
- const handleToggle = () => {
49
- console.log('Sidebar toggled');
50
- };
51
-
52
- return <aside onClick={handleToggle}>Sidebar Content</aside>;
53
- }
54
-
55
- const MemoizedSidebar = React.memo(Sidebar);
56
-
57
- function Content() {
58
- return <main>Main Content</main>;
59
- }
60
-
61
- const MemoizedContent = React.memo(Content);
62
-
63
- return (
64
- <div>
65
- <MemoizedSidebar />
66
- <MemoizedContent />
67
- </div>
68
- );
27
+ input: `
28
+'use no memo';
29
+export default function TestComponent({ x }) {
30
+ return <Button>{x}</Button>;
31
}`,
32
},
33
{
72
- name: 'function-scope-use-no-memo-function-expression',
73
- input: `const Dashboard = function() {
74
- 'use no memo';
75
- const Widget = function() {
76
- const handleExpand = () => {
77
- console.log('Widget expanded');
78
- };
79
-
80
- return <div onClick={handleExpand}>Widget Content</div>;
81
- };
82
-
83
- const Panel = function() {
84
- return <section>Panel Information</section>;
85
- };
86
-
87
- return (
88
- <div>
89
- <Widget />
90
- <Panel />
91
- </div>
92
- );
93
-};`,
94
- },
95
- {
96
- name: 'function-scope-use-memo-arrow-function-expression',
97
- input: `const Analytics = () => {
34
+ name: 'use-memo',
35
+ input: `
36
+function TestComponent({ x }) {
37
'use memo';
99
-
100
- const Chart = () => {
101
- const handleRefresh = () => {
102
- console.log('Chart refreshed');
103
- };
104
-
105
- return <div onClick={handleRefresh}>Chart Content</div>;
106
- };
107
-
108
- const MemoizedChart = React.memo(Chart);
109
-
110
- const Graph = () => {
111
- return <div>Graph Content</div>;
112
- };
113
-
114
- const MemoizedGraph = React.memo(Graph);
115
-
116
- return (
117
- <div>
118
- <MemoizedChart />
119
- <MemoizedGraph />
120
- </div>
121
- );
38
+ return <Button>{x}</Button>;
39
+}
40
+const TestComponent2 = ({ x }) => {
41
+ 'use memo';
42
+ return <Button>{x}</Button>;
43
};`,
44
},
45
{
125
- name: 'module-scope-use-no-memo-function-expression',
126
- input: `'use no memo';
127
-
128
-const Sidebar = function() {
129
- return <aside>Sidebar Information</aside>;
46
+ name: 'use-no-memo',
47
+ input: `
48
+const TestComponent = function() {
49
+ 'use no memo';
50
+ return <Button>{x}</Button>;
51
+};
52
+const TestComponent2 = ({ x }) => {
53
+ 'use no memo';
54
+ return <Button>{x}</Button>;
55
};`,
56
},
57
{
133
- name: 'function-scope-no-directive-arrow-function-expression',
58
+ name: 'function-scope-beats-module-scope',
59
input: `
135
-const Profile = () => {
60
'use no memo';
137
- const Avatar = () => {
138
- return <div>Avatar Content</div>;
139
- };
140
-
141
- const MemoizedAvatar = React.memo(Avatar);
142
-
143
- const Bio = () => {
144
- const handleBioUpdate = () => {
145
- console.log('Bio updated');
146
- };
147
-
148
- return <div onClick={handleBioUpdate}>Bio Content</div>;
149
- };
150
-
151
- const MemoizedBio = React.memo(Bio);
152
-
153
- return (
154
- <div>
155
- <MemoizedAvatar />
156
- <MemoizedBio />
157
- </div>
158
- );
159
-};`,
160
- },
161
- {
162
- name: 'function-scope-use-no-memo-function-declaration',
163
- input: `'use no memo';
164
-
165
-function Settings() {
61
+function TestComponent({ x }) {
62
'use memo';
167
-
168
- function Preferences() {
169
- const handleSave = () => {
170
- console.log('Preferences saved');
171
- };
172
-
173
- return <div onClick={handleSave}>Preferences Content</div>;
174
- }
175
-
176
- function Notifications() {
177
- return <div>Notifications Settings</div>;
178
- }
179
-
180
- return (
181
- <div>
182
- <Preferences />
183
- <Notifications />
184
- </div>
185
- );
63
+ return <Button>{x}</Button>;
64
}`,
65
},
66
];
67
+
68
test('editor should open successfully', async ({page}) => {
69
await page.goto(`/`, {waitUntil: 'networkidle'});
70
await page.screenshot({
@@ -193,6 +72,7 @@ test('editor should open successfully', async ({page}) => {
72
path: 'test-results/00-fresh-page.png',
73
});
74
});
75
+
76
test('editor should compile from hash successfully', async ({page}) => {
77
const store: Store = {
78
source: `export default function TestComponent({ x }) {
@@ -208,10 +88,14 @@ test('editor should compile from hash successfully', async ({page}) => {
88
fullPage: true,
89
path: 'test-results/01-compiles-from-hash.png',
90
});
211
- const userInput =
91
+ const text =
92
(await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? [];
213
- expect(concat(userInput)).toMatchSnapshot('01-user-output.txt');
93
+ const output = await print(text);
94
+
95
+ expect(output).not.toEqual('');
96
+ expect(output).toMatchSnapshot('01-user-output.txt');
97
});
98
+
99
test('reset button works', async ({page}) => {
100
const store: Store = {
101
source: `export default function TestComponent({ x }) {
@@ -229,10 +113,14 @@ test('reset button works', async ({page}) => {
113
fullPage: true,
114
path: 'test-results/02-reset-button-works.png',
115
});
232
- const defaultInput =
116
+ const text =
117
(await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? [];
234
- expect(concat(defaultInput)).toMatchSnapshot('02-default-output.txt');
118
+ const output = await print(text);
119
+
120
+ expect(output).not.toEqual('');
121
+ expect(output).toMatchSnapshot('02-default-output.txt');
122
});
123
+
124
DIRECTIVE_TEST_CASES.forEach((t, idx) =>
125
test(`directives work: ${t.name}`, async ({page}) => {
126
const store: Store = {
@@ -245,8 +133,11 @@ DIRECTIVE_TEST_CASES.forEach((t, idx) =>
133
path: `test-results/03-0${idx}-${t.name}.png`,
134
});
135
248
- const useMemoOutput =
136
+ const text =
137
(await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? [];
250
- expect(concat(useMemoOutput)).toMatchSnapshot(`${t.name}-output.txt`);
138
+ const output = await print(text);
139
+
140
+ expect(output).not.toEqual('');
141
+ expect(output).toMatchSnapshot(`${t.name}-output.txt`);
142
}),
143
);
compiler/apps/playground/playwright.config.js
+2
@@ -18,6 +18,8 @@ const baseURL = `http://localhost:${PORT}`;
18
export default defineConfig({
19
// Timeout per test
20
timeout: 30 * 1000,
21
+ // Run all tests in parallel.
22
+ fullyParallel: true,
23
// Test directory
24
testDir: path.join(__dirname, '__tests__/e2e'),
25
// If a test fails, retry it additional 2 times