sass-references/angular-material/material/menu/testing/menu-harness.spec.ts

199 lines
7.2 KiB
TypeScript
Raw Normal View History

2024-12-06 10:42:08 +08:00
import {Component} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {MatMenuModule} from '@angular/material/menu';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MatMenuHarness} from './menu-harness';
describe('MatMenuHarness', () => {
describe('single-level menu', () => {
let fixture: ComponentFixture<MenuHarnessTest>;
let loader: HarnessLoader;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [MatMenuModule, NoopAnimationsModule, MenuHarnessTest],
});
fixture = TestBed.createComponent(MenuHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should load all menu harnesses', async () => {
const menues = await loader.getAllHarnesses(MatMenuHarness);
expect(menues.length).toBe(2);
});
it('should load menu with exact text', async () => {
const menus = await loader.getAllHarnesses(MatMenuHarness.with({triggerText: 'Settings'}));
expect(menus.length).toBe(1);
expect(await menus[0].getTriggerText()).toBe('Settings');
});
it('should load menu with regex label match', async () => {
const menus = await loader.getAllHarnesses(MatMenuHarness.with({triggerText: /settings/i}));
expect(menus.length).toBe(1);
expect(await menus[0].getTriggerText()).toBe('Settings');
});
it('should get disabled state', async () => {
const [enabledMenu, disabledMenu] = await loader.getAllHarnesses(MatMenuHarness);
expect(await enabledMenu.isDisabled()).toBe(false);
expect(await disabledMenu.isDisabled()).toBe(true);
});
it('should get menu text', async () => {
const [firstMenu, secondMenu] = await loader.getAllHarnesses(MatMenuHarness);
expect(await firstMenu.getTriggerText()).toBe('Settings');
expect(await secondMenu.getTriggerText()).toBe('Disabled menu');
});
it('should focus and blur a menu', async () => {
const menu = await loader.getHarness(MatMenuHarness.with({triggerText: 'Settings'}));
expect(await menu.isFocused()).toBe(false);
await menu.focus();
expect(await menu.isFocused()).toBe(true);
await menu.blur();
expect(await menu.isFocused()).toBe(false);
});
it('should open and close', async () => {
const menu = await loader.getHarness(MatMenuHarness.with({triggerText: 'Settings'}));
expect(await menu.isOpen()).toBe(false);
await menu.open();
expect(await menu.isOpen()).toBe(true);
await menu.open();
expect(await menu.isOpen()).toBe(true);
await menu.close();
expect(await menu.isOpen()).toBe(false);
await menu.close();
expect(await menu.isOpen()).toBe(false);
});
it('should get all items', async () => {
const menu = await loader.getHarness(MatMenuHarness.with({triggerText: 'Settings'}));
await menu.open();
expect((await menu.getItems()).length).toBe(2);
});
it('should get filtered items', async () => {
const menu = await loader.getHarness(MatMenuHarness.with({triggerText: 'Settings'}));
await menu.open();
const items = await menu.getItems({text: 'Account'});
expect(items.length).toBe(1);
expect(await items[0].getText()).toBe('Account');
});
});
describe('multi-level menu', () => {
let fixture: ComponentFixture<NestedMenuHarnessTest>;
let loader: HarnessLoader;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [MatMenuModule, NoopAnimationsModule, NestedMenuHarnessTest],
});
fixture = TestBed.createComponent(NestedMenuHarnessTest);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should get submenus', async () => {
const menu1 = await loader.getHarness(MatMenuHarness.with({triggerText: 'Menu 1'}));
await menu1.open();
let submenus = await menu1.getItems({hasSubmenu: true});
expect(submenus.length).toBe(2);
const menu2 = (await submenus[0].getSubmenu())!;
const menu3 = (await submenus[1].getSubmenu())!;
expect(await menu2.getTriggerText()).toBe('Menu 2');
expect(await menu3.getTriggerText()).toBe('Menu 3');
await menu2.open();
expect((await menu2.getItems({hasSubmenu: true})).length).toBe(0);
await menu3.open();
submenus = await menu3.getItems({hasSubmenu: true});
expect(submenus.length).toBe(1);
const menu4 = (await submenus[0].getSubmenu())!;
expect(await menu4.getTriggerText()).toBe('Menu 4');
await menu4.open();
expect((await menu4.getItems({hasSubmenu: true})).length).toBe(0);
});
it('should select item in top-level menu', async () => {
const menu1 = await loader.getHarness(MatMenuHarness.with({triggerText: 'Menu 1'}));
await menu1.clickItem({text: /Leaf/});
expect(fixture.componentInstance.lastClickedLeaf).toBe(1);
});
it('should throw when item is not found', async () => {
const menu1 = await loader.getHarness(MatMenuHarness.with({triggerText: 'Menu 1'}));
await expectAsync(menu1.clickItem({text: 'Fake Item'})).toBeRejectedWithError(
/Could not find item matching {"text":"Fake Item"}/,
);
});
it('should select item in nested menu', async () => {
const menu1 = await loader.getHarness(MatMenuHarness.with({triggerText: 'Menu 1'}));
await menu1.clickItem({text: 'Menu 3'}, {text: 'Menu 4'}, {text: /Leaf/});
expect(fixture.componentInstance.lastClickedLeaf).toBe(3);
});
it('should throw when intermediate item does not have submenu', async () => {
const menu1 = await loader.getHarness(MatMenuHarness.with({triggerText: 'Menu 1'}));
await expectAsync(menu1.clickItem({text: 'Leaf Item 1'}, {})).toBeRejectedWithError(
/Item matching {"text":"Leaf Item 1"} does not have a submenu/,
);
});
});
});
@Component({
template: `
<button type="button" id="settings" [matMenuTriggerFor]="settingsMenu">Settings</button>
<button type="button" disabled [matMenuTriggerFor]="settingsMenu">Disabled menu</button>
<mat-menu #settingsMenu>
<menu mat-menu-item>Profile</menu>
<menu mat-menu-item>Account</menu>
</mat-menu>
`,
standalone: true,
imports: [MatMenuModule],
})
class MenuHarnessTest {}
@Component({
template: `
<button [matMenuTriggerFor]="menu1">Menu 1</button>
<mat-menu #menu1>
<button mat-menu-item [matMenuTriggerFor]="menu2">Menu 2</button>
<button mat-menu-item (click)="lastClickedLeaf = 1">Leaf Item 1</button>
<button mat-menu-item [matMenuTriggerFor]="menu3">Menu 3</button>
</mat-menu>
<mat-menu #menu2>
<button mat-menu-item (click)="lastClickedLeaf = 2">Leaf Item 2</button>
</mat-menu>
<mat-menu #menu3>
<button mat-menu-item [matMenuTriggerFor]="menu4">Menu 4</button>
</mat-menu>
<mat-menu #menu4>
<button mat-menu-item (click)="lastClickedLeaf = 3">Leaf Item 3</button>
</mat-menu>
`,
standalone: true,
imports: [MatMenuModule],
})
class NestedMenuHarnessTest {
lastClickedLeaf = 0;
}