Skip to content

Commit a6a6fda

Browse files
committed
feat: allow to pass component properties with the template syntax
BREAKING CHANGE: The parameters parameter has been renamed to componentProperties and has also been moved to RenderOptions. To create a component via the component syntax, just pass it to the render function. BEFORE: ```ts const component = createComponent( { component: HomeComponent, parameters: { welcomeText: 'hello' } }, { declarations: [ HomeComponent ] } ) ``` AFTER: ```ts const component = render(HomeComponent, { componentProperties: { welcomeText: 'hello' }, declarations: [ HomeComponent ] }) ```
1 parent 9251f06 commit a6a6fda

File tree

4 files changed

+90
-52
lines changed

4 files changed

+90
-52
lines changed

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,13 @@ export interface RenderResult extends RenderResultQueries, FireObject {
1010
fixture: ComponentFixture<any>;
1111
}
1212

13-
export interface RenderOptions<W = any, Q extends Queries = typeof queries> {
13+
export interface RenderOptions<C, Q extends Queries = typeof queries> {
1414
detectChanges?: boolean;
1515
declarations: any[];
1616
providers?: any[];
1717
imports?: any[];
1818
schemas?: any[];
19+
componentProperties?: Partial<C>;
1920
queries?: Q;
20-
wrapper?: Type<W>;
21-
}
22-
23-
export interface ComponentInput<T> {
24-
component: Type<T>;
25-
parameters?: Partial<T>;
21+
wrapper?: Type<any>;
2622
}

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

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Component, OnInit, ElementRef, Type } from '@angular/core';
2-
import { TestBed } from '@angular/core/testing';
1+
import { Component, OnInit, ElementRef, Type, DebugElement } from '@angular/core';
2+
import { TestBed, ComponentFixture } from '@angular/core/testing';
33
import { getQueriesForElement, prettyDOM, fireEvent, FireObject, FireFunction } from 'dom-testing-library';
44

5-
import { RenderResult, RenderOptions, ComponentInput } from './models';
5+
import { RenderResult, RenderOptions } from './models';
6+
import { By } from '@angular/platform-browser';
67

78
@Component({ selector: 'wrapper-component', template: '' })
89
class WrapperComponent implements OnInit {
@@ -13,10 +14,8 @@ class WrapperComponent implements OnInit {
1314
}
1415
}
1516

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>;
1817
export async function render<T>(
19-
templateOrComponent: string | ComponentInput<T>,
18+
templateOrComponent: string | Type<T>,
2019
{
2120
detectChanges = true,
2221
declarations = [],
@@ -25,7 +24,8 @@ export async function render<T>(
2524
schemas = [],
2625
queries,
2726
wrapper = WrapperComponent,
28-
}: RenderOptions,
27+
componentProperties = {},
28+
}: RenderOptions<T>,
2929
): Promise<RenderResult> {
3030
const isTemplate = typeof templateOrComponent === 'string';
3131
const testComponent = isTemplate ? [wrapper] : [];
@@ -38,8 +38,8 @@ export async function render<T>(
3838
});
3939

4040
const fixture = isTemplate
41-
? createWrapperComponentFixture(wrapper, <string>templateOrComponent)
42-
: createComponentFixture(<ComponentInput<T>>templateOrComponent);
41+
? createWrapperComponentFixture(templateOrComponent as string, { wrapper, componentProperties })
42+
: createComponentFixture(templateOrComponent as Type<T>, { componentProperties });
4343

4444
await TestBed.compileComponents();
4545

@@ -71,23 +71,63 @@ export async function render<T>(
7171
/**
7272
* Creates the wrapper component and sets its the template to the to-be-tested component
7373
*/
74-
function createWrapperComponentFixture<T>(wrapper: Type<T>, template: string) {
74+
function createWrapperComponentFixture<T>(
75+
template: string,
76+
{
77+
wrapper,
78+
componentProperties,
79+
}: {
80+
wrapper: RenderOptions<T>['wrapper'];
81+
componentProperties: RenderOptions<T>['componentProperties'];
82+
},
83+
): ComponentFixture<any> {
7584
TestBed.overrideComponent(wrapper, {
7685
set: {
7786
template: template,
7887
},
7988
});
80-
return TestBed.createComponent(wrapper);
89+
90+
const fixture = TestBed.createComponent(wrapper);
91+
// get the component selector, e.g. <foo color="green"> and <foo> results in foo
92+
const componentSelector = template.match(/\<(.*?)\ /) || template.match(/\<(.*?)\>/);
93+
if (!componentSelector) {
94+
throw Error(`Template ${template} is not valid.`);
95+
}
96+
97+
const sut = fixture.debugElement.query(By.css(componentSelector[1]));
98+
setComponentProperties(sut, { componentProperties });
99+
return fixture;
81100
}
82101

83102
/**
84-
* Creates the components and sets its properties via the provided properties from `componentInput`
103+
* Creates the components and sets its properties
85104
*/
86-
function createComponentFixture<T>(componentInput: ComponentInput<T>) {
87-
const { component, parameters = {} } = componentInput;
105+
function createComponentFixture<T>(
106+
component: Type<T>,
107+
{
108+
componentProperties = {},
109+
}: {
110+
componentProperties: RenderOptions<T>['componentProperties'];
111+
},
112+
): ComponentFixture<T> {
88113
const fixture = TestBed.createComponent(component);
89-
for (const key of Object.keys(parameters)) {
90-
fixture.componentInstance[key] = parameters[key];
114+
setComponentProperties(fixture, { componentProperties });
115+
return fixture;
116+
}
117+
118+
/**
119+
* Set the component properties
120+
*/
121+
function setComponentProperties<T>(
122+
fixture: ComponentFixture<T> | DebugElement,
123+
{
124+
componentProperties = {},
125+
}: {
126+
componentProperties: RenderOptions<T>['componentProperties'];
127+
},
128+
) {
129+
for (const key of Object.keys(componentProperties)) {
130+
fixture.componentInstance[key] = componentProperties[key];
91131
}
92132
return fixture;
93133
}

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

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,30 @@ test('Counter actions via template syntax', async () => {
3333
expect(getByTestId('count').textContent).toBe('Current Count: 10');
3434
});
3535

36-
test('Counter actions via component syntax', async () => {
37-
const { getByText, getByTestId, click } = await render(
38-
{
39-
component: CounterComponent,
40-
parameters: {
41-
counter: 10,
42-
},
36+
test('Counter actions via template syntax with parameters', async () => {
37+
const { getByText, getByTestId, click } = await render<CounterComponent>('<counter></counter>', {
38+
declarations: [CounterComponent],
39+
componentProperties: {
40+
counter: 10,
4341
},
44-
{
45-
declarations: [CounterComponent],
42+
});
43+
44+
click(getByText('+'));
45+
expect(getByText('Current Count: 11')).toBeTruthy();
46+
expect(getByTestId('count').textContent).toBe('Current Count: 11');
47+
48+
click(getByText('-'));
49+
expect(getByText('Current Count: 10')).toBeTruthy();
50+
expect(getByTestId('count').textContent).toBe('Current Count: 10');
51+
});
52+
53+
test('Counter actions via component syntax', async () => {
54+
const { getByText, getByTestId, click } = await render(CounterComponent, {
55+
declarations: [CounterComponent],
56+
componentProperties: {
57+
counter: 10,
4658
},
47-
);
59+
});
4860

4961
click(getByText('+'));
5062
expect(getByText('Current Count: 11')).toBeTruthy();
@@ -56,14 +68,9 @@ test('Counter actions via component syntax', async () => {
5668
});
5769

5870
test('Counter actions via component syntax without parameters', async () => {
59-
const { getByText, getByTestId, click } = await render(
60-
{
61-
component: CounterComponent,
62-
},
63-
{
64-
declarations: [CounterComponent],
65-
},
66-
);
71+
const { getByText, getByTestId, click } = await render(CounterComponent, {
72+
declarations: [CounterComponent],
73+
});
6774

6875
click(getByText('+'));
6976
expect(getByText('Current Count: 1')).toBeTruthy();

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,13 @@ test('login form submits using the component syntax', async () => {
88
emit: jest.fn(),
99
};
1010

11-
const { container, getByLabelText, getByText, input, submit } = await render(
12-
{
13-
component: LoginFormComponent,
14-
parameters: {
15-
handleLogin: handleLogin as any,
16-
},
11+
const { container, getByLabelText, getByText, input, submit } = await render(LoginFormComponent, {
12+
declarations: [LoginFormComponent],
13+
imports: [ReactiveFormsModule],
14+
componentProperties: {
15+
handleLogin: handleLogin as any,
1716
},
18-
{
19-
declarations: [LoginFormComponent],
20-
imports: [ReactiveFormsModule],
21-
},
22-
);
17+
});
2318

2419
const usernameNode = getByLabelText(/username/i) as HTMLInputElement;
2520
const passwordNode = getByLabelText(/password/i) as HTMLInputElement;

0 commit comments

Comments
 (0)