Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions typescript/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
node_modules
npm-debug.log*
.git
.gitignore
README.md
.env
.nyc_output
coverage
.nyc_output
.cache
dist
.DS_Store
*.log
.vscode
.idea
storybook-static
23 changes: 18 additions & 5 deletions typescript/.storybook/test-runner.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// @ts-expect-error TS7016
import { toMatchImageSnapshot } from "jest-image-snapshot";

import { getStoryContext, type TestRunnerConfig } from "@storybook/test-runner";
import type { Page } from "@playwright/test";
import {
getStoryContext,
type TestContext,
type TestRunnerConfig,
} from "@storybook/test-runner";

// https://github.com/mapbox/pixelmatch#pixelmatchimg1-img2-output-width-height-options
const customDiffConfig = {};

// @ts-expect-error TS7006
const screenshotTest = async (page, context) => {
const screenshotTest = async (page: Page, context: TestContext) => {
let previousScreenshot: Buffer = Buffer.from("");

let stable = false;
Expand All @@ -27,7 +30,6 @@ const screenshotTest = async (page, context) => {
}
}

// @ts-expect-error TS2551
expect(previousScreenshot).toMatchImageSnapshot({
customSnapshotIdentifier: context.id,
// https://www.npmjs.com/package/jest-image-snapshot/v/4.0.2#-api
Expand All @@ -38,6 +40,12 @@ const screenshotTest = async (page, context) => {
});
};

const domSnapshotTest = async (page: Page) => {
const elementHandler = await page.$("#storybook-root");
const innerHTML = elementHandler ? await elementHandler.innerHTML() : "";
expect(innerHTML).toMatchSnapshot();
};

const config: TestRunnerConfig = {
setup() {
jest.retryTimes(2);
Expand All @@ -55,6 +63,11 @@ const config: TestRunnerConfig = {
if (!storyContext.tags.includes("no-screenshot-test")) {
await screenshotTest(page, context);
}

// Run DOM snapshot test unless no-dom-test is specified
if (!storyContext.tags.includes("no-dom-test")) {
await domSnapshotTest(page);
}
},
};

Expand Down
12 changes: 0 additions & 12 deletions typescript/Dockerfile.test

This file was deleted.

4 changes: 2 additions & 2 deletions typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ Test snapshots can be updated using `npx nx run-many --target test_correctness -

Storybook test-runner is used to smoke test all stories in each package.

Tests can be run, given a running (`npm run storybook`) or static storybook, using `npm run docker:build && npm run docker:storybook:test`.
Tests can be run using `npm run compose:storybook:test`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this replace the previous version (ie. docker:build and docker:storybook:test), that is running in the docker ?
If so we can remove the docker:* version.
If not, add in the doc how to do it (needed for windows devs to update the ref images).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hoped everyone could use the new compose:* version. Could you give it a try?

DOM snapshots are not the same when running storybook dynamically. In CI it runs static, so you won't be able to create DOM snapshots locally with the previous scripts.

However, for creating screenshots, the dynamic version (docker:*) still works and is probably quicker.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, keep both version in the README and explain the difference.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deleted a reference .snap file and ran npm run compose:storybook:test => Result was green with a written snapshot :/

Snapshot Summary
› 1 snapshot written from 1 test suite.

Test Suites: 45 passed, 45 total
Tests: 186 passed, 186 total
Snapshots: 1 written, 181 passed, 182 total
Time: 527.003 s
Ran all test suites.

Unfortunately, the EOL was not matching the initial file's EOL :/

A second run failed because of 2 image comparison failures...

Then I deleted a reference .snap file and ran npm run compose:storybook:test:update twice => it ended green, but without restoring the missing .snap file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deleted a reference .snap file and ran npm run compose:storybook:test => Result was green with a written snapshot :/

Is this new behaviour?

Snapshot Summary
› 1 snapshot written from 1 test suite.
Test Suites: 45 passed, 45 total
Tests: 186 passed, 186 total
Snapshots: 1 written, 181 passed, 182 total
Time: 527.003 s
Ran all test suites.

Unfortunately, the EOL was not matching the initial file's EOL :/

I don't understand how this could happen. Does it fail the tests?

A second run failed because of 2 image comparison failures...

Are the tests more flaky than before?

Then I deleted a reference .snap file and ran npm run compose:storybook:test:update twice => it ended green, but without restoring the missing .snap file.

I haven't seen the update not working before. Can you show me more precisely what you did so that I can try to reproduce it?


Test snapshots can be updated using `npm run docker:build && npm run docker:storybook:test:update`.
Test snapshots can be updated using `npm run compose:storybook:test:update`
22 changes: 22 additions & 0 deletions typescript/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
storybook:
build:
context: ..
dockerfile: typescript/config/docker/storybook/Dockerfile
ports:
- "6006:6006"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:6006"]

test-storybook:
build:
context: .
dockerfile: config/docker/test_runner/Dockerfile
depends_on:
storybook:
condition: service_healthy
volumes:
- ./.storybook:/home/pwuser/test/.storybook:ro
- ./packages:/home/pwuser/test/packages
environment:
TARGET_URL: "http://storybook:6006/"
34 changes: 34 additions & 0 deletions typescript/config/docker/storybook/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
FROM node:22-alpine

# Install curl for health checks and http-server globally in one layer
RUN apk add --no-cache curl && \
npm install -g http-server

WORKDIR /app/typescript

# Copy package files first for better caching
COPY typescript/package.json typescript/package-lock.json ./

# Install dependencies early to cache this expensive step
RUN npm ci CYPRESS_INSTALL_BINARY=0 --ignore-scripts --workspace-root

# Copy configuration files
COPY typescript/tsconfig.json typescript/nx.json ./

COPY typescript/.storybook ./.storybook
COPY example-data ../example-data

# Copy source code (these change more frequently)
COPY typescript/packages ./packages

# Install remaining workspace dependencies
RUN npm ci CYPRESS_INSTALL_BINARY=0 --ignore-scripts

# Build storybook statically
RUN npm run build-storybook

# Expose port 6006
EXPOSE 6006

# Serve the built storybook with http-server
CMD ["http-server", "storybook-static", "--port", "6006", "-a", "0.0.0.0"]
14 changes: 14 additions & 0 deletions typescript/config/docker/test_runner/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM mcr.microsoft.com/playwright:v1.39.0-jammy

RUN mkdir -p /home/pwuser/test && chown -R pwuser:pwuser /home/pwuser/test
WORKDIR /home/pwuser/test

COPY package.json ./
COPY package-lock.json ./

RUN npm ci

COPY .storybook ./.storybook

# Create entrypoint that accepts additional arguments
ENTRYPOINT ["npm", "run", "storybook:test"]
38 changes: 38 additions & 0 deletions typescript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"storybook:test": "test-storybook --no-index-json",
"docker:build": "docker build --tag wsc_story_test --file Dockerfile.test .",
"docker:build": "docker build --tag wsc_story_test --file config/docker/test_runner/Dockerfile .",
"docker:storybook:test": "cross-env-shell PWD=$PWD npm run docker:storybook:test:docker:core -- -it --rm --mount type=bind,source=${PWD}/packages,target=/test/packages --network=host wsc_story_test",
"docker:storybook:test:update": "npm run docker:storybook:test -- npm run storybook:test -- --url http://host.docker.internal:6006/ --no-index-json --updateSnapshot",
"docker:storybook:test:docker:core": "docker run",
"compose:storybook:test": "docker-compose run --build test-storybook",
"compose:storybook:test:update": "docker-compose run --build test-storybook -- --updateSnapshot",
"cy:run": "npx cypress run -b chrome --component --headed",
"postpack": "npm run tidy-up",
"git:hooks:enable": "cd .. && husky install",
Expand All @@ -50,6 +52,7 @@
"@mui/material": "^5.15.15",
"@mui/system": "^5.15.14",
"@nx/jest": "^21.5.3",
"@playwright/test": "1.39",
"@storybook/addon-essentials": "^8.6.14",
"@storybook/addon-interactions": "^8.6.14",
"@storybook/addon-links": "^8.6.14",
Expand All @@ -69,6 +72,7 @@
"@types/d3-interpolate": "^3.0.4",
"@types/geojson": "^7946.0.14",
"@types/jest": "^29.5.12",
"@types/jest-image-snapshot": "^6.4.0",
"@types/lodash": "^4.17.5",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import _ from "lodash";
import type { Meta, StoryObj } from "@storybook/react";
import _ from "lodash";
import React from "react";

import { GroupTreePlot, type GroupTreePlotProps } from "../GroupTreePlot";

Expand Down Expand Up @@ -34,6 +34,7 @@ const stories: Meta<GroupTreePlotProps> = {
"When initially rendering the tree, automatically collapse all nodes at or below this depth",
},
},
tags: ["no-dom-test"],
};
export default stories;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DistanceScale } from "../../components/DistanceScale";
const stories: Meta = {
component: DistanceScale,
title: "SubsurfaceViewer / Components / DistanceScale",
tags: ["no-screenshot-test"],
};
export default stories;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { type LayerPickInfo } from "../../layers/utils/layerTools";
const stories: Meta = {
component: InfoCard,
title: "SubsurfaceViewer/Components/InfoCard",
tags: ["no-screenshot-test"],
};
export default stories;

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SubsurfaceViewer / Components / DistanceScale DarkMode smoke-test 1`] = `
<div style="position: absolute; color: white;">
<label style="color: white;">
800m
</label>
<div style="width: 100px; height: 4px; border-top: none; border-right: 2px solid; border-bottom: 2px solid; border-left: 2px solid; border-image: initial; display: inline-block; margin-left: 3px;">
</div>
</div>
`;

exports[`SubsurfaceViewer / Components / DistanceScale LightMode smoke-test 1`] = `
<div style="position: absolute;">
<label>
800m
</label>
<div style="width: 100px; height: 4px; border-top: none; border-right: 2px solid; border-bottom: 2px solid; border-left: 2px solid; border-image: initial; display: inline-block; margin-left: 3px;">
</div>
</div>
`;
Loading