Skip to content

Commit

Permalink
test(core): add type tests for ɵunwrapWritableSignal (#54387)
Browse files Browse the repository at this point in the history
Getting the typing for `ɵunwrapWritableSignal` just right was tricky so these changes add some tests to ensure that we don't regress.

Also reworks the type tester a bit to make it easier to find where to add new test files.

PR Close #54387
  • Loading branch information
crisbeto authored and AndrewKushnir committed Feb 12, 2024
1 parent 0ecc2d1 commit 1581988
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/core/test/authoring/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ts_library(
"signal_input_signature_test.ts",
"signal_model_signature_test.ts",
"signal_queries_signature_test.ts",
"unwrap_writable_signal_signature_test.ts",
],
deps = ["//packages/core"],
)
Expand Down
20 changes: 13 additions & 7 deletions packages/core/test/authoring/type_tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ import path from 'path';
import ts from 'typescript';
import url from 'url';

/** Currently-configured tests. */
const TESTS = new Map<string, (value: string) => string>([
[
'signal_input_signature_test',
v => v.includes(',') ? `InputSignalWithTransform<${v}>` : `InputSignal<${v}>`
],
['signal_queries_signature_test', v => `Signal<${v}>`],
['signal_model_signature_test', v => `ModelSignal<${v}>`],
['unwrap_writable_signal_signature_test', v => v]
]);

const containingDir = path.dirname(url.fileURLToPath(import.meta.url));

/**
Expand All @@ -21,8 +32,7 @@ function isTestClass(classDeclaration: ts.ClassDeclaration): boolean {
return classDeclaration.name !== undefined && classDeclaration.name.text.endsWith('Test');
}

function testFile(
testFileName: string, getType: (v: string) => string, inferWriteType: boolean): boolean {
function testFile(testFileName: string, getType: (v: string) => string): boolean {
const fileContent = fs.readFileSync(path.join(containingDir, `${testFileName}.d.ts`), 'utf8');
const sourceFile = ts.createSourceFile('test.ts', fileContent, ts.ScriptTarget.ESNext, true);
const testClazz = sourceFile.statements.find(
Expand Down Expand Up @@ -63,11 +73,7 @@ function testFile(
async function main() {
let failing = false;

failing ||= testFile(
'signal_input_signature_test',
v => v.includes(',') ? `InputSignalWithTransform<${v}>` : `InputSignal<${v}>`, true);
failing ||= testFile('signal_queries_signature_test', v => `Signal<${v}>`, false);
failing ||= testFile('signal_model_signature_test', v => `ModelSignal<${v}>`, false);
TESTS.forEach((callback, filename) => failing ||= testFile(filename, callback));

if (failing) {
throw new Error('Failing assertions');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/**
* @fileoverview
* This file contains various signal `model()` patterns and ensures
* the resulting types match our expectations (via comments asserting the `.d.ts`).
*/

import {input, model, signal, ɵunwrapWritableSignal as unwrapWritableSignal} from '@angular/core';
// clang-format off
// import preserved to simplify `.d.ts` emit and simplify the `type_tester` logic.
// tslint:disable-next-line no-duplicate-imports
import {InputSignal, WritableSignal} from '@angular/core';
// clang-format on

export class SignalModelSignatureTest {
/** string | undefined */
optionalModel = unwrapWritableSignal(model<string>());

/** string */
requiredModel = unwrapWritableSignal(model.required<string>());

/** string | number */
writableSignal = unwrapWritableSignal(signal<string|number>(0));

/** InputSignal<string | undefined> */
optionalReadonlySignal = unwrapWritableSignal(input<string>());

/** InputSignal<string> */
requiredReadonlySignal = unwrapWritableSignal(input.required<string>());

/** number */
primitiveValue = unwrapWritableSignal(123);

/** (value: string | null | undefined) => number */
getterFunction =
unwrapWritableSignal((value: string|null|undefined) => value ? parseInt(value) : 0);
}

0 comments on commit 1581988

Please sign in to comment.