Skip to content

Commit

Permalink
fix: add support for InputSignalWithTransform in inputs property (#484)
Browse files Browse the repository at this point in the history
Closes #483
  • Loading branch information
mlz11 authored Aug 13, 2024
1 parent 8ca97c7 commit 9160da1
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,45 @@ test('works with signal inputs', async () => {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'world',
age: '45',
},
});

const inputValue = within(screen.getByTestId('input-value'));
expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
expect(inputValue.getByText(/hello world of 45 years old/i)).toBeInTheDocument();
});

test('works with computed', async () => {
await render(SignalInputComponent, {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'world',
age: '45',
},
});

const computedValue = within(screen.getByTestId('computed-value'));
expect(computedValue.getByText(/hello world/i)).toBeInTheDocument();
expect(computedValue.getByText(/hello world of 45 years old/i)).toBeInTheDocument();
});

test('can update signal inputs', async () => {
const { fixture } = await render(SignalInputComponent, {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'world',
age: '45',
},
});

const inputValue = within(screen.getByTestId('input-value'));
const computedValue = within(screen.getByTestId('computed-value'));

expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
expect(inputValue.getByText(/hello world of 45 years old/i)).toBeInTheDocument();

fixture.componentInstance.name.set('updated');
// set doesn't trigger change detection within the test, findBy is needed to update the template
expect(await inputValue.findByText(/hello updated/i)).toBeInTheDocument();
expect(await computedValue.findByText(/hello updated/i)).toBeInTheDocument();
expect(await inputValue.findByText(/hello updated of 45 years old/i)).toBeInTheDocument();
expect(await computedValue.findByText(/hello updated of 45 years old/i)).toBeInTheDocument();

// it's not recommended to access the model directly, but it's possible
expect(fixture.componentInstance.name()).toBe('updated');
Expand All @@ -54,6 +57,7 @@ test('output emits a value', async () => {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'world',
age: '45',
},
on: {
submit: submitFn,
Expand All @@ -70,6 +74,7 @@ test('model update also updates the template', async () => {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'initial',
age: '45',
},
});

Expand Down Expand Up @@ -100,22 +105,24 @@ test('works with signal inputs, computed values, and rerenders', async () => {
inputs: {
...aliasedInput('greeting', 'Hello'),
name: 'world',
age: '45',
},
});

const inputValue = within(screen.getByTestId('input-value'));
const computedValue = within(screen.getByTestId('computed-value'));

expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
expect(computedValue.getByText(/hello world/i)).toBeInTheDocument();
expect(inputValue.getByText(/hello world of 45 years old/i)).toBeInTheDocument();
expect(computedValue.getByText(/hello world of 45 years old/i)).toBeInTheDocument();

await view.rerender({
inputs: {
...aliasedInput('greeting', 'bye'),
name: 'test',
age: '0',
},
});

expect(inputValue.getByText(/bye test/i)).toBeInTheDocument();
expect(computedValue.getByText(/bye test/i)).toBeInTheDocument();
expect(inputValue.getByText(/bye test of 0 years old/i)).toBeInTheDocument();
expect(computedValue.getByText(/bye test of 0 years old/i)).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component, computed, input, model, output } from '@angular/core';
import { Component, computed, input, model, numberAttribute, output } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
selector: 'app-signal-input',
template: `
<div data-testid="input-value">{{ greetings() }} {{ name() }}</div>
<div data-testid="input-value">{{ greetings() }} {{ name() }} of {{ age() }} years old</div>
<div data-testid="computed-value">{{ greetingMessage() }}</div>
<button (click)="submitName()">Submit</button>
<input type="text" [(ngModel)]="name" />
Expand All @@ -16,10 +16,11 @@ export class SignalInputComponent {
greetings = input<string>('', {
alias: 'greeting',
});
age = input.required<number, string>({ transform: numberAttribute });
name = model.required<string>();
submit = output<string>();

greetingMessage = computed(() => `${this.greetings()} ${this.name()}`);
greetingMessage = computed(() => `${this.greetings()} ${this.name()} of ${this.age()} years old`);

submitName() {
this.submit.emit(this.name());
Expand Down
8 changes: 6 additions & 2 deletions projects/testing-library/src/lib/models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Type, DebugElement, EventEmitter, Signal } from '@angular/core';
import { Type, DebugElement, EventEmitter, Signal, InputSignalWithTransform } from '@angular/core';
import { ComponentFixture, DeferBlockBehavior, DeferBlockState, TestBed } from '@angular/core/testing';
import { Routes } from '@angular/router';
import { BoundFunction, Queries, queries, Config as dtlConfig, PrettyDOMOptions } from '@testing-library/dom';
Expand Down Expand Up @@ -94,7 +94,11 @@ export type AliasedInputs = Record<string, AliasedInput<unknown>>;

export type ComponentInput<T> =
| {
[P in keyof T]?: T[P] extends Signal<infer U> ? U : T[P];
[P in keyof T]?: T[P] extends InputSignalWithTransform<any, infer U>
? U
: T[P] extends Signal<infer U>
? U
: T[P];
}
| AliasedInputs;

Expand Down

0 comments on commit 9160da1

Please sign in to comment.