Skip to content

Commit

Permalink
feat: Styleguide regression tests (#1639)
Browse files Browse the repository at this point in the history
- 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>
  • Loading branch information
bmingles and mofojed authored Nov 16, 2023
1 parent e4e2590 commit 561ff22
Show file tree
Hide file tree
Showing 376 changed files with 501 additions and 92 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
steps:
- name: Check installed fonts
run: 'fc-list : family'

- name: Run core server:${{ env.DOCKER_TAG }}
run: |
docker pull --quiet ghcr.io/deephaven/server:${{ env.DOCKER_TAG }}
Expand Down Expand Up @@ -52,6 +55,9 @@ jobs:
- name: Install Playwright dependencies
run: PLAYWRIGHT_BROWSERS_PATH=0 npx playwright install --with-deps

- name: Playwright version
run: npx playwright --version

- name: Run Playwright tests
run: PLAYWRIGHT_BROWSERS_PATH=0 npx playwright test --config=playwright-ci.config.ts

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ Snapshots are used by end-to-end tests to visually verify the output. Snapshots

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).

### Differences in CI vs Local Docker Environments
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.

- The `DejaVu Sans` font gets installed via the [Dockerfile](tests/docker-scripts/Dockerfile). It already exists in the CI environment.
- 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`

### Local

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.
Expand Down
6 changes: 4 additions & 2 deletions packages/chart/src/MockChartModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface Series {

/** Displays a basic random chart */
class MockChartModel extends ChartModel {
static random: () => number = Math.random.bind(Math);

static smoothing = 1.5;

static _theme: ChartTheme;
Expand Down Expand Up @@ -50,7 +52,7 @@ class MockChartModel extends ChartModel {
((Math.sin((i / steps) * offset) * steps) / 3 +
(Math.cos(i * 0.2) * steps) / 6 +
(Math.sin(i * 0.5) * steps) / 10 +
(Math.random() * steps) / 5 +
(MockChartModel.random() * steps) / 5 +
i * MockChartModel.smoothing) *
scale;
v = Math.round(v * 100) / 100; // 2 decimals only
Expand All @@ -61,7 +63,7 @@ class MockChartModel extends ChartModel {
linear.push(40 + i * MockChartModel.smoothing);
smooth.push(
(Math.sin((i / steps) * offset) * steps) / 3 +
(Math.random() * steps) / 10 +
(MockChartModel.random() * steps) / 10 +
i * MockChartModel.smoothing
); // push a smoother version of the same thing
}
Expand Down
2 changes: 1 addition & 1 deletion packages/code-studio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ When new functions are added to the API, ideally stubs returning a generic succe

## Styleguide/Component Development

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/).
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.

## Architecture

Expand Down
8 changes: 6 additions & 2 deletions packages/code-studio/src/main/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ import {
} from 'react-router-dom';
import AppInit from './AppInit';

const basename = document.location.pathname;
const StyleGuideRoot = React.lazy(() => import('../styleguide/StyleGuideRoot'));

const baseURI = new URL(document.baseURI).pathname.replace(/\/$/, '');

function AppRouter(): ReactElement {
return (
<Router basename={basename}>
<Router basename={baseURI}>
<Switch>
<Route exact path="/" component={AppInit} />
<Route
path={`/${import.meta.env.VITE_ROUTE_NOTEBOOKS}:notebookPath+`}
component={AppInit}
/>
<Route path="/styleguide" component={StyleGuideRoot} />
<Redirect from="*" to="/" />
</Switch>
</Router>
Expand Down
4 changes: 3 additions & 1 deletion packages/code-studio/src/styleguide/Alerts.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { Component, ReactElement } from 'react';
import classNames from 'classnames';
import { sampleSectionIdAndClasses } from './utils';

class Alerts extends Component {
static renderAlert(brand: string): ReactElement {
Expand All @@ -16,7 +18,7 @@ class Alerts extends Component {
Alerts.renderAlert(brand)
);
return (
<div>
<div {...sampleSectionIdAndClasses('alerts')}>
<h2 className="ui-title">Alerts</h2>
<div style={{ padding: '1rem 0' }}>{alerts}</div>
</div>
Expand Down
16 changes: 13 additions & 3 deletions packages/code-studio/src/styleguide/Buttons.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { Component, ReactElement } from 'react';
import classNames from 'classnames';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ButtonOld, SocketedButton } from '@deephaven/components';
import { dhTruck } from '@deephaven/icons';
import { sampleSectionIdAndClasses } from './utils';

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

return (
<div key={type}>
<div
key={type}
{...sampleSectionIdAndClasses(
`buttons-${type.length ? 'outline' : 'regular'}`
)}
>
<h5>{type.length ? 'Outline' : 'Regular'}</h5>
{brands}
</div>
Expand All @@ -36,7 +43,7 @@ class Buttons extends Component<Record<string, never>, ButtonsState> {

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

return (
<div style={{ padding: '1rem 0' }}>
<div
{...sampleSectionIdAndClasses('buttons-inline')}
style={{ padding: '1rem 0' }}
>
<h5>Inline Buttons</h5>
Regular btn-inline:
<ButtonOld className="btn-inline mx-2">
Expand Down
10 changes: 9 additions & 1 deletion packages/code-studio/src/styleguide/Charts.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, { ReactElement, useState } from 'react';
import { Chart, ChartModel, MockChartModel } from '@deephaven/chart';
import { useApi } from '@deephaven/jsapi-bootstrap';
import {
sampleSectionIdAndClasses,
useSeededRandomNumberCallback,
} from './utils';

function Charts(): ReactElement {
const dh = useApi();

MockChartModel.random = useSeededRandomNumberCallback();

const [model] = useState(() => new MockChartModel(dh));

return (
<div>
<div {...sampleSectionIdAndClasses('charts')}>
<h2 className="ui-title">Chart</h2>
<div style={{ height: 500 }}>
<Chart model={model as ChartModel} />
Expand Down
6 changes: 4 additions & 2 deletions packages/code-studio/src/styleguide/Colors.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import React from 'react';
import classNames from 'classnames';
import { sampleSectionIdAndClasses } from './utils';

function Colors(): React.ReactElement {
const graySwatches = [
Expand All @@ -16,8 +18,8 @@ function Colors(): React.ReactElement {
['900', '75'],
].map(([swatch, dh]) => (
<div
key={swatch}
className={classNames('swatch', 'gray-swatch', `gray-swatch-${swatch}`)}
key={swatch}
>
<span>
Gray-
Expand Down Expand Up @@ -50,7 +52,7 @@ function Colors(): React.ReactElement {
));

return (
<div>
<div {...sampleSectionIdAndClasses('colors')}>
<h2 className="ui-title">Colors</h2>
<div className="row">
<div className="col">{graySwatches}</div>
Expand Down
4 changes: 3 additions & 1 deletion packages/code-studio/src/styleguide/ContextMenus.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint no-alert: "off" */
/* eslint no-console: "off" */
import React, { Component } from 'react';
Expand All @@ -15,6 +16,7 @@ import {
vsQuestion,
IconDefinition,
} from '@deephaven/icons';
import { sampleSectionIdAndClasses } from './utils';

interface ContextMenuItem {
title: string;
Expand Down Expand Up @@ -106,7 +108,7 @@ class ContextMenus extends Component {
});

return (
<div>
<div {...sampleSectionIdAndClasses('context-menus')}>
<h2 className="ui-title">Context Menu</h2>
<Button
kind="primary"
Expand Down
4 changes: 3 additions & 1 deletion packages/code-studio/src/styleguide/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint no-alert: "off" */
/* eslint no-console: "off" */
import React, { Component } from 'react';
Expand All @@ -7,6 +8,7 @@ import {
HierarchicalCheckboxValueMap,
Button,
} from '@deephaven/components';
import { sampleSectionIdAndClasses } from './utils';

interface DialogState {
isShown: boolean;
Expand Down Expand Up @@ -61,7 +63,7 @@ class Dialog extends Component<unknown, DialogState> {

renderChild(): React.ReactElement {
return (
<div className="p-3">
<div {...sampleSectionIdAndClasses('dialog', ['p-3'])}>
<h4>Sample Child</h4>
<div className="form-group">
<label htmlFor="exampleInput1">
Expand Down
8 changes: 7 additions & 1 deletion packages/code-studio/src/styleguide/DraggableLists.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint no-console: "off" */
import React, { Component } from 'react';
import {
Expand All @@ -9,6 +10,7 @@ import {
import memoize from 'memoizee';
import { DragUtils, DraggableItemList, Range } from '@deephaven/components';
import DraggableListInput from './DraggableListInput';
import { sampleSectionIdAndClasses } from './utils';

const DRAG_LIST_TITLES = ['Draggable Only', 'Drag and Drop', 'Droppable Only'];
const DRAG_LIST_PROPS = [
Expand Down Expand Up @@ -188,7 +190,11 @@ class DraggableLists extends Component<
render(): React.ReactElement {
const { items, lists, selectedRanges } = this.state;
return (
<div className="style-guide-inputs">
<div
{...sampleSectionIdAndClasses('draggable-lists', [
'style-guide-inputs',
])}
>
<h2 className="ui-title">Drag and Drop Lists</h2>
<div className="row">
<DragDropContext
Expand Down
4 changes: 3 additions & 1 deletion packages/code-studio/src/styleguide/DropdownMenus.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/jsx-props-no-spreading */
/* eslint no-alert: "off" */
/* eslint no-console: "off" */
import React, { Component } from 'react';
Expand All @@ -17,6 +18,7 @@ import {
vsKebabVertical,
vsQuestion,
} from '@deephaven/icons';
import { sampleSectionIdAndClasses } from './utils';

interface DropdownMenus {
button: React.RefObject<HTMLDivElement>;
Expand Down Expand Up @@ -90,7 +92,7 @@ class DropdownMenus extends Component<
const { isShown } = this.state;

return (
<div>
<div {...sampleSectionIdAndClasses('dropdown-menus')}>
<h2 className="ui-title">Dropdown Menu</h2>
<p>
A simple dropdown menu of actions, can open on click of parent
Expand Down
4 changes: 3 additions & 1 deletion packages/code-studio/src/styleguide/Editors.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable react/jsx-props-no-spreading */
import React from 'react';
import { Editor } from '@deephaven/console';
import Constants from './StyleConstants';
import { sampleSectionIdAndClasses } from './utils';

function Editors(): React.ReactElement {
return (
<div>
<div {...sampleSectionIdAndClasses('editors')}>
<h2 className="ui-title">Editor</h2>
<h5 className="sub-title">Python</h5>
<div style={{ height: 400, position: 'relative' }}>
Expand Down
Loading

0 comments on commit 561ff22

Please sign in to comment.