Skip to content
Draft
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
29 changes: 29 additions & 0 deletions apps/popover-tests-headless/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.storybook/
.vscode/
bundle-size/
config/
coverage/
e2e/
etc/
node_modules/
src/
dist/types/
temp/
__fixtures__
__mocks__
__tests__

*.api.json
*.log
*.spec.*
*.stories.*
*.test.*
*.yml

# config files
*config.*
*rc.*
.editorconfig
.eslint*
.git*
.prettierignore
10 changes: 10 additions & 0 deletions apps/popover-tests-headless/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const rootMain = require('../../../.storybook/main');

module.exports = /** @type {Omit<import('../../../.storybook/main'), 'typescript'|'babel'>} */ ({
...rootMain,
stories: [...rootMain.stories, '../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'],
addons: [...rootMain.addons],
webpackFinal: (config, options) => {
return { ...rootMain.webpackFinal(config, options) };
},
});
9 changes: 9 additions & 0 deletions apps/popover-tests-headless/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as rootPreview from '../../../.storybook/preview';

/** @type {typeof rootPreview.decorators} */
export const decorators = [...rootPreview.decorators];

/** @type {typeof rootPreview.parameters} */
export const parameters = { ...rootPreview.parameters };

export const tags = ['autodocs'];
10 changes: 10 additions & 0 deletions apps/popover-tests-headless/.storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "",
"allowJs": true,
"checkJs": true,
"types": ["static-assets", "environment"]
},
"include": ["../src/**/*.stories.ts", "../src/**/*.stories.tsx", "*.js"]
}
77 changes: 77 additions & 0 deletions apps/popover-tests-headless/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# @fluentui/popover-tests-headless

Private test application for the Headless adaptive positioning runtime.

The app exercises both positioning implementations behind the same component
APIs:

- native HTML Popover API with CSS Anchor Positioning;
- native HTML Popover API with lazy `react-positioning` fallback.

No Playwright tests are included yet. The initial workflow is manual
verification, followed by Playwright coverage after the scenarios are approved.

## CSR manual verification

Start the private Storybook from the repository root:

```bash
yarn nx storybook popover-tests-headless
```

Each anchored control has its own page under **Positioning Runtime / CSR**:

| Control | Story URL |
| --------------- | -------------------------------------------------------- |
| Popover | `?path=/story/positioning-runtime-csr--popover` |
| TeachingPopover | `?path=/story/positioning-runtime-csr--teaching-popover` |
| Menu | `?path=/story/positioning-runtime-csr--menu` |
| Tooltip | `?path=/story/positioning-runtime-csr--tooltip` |
| Dropdown | `?path=/story/positioning-runtime-csr--dropdown` |
| Combobox | `?path=/story/positioning-runtime-csr--combobox` |
| TagPicker | `?path=/story/positioning-runtime-csr--tag-picker` |

Every CSR page provides reload controls for:

- auto-detected mode;
- forced native mode;
- forced fallback mode.

The Popover page includes basic, nested, and collision-placement scenarios.
Stable `data-testid` hooks are included for future Playwright tests.

## SSR verification

Run the SSR harness:

```bash
yarn nx run popover-tests-headless:test-ssr
```

Each control also has a separate **Positioning Runtime / SSR** page:

| Control | Story URL |
| --------------- | -------------------------------------------------------- |
| Popover | `?path=/story/positioning-runtime-ssr--popover` |
| TeachingPopover | `?path=/story/positioning-runtime-ssr--teaching-popover` |
| Menu | `?path=/story/positioning-runtime-ssr--menu` |
| Tooltip | `?path=/story/positioning-runtime-ssr--tooltip` |
| Dropdown | `?path=/story/positioning-runtime-ssr--dropdown` |
| Combobox | `?path=/story/positioning-runtime-ssr--combobox` |
| TagPicker | `?path=/story/positioning-runtime-ssr--tag-picker` |

The SSR harness server-renders every story, then loads the generated output in
Chrome to catch browser and hydration errors. The SSR Storybook pages mirror
those scenarios and expose the hydration runtime controls for manual
inspection.

Every SSR page reports:

- server render mode: always `ssr`;
- requested hydration runtime: auto, native, or fallback;
- runtime resolved by the hydrated client.

The hydration runtime buttons use the same `positioningRuntime` query parameter
as the CSR pages. They do not change the server render mode. In auto mode,
hydration keeps native anchor positioning on supported browsers and only loads
the fallback on unsupported browsers.
3 changes: 3 additions & 0 deletions apps/popover-tests-headless/config/tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/** Jest test setup file. */

require('@testing-library/jest-dom');
14 changes: 14 additions & 0 deletions apps/popover-tests-headless/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @ts-check
const fluentPlugin = require('@fluentui/eslint-plugin');

/** @type {import("eslint").Linter.Config[]} */
module.exports = [
...fluentPlugin.configs['flat/node'],
{
rules: {
'@typescript-eslint/explicit-module-boundary-types': 'off',
'import/no-extraneous-dependencies': ['error', { packageDir: ['../../', './'] }],
'no-restricted-globals': 'off',
},
},
];
15 changes: 15 additions & 0 deletions apps/popover-tests-headless/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @ts-check

/**
* @type {import('@jest/types').Config.InitialOptions}
*/
module.exports = {
displayName: 'popover-tests-headless',
preset: '../../jest.preset.js',
transform: {
'^.+\\.tsx?$': ['@swc/jest', {}],
},
testEnvironment: 'jsdom',
coverageDirectory: './coverage',
setupFilesAfterEnv: ['./config/tests.js'],
};
3 changes: 3 additions & 0 deletions apps/popover-tests-headless/just.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { preset } from '@fluentui/scripts-tasks';

preset();
24 changes: 24 additions & 0 deletions apps/popover-tests-headless/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@fluentui/popover-tests-headless",
"version": "0.0.0",
"description": "Private SSR and CSR verification app for Headless adaptive positioning",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/microsoft/fluentui"
},
"license": "MIT",
"scripts": {
"clean": "yarn run -T just-scripts clean",
"code-style": "yarn run -T just-scripts code-style",
"lint": "yarn run -T just-scripts lint",
"storybook": "yarn run -T storybook dev",
"test": "yarn run -T jest --passWithNoTests",
"type-check": "yarn run -T just-scripts type-check",
"test-ssr": "yarn run -T test-ssr \"./src/stories/**/*.stories.tsx\""
},
"dependencies": {
"@fluentui/react-components": "*",
"@fluentui/react-headless-components-preview": "*"
}
}
8 changes: 8 additions & 0 deletions apps/popover-tests-headless/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "popover-tests-headless",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"implicitDependencies": [],
"sourceRoot": "apps/popover-tests-headless/src",
"tags": ["vNext", "platform:web"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ComboboxControl } from './Controls';

export const Combobox = ComboboxControl;

export default { title: 'Positioning Runtime / CSR' };
Loading
Loading