Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
df1f5ea
chore: migrate repo to React 19
Hotell Oct 31, 2025
1887b3d
chore(rit): update major react version runner settings
Hotell Oct 31, 2025
792d23c
chore: remove react-19-tests-v9 as its redundant with R19 in place
Hotell Oct 31, 2025
38e2a8b
chore(react-conformance-griffel): backport removed legacy react-dom t…
Hotell Oct 31, 2025
917ef8a
chore(react-utilities): resolve issues exposed by R19
Hotell Oct 31, 2025
546f50d
chore(react-context-selector): resolve issues exposed by R19
Hotell Oct 31, 2025
9610b65
fix(react-tabster): resolve invalid RefObject return types
Hotell Oct 31, 2025
12eaeb4
fix(v9 deprecated): resolve type issues exposed by R19
Hotell Oct 31, 2025
ca3509d
fix(v8): resolve issues exposed by R19
Hotell Oct 31, 2025
86188f9
chore(v9-sb-addon): turn on skipLibCheck to make generate-api pass - …
Hotell Oct 31, 2025
7a7ac74
fix(v8/react-experiments): resolve issues exposed by R19
Hotell Oct 31, 2025
190cf7d
fix(v8/storybook): resolve issues exposed by R19
Hotell Oct 31, 2025
dd69387
fix(v8/react-charting): resolve issues exposed by R19
Hotell Oct 31, 2025
a4260d7
fix(v9/react-charts): resolve issues exposed by R19
Hotell Oct 31, 2025
93a0e3f
fix(v8/react-monaco-editor): resolve issues exposed by R19
Hotell Oct 31, 2025
78f62de
fix(v8/react-docsite-components): resolve issues exposed by R19
Hotell Oct 31, 2025
147bff6
fix(v9/react-migration-v0-v9): resolve issues exposed by R19
Hotell Oct 31, 2025
53f5b90
fix(v9/react-migration-v8-v9): resolve issues exposed by R19
Hotell Nov 3, 2025
455398e
fix(v8/public-docsite): resolve issues exposed by R19
Hotell Nov 3, 2025
83cd283
chore(react-utilities): resolve issues exposed by R19 v2
Hotell Nov 3, 2025
d2fc4b9
chore(react-tabster): resolve issues exposed by R19 v2
Hotell Nov 3, 2025
0d22116
chore(react-jsx-runtime): resolve issues exposed by R19
Hotell Nov 3, 2025
c8ed248
test(react-examples): fix RIT configuration
Hotell Nov 3, 2025
2642c26
chore(v9): resolve issues exposed by R19
Hotell Nov 3, 2025
4e6e2f9
style: mitigate lint issues after R19 bump
Hotell Nov 3, 2025
8d3a93f
ci(pr-vrt): add 60min timeout
Hotell Nov 3, 2025
5b9b4ec
test(v9): update snapshots
Hotell Nov 3, 2025
09680a6
fix(charts): update snapshots and resolve infinite loop within useEff…
Hotell Nov 3, 2025
2594f44
test(react): decouple SSR tests causing invalid react resolution coru…
Hotell Nov 3, 2025
d48a454
test(scripts-tests): make test pass
Hotell Nov 3, 2025
a9acb50
fix(ssr-tests): resolve type check issues after R19 migration
Hotell Nov 3, 2025
a128bf1
test(docstive-v9): resolve type issues and invalid tests
Hotell Nov 4, 2025
5d49ae1
fix(ssr-tests): make the ssr test sync to match behaviour if renderTo…
Hotell Nov 4, 2025
9c698fd
fix(rit-tests-v9): update type-check ref to run against repo r19
Hotell Nov 4, 2025
23602b8
chore(vr-tests-v9): fix type errors
Hotell Nov 4, 2025
fb6fec2
fix(vr-tests-web-components): resolve type issues
Hotell Nov 4, 2025
62ed9b3
fix(web-components): make build deterministic and remove global @type…
Hotell Nov 4, 2025
85c58cd
fix(react): don't leak R19 Promise api to JSX for dts
Hotell Nov 4, 2025
2fa2109
change files
Hotell Nov 4, 2025
0f3cd28
test(docsite-v9): fix tests after SB8 migration
Hotell Nov 5, 2025
cd4097f
chore: update yarn lock after dropping r18
Hotell Nov 5, 2025
8d06535
style(charts): fix lint issues after rebase
Hotell Nov 5, 2025
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: 1 addition & 0 deletions .github/workflows/pr-vrt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
if: ${{ github.repository_owner == 'microsoft' }}
Copy link

@github-actions github-actions bot Nov 4, 2025

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Charts-DonutChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 27053 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 276 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 595 Changed
vr-tests-react-components/TagPicker 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 659 Changed
vr-tests-react-components/TagPicker.disabled - High Contrast.disabled input hover.chromium.png 1321 Changed
vr-tests-react-components/TagPicker.disabled - RTL.disabled input hover.chromium.png 635 Changed
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 678 Changed
vr-tests-web-components/Accordion 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Accordion. - Dark Mode.normal.chromium_1.png 3151 Changed
vr-tests-web-components/Checkbox 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Checkbox. - Dark Mode.normal.chromium_1.png 29 Changed
vr-tests-web-components/Checkbox.Checked.normal.chromium.png 118 Changed
vr-tests-web-components/Checkbox.Circular Checked.normal.chromium.png 90 Changed
vr-tests-web-components/Checkbox.Disabled.normal.chromium.png 39 Changed
vr-tests-web-components/MenuList 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/MenuList. - Dark Mode.normal.chromium.png 500 Changed
vr-tests-web-components/MenuList. - RTL.normal.chromium_1.png 39082 Changed
vr-tests-web-components/Radio 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Radio. - Dark Mode.normal.chromium_1.png 29 Changed
vr-tests-web-components/RadioGroup 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/RadioGroup. - Dark Mode.normal.chromium_1.png 59 Changed
vr-tests-web-components/RadioGroup.Default Checked.normal.chromium.png 51 Changed
vr-tests-web-components/RadioGroup.Disabled Item.normal.chromium.png 27 Changed
vr-tests-web-components/Switch 5 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Switch. - Dark Mode.normal.chromium_1.png 179 Changed
vr-tests-web-components/Switch.Disabled Checked.hover.chromium.png 187 Changed
vr-tests-web-components/Switch.Checked.normal.chromium.png 201 Changed
vr-tests-web-components/Switch.Disabled Checked.normal.chromium.png 165 Changed
vr-tests-web-components/Switch.Disabled.normal.chromium.png 100 Changed
vr-tests/Callout 7 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/Callout.Right center.default.chromium.png 2080 Changed
vr-tests/Callout.Gap space 25.default.chromium.png 2181 Changed
vr-tests/Callout.Right top edge.default.chromium.png 1116 Changed
vr-tests/Callout.No callout width specified.default.chromium.png 2126 Changed
vr-tests/Callout.Rendering callout attached to a rectangle.default.chromium.png 1832 Changed
vr-tests/Callout.Top auto edge.default.chromium.png 2196 Changed
vr-tests/Callout.Top center.default.chromium.png 2113 Changed
vr-tests/Keytip 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/Keytip.Offset.default.chromium.png 86 Changed
vr-tests/react-charting-MultiStackBarChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-MultiStackBarChart.Basic_Absolute - RTL.default.chromium.png 343 Changed

There were 15 duplicate changes discarded. Check the build logs for more information.

runs-on: macos-14-xlarge
name: Generate screenshots
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
Expand Down
45 changes: 7 additions & 38 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,17 @@ jobs:
- run: |
yarn install --frozen-lockfile
yarn rit --react 17 --install-deps
yarn rit --react 19 --install-deps
yarn rit --react 18 --install-deps

- name: Verify Cypress installs from RIT temp workspaces (React 17 -> v13, React 19 -> v14)
- name: Verify Cypress installs from RIT temp workspaces (React 17 -> v13, React 18 -> v14)
run: |
"$GITHUB_WORKSPACE"/tmp/rit/react-17/node_modules/.bin/cypress verify
"$GITHUB_WORKSPACE"/tmp/rit/react-19/node_modules/.bin/cypress verify
"$GITHUB_WORKSPACE"/tmp/rit/react-18/node_modules/.bin/cypress verify

- name: React Versions Integration Tests (17,19) - E2E
- name: React Versions Integration Tests (17,18) - E2E
id: e2e
run: |
yarn nx affected -t test-rit--17--e2e,test-rit--19--e2e --exclude='react-19-tests-v9,react-charting,react'
yarn nx affected -t test-rit--17--e2e,test-rit--18--e2e --exclude='react-19-tests-v9,react-charting,react'

- name: Upload Cypress screenshots if exist
uses: actions/upload-artifact@v4
Expand All @@ -125,40 +125,9 @@ jobs:
tmp/rit/**/cypress/screenshots/**/*.png
retention-days: 1

- name: React Versions Integration Tests (17,19) - Type-check & Test
- name: React Versions Integration Tests (17,18) - Type-check & Test
run: |
FLUENT_JEST_WORKER=2 yarn nx affected -t test-rit--17--type-check,test-rit--19--type-check,test-rit--17--test,test-rit--19--test --exclude='react-19-tests-v9'

react_19_v9_source_code_typecheck:
if: ${{ github.repository_owner == 'microsoft' }}
runs-on: ubuntu-latest
permissions:
contents: 'read'
actions: 'read'
name: v9 source code type-check against React 19
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@826660b82addbef3abff5fa871492ebad618c9e1 # v4.3.3
with:
main-branch-name: 'master'

- uses: actions/setup-node@v4
with:
cache: 'yarn'
node-version: '22'

- run: echo number of CPUs "$(getconf _NPROCESSORS_ONLN)"

- run: |
yarn install --frozen-lockfile
yarn rit --react 19 --install-deps

- run: |
yarn nx affected -t test-rit--19--type-check --exclude='*,!react-19-tests-v9'
FLUENT_JEST_WORKER=2 yarn nx affected -t test-rit--17--type-check,test-rit--18--type-check,test-rit--17--test,test-rit--18--test --exclude='react-19-tests-v9'

e2e:
if: ${{ github.repository_owner == 'microsoft' }}
Expand Down
4 changes: 2 additions & 2 deletions apps/chart-docsite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"@fluentui/react-charts": "*",
"@fluentui/react-storybook-addon": "*",
"@fluentui/react-storybook-addon-export-to-sandbox": "*",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"tslib": "^2.1.0"
}
}
4 changes: 2 additions & 2 deletions apps/perf-test-react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"@fluentui/react-theme": "*",
"@griffel/core": "^1.16.0",
"@microsoft/load-themed-styles": "^1.10.26",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"tslib": "^2.1.0"
}
}
4 changes: 2 additions & 2 deletions apps/perf-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"@fluentui/example-data": "*",
"@fluentui/react": "*",
"@microsoft/load-themed-styles": "^1.10.26",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"tslib": "^2.1.0"
}
}
4 changes: 2 additions & 2 deletions apps/public-docsite-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
"@fluentui/theme-samples": "*",
"@fluentui/react-monaco-editor": "*",
"office-ui-fabric-core": "^11.0.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"tslib": "^2.1.0"
}
}
4 changes: 2 additions & 2 deletions apps/public-docsite-v9/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"@fluentui/react-timepicker-compat": "*",
"@griffel/react": "^1.5.22",
"@microsoft/applicationinsights-web": "^3",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-window": "^1.8.6",
"tslib": "^2.1.0",
"react-hook-form": "^5.7.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
/* eslint-disable react/jsx-key */
/* eslint-disable @typescript-eslint/naming-convention */

import * as React from 'react';
import { Source } from '@storybook/addon-docs';
import { createRenderer } from 'react-test-renderer/shallow';
import { render } from '@testing-library/react';

import { CodeExample } from './utils.stories';

// Mock the Source component to verify it receives correct props
const mockSource = jest.fn(({ code, language }: { code: string; language: string }) => (
<pre data-testid="source" data-language={language}>
<code>{code}</code>
</pre>
));

// `Source` wont be available in the test environment, so we need to mock it to test the code output
jest.mock('@storybook/addon-docs', () => ({
Source: (props: { code: string; language: string }) => mockSource(props),
}));

function mockMDXSourceCodeBlock(source: string) {
return {
props: {
Expand All @@ -16,23 +29,22 @@ function mockMDXSourceCodeBlock(source: string) {
} as React.ReactElement;
}

beforeEach(() => {
mockSource.mockClear();
});

test('renders children', () => {
const renderer = createRenderer();
renderer.render(
const { container } = render(
<CodeExample>
<span>Child</span>
</CodeExample>,
);
const result = renderer.getRenderOutput();

expect(result.props).toEqual({
children: 'Child',
});
expect(container.textContent).toBe('Child');
});

test('renders Markdown source blocks', () => {
const renderer = createRenderer();
renderer.render(
const { getByRole, getByTestId } = render(
<CodeExample>
{mockMDXSourceCodeBlock(`\`\`\`js
function test() {
Expand All @@ -41,53 +53,60 @@ test('renders Markdown source blocks', () => {
\`\`\``)}
</CodeExample>,
);
const result = renderer.getRenderOutput();

expect(result.props).toEqual({
children: [
<h3>JavaScript</h3>,
<Source
code={`function test() {
// Test that CodeExample correctly parses and renders the header
const heading = getByRole('heading', { level: 3 });
expect(heading.textContent).toBe('JavaScript');

// Verify Source component was called with correct props
expect(mockSource).toHaveBeenCalledWith(
expect.objectContaining({
code: `function test() {
console.log("test");
}`}
language="jsextra"
/>,
],
});
}`,
language: 'jsextra',
}),
);

// Verify Source component rendered correctly
const sourceElement = getByTestId('source');
expect(sourceElement.getAttribute('data-language')).toBe('jsextra');
expect(sourceElement.textContent).toContain('function test()');
});

test('uses JSX for no header JSX source code blocks', () => {
const renderer = createRenderer();
renderer.render(
const { getByRole, getByTestId } = render(
<CodeExample>
{mockMDXSourceCodeBlock(`<div>
<Test title={"Example"} />
</div>`)}
</CodeExample>,
);
const result = renderer.getRenderOutput();

expect(result.props).toEqual({
children: [
<h3>React</h3>,
<Source
code={`<div>
const heading = getByRole('heading', { level: 3 });
expect(heading.textContent).toBe('React');

// Verify Source component was called with JSX language
expect(mockSource).toHaveBeenCalledWith(
expect.objectContaining({
code: `<div>
<Test title={"Example"} />
</div>`}
language="jsx"
/>,
],
});
</div>`,
language: 'jsx',
}),
);

const sourceElement = getByTestId('source');
expect(sourceElement.getAttribute('data-language')).toBe('jsx');
});

test.each([
['html', 'HTML'],
['css', 'CSS'],
['js', 'JavaScript'],
['jsx', 'React'],
] as const)('for language %s uses the header %s', (language, expectedHeader) => {
const renderer = createRenderer();
renderer.render(
])('for language %s uses the header %s', (language, expectedHeader) => {
const { getByRole, getByTestId } = render(
<CodeExample>
{mockMDXSourceCodeBlock(`
\`\`\`${language}
Expand All @@ -96,16 +115,27 @@ test.each([
`)}
</CodeExample>,
);
const result = renderer.getRenderOutput();

expect(result.props).toEqual({
children: [<h3>{expectedHeader}</h3>, <Source code={`Code`} language={language === 'js' ? 'jsextra' : language} />],
});
const resolvedLanguage = language === 'js' ? 'jsextra' : language;

const heading = getByRole('heading', { level: 3 });
expect(heading.textContent).toBe(expectedHeader);

// Verify Source component was called with correct language
expect(mockSource).toHaveBeenCalledWith(
expect.objectContaining({
code: 'Code',
language: resolvedLanguage,
}),
);

const sourceElement = getByTestId('source');
expect(sourceElement.getAttribute('data-language')).toBe(resolvedLanguage);
expect(sourceElement.textContent).toBe('Code');
});

test('overrides the default title', () => {
const renderer = createRenderer();
renderer.render(
const { getByRole, getByTestId } = render(
<CodeExample title="Custom title">
{mockMDXSourceCodeBlock(`
\`\`\`js
Expand All @@ -114,9 +144,18 @@ test('overrides the default title', () => {
`)}
</CodeExample>,
);
const result = renderer.getRenderOutput();

expect(result.props).toEqual({
children: [<h3>Custom title</h3>, <Source code={`Code`} language="jsextra" />],
});
const heading = getByRole('heading', { level: 3 });
expect(heading.textContent).toBe('Custom title');

// Verify Source component still receives correct code and language
expect(mockSource).toHaveBeenCalledWith(
expect.objectContaining({
code: 'Code',
language: 'jsextra',
}),
);

const sourceElement = getByTestId('source');
expect(sourceElement.getAttribute('data-language')).toBe('jsextra');
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const codeLanguages = {
js: 'JavaScript',
jsx: 'React',
};
export const CodeExample = (props: { title?: string; children: React.ReactElement }) => {
export const CodeExample = (props: { title?: string; children?: React.ReactElement<any> }) => {
const { title, children } = props;
// Access the raw values from the markdown source code block
const markdownCodeBlockValue: string | undefined = children?.props?.children?.props?.children;
Expand Down
4 changes: 2 additions & 2 deletions apps/public-docsite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"@fluentui/utilities": "*",
"@microsoft/load-themed-styles": "^1.10.26",
"office-ui-fabric-core": "^11.0.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.2.0",
"react-dom": "19.2.0",
"tslib": "^2.1.0",
"whatwg-fetch": "2.0.4"
}
Expand Down
2 changes: 1 addition & 1 deletion apps/public-docsite/src/components/IconGrid/IconGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type IIconGridProps = IFontIconGridProps | ISvgIconGridProps;

interface IFontIconDefinition {
name: string;
ref: React.RefObject<HTMLElement>;
ref: React.RefObject<HTMLElement | null>;
iconType: 'core-font' | 'react-font';
}

Expand Down
2 changes: 1 addition & 1 deletion apps/public-docsite/src/components/Nav/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class Nav extends React.Component<INavProps, INavState> {
);
}

private _renderLinkList = (pages: INavPage[], isSubMenu: boolean): React.ReactElement => {
private _renderLinkList = (pages: INavPage[], isSubMenu: boolean): React.ReactElement<any> => {
const { searchablePageTitle } = this.props;
const { sortState } = this.state;

Expand Down
3 changes: 2 additions & 1 deletion apps/public-docsite/webpack.serve.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ module.exports = [

resolve: {
alias: {
...getResolveAlias(), // react-monaco-editor dynamically loads @types/react via proprietary webpack require.ensure,
...getResolveAlias(),
// react-monaco-editor dynamically loads @types/react via proprietary webpack require.ensure,
// this doesn't work starting @types/react@17.0.48 as the types package introduced Export Maps
'@types/react/index.d.ts': path.resolve(__dirname, '../../node_modules/@types/react/index.d.ts'),
},
Expand Down
Loading