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
28 changes: 7 additions & 21 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,31 @@ updates:
- 'minor'
- 'patch'

# npm dependencies - weekly updates for devDependencies
# npm dependencies - weekly minor and patch updates grouped by dependency type
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
allow:
- dependency-type: 'development'
open-pull-requests-limit: 6
versioning-strategy: increase
ignore:
# Ignore major version bumps for all npm dependencies in weekly updates
- dependency-name: '*'
update-types: ['version-update:semver-major']
groups:
npm-security-updates:
applies-to: security-updates
patterns:
- '*'
npm-dev-minor-patch:
dependency-type: 'development'
patterns:
- '*'
update-types:
- 'minor'
- 'patch'
# Note: Security updates for known vulnerabilities are handled automatically by GitHub
# and will create PRs regardless of the ignore rules above

# Additional configuration for production dependencies security updates
# This ensures production dependencies get security updates more frequently
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'daily'
allow:
- dependency-type: 'production'
open-pull-requests-limit: 3
versioning-strategy: increase
# Only create PRs for security updates and minor/patch versions
ignore:
- dependency-name: '*'
update-types: ['version-update:semver-major']
groups:
npm-prod-minor-patch:
dependency-type: 'production'
patterns:
- '*'
update-types:
Expand Down
11 changes: 6 additions & 5 deletions .github/instructions/dependabot-security-fixes.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,24 @@ This instruction guide explains how Dependabot automation works for security fix

Dependabot is configured to automatically create pull requests for:

1. **Security updates** - Daily scanning for vulnerable production dependencies
2. **Development dependencies** - Weekly updates for devDependencies
1. **Security updates** - Advisory-driven updates grouped into consolidated npm pull requests
2. **npm dependencies** - Weekly minor and patch updates grouped by dependency type
3. **GitHub Actions** - Weekly updates for workflow dependencies

## Configuration

The Dependabot configuration is defined in `.github/dependabot.yml`:

- **Production dependencies**: Daily security updates with higher priority
- **Development dependencies**: Weekly updates, excluding major version bumps
- **Production dependencies**: Weekly minor and patch version updates
- **Development dependencies**: Weekly minor and patch version updates
- **GitHub Actions**: Weekly updates
- **Security updates**: Grouped separately and not limited by the version update schedule

## Security Vulnerability Resolution

### Automatic Security Updates

GitHub's automatic security updates work independently of the Dependabot configuration and will create PRs for known vulnerabilities even if they require major version bumps.
GitHub triggers automatic security updates independently of the configured version update schedule. The Dependabot configuration groups eligible npm security updates into consolidated pull requests, including fixes that require major version bumps.

### Manual Resolution via Yarn Resolutions

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "test: add regression tests for split-group submenu trigger alignment icons",
"packageName": "@fluentui/react-menu",
"email": "paulmardling@microsoft.com",
"dependentChangeType": "none"
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useMenuItem_unstable } from './useMenuItem';
import { MenuListProvider } from '../../contexts/menuListContext';
import { MenuProvider } from '../../contexts/menuContext';
import { MenuTriggerContextProvider } from '../../contexts/menuTriggerContext';
import { MenuSplitGroupContextProvider } from '../../contexts/menuSplitGroupContext';
import type { MenuListContextValue } from '../../contexts/menuListContext';
import type { MenuContextValue } from '../../contexts/menuContext';
import type { ARIAButtonElement } from '@fluentui/react-aria';
Expand Down Expand Up @@ -51,15 +52,28 @@ function makeWrapper(
menuList?: Partial<MenuListContextValue>;
menu?: Partial<MenuContextValue>;
isSubmenuTrigger?: boolean;
inMenuSplitGroup?: boolean;
} = {},
) {
const menuListValue: MenuListContextValue = { ...defaultMenuListContextValue, ...options.menuList };
const menuValue: MenuContextValue = { ...defaultMenuContextValue, ...options.menu };

const splitGroupContextValue = {
setMultiline: () => null,
};

return ({ children }: { children: React.ReactNode }) => (
<MenuProvider value={menuValue}>
<MenuListProvider value={menuListValue}>
<MenuTriggerContextProvider value={options.isSubmenuTrigger ?? false}>{children}</MenuTriggerContextProvider>
{options.inMenuSplitGroup ? (
<MenuSplitGroupContextProvider value={splitGroupContextValue}>
<MenuTriggerContextProvider value={options.isSubmenuTrigger ?? false}>
{children}
</MenuTriggerContextProvider>
</MenuSplitGroupContextProvider>
) : (
<MenuTriggerContextProvider value={options.isSubmenuTrigger ?? false}>{children}</MenuTriggerContextProvider>
)}
</MenuListProvider>
</MenuProvider>
);
Expand Down Expand Up @@ -254,6 +268,17 @@ describe('useMenuItem_unstable', () => {
expect(result.current.icon).toBeDefined();
});

it('icon is undefined for a split-group submenu trigger even when hasIcons=true', () => {
const ref = React.createRef<ARIAButtonElement<'div'>>();

const { result } = renderHook(() => useMenuItem_unstable({}, ref), {
wrapper: makeWrapper({ menuList: { hasIcons: true }, isSubmenuTrigger: true, inMenuSplitGroup: true }),
});

expect(result.current.hasSubmenu).toBe(true);
expect(result.current.icon).toBeUndefined();
});

it('checkmark is undefined when hasCheckmarks=false and no checkmark prop', () => {
const ref = React.createRef<ARIAButtonElement<'div'>>();

Expand All @@ -273,5 +298,16 @@ describe('useMenuItem_unstable', () => {

expect(result.current.checkmark).toBeDefined();
});

it('checkmark is undefined for a split-group submenu trigger even when hasCheckmarks=true', () => {
const ref = React.createRef<ARIAButtonElement<'div'>>();

const { result } = renderHook(() => useMenuItem_unstable({}, ref), {
wrapper: makeWrapper({ menuList: { hasCheckmarks: true }, isSubmenuTrigger: true, inMenuSplitGroup: true }),
});

expect(result.current.hasSubmenu).toBe(true);
expect(result.current.checkmark).toBeUndefined();
});
});
});
2 changes: 2 additions & 0 deletions tools/react-integration-tester/src/__tests__/setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ describe('setup()', () => {
join(fs.tempDir, 'tsconfig.lib.json'),
JSON.stringify({ include: ['src/index.ts'], compilerOptions: { target: 'ES2020', lib: ['ES2020', 'DOM'] } }),
);
writeFileSync(join(fs.tempDir, 'tsconfig.base.json'), JSON.stringify({ compilerOptions: { paths: {} } }));
writeFileSync(join(fs.tempDir, 'jest.config.js'), 'module.exports = {};');
writeFileSync(join(fs.tempDir, 'cypress.config.ts'), 'export default {};');

Expand Down Expand Up @@ -191,6 +192,7 @@ describe('setup()', () => {
'.swcrc',
'cypress.config.ts',
'tsconfig.cy.json',
'tsconfig.base.json',
'package.json',
];
for (const f of expectedFiles) {
Expand Down
8 changes: 8 additions & 0 deletions tools/react-integration-tester/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,14 @@ export async function setup(
metadata.tmpl,
join(projectPath, 'tsconfig.cy.json'),
);

const workspaceTsConfigBasePath = join(workspaceRoot, 'tsconfig.base.json');
if (existsSync(workspaceTsConfigBasePath)) {
// Provide a local tsconfig.base.json so relative TsconfigPathsPlugin lookups keep working in RIT context.
writeJsonFile(join(projectPath, 'tsconfig.base.json'), {
extends: relative(projectPath, workspaceTsConfigBasePath).replace(/\\/g, '/'),
});
}
}

// 4) Create package.json for test project including npm scripts
Expand Down
Loading