Skip to content

Commit 6f73c21

Browse files
authored
test: fix invalid directionality providers (#31110)
1 parent 4bea9b7 commit 6f73c21

33 files changed

+305
-368
lines changed

src/cdk/drag-drop/directives/drop-list-shared.spec.ts

+19-40
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
import {Directionality} from '../../bidi';
2-
import {Platform, _supportsShadowDom} from '../../platform';
3-
import {CdkScrollable, ViewportRuler} from '../../scrolling';
4-
import {
5-
createMouseEvent,
6-
createTouchEvent,
7-
dispatchEvent,
8-
dispatchFakeEvent,
9-
dispatchMouseEvent,
10-
dispatchTouchEvent,
11-
} from '../../testing/private';
121
import {
132
AfterViewInit,
143
ChangeDetectionStrategy,
@@ -25,20 +14,33 @@ import {
2514
signal,
2615
} from '@angular/core';
2716
import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing';
28-
import {of as observableOf} from 'rxjs';
17+
import {Platform, _supportsShadowDom} from '../../platform';
18+
import {CdkScrollable, ViewportRuler} from '../../scrolling';
19+
import {
20+
createMouseEvent,
21+
createTouchEvent,
22+
dispatchEvent,
23+
dispatchFakeEvent,
24+
dispatchMouseEvent,
25+
dispatchTouchEvent,
26+
} from '../../testing/private';
2927

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

33+
import {provideFakeDirectionality} from '@angular/cdk/testing/private/fake-directionality';
34+
import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common';
3535
import {CDK_DRAG_CONFIG, DragAxis, DragDropConfig, DropListOrientation} from './config';
3636
import {CdkDrag} from './drag';
37+
import {CdkDragPlaceholder} from './drag-placeholder';
38+
import {CdkDragPreview} from './drag-preview';
3739
import {CdkDropList} from './drop-list';
3840
import {CdkDropListGroup} from './drop-list-group';
3941
import {
40-
createComponent as _createComponent,
4142
DragDropTestConfig,
43+
createComponent as _createComponent,
4244
continueDraggingViaTouch,
4345
dragElementViaMouse,
4446
makeScrollable,
@@ -47,9 +49,6 @@ import {
4749
stopDraggingViaTouch,
4850
tickAnimationFrames,
4951
} from './test-utils.spec';
50-
import {NgClass, NgFor, NgIf, NgTemplateOutlet} from '@angular/common';
51-
import {CdkDragPreview} from './drag-preview';
52-
import {CdkDragPlaceholder} from './drag-placeholder';
5352

5453
export const ITEM_HEIGHT = 25;
5554
export const ITEM_WIDTH = 75;
@@ -551,12 +550,7 @@ export function defineCommonDropListTests(config: {
551550

552551
it('should dispatch the correct `dropped` event in RTL horizontal drop zone', fakeAsync(() => {
553552
const fixture = createComponent(DraggableInHorizontalDropZone, {
554-
providers: [
555-
{
556-
provide: Directionality,
557-
useValue: {value: 'rtl', change: observableOf()},
558-
},
559-
],
553+
providers: [provideFakeDirectionality('rtl')],
560554
});
561555

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

12011195
it('should pass the proper direction to the preview in rtl', fakeAsync(() => {
12021196
const fixture = createComponent(DraggableInDropZone, {
1203-
providers: [
1204-
{
1205-
provide: Directionality,
1206-
useValue: {value: 'rtl', change: observableOf()},
1207-
},
1208-
],
1197+
providers: [provideFakeDirectionality('rtl')],
12091198
});
12101199

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

25012490
it('should auto-scroll right if the user holds their pointer at right edge in rtl', fakeAsync(() => {
25022491
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, {
2503-
providers: [
2504-
{
2505-
provide: Directionality,
2506-
useValue: {value: 'rtl', change: observableOf()},
2507-
},
2508-
],
2492+
providers: [provideFakeDirectionality('rtl')],
25092493
});
25102494
fixture.nativeElement.setAttribute('dir', 'rtl');
25112495
fixture.detectChanges();
@@ -2529,12 +2513,7 @@ export function defineCommonDropListTests(config: {
25292513

25302514
it('should auto-scroll left if the user holds their pointer at left edge in rtl', fakeAsync(() => {
25312515
const fixture = createComponent(DraggableInScrollableHorizontalDropZone, {
2532-
providers: [
2533-
{
2534-
provide: Directionality,
2535-
useValue: {value: 'rtl', change: observableOf()},
2536-
},
2537-
],
2516+
providers: [provideFakeDirectionality('rtl')],
25382517
});
25392518
fixture.nativeElement.setAttribute('dir', 'rtl');
25402519
fixture.detectChanges();

src/cdk/overlay/overlay-directives.spec.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import {Directionality} from '../bidi';
2-
import {A, ESCAPE} from '../keycodes';
3-
import {Component, ElementRef, Injector, ViewChild} from '@angular/core';
4-
import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing';
1+
import {Component, ElementRef, Injector, signal, ViewChild, WritableSignal} from '@angular/core';
2+
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
53
import {By} from '@angular/platform-browser';
64
import {Subject} from 'rxjs';
5+
import {Direction} from '../bidi';
6+
import {A, ESCAPE} from '../keycodes';
77
import {createKeyboardEvent, dispatchEvent, dispatchKeyboardEvent} from '../testing/private';
8+
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
89
import {
910
CdkConnectedOverlay,
1011
CdkOverlayOrigin,
@@ -27,14 +28,16 @@ import {
2728
describe('Overlay directives', () => {
2829
let overlayContainerElement: HTMLElement;
2930
let fixture: ComponentFixture<ConnectedOverlayDirectiveTest>;
30-
let dir: {value: string};
31+
let dir: WritableSignal<Direction>;
3132
let scrolledSubject = new Subject();
3233

3334
beforeEach(() => {
35+
dir = signal<Direction>('ltr');
36+
3437
TestBed.configureTestingModule({
3538
imports: [OverlayModule, ConnectedOverlayDirectiveTest, ConnectedOverlayPropertyInitOrder],
3639
providers: [
37-
{provide: Directionality, useFactory: () => (dir = {value: 'ltr'})},
40+
provideFakeDirectionality(dir),
3841
{
3942
provide: ScrollDispatcher,
4043
useFactory: () => ({
@@ -115,7 +118,7 @@ describe('Overlay directives', () => {
115118
});
116119

117120
it('should set and update the `dir` attribute', () => {
118-
dir.value = 'rtl';
121+
dir.set('rtl');
119122
fixture.componentInstance.isOpen = true;
120123
fixture.changeDetectorRef.markForCheck();
121124
fixture.detectChanges();
@@ -130,7 +133,7 @@ describe('Overlay directives', () => {
130133
fixture.changeDetectorRef.markForCheck();
131134
fixture.detectChanges();
132135

133-
dir.value = 'ltr';
136+
dir.set('ltr');
134137
fixture.componentInstance.isOpen = true;
135138
fixture.changeDetectorRef.markForCheck();
136139
fixture.detectChanges();

src/cdk/overlay/overlay.spec.ts

+8-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import {
99
Type,
1010
ViewChild,
1111
ViewContainerRef,
12+
WritableSignal,
1213
inject,
14+
signal,
1315
} from '@angular/core';
1416
import {
1517
ComponentFixture,
@@ -23,15 +25,16 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
2325
import {Direction, Directionality} from '../bidi';
2426
import {CdkPortal, ComponentPortal, TemplatePortal} from '../portal';
2527
import {dispatchFakeEvent} from '../testing/private';
28+
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
2629
import {
27-
createOverlayRef,
2830
Overlay,
2931
OverlayConfig,
3032
OverlayContainer,
3133
OverlayModule,
3234
OverlayRef,
3335
PositionStrategy,
3436
ScrollStrategy,
37+
createOverlayRef,
3538
} from './index';
3639

3740
describe('Overlay', () => {
@@ -41,22 +44,15 @@ describe('Overlay', () => {
4144
let overlayContainerElement: HTMLElement;
4245
let overlayContainer: OverlayContainer;
4346
let viewContainerFixture: ComponentFixture<TestComponentWithTemplatePortals>;
44-
let dir: Direction;
47+
let dir: WritableSignal<Direction>;
4548
let mockLocation: SpyLocation;
4649

4750
function setup(imports: Type<unknown>[] = []) {
48-
dir = 'ltr';
51+
dir = signal<Direction>('ltr');
4952
TestBed.configureTestingModule({
5053
imports: [OverlayModule, ...imports],
5154
providers: [
52-
{
53-
provide: Directionality,
54-
useFactory: () => {
55-
const fakeDirectionality = {};
56-
Object.defineProperty(fakeDirectionality, 'value', {get: () => dir});
57-
return fakeDirectionality;
58-
},
59-
},
55+
provideFakeDirectionality(dir),
6056
{
6157
provide: Location,
6258
useClass: SpyLocation,
@@ -175,7 +171,7 @@ describe('Overlay', () => {
175171
});
176172

177173
it('should take the default direction from the global Directionality', () => {
178-
dir = 'rtl';
174+
dir.set('rtl');
179175
const overlayRef = createOverlayRef(injector);
180176

181177
overlayRef.attach(componentPortal);

src/cdk/testing/private/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ts_project(
1212
deps = [
1313
"//:node_modules/@angular/core",
1414
"//:node_modules/@types/jasmine",
15+
"//src/cdk/bidi",
1516
"//src/cdk/testing/testbed",
1617
],
1718
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {Direction, Directionality} from '@angular/cdk/bidi';
10+
import {EventEmitter, signal, WritableSignal} from '@angular/core';
11+
import {toObservable} from '@angular/core/rxjs-interop';
12+
import {skip} from 'rxjs/operators';
13+
14+
// Note: ngOnDestroy not needed, but must include it to match the Directionality interface.
15+
// Implementing the interface ensures the fake stays in sync with the real API.
16+
// tslint:disable-next-line:no-undecorated-class-with-angular-features lifecycle-hook-interface
17+
class FakeDirectionality implements Directionality {
18+
readonly change: EventEmitter<Direction>;
19+
20+
get value(): Direction {
21+
return this.valueSignal();
22+
}
23+
24+
constructor(readonly valueSignal: WritableSignal<Direction>) {
25+
this.change = toObservable(valueSignal).pipe(skip(1)) as EventEmitter<Direction>;
26+
}
27+
28+
ngOnDestroy() {}
29+
}
30+
31+
export function provideFakeDirectionality(direction: Direction | WritableSignal<Direction>) {
32+
return {
33+
provide: Directionality,
34+
useFactory: () =>
35+
new FakeDirectionality(typeof direction === 'string' ? signal(direction) : direction),
36+
deps: [],
37+
};
38+
}

src/cdk/testing/private/public-api.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
export * from './fake-directionality';
910
export * from './text-dedent';
1011
export * from './wrapped-error-message';
1112

src/cdk/tree/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ ts_project(
4141
"//src/cdk/bidi",
4242
"//src/cdk/collections",
4343
"//src/cdk/keycodes",
44+
"//src/cdk/testing/private",
4445
"//src/cdk/testing/testbed",
4546
],
4647
)

src/cdk/tree/tree-with-tree-control.spec.ts

+14-15
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,29 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.dev/license
77
*/
8-
import {ComponentFixture, TestBed} from '@angular/core/testing';
98
import {
109
Component,
1110
ErrorHandler,
12-
ViewChild,
11+
QueryList,
12+
signal,
1313
TrackByFunction,
1414
Type,
15-
EventEmitter,
15+
ViewChild,
1616
ViewChildren,
17-
QueryList,
17+
WritableSignal,
1818
} from '@angular/core';
19+
import {ComponentFixture, TestBed} from '@angular/core/testing';
1920

21+
import {BehaviorSubject, combineLatest, Observable} from 'rxjs';
22+
import {map} from 'rxjs/operators';
23+
import {Direction} from '../bidi';
2024
import {CollectionViewer, DataSource} from '../collections';
21-
import {Directionality, Direction} from '../bidi';
2225
import {createKeyboardEvent} from '../testing/testbed/fake-events';
23-
import {combineLatest, BehaviorSubject, Observable} from 'rxjs';
24-
import {map} from 'rxjs/operators';
2526

26-
import {TreeControl} from './control/tree-control';
27+
import {provideFakeDirectionality} from '../testing/private/fake-directionality';
2728
import {FlatTreeControl} from './control/flat-tree-control';
2829
import {NestedTreeControl} from './control/nested-tree-control';
30+
import {TreeControl} from './control/tree-control';
2931
import {CdkTreeModule, CdkTreeNodePadding} from './index';
3032
import {CdkTree, CdkTreeNode} from './tree';
3133

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

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

245-
dir.value = 'rtl';
246-
dir.change.emit('rtl');
245+
dir.set('rtl');
247246
fixture.detectChanges();
248247

249248
expect(node.style.paddingRight).toBe('10px');

0 commit comments

Comments
 (0)