-
Notifications
You must be signed in to change notification settings - Fork 139
fix(core): stabilize flaky component tests #2666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
febf143
30f1c7c
0d1949f
604ee5f
c48da43
1af9369
bf23f72
5805c82
1de309e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Forward updated and removed ARIA attributes to each component's accessible element without leaving invalid host copies. `ix-toggle` now keeps its component managed attributes (`role`, `aria-checked`, `aria-disabled`, `aria-required`) intact while still accepting custom ARIA attributes such as `aria-label`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Fixed `ix-dropdown` trigger handling: an empty `trigger` value no longer matches | ||
| elements without an `id`, changing the trigger to an empty value now removes the | ||
| previously registered listeners, and asynchronously resolved triggers that became | ||
| stale are discarded instead of attaching orphaned listeners. | ||
|
Comment on lines
+5
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ Maintainability & Code Quality | ๐ก Minor | โก Quick win Add the required requirement reference. The PR context lists As per path instructions: โRequire GitHub issue or Jira reference (IX-) in PR description or commit message when work is tied to a tracked requirement.โ ๐งฐ Tools๐ช markdownlint-cli2 (0.23.1)[warning] 5-5: First line in a file should be a top-level heading (MD041, first-line-heading, first-line-h1) ๐ค Prompt for AI AgentsSource: Path instructions |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Keep pinned `ix-menu` components expanded when a menu item is selected. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Fix `ix-tab-set` panel activation and `ix-menu-about` tab activation when child components are still initializing. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Fix `ix-date-picker` keyboard navigation so focus consistently moves to the expected day. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@siemens/ix': patch | ||
| --- | ||
|
|
||
| Fix `ix-dropdown` trigger initialization so dropdowns open reliably immediately after rendering or when triggers are added dynamically. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -259,6 +259,7 @@ export class Dropdown | |
| private readonly dialogRef = makeRef<HTMLDialogElement>(); | ||
| private intersectObserverTrigger?: IntersectionObserver; | ||
| private triggerElement?: Element; | ||
| private triggerResolutionToken = 0; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ฉบ Stability & Availability | ๐ Major Invalidate all stale trigger resolutions.
The early return also leaves Increment the token before the falsy guard, clear Proposed token fix private async registerListener(element: ElementReference) {
+ const resolutionToken = ++this.triggerResolutionToken;
+
if (!element) {
+ this.triggerElement = undefined;
return;
}
- const resolutionToken = ++this.triggerResolutionToken;Also applies to: 523-552, 754-765 ๐ค Prompt for AI Agents |
||
| private anchorElement?: Element; | ||
| private forwardQueryElement: HTMLElement | null = null; | ||
| private dropdownElementId = `dropdown-${sequenceId++}`; | ||
|
|
@@ -316,6 +317,20 @@ export class Dropdown | |
| return this.dropdownElementId; | ||
| } | ||
|
|
||
| matchesTrigger(eventTargets: EventTarget[]) { | ||
| const trigger = | ||
| this.trigger ?? this.hostElement.getAttribute('trigger') ?? undefined; | ||
|
|
||
| return eventTargets.some( | ||
| (target) => | ||
| target === trigger || | ||
| (typeof trigger === 'string' && | ||
| trigger !== '' && | ||
| target instanceof HTMLElement && | ||
| target.id === trigger) | ||
| ); | ||
| } | ||
|
danielleroux marked this conversation as resolved.
|
||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| willDismiss() { | ||
| const { defaultPrevented } = this.showChange.emit(false); | ||
| return !defaultPrevented; | ||
|
|
@@ -505,12 +520,36 @@ export class Dropdown | |
| } | ||
|
|
||
| private async registerListener(element: ElementReference) { | ||
| this.triggerElement = await this.resolveElement(element); | ||
| if (!element) { | ||
| return; | ||
| } | ||
|
|
||
| if (!this.triggerElement) { | ||
| const resolutionToken = ++this.triggerResolutionToken; | ||
| const immediateElement = this.resolveImmediateElement(element); | ||
| const canRegisterImmediately = | ||
| immediateElement && | ||
| (!hasDropdownItemWrapperImplemented(immediateElement) || | ||
| immediateElement.tagName === 'IX-DROPDOWN-ITEM'); | ||
|
|
||
| if (canRegisterImmediately) { | ||
| this.triggerElement = immediateElement; | ||
| if (immediateElement.tagName === 'IX-DROPDOWN-ITEM') { | ||
| (immediateElement as HTMLIxDropdownItemElement).isSubMenu = true; | ||
| this.hostElement.style.zIndex = `var(--theme-z-index-dropdown)`; | ||
| } | ||
| this.addEventListenersFor(); | ||
| this.discoverSubmenu(); | ||
| return; | ||
| } | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| const resolvedElement = await this.resolveElement(element); | ||
|
|
||
| if (!resolvedElement || resolutionToken !== this.triggerResolutionToken) { | ||
| return; | ||
| } | ||
|
|
||
| this.triggerElement = resolvedElement; | ||
|
|
||
| this.addEventListenersFor(); | ||
| this.discoverSubmenu(); | ||
| } | ||
|
|
@@ -586,6 +625,32 @@ export class Dropdown | |
| return this.checkForSubmenuAnchor(el); | ||
| } | ||
|
|
||
| private resolveImmediateElement( | ||
| element: ElementReference | ||
| ): HTMLElement | undefined { | ||
| if (element instanceof Promise) { | ||
| return undefined; | ||
| } | ||
|
|
||
| if (element instanceof HTMLElement) { | ||
| return element; | ||
| } | ||
|
|
||
| const documentElement = document.getElementById(element); | ||
| if (documentElement) { | ||
| return documentElement; | ||
| } | ||
|
|
||
| const root = this.hostElement.getRootNode(); | ||
| if (root instanceof ShadowRoot) { | ||
| return ( | ||
| root.querySelector<HTMLElement>(`#${CSS.escape(element)}`) ?? undefined | ||
| ); | ||
| } | ||
|
|
||
| return undefined; | ||
| } | ||
|
|
||
| private async checkForSubmenuAnchor(element?: Element) { | ||
| if (!element) { | ||
| return undefined; | ||
|
|
@@ -686,18 +751,18 @@ export class Dropdown | |
| } | ||
|
|
||
| @Watch('trigger') | ||
| changedTrigger( | ||
| async changedTrigger( | ||
| newTriggerValue: ElementReference, | ||
| oldTriggerValue: ElementReference | undefined | ||
| ) { | ||
| if (newTriggerValue && newTriggerValue !== oldTriggerValue) { | ||
| if (newTriggerValue !== oldTriggerValue) { | ||
| this.disposeClickListener?.(); | ||
| this.disposeClickListener = undefined; | ||
| this.disposeKeyListener?.(); | ||
| this.disposeKeyListener = undefined; | ||
| } | ||
|
|
||
| this.registerListener(newTriggerValue); | ||
| await this.registerListener(newTriggerValue); | ||
| } | ||
|
|
||
| private applyFallbackPosition(element: HTMLElement) { | ||
|
|
@@ -706,9 +771,9 @@ export class Dropdown | |
| this.hostElement.parentElement || this.hostElement; | ||
| const refRect = referenceElement.getBoundingClientRect(); | ||
|
|
||
| const transform = `translate(${Math.round( | ||
| refRect.left | ||
| )}px, ${Math.round(refRect.top)}px)`; | ||
| const transform = `translate(${Math.round(refRect.left)}px, ${Math.round( | ||
| refRect.top | ||
| )}px)`; | ||
|
|
||
| Object.assign(element.style, { | ||
| top: '0', | ||
|
|
@@ -864,7 +929,7 @@ export class Dropdown | |
| return; | ||
| } | ||
|
|
||
| this.changedTrigger(this.trigger, undefined); | ||
| await this.changedTrigger(this.trigger, undefined); | ||
| } | ||
|
|
||
| override async componentDidRender() { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.