Skip to content

Commit 485c7cc

Browse files
authored
test: golden-layout playwright tests (#1317)
Adds some base test coverage for golden-layout. Intent is to add coverage for visual regressions when consolidating golden layout css and preparing it for theming in an upcoming pr. Relies on importing layouts and the component placeholder fallback as part of test.
1 parent 860e4c5 commit 485c7cc

30 files changed

Lines changed: 389 additions & 3 deletions

File tree

packages/dashboard/src/PanelPlaceholder.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
justify-content: center;
77
padding: $spacer-3;
88
min-height: 100%;
9+
max-height: 100%;
910
text-align: center;
11+
overflow: hidden;
1012
}

packages/golden-layout/src/controls/Tab.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default class Tab {
2020
'<li class="lm_tab">',
2121
'<span class="lm_title_before"></span>',
2222
'<span class="lm_title"></span>',
23-
'<div class="lm_close_tab"></div>',
23+
'<div class="lm_close_tab" aria-label="Close tab"></div>',
2424
'</li>',
2525
].join('');
2626

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
{
2+
"filterSets": [],
3+
"layoutConfig": [
4+
{
5+
"type": "column",
6+
"isClosable": true,
7+
"isFocusOnShow": true,
8+
"reorderEnabled": true,
9+
"title": "",
10+
"content": [
11+
{
12+
"type": "row",
13+
"content": [
14+
{
15+
"type": "column",
16+
"width": 61.803,
17+
"content": [
18+
{
19+
"type": "stack",
20+
"isClosable": true,
21+
"isFocusOnShow": true,
22+
"reorderEnabled": true,
23+
"title": "",
24+
"height": 61.803,
25+
"activeItemIndex": 0,
26+
"content": [
27+
{
28+
"type": "react-component",
29+
"component": "test-a",
30+
"title": "test-a"
31+
},
32+
{
33+
"type": "react-component",
34+
"component": "test-b",
35+
"title": "test-b"
36+
},
37+
{
38+
"type": "react-component",
39+
"component": "test-c",
40+
"title": "test-c"
41+
},
42+
{
43+
"type": "react-component",
44+
"component": "test-d",
45+
"title": "test-d"
46+
},
47+
{
48+
"type": "react-component",
49+
"component": "test-e",
50+
"title": "test-e"
51+
},
52+
{
53+
"type": "react-component",
54+
"component": "test-f",
55+
"title": "test-f"
56+
},
57+
{
58+
"type": "react-component",
59+
"component": "test-g",
60+
"title": "test-g"
61+
},
62+
{
63+
"type": "react-component",
64+
"component": "test-h",
65+
"title": "test-h"
66+
},
67+
{
68+
"type": "react-component",
69+
"component": "test-i",
70+
"title": "test-i"
71+
},
72+
{
73+
"type": "react-component",
74+
"component": "test-j",
75+
"title": "test-j"
76+
},
77+
{
78+
"type": "react-component",
79+
"component": "test-k",
80+
"title": "test-k"
81+
},
82+
{
83+
"type": "react-component",
84+
"component": "test-l",
85+
"title": "test-l"
86+
},
87+
{
88+
"type": "react-component",
89+
"component": "test-m",
90+
"title": "test-m"
91+
},
92+
{
93+
"type": "react-component",
94+
"component": "test-n",
95+
"title": "test-n"
96+
},
97+
{
98+
"type": "react-component",
99+
"component": "test-o",
100+
"title": "test-o"
101+
},
102+
{
103+
"type": "react-component",
104+
"component": "test-p",
105+
"title": "test-p"
106+
},
107+
{
108+
"type": "react-component",
109+
"component": "test-q",
110+
"title": "test-q"
111+
},
112+
{
113+
"type": "react-component",
114+
"component": "test-r",
115+
"title": "test-r"
116+
},
117+
{
118+
"type": "react-component",
119+
"component": "test-s",
120+
"title": "test-s"
121+
},
122+
{
123+
"type": "react-component",
124+
"component": "test-t",
125+
"title": "test-t"
126+
},
127+
{
128+
"type": "react-component",
129+
"component": "test-u",
130+
"title": "test-u"
131+
},
132+
{
133+
"type": "react-component",
134+
"component": "test-v",
135+
"title": "test-v"
136+
},
137+
{
138+
"type": "react-component",
139+
"component": "test-w",
140+
"title": "test-w"
141+
},
142+
{
143+
"type": "react-component",
144+
"component": "test-x",
145+
"title": "test-x"
146+
},
147+
{
148+
"type": "react-component",
149+
"component": "test-y",
150+
"title": "test-y"
151+
},
152+
{
153+
"type": "react-component",
154+
"component": "test-z",
155+
"title": "test-z"
156+
}
157+
]
158+
},
159+
{
160+
"type": "react-component",
161+
"component": "test"
162+
}
163+
]
164+
},
165+
{
166+
"type": "column",
167+
"width": 38.197,
168+
"content": [
169+
{
170+
"type": "react-component",
171+
"component": "test",
172+
"height": 61.803
173+
},
174+
{
175+
"type": "row",
176+
"content": [
177+
{
178+
"type": "column",
179+
"width": 61.803,
180+
"content": [
181+
{
182+
"type": "row",
183+
"content": [
184+
{
185+
"type": "react-component",
186+
"component": "test",
187+
"width": 61.803
188+
},
189+
{
190+
"type": "column",
191+
"content": [
192+
{
193+
"type": "react-component",
194+
"component": "test",
195+
"height": 61.803
196+
},
197+
{
198+
"type": "row",
199+
"content": [
200+
{
201+
"type": "react-component",
202+
"component": "test"
203+
},
204+
{
205+
"type": "react-component",
206+
"component": "test",
207+
"width": 61.803
208+
}
209+
]
210+
}
211+
]
212+
}
213+
]
214+
},
215+
{
216+
"type": "react-component",
217+
"component": "test",
218+
"height": 38.197
219+
}
220+
]
221+
},
222+
{
223+
"type": "react-component",
224+
"component": "test",
225+
"width": 61.803
226+
}
227+
]
228+
}
229+
]
230+
}
231+
]
232+
}
233+
]
234+
}
235+
],
236+
"links": [],
237+
"version": 2
238+
}

tests/golden-layout.spec.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { test, expect, Page } from '@playwright/test';
2+
3+
// Run tests serially
4+
test.describe.configure({ mode: 'serial' });
5+
6+
test.describe('tests golden-layout operations', () => {
7+
let page: Page;
8+
9+
test.beforeAll(async ({ browser }) => {
10+
page = await browser.newPage();
11+
await page.goto('');
12+
13+
// reset the layout before each test
14+
await page.getByTestId('app-main-panels-button').click();
15+
// start listener before click
16+
const fileChooserPromise = page.waitForEvent('filechooser');
17+
await page.locator('button:has-text("Import Layout")').click();
18+
const fileChooser = await fileChooserPromise;
19+
// load a test layout that uses the panel placeholder
20+
await fileChooser.setFiles('tests/deephaven-app-layout.test.json');
21+
22+
// expect a tab "test-a" to have been successfully loaded
23+
await expect(
24+
page.locator('.lm_tab').filter({ has: page.getByText('test-a') })
25+
).toHaveCount(1);
26+
});
27+
28+
test.afterAll(async () => {
29+
// reset layout
30+
await page.getByTestId('app-main-panels-button').click();
31+
await page.getByLabel('Reset Layout').click();
32+
33+
await expect(
34+
page.locator('.lm_tab').filter({ has: page.getByText('test-a') })
35+
).toHaveCount(0);
36+
});
37+
38+
test('golden-layout can import a layout', async () => {
39+
// general overall visual check of layout
40+
await expect(page.locator('.lm_root')).toHaveScreenshot();
41+
});
42+
43+
test('golden-layout can maximize the first stack', async () => {
44+
await page.getByTitle('Maximize').first().click();
45+
// visual check for maximized tab
46+
await expect(page.locator('.lm_root')).toHaveScreenshot();
47+
48+
// minimize it again for next test
49+
await page.getByTitle('Minimize').first().click();
50+
await expect(page.getByTitle('Minimize')).toHaveCount(0);
51+
});
52+
53+
test('golden-layout can use additional tabs menu', async () => {
54+
// open the first additional tab drop down
55+
await page.getByTitle('Additional tabs').first().click();
56+
57+
// check snapshot
58+
await expect(
59+
page.locator('.lm_tabdropdown_list').locator('visible=true')
60+
).toHaveScreenshot();
61+
62+
// test search
63+
await page
64+
.getByPlaceholder('Find tab...')
65+
.locator('visible=true')
66+
.fill('test-z');
67+
68+
// check that drop-down is filtered screenshot
69+
await expect(
70+
page.locator('.lm_tabdropdown_list').locator('visible=true')
71+
).toHaveScreenshot();
72+
73+
await page
74+
.locator('.lm_tabdropdown_list')
75+
.locator('visible=true')
76+
.getByText('test-z')
77+
.click();
78+
79+
// check that it is shown in header as expected
80+
// and visuals are styled correctly, scrolled into view etc
81+
await expect(page.locator('.lm_header').first()).toHaveScreenshot();
82+
83+
// check that the selected panel is open
84+
await expect(
85+
page.locator('.test-z-component').locator('.panel-placeholder')
86+
).toHaveText('Component "test-z" is not registered.');
87+
});
88+
89+
test('golden-layout can close a tab', async () => {
90+
await page
91+
.locator('.lm_tab')
92+
.filter({ has: page.getByText('test-y') })
93+
.getByLabel('Close tab')
94+
.click();
95+
96+
// check that the selected panel is open
97+
await expect(page.getByText('test-y')).toHaveCount(0);
98+
99+
// check middle click closes tab
100+
await page
101+
.locator('.lm_tab')
102+
.filter({ has: page.getByText('test-x') })
103+
.getByLabel('Close tab')
104+
.click({ button: 'middle' });
105+
106+
// check that the selected panel is open
107+
await expect(page.getByText('test-x')).toHaveCount(0);
108+
});
109+
110+
test('golden-layout can drag tab to left edge', async () => {
111+
const dragTab = await page
112+
.locator('.lm_tab')
113+
.filter({ has: page.getByText('test-z') });
114+
115+
const dropTargetIndicator = page.locator('.lm_dropTargetIndicator');
116+
117+
// manual drag so we can take screenshot of indicator
118+
await dragTab.hover();
119+
await page.mouse.down();
120+
await page.mouse.move(10, 100);
121+
122+
// check that the drop target indicator is visible
123+
await expect(dropTargetIndicator).toBeVisible();
124+
125+
// remove the marching ants animation so we can take consistent screen shot
126+
await dropTargetIndicator.evaluate(element => {
127+
// eslint-disable-next-line no-param-reassign
128+
element.style.animation = 'none';
129+
});
130+
131+
// check the drop indicator
132+
await expect(dropTargetIndicator).toHaveScreenshot();
133+
134+
// check the drag proxy
135+
await expect(page.locator('.lm_dragProxy')).toHaveScreenshot();
136+
137+
// drop item
138+
await page.mouse.up();
139+
140+
// check new layout
141+
await expect(page.locator('.lm_root')).toHaveScreenshot();
142+
});
143+
});
5.37 KB
Loading
6.61 KB
Loading
4.67 KB
Loading
4.19 KB
Loading
6.39 KB
Loading
3.77 KB
Loading

0 commit comments

Comments
 (0)