Skip to content

Commit

Permalink
feat: query for cutom test elements
Browse files Browse the repository at this point in the history
  • Loading branch information
jnizet committed Feb 21, 2022
1 parent a84096b commit 53b3a45
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 1 deletion.
22 changes: 22 additions & 0 deletions projects/ngx-speculoos/src/lib/component-tester.ts
Expand Up @@ -366,6 +366,28 @@ export class ComponentTester<C> {
return this.testElement.tokens(selector, token);
}

/**
* Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided
* type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for
* custom elements or components.
* @param selector a CSS or directive selector
* @param customTestElementType the type of the TestElement subclass that will wrap the found element
*/
custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {
return this.testElement.custom(selector, customTestElementType);
}

/**
* Gets the elements matching the given selector, and creates and returns custom TestElements of the provided
* type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for
* custom elements or components.
* @param selector a CSS or directive selector
* @param customTestElementType the type of the TestElement subclass that will wrap the found elements
*/
customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {
return this.testElement.customs(selector, customTestElementType);
}

/**
* Triggers a change detection using the wrapped fixture
*/
Expand Down
46 changes: 45 additions & 1 deletion projects/ngx-speculoos/src/lib/test-element.spec.ts
@@ -1,4 +1,4 @@
import { Component, Directive, Input } from '@angular/core';
import { Component, DebugElement, Directive, Input } from '@angular/core';
import { ComponentTester } from './component-tester';
import { TestBed } from '@angular/core/testing';
import { TestElement } from './test-element';
Expand All @@ -23,6 +23,24 @@ class SubComponent {
@Input() sub?: string;
}

class TestDatepicker extends TestHtmlElement<HTMLElement> {
constructor(tester: ComponentTester<unknown>, debugElement: DebugElement) {
super(tester, debugElement);
}

get inputField() {
return this.input('input');
}

setDate(year: number, month: number, day: number) {
this.inputField.fillWith(`${year}-${month}-${day}`);
}

toggleDropdown() {
this.button('button').click();
}
}

@Component({
template: `
<svg id="s1" foo="bar" class="baz bing" (change)="onChange($event)">Test</svg>
Expand All @@ -43,6 +61,10 @@ class SubComponent {
<lib-sub id="sub2" sub="sub2"></lib-sub>
</div>
</div>
<div datepicker>
<input />
<button>Open</button>
</div>
`
})
class TestComponent {
Expand All @@ -66,6 +88,14 @@ class TestComponentTester extends ComponentTester<TestComponent> {
get typeParent() {
return this.element('#type-parent');
}

get datepicker() {
return this.custom('div[datepicker]', TestDatepicker);
}

get datepickers() {
return this.customs('div[datepicker]', TestDatepicker);
}
}

describe('TestElement', () => {
Expand Down Expand Up @@ -284,4 +314,18 @@ describe('TestElement', () => {
expect(directives[1]?.value).toBe('b');
});
});

describe('custom element', () => {
it(`should create custom test element`, () => {
expect(tester.datepicker).toBeInstanceOf(TestDatepicker);
tester.datepicker.setDate(2022, 10, 11);
expect(tester.datepicker.inputField.value).toBe('2022-10-11');
});

it(`should create custom test elements`, () => {
expect(tester.datepickers.length).toBe(1);
tester.datepickers[0].setDate(2022, 10, 11);
expect(tester.datepickers[0].inputField.value).toBe('2022-10-11');
});
});
});
23 changes: 23 additions & 0 deletions projects/ngx-speculoos/src/lib/test-element.ts
Expand Up @@ -361,4 +361,27 @@ export class TestElement<E extends Element = Element> {
tokens<R>(selector: string | Type<any>, token: ProviderToken<R>): Array<R | null> {
return this.querier.elements(selector).map(e => e.debugElement.injector.get(token, null) ?? null);
}

/**
* Gets the element matching the given selector, and if found, creates and returns a custom TestElement of the provided
* type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for
* custom elements or components.
* @param selector a CSS or directive selector
* @param customTestElementType the type of the TestElement subclass that will wrap the found element
*/
custom<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): E | null {
const element = this.querier.element(selector);
return element && new customTestElementType(this.tester, element.debugElement);
}

/**
* Gets the elements matching the given selector, and creates and returns custom TestElements of the provided
* type. This is useful to create custom higher-level abstractions similar to TestInput, TestSelect, etc. for
* custom elements or components.
* @param selector a CSS or directive selector
* @param customTestElementType the type of the TestElement subclass that will wrap the found elements
*/
customs<E extends TestElement>(selector: string | Type<any>, customTestElementType: Type<E>): Array<E> {
return this.querier.elements(selector).map(element => new customTestElementType(this.tester, element.debugElement));
}
}

0 comments on commit 53b3a45

Please sign in to comment.