Skip to content

Commit 3b04682

Browse files
committed
feat: add wrapper and queries render options
1 parent 4a793b2 commit 3b04682

File tree

6 files changed

+80
-17
lines changed

6 files changed

+80
-17
lines changed

projects/testing-library/src/lib/models.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ export type RenderResultQueries<Q extends Queries = typeof queries> = { [P in ke
66

77
export interface RenderResult extends RenderResultQueries, FireObject {
88
container: HTMLElement;
9-
debug: (element: HTMLElement) => void;
9+
debug: (element?: HTMLElement) => void;
1010
fixture: ComponentFixture<any>;
1111
}
1212

13-
export interface Options {
13+
export interface RenderOptions<W = any, Q extends Queries = typeof queries> {
1414
detectChanges?: boolean;
1515
declarations: any[];
1616
providers?: any[];
1717
imports?: any[];
1818
schemas?: any[];
19+
queries?: Q;
20+
wrapper?: Type<W>;
1921
}
2022

2123
export interface ComponentInput<T> {

projects/testing-library/src/lib/testing-library.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
import { Component, OnInit, ElementRef } from '@angular/core';
1+
import { Component, OnInit, ElementRef, Type } from '@angular/core';
22
import { TestBed } from '@angular/core/testing';
33
import { getQueriesForElement, prettyDOM, fireEvent, FireObject, FireFunction } from 'dom-testing-library';
44

5-
import { RenderResult, Options, ComponentInput } from './models';
5+
import { RenderResult, RenderOptions, ComponentInput } from './models';
66

7-
@Component({ selector: 'test-component', template: '' })
8-
class TestComponent implements OnInit {
7+
@Component({ selector: 'wrapper-component', template: '' })
8+
class WrapperComponent implements OnInit {
99
constructor(private elemtRef: ElementRef) {}
1010

1111
ngOnInit() {
1212
this.elemtRef.nativeElement.removeAttribute('ng-version');
1313
}
1414
}
1515

16-
export async function render<T>(template: string, options: Options): Promise<RenderResult>;
17-
export async function render<T>(component: ComponentInput<T>, options: Options): Promise<RenderResult>;
16+
export async function render<T>(template: string, renderOptions: RenderOptions): Promise<RenderResult>;
17+
export async function render<T>(component: ComponentInput<T>, renderOptions: RenderOptions): Promise<RenderResult>;
1818
export async function render<T>(
1919
templateOrComponent: string | ComponentInput<T>,
20-
{ detectChanges = true, declarations = [], providers = [], imports = [], schemas = [] }: Options,
20+
{
21+
detectChanges = true,
22+
declarations = [],
23+
imports = [],
24+
providers = [],
25+
schemas = [],
26+
queries,
27+
wrapper = WrapperComponent,
28+
}: RenderOptions,
2129
): Promise<RenderResult> {
2230
const isTemplate = typeof templateOrComponent === 'string';
23-
const testComponent = isTemplate ? [TestComponent] : [];
31+
const testComponent = isTemplate ? [wrapper] : [];
2432

2533
TestBed.configureTestingModule({
2634
declarations: [...declarations, ...testComponent],
@@ -30,7 +38,7 @@ export async function render<T>(
3038
});
3139

3240
const fixture = isTemplate
33-
? createTestComponentFixture(<string>templateOrComponent)
41+
? createWrapperComponentFixture(wrapper, <string>templateOrComponent)
3442
: createComponentFixture(<ComponentInput<T>>templateOrComponent);
3543

3644
await TestBed.compileComponents();
@@ -55,20 +63,26 @@ export async function render<T>(
5563
fixture,
5664
container: fixture.nativeElement,
5765
debug: (element = fixture.nativeElement) => console.log(prettyDOM(element)),
58-
...getQueriesForElement(fixture.nativeElement),
66+
...getQueriesForElement(fixture.nativeElement, queries),
5967
...eventsWithDetectChanges,
6068
} as any;
6169
}
6270

63-
function createTestComponentFixture(template: string) {
64-
TestBed.overrideComponent(TestComponent, {
71+
/**
72+
* Creates the wrapper component and sets its the template to the to-be-tested component
73+
*/
74+
function createWrapperComponentFixture<T>(wrapper: Type<T>, template: string) {
75+
TestBed.overrideComponent(wrapper, {
6576
set: {
6677
template: template,
6778
},
6879
});
69-
return TestBed.createComponent(TestComponent);
80+
return TestBed.createComponent(wrapper);
7081
}
7182

83+
/**
84+
* Creates the components and sets its properties via the provided properties from `componentInput`
85+
*/
7286
function createComponentFixture<T>(componentInput: ComponentInput<T>) {
7387
const { component, parameters = {} } = componentInput;
7488
const fixture = TestBed.createComponent(component);

projects/testing-library/tests/debug.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { render } from '../src/public_api';
55
selector: 'fixture',
66
template: `
77
<p>rawr</p>
8+
<button data-testid="btn">I'm a button</button>
89
`,
910
})
1011
class FixtureComponent {}
@@ -14,7 +15,23 @@ test('debug', async () => {
1415
const { debug } = await render('<fixture></fixture>', {
1516
declarations: [FixtureComponent],
1617
});
18+
1719
debug();
20+
1821
expect(console.log).toBeCalledWith(expect.stringContaining('rawr'));
1922
(<any>console.log).mockRestore();
2023
});
24+
25+
test('debug allows to be called with an element', async () => {
26+
jest.spyOn(console, 'log').mockImplementation(() => {});
27+
const { debug, getByTestId } = await render('<fixture></fixture>', {
28+
declarations: [FixtureComponent],
29+
});
30+
const btn = getByTestId('btn');
31+
32+
debug(btn);
33+
34+
expect(console.log).not.toBeCalledWith(expect.stringContaining('rawr'));
35+
expect(console.log).toBeCalledWith(expect.stringContaining(`I'm a button`));
36+
(<any>console.log).mockRestore();
37+
});

projects/testing-library/tests/form/form.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input, Output, EventEmitter } from '@angular/core';
1+
import { Component, Output, EventEmitter } from '@angular/core';
22
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
33

44
@Component({

projects/testing-library/tests/form/form.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ test('login form submits using the component syntax', async () => {
2323

2424
const usernameNode = getByLabelText(/username/i) as HTMLInputElement;
2525
const passwordNode = getByLabelText(/password/i) as HTMLInputElement;
26-
const submitButtonNode = getByText(/submit/i);
26+
const submitButtonNode = getByText(/submit/i) as HTMLButtonElement;
2727
const formNode = container.querySelector('form');
2828

2929
input(usernameNode, {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Component, Input, ElementRef, OnInit } from '@angular/core';
2+
import { render } from '../src/public_api';
3+
4+
@Component({
5+
selector: 'fixture',
6+
template: `
7+
<p>rawr</p>
8+
`,
9+
})
10+
class FixtureComponent {}
11+
12+
@Component({ selector: 'wrapper-component', template: '' })
13+
class WrapperComponent implements OnInit {
14+
constructor(private elemtRef: ElementRef) {}
15+
16+
ngOnInit() {
17+
const textnode = document.createTextNode('I should be visible');
18+
this.elemtRef.nativeElement.appendChild(textnode);
19+
}
20+
}
21+
22+
test('allows for a custom wrapper', async () => {
23+
jest.spyOn(console, 'log').mockImplementation(() => {});
24+
const { getByText } = await render('<fixture></fixture>', {
25+
declarations: [FixtureComponent],
26+
wrapper: WrapperComponent,
27+
});
28+
29+
getByText('I should be visible');
30+
});

0 commit comments

Comments
 (0)