Skip to content

test: fix invalid directionality providers #31110

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

Merged
merged 1 commit into from
May 14, 2025
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
59 changes: 19 additions & 40 deletions src/cdk/drag-drop/directives/drop-list-shared.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
import {Directionality} from '../../bidi';
import {Platform, _supportsShadowDom} from '../../platform';
import {CdkScrollable, ViewportRuler} from '../../scrolling';
import {
createMouseEvent,
createTouchEvent,
dispatchEvent,
dispatchFakeEvent,
dispatchMouseEvent,
dispatchTouchEvent,
} from '../../testing/private';
import {
AfterViewInit,
ChangeDetectionStrategy,
Expand All @@ -25,20 +14,33 @@ import {
signal,
} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing';
import {of as observableOf} from 'rxjs';
import {Platform, _supportsShadowDom} from '../../platform';
import {CdkScrollable, ViewportRuler} from '../../scrolling';
import {
createMouseEvent,
createTouchEvent,
dispatchEvent,
dispatchFakeEvent,
dispatchMouseEvent,
dispatchTouchEvent,
} from '../../testing/private';

import {extendStyles} from '../dom/styling';
import {CdkDragDrop, CdkDragEnter, CdkDragStart} from '../drag-events';
import {DragRef, Point, PreviewContainer} from '../drag-ref';
import {moveItemInArray} from '../drag-utils';

import {provideFakeDirectionality} from '@angular/cdk/testing/private/fake-directionality';
import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common';
import {CDK_DRAG_CONFIG, DragAxis, DragDropConfig, DropListOrientation} from './config';
import {CdkDrag} from './drag';
import {CdkDragPlaceholder} from './drag-placeholder';
import {CdkDragPreview} from './drag-preview';
import {CdkDropList} from './drop-list';
import {CdkDropListGroup} from './drop-list-group';
import {
createComponent as _createComponent,
DragDropTestConfig,
createComponent as _createComponent,
continueDraggingViaTouch,
dragElementViaMouse,
makeScrollable,
Expand All @@ -47,9 +49,6 @@ import {
stopDraggingViaTouch,
tickAnimationFrames,
} from './test-utils.spec';
import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common';
import {CdkDragPreview} from './drag-preview';
import {CdkDragPlaceholder} from './drag-placeholder';

export const ITEM_HEIGHT = 25;
export const ITEM_WIDTH = 75;
Expand Down Expand Up @@ -551,12 +550,7 @@ export function defineCommonDropListTests(config: {

it('should dispatch the correct `dropped` event in RTL horizontal drop zone', fakeAsync(() => {
const fixture = createComponent(DraggableInHorizontalDropZone, {
providers: [
{
provide: Directionality,
useValue: {value: 'rtl', change: observableOf()},
},
],
providers: [provideFakeDirectionality('rtl')],
});

fixture.nativeElement.setAttribute('dir', 'rtl');
Expand Down Expand Up @@ -1200,12 +1194,7 @@ export function defineCommonDropListTests(config: {

it('should pass the proper direction to the preview in rtl', fakeAsync(() => {
const fixture = createComponent(DraggableInDropZone, {
providers: [
{
provide: Directionality,
useValue: {value: 'rtl', change: observableOf()},
},
],
providers: [provideFakeDirectionality('rtl')],
});

fixture.detectChanges();
Expand Down Expand Up @@ -2500,12 +2489,7 @@ export function defineCommonDropListTests(config: {

it('should auto-scroll right if the user holds their pointer at right edge in rtl', fakeAsync(() => {
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, {
providers: [
{
provide: Directionality,
useValue: {value: 'rtl', change: observableOf()},
},
],
providers: [provideFakeDirectionality('rtl')],
});
fixture.nativeElement.setAttribute('dir', 'rtl');
fixture.detectChanges();
Expand All @@ -2529,12 +2513,7 @@ export function defineCommonDropListTests(config: {

it('should auto-scroll left if the user holds their pointer at left edge in rtl', fakeAsync(() => {
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, {
providers: [
{
provide: Directionality,
useValue: {value: 'rtl', change: observableOf()},
},
],
providers: [provideFakeDirectionality('rtl')],
});
fixture.nativeElement.setAttribute('dir', 'rtl');
fixture.detectChanges();
Expand Down
19 changes: 11 additions & 8 deletions src/cdk/overlay/overlay-directives.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Directionality} from '../bidi';
import {A, ESCAPE} from '../keycodes';
import {Component, ElementRef, Injector, ViewChild} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing';
import {Component, ElementRef, Injector, signal, ViewChild, WritableSignal} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {Subject} from 'rxjs';
import {Direction} from '../bidi';
import {A, ESCAPE} from '../keycodes';
import {createKeyboardEvent, dispatchEvent, dispatchKeyboardEvent} from '../testing/private';
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
import {
CdkConnectedOverlay,
CdkOverlayOrigin,
Expand All @@ -27,14 +28,16 @@ import {
describe('Overlay directives', () => {
let overlayContainerElement: HTMLElement;
let fixture: ComponentFixture<ConnectedOverlayDirectiveTest>;
let dir: {value: string};
let dir: WritableSignal<Direction>;
let scrolledSubject = new Subject();

beforeEach(() => {
dir = signal<Direction>('ltr');

TestBed.configureTestingModule({
imports: [OverlayModule, ConnectedOverlayDirectiveTest, ConnectedOverlayPropertyInitOrder],
providers: [
{provide: Directionality, useFactory: () => (dir = {value: 'ltr'})},
provideFakeDirectionality(dir),
{
provide: ScrollDispatcher,
useFactory: () => ({
Expand Down Expand Up @@ -115,7 +118,7 @@ describe('Overlay directives', () => {
});

it('should set and update the `dir` attribute', () => {
dir.value = 'rtl';
dir.set('rtl');
fixture.componentInstance.isOpen = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
Expand All @@ -130,7 +133,7 @@ describe('Overlay directives', () => {
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();

dir.value = 'ltr';
dir.set('ltr');
fixture.componentInstance.isOpen = true;
fixture.changeDetectorRef.markForCheck();
fixture.detectChanges();
Expand Down
20 changes: 8 additions & 12 deletions src/cdk/overlay/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
Type,
ViewChild,
ViewContainerRef,
WritableSignal,
inject,
signal,
} from '@angular/core';
import {
ComponentFixture,
Expand All @@ -23,15 +25,16 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {Direction, Directionality} from '../bidi';
import {CdkPortal, ComponentPortal, TemplatePortal} from '../portal';
import {dispatchFakeEvent} from '../testing/private';
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
import {
createOverlayRef,
Overlay,
OverlayConfig,
OverlayContainer,
OverlayModule,
OverlayRef,
PositionStrategy,
ScrollStrategy,
createOverlayRef,
} from './index';

describe('Overlay', () => {
Expand All @@ -41,22 +44,15 @@ describe('Overlay', () => {
let overlayContainerElement: HTMLElement;
let overlayContainer: OverlayContainer;
let viewContainerFixture: ComponentFixture<TestComponentWithTemplatePortals>;
let dir: Direction;
let dir: WritableSignal<Direction>;
let mockLocation: SpyLocation;

function setup(imports: Type<unknown>[] = []) {
dir = 'ltr';
dir = signal<Direction>('ltr');
TestBed.configureTestingModule({
imports: [OverlayModule, ...imports],
providers: [
{
provide: Directionality,
useFactory: () => {
const fakeDirectionality = {};
Object.defineProperty(fakeDirectionality, 'value', {get: () => dir});
return fakeDirectionality;
},
},
provideFakeDirectionality(dir),
{
provide: Location,
useClass: SpyLocation,
Expand Down Expand Up @@ -175,7 +171,7 @@ describe('Overlay', () => {
});

it('should take the default direction from the global Directionality', () => {
dir = 'rtl';
dir.set('rtl');
const overlayRef = createOverlayRef(injector);

overlayRef.attach(componentPortal);
Expand Down
1 change: 1 addition & 0 deletions src/cdk/testing/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ts_project(
deps = [
"//:node_modules/@angular/core",
"//:node_modules/@types/jasmine",
"//src/cdk/bidi",
"//src/cdk/testing/testbed",
],
)
38 changes: 38 additions & 0 deletions src/cdk/testing/private/fake-directionality.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import {Direction, Directionality} from '@angular/cdk/bidi';
import {EventEmitter, signal, WritableSignal} from '@angular/core';
import {toObservable} from '@angular/core/rxjs-interop';
import {skip} from 'rxjs/operators';

// Note: ngOnDestroy not needed, but must include it to match the Directionality interface.
// Implementing the interface ensures the fake stays in sync with the real API.
// tslint:disable-next-line:no-undecorated-class-with-angular-features lifecycle-hook-interface
class FakeDirectionality implements Directionality {
readonly change: EventEmitter<Direction>;

get value(): Direction {
return this.valueSignal();
}

constructor(readonly valueSignal: WritableSignal<Direction>) {
this.change = toObservable(valueSignal).pipe(skip(1)) as EventEmitter<Direction>;
}

ngOnDestroy() {}
}

export function provideFakeDirectionality(direction: Direction | WritableSignal<Direction>) {
return {
provide: Directionality,
useFactory: () =>
new FakeDirectionality(typeof direction === 'string' ? signal(direction) : direction),
deps: [],
};
}
1 change: 1 addition & 0 deletions src/cdk/testing/private/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

export * from './fake-directionality';
export * from './text-dedent';
export * from './wrapped-error-message';

Expand Down
1 change: 1 addition & 0 deletions src/cdk/tree/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ ts_project(
"//src/cdk/bidi",
"//src/cdk/collections",
"//src/cdk/keycodes",
"//src/cdk/testing/private",
"//src/cdk/testing/testbed",
],
)
Expand Down
29 changes: 14 additions & 15 deletions src/cdk/tree/tree-with-tree-control.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,29 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {
Component,
ErrorHandler,
ViewChild,
QueryList,
signal,
TrackByFunction,
Type,
EventEmitter,
ViewChild,
ViewChildren,
QueryList,
WritableSignal,
} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';

import {BehaviorSubject, combineLatest, Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {Direction} from '../bidi';
import {CollectionViewer, DataSource} from '../collections';
import {Directionality, Direction} from '../bidi';
import {createKeyboardEvent} from '../testing/testbed/fake-events';
import {combineLatest, BehaviorSubject, Observable} from 'rxjs';
import {map} from 'rxjs/operators';

import {TreeControl} from './control/tree-control';
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
import {FlatTreeControl} from './control/flat-tree-control';
import {NestedTreeControl} from './control/nested-tree-control';
import {TreeControl} from './control/tree-control';
import {CdkTreeModule, CdkTreeNodePadding} from './index';
import {CdkTree, CdkTreeNode} from './tree';

Expand All @@ -35,16 +37,14 @@ describe('CdkTree with TreeControl', () => {
let dataSource: FakeDataSource;
let treeElement: HTMLElement;
let tree: CdkTree<TestData>;
let dir: {value: Direction; readonly change: EventEmitter<Direction>};
let dir: WritableSignal<Direction>;

function configureCdkTreeTestingModule(declarations: Type<any>[]) {
dir = signal('ltr');
TestBed.configureTestingModule({
imports: [CdkTreeModule],
providers: [
{
provide: Directionality,
useFactory: () => (dir = {value: 'ltr', change: new EventEmitter<Direction>()}),
},
provideFakeDirectionality(dir),
// Custom error handler that re-throws the error. Errors happening within
// change detection phase will be reported through the handler and thrown
// in Ivy. Since we do not want to pollute the "console.error", but rather
Expand Down Expand Up @@ -242,8 +242,7 @@ describe('CdkTree with TreeControl', () => {
expect(node.style.paddingLeft).toBe('10px');
expect(node.style.paddingRight).toBeFalsy();

dir.value = 'rtl';
dir.change.emit('rtl');
dir.set('rtl');
fixture.detectChanges();

expect(node.style.paddingRight).toBe('10px');
Expand Down
Loading
Loading