Skip to content

Commit 561ff22

Browse files
bminglesmofojed
andauthored
feat: Styleguide regression tests (#1639)
- Enabled styleguide in production builds - Added a base set of e2e regression snapshot tests on the styleguide - Changed router basename to be based on document.baseURI #1634 --------- Co-authored-by: mikebender <mikebender@deephaven.io>
1 parent e4e2590 commit 561ff22

376 files changed

Lines changed: 501 additions & 92 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ jobs:
2020
group: ${{ github.workflow }}-${{ github.ref }}
2121
cancel-in-progress: true
2222
steps:
23+
- name: Check installed fonts
24+
run: 'fc-list : family'
25+
2326
- name: Run core server:${{ env.DOCKER_TAG }}
2427
run: |
2528
docker pull --quiet ghcr.io/deephaven/server:${{ env.DOCKER_TAG }}
@@ -52,6 +55,9 @@ jobs:
5255
- name: Install Playwright dependencies
5356
run: PLAYWRIGHT_BROWSERS_PATH=0 npx playwright install --with-deps
5457

58+
- name: Playwright version
59+
run: npx playwright --version
60+
5561
- name: Run Playwright tests
5662
run: PLAYWRIGHT_BROWSERS_PATH=0 npx playwright test --config=playwright-ci.config.ts
5763

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ Snapshots are used by end-to-end tests to visually verify the output. Snapshots
112112

113113
Once you are satisfied with the snapshots and everything is passing locally, you need to use the docker image to update snapshots for CI (unless you are running the same platform as CI (Ubuntu)). Run `npm run e2e:update-ci-snapshots` to update the CI snapshots. The snapshots will be written to your local directories. The Linux snapshots should be committed to git (non-Linux snapshots should be automatically ignored by git).
114114

115+
### Differences in CI vs Local Docker Environments
116+
Note that while both the GH actions and docker configuration use Ubuntu 22.04 images, their configurations are not identical. One known difference is the available system fonts. In some cases this can cause snapshots to differ when running locally vs in CI such as when rendering unicode characters. To mitigate this, some of our e2e tests have been configured to ensure a consistent unicode font fallback.
117+
118+
- The `DejaVu Sans` font gets installed via the [Dockerfile](tests/docker-scripts/Dockerfile). It already exists in the CI environment.
119+
- Font family stacks that involve unicode characters can explicitly fallback to `DejaVu Sans` if they impact snapshots. e.g We do so in [Grids.tsx](packages/code-studio/src/styleguide/Grids.tsx) by setting the canvas font to `12px Arial, "DejaVu Sans", sans-serif`
120+
115121
### Local
116122

117123
These scripts are recommended while developing your tests as they will be quicker to iterate and offer headed mode for debugging. You will need to run `npx playwright install` before using these scripts. You may also need to update the browsers with the same command any time the Playwright version is updated. See [Playwright Browsers](https://playwright.dev/docs/browsers) for more details.

packages/chart/src/MockChartModel.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ interface Series {
1616

1717
/** Displays a basic random chart */
1818
class MockChartModel extends ChartModel {
19+
static random: () => number = Math.random.bind(Math);
20+
1921
static smoothing = 1.5;
2022

2123
static _theme: ChartTheme;
@@ -50,7 +52,7 @@ class MockChartModel extends ChartModel {
5052
((Math.sin((i / steps) * offset) * steps) / 3 +
5153
(Math.cos(i * 0.2) * steps) / 6 +
5254
(Math.sin(i * 0.5) * steps) / 10 +
53-
(Math.random() * steps) / 5 +
55+
(MockChartModel.random() * steps) / 5 +
5456
i * MockChartModel.smoothing) *
5557
scale;
5658
v = Math.round(v * 100) / 100; // 2 decimals only
@@ -61,7 +63,7 @@ class MockChartModel extends ChartModel {
6163
linear.push(40 + i * MockChartModel.smoothing);
6264
smooth.push(
6365
(Math.sin((i / steps) * offset) * steps) / 3 +
64-
(Math.random() * steps) / 10 +
66+
(MockChartModel.random() * steps) / 10 +
6567
i * MockChartModel.smoothing
6668
); // push a smoother version of the same thing
6769
}

packages/code-studio/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ When new functions are added to the API, ideally stubs returning a generic succe
6363

6464
## Styleguide/Component Development
6565

66-
When running in development mode (`npm run start`), a style guide is served up at http://localhost:4000/styleguide. Styleguide can be used to develop components. The styleguide displays many common components and how to use them. When creating a new component, it should be added to the [styleguide](./src/styleguide/).
66+
When running in development mode (`npm run start`), a style guide is served up at http://localhost:4000/ide/styleguide. Styleguide can be used to develop components. The styleguide displays many common components and how to use them. When creating a new component, it should be added to the [styleguide](./src/styleguide/). Note that the styleguide is lazy loaded in [AppRouter](packages/code-studio/src/main/AppRouter.tsx), so it should not increase the main app bundle size.
6767

6868
## Architecture
6969

packages/code-studio/src/main/AppRouter.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ import {
77
} from 'react-router-dom';
88
import AppInit from './AppInit';
99

10-
const basename = document.location.pathname;
10+
const StyleGuideRoot = React.lazy(() => import('../styleguide/StyleGuideRoot'));
11+
12+
const baseURI = new URL(document.baseURI).pathname.replace(/\/$/, '');
13+
1114
function AppRouter(): ReactElement {
1215
return (
13-
<Router basename={basename}>
16+
<Router basename={baseURI}>
1417
<Switch>
1518
<Route exact path="/" component={AppInit} />
1619
<Route
1720
path={`/${import.meta.env.VITE_ROUTE_NOTEBOOKS}:notebookPath+`}
1821
component={AppInit}
1922
/>
23+
<Route path="/styleguide" component={StyleGuideRoot} />
2024
<Redirect from="*" to="/" />
2125
</Switch>
2226
</Router>

packages/code-studio/src/styleguide/Alerts.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
12
import React, { Component, ReactElement } from 'react';
23
import classNames from 'classnames';
4+
import { sampleSectionIdAndClasses } from './utils';
35

46
class Alerts extends Component {
57
static renderAlert(brand: string): ReactElement {
@@ -16,7 +18,7 @@ class Alerts extends Component {
1618
Alerts.renderAlert(brand)
1719
);
1820
return (
19-
<div>
21+
<div {...sampleSectionIdAndClasses('alerts')}>
2022
<h2 className="ui-title">Alerts</h2>
2123
<div style={{ padding: '1rem 0' }}>{alerts}</div>
2224
</div>

packages/code-studio/src/styleguide/Buttons.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
12
import React, { Component, ReactElement } from 'react';
23
import classNames from 'classnames';
34
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
45
import { ButtonOld, SocketedButton } from '@deephaven/components';
56
import { dhTruck } from '@deephaven/icons';
7+
import { sampleSectionIdAndClasses } from './utils';
68

79
interface ButtonsState {
810
toggle: boolean;
@@ -27,7 +29,12 @@ class Buttons extends Component<Record<string, never>, ButtonsState> {
2729
);
2830

2931
return (
30-
<div key={type}>
32+
<div
33+
key={type}
34+
{...sampleSectionIdAndClasses(
35+
`buttons-${type.length ? 'outline' : 'regular'}`
36+
)}
37+
>
3138
<h5>{type.length ? 'Outline' : 'Regular'}</h5>
3239
{brands}
3340
</div>
@@ -36,7 +43,7 @@ class Buttons extends Component<Record<string, never>, ButtonsState> {
3643

3744
static renderSocketedButtons(): ReactElement {
3845
return (
39-
<div>
46+
<div {...sampleSectionIdAndClasses('buttons-socketed')}>
4047
<h5>Socketed Buttons (for linker)</h5>
4148
<SocketedButton style={{ marginBottom: '1rem', marginRight: '1rem' }}>
4249
Unlinked
@@ -82,7 +89,10 @@ class Buttons extends Component<Record<string, never>, ButtonsState> {
8289
const { toggle } = this.state;
8390

8491
return (
85-
<div style={{ padding: '1rem 0' }}>
92+
<div
93+
{...sampleSectionIdAndClasses('buttons-inline')}
94+
style={{ padding: '1rem 0' }}
95+
>
8696
<h5>Inline Buttons</h5>
8797
Regular btn-inline:
8898
<ButtonOld className="btn-inline mx-2">

packages/code-studio/src/styleguide/Charts.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
12
import React, { ReactElement, useState } from 'react';
23
import { Chart, ChartModel, MockChartModel } from '@deephaven/chart';
34
import { useApi } from '@deephaven/jsapi-bootstrap';
5+
import {
6+
sampleSectionIdAndClasses,
7+
useSeededRandomNumberCallback,
8+
} from './utils';
49

510
function Charts(): ReactElement {
611
const dh = useApi();
12+
13+
MockChartModel.random = useSeededRandomNumberCallback();
14+
715
const [model] = useState(() => new MockChartModel(dh));
816

917
return (
10-
<div>
18+
<div {...sampleSectionIdAndClasses('charts')}>
1119
<h2 className="ui-title">Chart</h2>
1220
<div style={{ height: 500 }}>
1321
<Chart model={model as ChartModel} />

packages/code-studio/src/styleguide/Colors.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
12
import React from 'react';
23
import classNames from 'classnames';
4+
import { sampleSectionIdAndClasses } from './utils';
35

46
function Colors(): React.ReactElement {
57
const graySwatches = [
@@ -16,8 +18,8 @@ function Colors(): React.ReactElement {
1618
['900', '75'],
1719
].map(([swatch, dh]) => (
1820
<div
19-
key={swatch}
2021
className={classNames('swatch', 'gray-swatch', `gray-swatch-${swatch}`)}
22+
key={swatch}
2123
>
2224
<span>
2325
Gray-
@@ -50,7 +52,7 @@ function Colors(): React.ReactElement {
5052
));
5153

5254
return (
53-
<div>
55+
<div {...sampleSectionIdAndClasses('colors')}>
5456
<h2 className="ui-title">Colors</h2>
5557
<div className="row">
5658
<div className="col">{graySwatches}</div>

packages/code-studio/src/styleguide/ContextMenus.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
12
/* eslint no-alert: "off" */
23
/* eslint no-console: "off" */
34
import React, { Component } from 'react';
@@ -15,6 +16,7 @@ import {
1516
vsQuestion,
1617
IconDefinition,
1718
} from '@deephaven/icons';
19+
import { sampleSectionIdAndClasses } from './utils';
1820

1921
interface ContextMenuItem {
2022
title: string;
@@ -106,7 +108,7 @@ class ContextMenus extends Component {
106108
});
107109

108110
return (
109-
<div>
111+
<div {...sampleSectionIdAndClasses('context-menus')}>
110112
<h2 className="ui-title">Context Menu</h2>
111113
<Button
112114
kind="primary"

0 commit comments

Comments
 (0)