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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
react: [17, 18]
react: [17, 18, 19]
fail-fast: false
permissions:
contents: 'read'
Expand Down
3 changes: 2 additions & 1 deletion .syncpackrc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
{
"packages": [
"react-17-tests",
"react-18-tests"
"react-18-tests",
"react-19-tests"
],
"dependencies": [
"**"
Expand Down
18 changes: 18 additions & 0 deletions apps/react-19-tests/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
30 changes: 30 additions & 0 deletions apps/react-19-tests/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"exclude": [
"/testing",
"/**/*.cy.ts",
"/**/*.cy.tsx",
"/**/*.spec.ts",
"/**/*.spec.tsx",
"/**/*.test.ts",
"/**/*.test.tsx"
],
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"externalHelpers": true,
"transform": {
"react": {
"runtime": "classic",
"useSpread": true
}
},
"target": "es2019"
},
"minify": false,
"sourceMaps": true
}
3 changes: 3 additions & 0 deletions apps/react-19-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# react-17-tests

This app was generated with [Nx](https://nx.dev).
27 changes: 27 additions & 0 deletions apps/react-19-tests/jest-custom-transformer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @ts-check
const { createTransformer: swcCreateTransformer } = require('@swc/jest');

/**
* @param {Parameters<typeof swcCreateTransformer>[number]} swcTransformOpts
* @returns {import('@jest/transform').Transformer}
*/
function createTransformer(swcTransformOpts) {
const swcTransformer = swcCreateTransformer(swcTransformOpts);

return {
process(src, filename, options) {
const transformedCode = swcTransformer.process?.(src, filename, options);
const code = transformedCode?.code || '';

return {
...transformedCode,
code,
};
},
};
}

// Custom transformer to replace @testing-library/react renderHook imports with @testing-library/react-hooks
module.exports = {
createTransformer,
};
109 changes: 109 additions & 0 deletions apps/react-19-tests/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// @ts-check
/* eslint-disable */

const { readFileSync } = require('node:fs');
const { join } = require('node:path');
import { existsSync, readdirSync } from 'node:fs';
import { resolve } from 'node:path';

// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(join(__dirname, '.swcrc'), 'utf-8')
);

// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}

// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;

const rootNodeModulesPath = join(__dirname, '../..', 'node_modules');
const nohoistNodeModulesPath = join(__dirname, 'node_modules');
const usedNodeModulesPath = existsSync(join(nohoistNodeModulesPath, 'react'))
? nohoistNodeModulesPath
: rootNodeModulesPath;

export default {
displayName: 'react-19-tests',
preset: '../../jest.preset.js',
roots: createRoots(),
transform: {
'^.+\\.tsx?$': ['<rootDir>/jest-custom-transformer.js', swcJestConfig],
},
coverageDirectory: '../../coverage/apps/react-19-tests',
moduleNameMapper: {
'^react$': join(usedNodeModulesPath, 'react'),
'^react/jsx-runtime$': join(usedNodeModulesPath, 'react/jsx-runtime'),
'^react-dom$': join(usedNodeModulesPath, 'react-dom'),
'^react-dom/(.+)$': join(usedNodeModulesPath, 'react-dom/$1'),
'^react-test-renderer$': join(usedNodeModulesPath, 'react-test-renderer'),
'^@testing-library/(react|dom)$': join(
rootNodeModulesPath,
'@testing-library/$1'
),
},
};

/**
* Creates an array of paths to packages that don't have specific tags
* @returns {string[]} An array of paths to test
*/
function createRoots() {
const rootDir = resolve(__dirname, '../../packages/');
return findValidPackagePaths(rootDir);

/**
* Recursively finds valid package paths that don't have excluded tags
* @param {string} dirPath - Directory to scan
* @returns {string[]} Array of valid package paths
*/
function findValidPackagePaths(dirPath: string) {
const entries = readdirSync(dirPath, { withFileTypes: true });
let validPaths = [] as string[];

// Check if current directory is a valid package
if (isValidPackage(dirPath)) {
validPaths.push(dirPath);
}

// Recursively check subdirectories
for (const entry of entries) {
if (entry.isDirectory()) {
const fullPath = join(dirPath, entry.name);
validPaths = validPaths.concat(findValidPackagePaths(fullPath));
}
}

return validPaths;
}

/**
* Checks if a directory is a valid package based on its project.json
* @param {string} packagePath - Path to potential package
* @returns {boolean} Whether the package is valid
*/
function isValidPackage(packagePath: string) {
try {
const projectJsonPath = join(packagePath, 'project.json');

if (existsSync(projectJsonPath)) {
const projectJson = JSON.parse(readFileSync(projectJsonPath, 'utf8'));

return !['nx-plugin', 'houdini-utils', 'stylelint-plugin'].some(
(projectName) => projectName === projectJson.name
);
}

return false; // Only include directories with project.json
} catch (error) {
console.warn(`Error reading project.json for ${packagePath}:`, error);
return false; // Skip directories with invalid project.json
}
}
}
17 changes: 17 additions & 0 deletions apps/react-19-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "react-19-tests",
"version": "0.0.1",
"private": true,
"dependencies": {
"@fluentui/react-components": "^9.54.13",
"@fluentui/react-icons": "^2.0.249",
"@testing-library/dom": "10.4.0",
"@testing-library/react": "16.3.0",
"@types/react": "19.1.10",
"@types/react-dom": "19.1.7",
"react": "19.1.1",
"react-dom": "19.1.1",
"react-test-renderer": "19.1.1",
"@playwright/experimental-ct-react": "1.49.1"
}
}
43 changes: 43 additions & 0 deletions apps/react-19-tests/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "react-19-tests",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/react-19-tests/src",
"projectType": "application",
"tags": ["react-19"],
"targets": {
"type-check:integration": {
"dependsOn": ["build:integration"],
"command": "tsc -p tsconfig.react-19.json",
"options": {
"cwd": "{projectRoot}"
},
"inputs": [
"{projectRoot}/tsconfig.react-19.json",
"{workspaceRoot}/packages/**/stories/**/*.stories.tsx?",
"!{workspaceRoot}/packages/**/stories/**/index.stories.tsx?"
]
},
"build:integration": {
"command": "nx run-many -t build,type-check"
},
"e2e:integration": {
"command": "nx run-many -t component-test --reactVersion 18 --skipInstall",
"options": {
"cwd": "{workspaceRoot}"
},
"inputs": [
"{workspaceRoot}/packages/**/stories/**/*.stories.tsx?",
"!{workspaceRoot}/packages/**/stories/**/index.stories.tsx?",
"{workspaceRoot}/packages/**/*.component-browser-spec.tsx",
"{projectRoot}/.storybook/**"
],
"dependsOn": []
},
"test:integration": {
"command": "jest --passWithNoTests",
"options": {
"cwd": "{projectRoot}"
}
}
}
}
Empty file.
27 changes: 27 additions & 0 deletions apps/react-19-tests/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx",
"**/*.stories.ts",
"**/*.stories.js",
"**/*.stories.jsx",
"**/*.stories.tsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}
23 changes: 23 additions & 0 deletions apps/react-19-tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"strict": true,
"noEmit": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"extends": "../../tsconfig.base.json"
}
35 changes: 35 additions & 0 deletions apps/react-19-tests/tsconfig.react-19.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "ES2019",
"module": "esnext",
"moduleResolution": "node",
"lib": ["ES2019", "dom"],
"sourceMap": true,
"strict": true,
"pretty": true,
"noEmit": true,
"isolatedModules": true,
"importHelpers": true,
"jsx": "react",
"preserveConstEnums": true,
"skipLibCheck": true,
"typeRoots": ["./node_modules/@types"],
"types": [],
"baseUrl": ".",
"paths": {
"react/jsx-runtime": ["./node_modules/@types/react/jsx-runtime.d.ts"],
"react": ["./node_modules/@types/react/index.d.ts"],
"react-dom": ["./node_modules/@types/react-dom/index.d.ts"],
"@fluentui-contrib/*": ["../../dist/packages/*/src/index.d.ts"]
}
},
"exclude": [
"../../packages/**/index.stories.tsx",
"../../packages/**/index.stories.ts"
],
"include": [
"../../packages/**/stories/**/*.stories.tsx",
"../../packages/**/stories/**/*.stories.ts"
],
"files": ["../../node_modules/@types/mdx/index.d.ts"]
}
17 changes: 17 additions & 0 deletions apps/react-19-tests/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.test.ts",
"**/*.test.tsx",
"**/*.d.ts",
"./src/testing/**/*.ts",
"./src/testing/**/*.tsx"
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"type-check": "nx affected --target=type-check",
"preinstall": "node ./tools/scripts/preinstall.mjs",
"postinstall": "patch-package",
"dedupe": "npx yarn-deduplicate --strategy highest"
"dedupe": "npx yarn-deduplicate --strategy highest --exclude @types/react-dom @types/react"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Running npx yarn-deduplicate --strategy highest leads to this: https://github.com/microsoft/fluentui-contrib/pull/468/files#diff-51e4f558fae534656963876761c95b83b6ef5da5103c4adef6768219ed76c2deR6127-R6130.

This forces @types/[email protected] everywhere, causing pipeline failures. So far, adding excludes is the only workaround I've found. Open to better ideas.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, either detective work and trying resolutions on sub paths ( which might not work with current yarn ) or this. it's ok for now / once react integration tester CLI will land we will replace current approach which will also not cause this kind of issues

Copy link
Contributor

@Hotell Hotell Aug 18, 2025

Choose a reason for hiding this comment

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

note that excluding @types/react should be enough

image

Copy link
Contributor Author

@dmytrokirpa dmytrokirpa Aug 18, 2025

Choose a reason for hiding this comment

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

Unfortunately that doesn't work, removing @types/react-dom leads to:

Screenshot 2025-08-18 at 15 05 58

},
"repository": {
"url": "https://github.com/microsoft/fluentui-contrib",
Expand Down
Loading
Loading