Skip to content
Merged
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
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

67 changes: 67 additions & 0 deletions .github/workflows/storybook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Storybook

on:
pull_request:
branches: [master]
push:
branches: [master]

permissions:
contents: read

jobs:
build:
name: Build Storybook
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build Storybook
run: npm run build-storybook

- name: Upload Storybook artifacts
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
with:
name: storybook-static
path: storybook-static
retention-days: 7

test:
name: Storybook interaction tests
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Install Playwright browsers
run: npx playwright install --with-deps chromium

# The Vitest addon runs the stories directly in a browser through
# @vitest/browser-playwright — no built Storybook or HTTP server needed.
- name: Run Storybook tests
run: npm run test:storybook
Comment thread
riccardo-forina marked this conversation as resolved.
Resolved
env:
CI: true
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ cypress/screenshots/*
playwright-report/
test-results/
playwright/.auth/

# storybook build output
storybook-static

# vitest coverage
coverage
39 changes: 39 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import path from 'path';
import { fileURLToPath } from 'node:url';
import { createMainConfig } from '@redhat-cloud-services/hcc-storybook-hub/config';

const dirname = path.dirname(fileURLToPath(import.meta.url));

const config = createMainConfig({
stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
msw: true,
a11y: false,
extraAliases: {
'@redhat-cloud-services/chrome': path.resolve(dirname, 'mocks/chrome.ts'),
'@scalprum/react-core': path.resolve(dirname, 'mocks/scalprum.tsx'),
},
});

// The fec utilities mixins (frontend-components-utilities/styles/_mixins)
// use Sass global built-ins (round(), unit(), type-of()) that Dart Sass
// deprecates. That's library-internal — silence those IDs, keep ours loud.
const originalViteFinal = config.viteFinal;
config.viteFinal = async (
viteConfig: Parameters<NonNullable<typeof originalViteFinal>>[0],
) => {
const result = await originalViteFinal?.(viteConfig);
if (result) {
result.css = result.css ?? {};
result.css.preprocessorOptions = {
...(result.css.preprocessorOptions ?? {}),
scss: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...((result.css.preprocessorOptions as any)?.scss ?? {}),
silenceDeprecations: ['global-builtin', 'import'],
},
};
}
return result;
};

export default config;
18 changes: 18 additions & 0 deletions .storybook/mocks/chrome.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Storybook mock for @redhat-cloud-services/chrome's useLastVisited.
// Wired through extraAliases in .storybook/main.ts (deterministic module
// replacement — stronger than per-story moduleMock in browser mode).
export const lastVisitedData = [
{
bundle: 'Insights',
pathname: '/insights/advisor',
title: 'Advisor recommendations',
},
{
bundle: 'OpenShift',
pathname: '/openshift/',
title: 'OpenShift cluster list',
},
{ bundle: 'Settings', pathname: '/settings/', title: 'Settings' },
];

export const useLastVisited = () => lastVisitedData;
25 changes: 25 additions & 0 deletions .storybook/mocks/scalprum.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

/**
* Storybook stub for @scalprum/react-core's remote loader.
*
* The app is a federation host: the Landing route mounts widgetLayout's
* WidgetLayout module through ScalprumComponent. Stories exercise the
* app's own wiring (routing, prop passthrough, chrome navigation) — the
* stub renders what the federated module WOULD mount, labeled by
* scope/module, without loading real remotes.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const ScalprumComponent = ({ scope, module, layoutType }: any) => (
<div
data-testid="scalprum-stub"
data-scope={scope}
data-module={module}
data-layout-type={layoutType}
>
Scalprum stub: {scope}/{module}
</div>
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const ScalprumProvider = ({ children }: any) => <>{children}</>;
42 changes: 42 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Preview } from '@storybook/react-vite';
import '@patternfly/react-core/dist/styles/base.css';
import '@redhat-cloud-services/hcc-storybook-hub/css/storybook.css';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import {
HccStorybookProvider,
hccPreviewDefaults,
} from '@redhat-cloud-services/hcc-storybook-hub';

const preview: Preview = {
...hccPreviewDefaults,
decorators: [
(Story, { parameters }) => (
<HccStorybookProvider
bundle="landing-page"
app="landing"
environment={parameters.chrome?.environment ?? 'production'}
featureFlags={parameters.featureFlags}
>
<MemoryRouter>
<Story />
</MemoryRouter>
</HccStorybookProvider>
),
],
parameters: {
...hccPreviewDefaults.parameters,
options: {
storySort: {
method: 'alphabetical',
order: ['Documentation', 'Widgets', 'Routes', 'Components', '*'],
},
},
chrome: {
environment: 'production',
},
featureFlags: {},
},
};

export default preview;
4 changes: 3 additions & 1 deletion .tekton/landing-page-frontend-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ spec:
set -ex

npm run lint
npm test -- --runInBand --no-cache
# unit tests only in the container: the storybook project needs browser
# binaries (playwright) that the hermetic image does not carry
npm run test:unit
Comment thread
riccardo-forina marked this conversation as resolved.
Resolved
- name: test-app-name
value: "landing-page-frontend"
- name: test-app-port
Expand Down
40 changes: 0 additions & 40 deletions config/setupTests.js

This file was deleted.

28 changes: 28 additions & 0 deletions config/setupTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Vitest setup for unit tests (ported from config/setupTests.js — jest globals).
// Property assignment only: never replace `window` whole, prototype-bound
// methods (getComputedStyle etc.) must survive for react-jss/css-vendor.

/* eslint-disable @typescript-eslint/no-explicit-any */

const insights = {
chrome: {
getEnvironment: () => 'prod',
},
};

(globalThis as any).insights = insights;
(globalThis as any).window.insights = insights;
(globalThis as any).window.__webpack_share_scopes__ = {
default: {},
};

// fix: `matchMedia` not present, jsdom/happy-dom require a polyfill
if (typeof (globalThis as any).matchMedia !== 'function') {
(globalThis as any).matchMedia = function () {
return {
matches: false,
addListener: function () {},
removeListener: function () {},
};
};
}
83 changes: 0 additions & 83 deletions config/webpack.cy.config.js

This file was deleted.

Loading