From 06356d806a3949a9c2ae8218488c763d60cbffca Mon Sep 17 00:00:00 2001 From: Sonu Kapoor Date: Tue, 14 Jul 2020 08:38:44 -0400 Subject: [PATCH] build(forms): create sample forms app (#38044) This commit creates a sample forms test application to introduce the symbol tests. It serves as a guard to ensure that any future work on the forms package does not unintentionally increase the payload size. PR Close #38044 --- packages/core/test/bundling/forms/BUILD.bazel | 85 + .../bundling/forms/bundle.golden_symbols.json | 1736 +++++++++++++++++ .../test/bundling/forms/forms_e2e_spec.ts | 67 + packages/core/test/bundling/forms/index.html | 32 + packages/core/test/bundling/forms/index.ts | 138 ++ .../test/bundling/forms/treeshaking_spec.ts | 35 + 6 files changed, 2093 insertions(+) create mode 100644 packages/core/test/bundling/forms/BUILD.bazel create mode 100644 packages/core/test/bundling/forms/bundle.golden_symbols.json create mode 100644 packages/core/test/bundling/forms/forms_e2e_spec.ts create mode 100644 packages/core/test/bundling/forms/index.html create mode 100644 packages/core/test/bundling/forms/index.ts create mode 100644 packages/core/test/bundling/forms/treeshaking_spec.ts diff --git a/packages/core/test/bundling/forms/BUILD.bazel b/packages/core/test/bundling/forms/BUILD.bazel new file mode 100644 index 0000000000..5c0930c0d9 --- /dev/null +++ b/packages/core/test/bundling/forms/BUILD.bazel @@ -0,0 +1,85 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ng_module", "ng_rollup_bundle", "ts_library") +load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test") +load("@npm//http-server:index.bzl", "http_server") + +ng_module( + name = "forms", + srcs = ["index.ts"], + tags = [ + "ivy-only", + ], + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + ], +) + +ng_rollup_bundle( + name = "bundle", + entry_point = ":index.ts", + tags = [ + "ivy-only", + ], + deps = [ + ":forms", + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "@npm//rxjs", + ], +) + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob(["*_spec.ts"]), + tags = [ + "ivy-only", + ], + deps = [ + "//packages:types", + "//packages/compiler", + "//packages/core", + "//packages/core/testing", + "//packages/private/testing", + ], +) + +jasmine_node_test( + name = "test", + data = [ + ":bundle.js", + ":bundle.min.js", + ":bundle.min.js.br", + ":bundle.min_debug.js", + ], + tags = [ + "ivy-only", + ], + deps = [":test_lib"], +) + +js_expected_symbol_test( + name = "symbol_test", + src = ":bundle.min_debug.js", + golden = ":bundle.golden_symbols.json", + tags = [ + "ivy-aot", + "ivy-only", + ], +) + +http_server( + name = "prodserver", + data = [ + "index.html", + ":bundle.min.js", + ":bundle.min_debug.js", + ], + tags = [ + "ivy-only", + ], +) diff --git a/packages/core/test/bundling/forms/bundle.golden_symbols.json b/packages/core/test/bundling/forms/bundle.golden_symbols.json new file mode 100644 index 0000000000..85063ccff6 --- /dev/null +++ b/packages/core/test/bundling/forms/bundle.golden_symbols.json @@ -0,0 +1,1736 @@ +[ + { + "name": "ALLOW_MULTIPLE_PLATFORMS" + }, + { + "name": "APPLICATION_MODULE_PROVIDERS" + }, + { + "name": "APP_BOOTSTRAP_LISTENER" + }, + { + "name": "APP_ID" + }, + { + "name": "APP_ID_RANDOM_PROVIDER" + }, + { + "name": "APP_INITIALIZER" + }, + { + "name": "AbstractControl" + }, + { + "name": "AbstractControlDirective" + }, + { + "name": "AbstractControlStatus" + }, + { + "name": "AbstractFormGroupDirective" + }, + { + "name": "AnonymousSubject" + }, + { + "name": "ApplicationInitStatus" + }, + { + "name": "ApplicationModule" + }, + { + "name": "ApplicationRef" + }, + { + "name": "BROWSER_MODULE_PROVIDERS" + }, + { + "name": "BUILTIN_ACCESSORS" + }, + { + "name": "BrowserDomAdapter" + }, + { + "name": "BrowserGetTestability" + }, + { + "name": "BrowserModule" + }, + { + "name": "CHECKBOX_VALUE_ACCESSOR" + }, + { + "name": "CIRCULAR" + }, + { + "name": "CLEAN_PROMISE" + }, + { + "name": "COMPONENT_REGEX" + }, + { + "name": "COMPOSITION_BUFFER_MODE" + }, + { + "name": "ChangeDetectionStrategy" + }, + { + "name": "CheckboxControlValueAccessor" + }, + { + "name": "CommonModule" + }, + { + "name": "Compiler" + }, + { + "name": "Compiler_compileModuleAndAllComponentsAsync" + }, + { + "name": "Compiler_compileModuleAndAllComponentsSync" + }, + { + "name": "Compiler_compileModuleAndAllComponentsSync__POST_R3__" + }, + { + "name": "Compiler_compileModuleAsync" + }, + { + "name": "Compiler_compileModuleSync" + }, + { + "name": "Compiler_compileModuleSync__POST_R3__" + }, + { + "name": "ComponentFactory" + }, + { + "name": "ComponentFactory" + }, + { + "name": "ComponentFactoryResolver" + }, + { + "name": "ComponentFactoryResolver" + }, + { + "name": "ComponentRef" + }, + { + "name": "ConnectableObservable" + }, + { + "name": "ConnectableSubscriber" + }, + { + "name": "Console" + }, + { + "name": "ControlContainer" + }, + { + "name": "DEFAULT_CURRENCY_CODE" + }, + { + "name": "DEFAULT_VALUE_ACCESSOR" + }, + { + "name": "DOCUMENT" + }, + { + "name": "DOCUMENT" + }, + { + "name": "DefaultDomRenderer2" + }, + { + "name": "DefaultIterableDiffer" + }, + { + "name": "DefaultIterableDifferFactory" + }, + { + "name": "DefaultKeyValueDiffer" + }, + { + "name": "DefaultKeyValueDifferFactory" + }, + { + "name": "DefaultValueAccessor" + }, + { + "name": "DomEventsPlugin" + }, + { + "name": "DomRendererFactory2" + }, + { + "name": "DomSharedStylesHost" + }, + { + "name": "EMAIL_REGEXP" + }, + { + "name": "EMPTY_ARRAY" + }, + { + "name": "EMPTY_ARRAY" + }, + { + "name": "EMPTY_ARRAY" + }, + { + "name": "EMPTY_OBJ" + }, + { + "name": "EMPTY_PAYLOAD" + }, + { + "name": "EVENT_MANAGER_PLUGINS" + }, + { + "name": "ElementRef" + }, + { + "name": "EmulatedEncapsulationDomRenderer2" + }, + { + "name": "ErrorHandler" + }, + { + "name": "EventEmitter" + }, + { + "name": "EventManager" + }, + { + "name": "EventManagerPlugin" + }, + { + "name": "FormArray" + }, + { + "name": "FormArrayName" + }, + { + "name": "FormBuilder" + }, + { + "name": "FormControl" + }, + { + "name": "FormControlName" + }, + { + "name": "FormErrorExamples_formControlName" + }, + { + "name": "FormErrorExamples_formGroupName" + }, + { + "name": "FormErrorExamples_ngModelGroup" + }, + { + "name": "FormGroup" + }, + { + "name": "FormGroupDirective" + }, + { + "name": "FormGroupName" + }, + { + "name": "FormsExampleModule" + }, + { + "name": "FormsModule" + }, + { + "name": "INJECTOR" + }, + { + "name": "INJECTOR_IMPL" + }, + { + "name": "INJECTOR_SCOPE" + }, + { + "name": "Inject" + }, + { + "name": "InjectFlags" + }, + { + "name": "InjectionToken" + }, + { + "name": "Injector" + }, + { + "name": "InnerSubscriber" + }, + { + "name": "IterableChangeRecord_" + }, + { + "name": "IterableDiffers" + }, + { + "name": "KeyEventsPlugin" + }, + { + "name": "KeyValueChangeRecord_" + }, + { + "name": "KeyValueDiffers" + }, + { + "name": "LOCALE_DATA" + }, + { + "name": "LOCALE_ID" + }, + { + "name": "LOCALE_ID" + }, + { + "name": "LifecycleHooksFeature" + }, + { + "name": "LocaleDataIndex" + }, + { + "name": "MODIFIER_KEYS" + }, + { + "name": "MODIFIER_KEY_GETTERS" + }, + { + "name": "MapOperator" + }, + { + "name": "MapSubscriber" + }, + { + "name": "MergeMapOperator" + }, + { + "name": "MergeMapSubscriber" + }, + { + "name": "ModuleWithComponentFactories" + }, + { + "name": "NAMESPACE_URIS" + }, + { + "name": "NEW_LINE" + }, + { + "name": "NG_ASYNC_VALIDATORS" + }, + { + "name": "NG_COMP_DEF" + }, + { + "name": "NG_DIR_DEF" + }, + { + "name": "NG_ELEMENT_ID" + }, + { + "name": "NG_FACTORY_DEF" + }, + { + "name": "NG_INJECTABLE_DEF" + }, + { + "name": "NG_INJECTOR_DEF" + }, + { + "name": "NG_INJ_DEF" + }, + { + "name": "NG_LOC_ID_DEF" + }, + { + "name": "NG_MODEL_WITH_FORM_CONTROL_WARNING" + }, + { + "name": "NG_MOD_DEF" + }, + { + "name": "NG_PIPE_DEF" + }, + { + "name": "NG_PROV_DEF" + }, + { + "name": "NG_PROV_DEF_FALLBACK" + }, + { + "name": "NG_VALIDATORS" + }, + { + "name": "NG_VALUE_ACCESSOR" + }, + { + "name": "NOT_FOUND" + }, + { + "name": "NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR" + }, + { + "name": "NOT_YET" + }, + { + "name": "NO_CHANGE" + }, + { + "name": "NULL_INJECTOR" + }, + { + "name": "NUMBER_VALUE_ACCESSOR" + }, + { + "name": "NgControl" + }, + { + "name": "NgControlStatus" + }, + { + "name": "NgControlStatusGroup" + }, + { + "name": "NgForOf" + }, + { + "name": "NgForOfContext" + }, + { + "name": "NgForm" + }, + { + "name": "NgLocaleLocalization" + }, + { + "name": "NgLocalization" + }, + { + "name": "NgModel" + }, + { + "name": "NgModelGroup" + }, + { + "name": "NgModuleFactory" + }, + { + "name": "NgModuleRef" + }, + { + "name": "NgModuleRef" + }, + { + "name": "NgOnChangesFeatureImpl" + }, + { + "name": "NgZone" + }, + { + "name": "NodeInjector" + }, + { + "name": "NodeInjectorFactory" + }, + { + "name": "NoopNgZone" + }, + { + "name": "NullInjector" + }, + { + "name": "NumberValueAccessor" + }, + { + "name": "ObjectUnsubscribedError" + }, + { + "name": "Observable" + }, + { + "name": "Optional" + }, + { + "name": "OuterSubscriber" + }, + { + "name": "PLATFORM_ID" + }, + { + "name": "PLATFORM_INITIALIZER" + }, + { + "name": "PlatformRef" + }, + { + "name": "Plural" + }, + { + "name": "R3Injector" + }, + { + "name": "RADIO_VALUE_ACCESSOR" + }, + { + "name": "RANGE_VALUE_ACCESSOR" + }, + { + "name": "REQUIRED_VALIDATOR" + }, + { + "name": "RadioControlRegistry" + }, + { + "name": "RadioControlValueAccessor" + }, + { + "name": "RangeValueAccessor" + }, + { + "name": "ReactiveErrors" + }, + { + "name": "ReactiveFormsComponent" + }, + { + "name": "ReactiveFormsComponent_div_14_Template" + }, + { + "name": "ReactiveFormsModule" + }, + { + "name": "RecordViewTuple" + }, + { + "name": "RefCountOperator" + }, + { + "name": "RefCountSubscriber" + }, + { + "name": "Renderer2" + }, + { + "name": "RendererFactory2" + }, + { + "name": "RendererStyleFlags2" + }, + { + "name": "RequiredValidator" + }, + { + "name": "RootComponent" + }, + { + "name": "RootViewRef" + }, + { + "name": "SCHEDULER" + }, + { + "name": "SELECT_MULTIPLE_VALUE_ACCESSOR" + }, + { + "name": "SELECT_VALUE_ACCESSOR" + }, + { + "name": "SERVER_TRANSITION_PROVIDERS" + }, + { + "name": "SWITCH_ELEMENT_REF_FACTORY" + }, + { + "name": "SWITCH_RENDERER2_FACTORY" + }, + { + "name": "SWITCH_TEMPLATE_REF_FACTORY" + }, + { + "name": "SWITCH_VIEW_CONTAINER_REF_FACTORY" + }, + { + "name": "SafeSubscriber" + }, + { + "name": "Sanitizer" + }, + { + "name": "SelectControlValueAccessor" + }, + { + "name": "SelectMultipleControlValueAccessor" + }, + { + "name": "Self" + }, + { + "name": "ShadowDomRenderer" + }, + { + "name": "SharedStylesHost" + }, + { + "name": "SimpleChange" + }, + { + "name": "SkipSelf" + }, + { + "name": "Subject" + }, + { + "name": "SubjectSubscriber" + }, + { + "name": "SubjectSubscription" + }, + { + "name": "Subscriber" + }, + { + "name": "Subscription" + }, + { + "name": "THROW_IF_NOT_FOUND" + }, + { + "name": "TRANSITION_ID" + }, + { + "name": "TemplateDrivenErrors" + }, + { + "name": "TemplateFormsComponent" + }, + { + "name": "TemplateFormsComponent_div_14_Template" + }, + { + "name": "TemplateRef" + }, + { + "name": "Testability" + }, + { + "name": "TestabilityRegistry" + }, + { + "name": "USE_VALUE" + }, + { + "name": "UnsubscriptionError" + }, + { + "name": "VERSION" + }, + { + "name": "Validators" + }, + { + "name": "Version" + }, + { + "name": "ViewContainerRef" + }, + { + "name": "ViewEncapsulation" + }, + { + "name": "ViewRef" + }, + { + "name": "_DOM" + }, + { + "name": "_DuplicateItemRecordList" + }, + { + "name": "_DuplicateMap" + }, + { + "name": "_NoopGetTestability" + }, + { + "name": "_NullComponentFactoryResolver" + }, + { + "name": "__extends" + }, + { + "name": "__forward_ref__" + }, + { + "name": "__global" + }, + { + "name": "__globalThis" + }, + { + "name": "__self" + }, + { + "name": "__window" + }, + { + "name": "_chromeNumKeyPadMap" + }, + { + "name": "_currentInjector" + }, + { + "name": "_enable_super_gross_mode_that_will_cause_bad_things" + }, + { + "name": "_global" + }, + { + "name": "_hasInvalidParent" + }, + { + "name": "_keyMap" + }, + { + "name": "_mergeErrors" + }, + { + "name": "_noControlError" + }, + { + "name": "_randomChar" + }, + { + "name": "_renderCompCount" + }, + { + "name": "_symbolIterator" + }, + { + "name": "_testabilityGetter" + }, + { + "name": "_throwError" + }, + { + "name": "addComponentLogic" + }, + { + "name": "addHostBindingsToExpandoInstructions" + }, + { + "name": "addRemoveViewFromContainer" + }, + { + "name": "addToArray" + }, + { + "name": "addToViewTree" + }, + { + "name": "allocLFrame" + }, + { + "name": "appendChild" + }, + { + "name": "applyNodes" + }, + { + "name": "applyProjectionRecursive" + }, + { + "name": "applyToElementOrContainer" + }, + { + "name": "applyView" + }, + { + "name": "attachPatchData" + }, + { + "name": "autoRegisterModuleById" + }, + { + "name": "baseElement" + }, + { + "name": "baseResolveDirective" + }, + { + "name": "bindingUpdated" + }, + { + "name": "bloomHasToken" + }, + { + "name": "callHook" + }, + { + "name": "callHooks" + }, + { + "name": "checkStable" + }, + { + "name": "classIndexOf" + }, + { + "name": "cleanUpView" + }, + { + "name": "coerceToAsyncValidator" + }, + { + "name": "coerceToValidator" + }, + { + "name": "collectStylingFromDirectives" + }, + { + "name": "collectStylingFromTAttrs" + }, + { + "name": "composeAsyncValidators" + }, + { + "name": "composeValidators" + }, + { + "name": "computeStaticStyling" + }, + { + "name": "concatStringsWithSpace" + }, + { + "name": "config" + }, + { + "name": "connectableObservableDescriptor" + }, + { + "name": "controlNameBinding" + }, + { + "name": "controlPath" + }, + { + "name": "createDirectivesInstances" + }, + { + "name": "createElementRef" + }, + { + "name": "createInjectorWithoutInjectorInstances" + }, + { + "name": "createLContainer" + }, + { + "name": "createLFrame" + }, + { + "name": "createLView" + }, + { + "name": "createPlatformFactory" + }, + { + "name": "createTNode" + }, + { + "name": "createTView" + }, + { + "name": "decoratePreventDefault" + }, + { + "name": "deepForEach" + }, + { + "name": "defaultErrorLogger" + }, + { + "name": "defaultIterableDiffers" + }, + { + "name": "defaultKeyValueDiffers" + }, + { + "name": "defaultScheduler" + }, + { + "name": "destroyLView" + }, + { + "name": "detachMovedView" + }, + { + "name": "detachView" + }, + { + "name": "detectChangesInRootView" + }, + { + "name": "detectChangesInternal" + }, + { + "name": "diPublicInInjector" + }, + { + "name": "domRendererFactory3" + }, + { + "name": "elementCreate" + }, + { + "name": "empty" + }, + { + "name": "enterDI" + }, + { + "name": "enterView" + }, + { + "name": "executeCheckHooks" + }, + { + "name": "executeInitAndCheckHooks" + }, + { + "name": "executeListenerWithErrorHandling" + }, + { + "name": "executeTemplate" + }, + { + "name": "executeViewQueryFn" + }, + { + "name": "extendStatics" + }, + { + "name": "extractDirectiveDef" + }, + { + "name": "extractPipeDef" + }, + { + "name": "fillProperties" + }, + { + "name": "findAttrIndexInNode" + }, + { + "name": "findStylingValue" + }, + { + "name": "flattenStyles" + }, + { + "name": "flattenUnsubscriptionErrors" + }, + { + "name": "forkJoinInternal" + }, + { + "name": "formArrayNameProvider" + }, + { + "name": "formControlBinding" + }, + { + "name": "formDirectiveProvider" + }, + { + "name": "formDirectiveProvider" + }, + { + "name": "formGroupNameProvider" + }, + { + "name": "forwardRef" + }, + { + "name": "from" + }, + { + "name": "fromArray" + }, + { + "name": "generateExpandoInstructionBlock" + }, + { + "name": "generateInitialInputs" + }, + { + "name": "generatePropertyAliases" + }, + { + "name": "getBeforeNodeForView" + }, + { + "name": "getCheckNoChangesMode" + }, + { + "name": "getClosureSafeProperty" + }, + { + "name": "getComponentDef" + }, + { + "name": "getComponentLViewByIndex" + }, + { + "name": "getConstant" + }, + { + "name": "getContainerRenderParent" + }, + { + "name": "getDOM" + }, + { + "name": "getDebugContext" + }, + { + "name": "getFactoryDef" + }, + { + "name": "getFirstLContainer" + }, + { + "name": "getInjectableDef" + }, + { + "name": "getInjectorDef" + }, + { + "name": "getInjectorIndex" + }, + { + "name": "getIsParent" + }, + { + "name": "getLCleanup" + }, + { + "name": "getLContainer" + }, + { + "name": "getLView" + }, + { + "name": "getLViewParent" + }, + { + "name": "getLocaleData" + }, + { + "name": "getNativeByTNode" + }, + { + "name": "getNearestLContainer" + }, + { + "name": "getNextLContainer" + }, + { + "name": "getNgModuleDef" + }, + { + "name": "getNodeInjectable" + }, + { + "name": "getNullInjector" + }, + { + "name": "getOrCreateInjectable" + }, + { + "name": "getOrCreateNodeInjectorForNode" + }, + { + "name": "getOrCreateTComponentView" + }, + { + "name": "getOrCreateTNode" + }, + { + "name": "getOriginalError" + }, + { + "name": "getOwnDefinition" + }, + { + "name": "getParentInjectorIndex" + }, + { + "name": "getParentInjectorLocation" + }, + { + "name": "getParentInjectorView" + }, + { + "name": "getParentInjectorViewOffset" + }, + { + "name": "getParentState" + }, + { + "name": "getPlatform" + }, + { + "name": "getPreviousIndex" + }, + { + "name": "getPreviousOrParentTNode" + }, + { + "name": "getPromiseCtor" + }, + { + "name": "getSelectedIndex" + }, + { + "name": "getSelectedTNode" + }, + { + "name": "getSimpleChangesStore" + }, + { + "name": "getSymbolIterator" + }, + { + "name": "getSymbolIterator" + }, + { + "name": "getTNode" + }, + { + "name": "getTStylingRangeNext" + }, + { + "name": "getTStylingRangePrev" + }, + { + "name": "getTView" + }, + { + "name": "growHostVarsSpace" + }, + { + "name": "handleError" + }, + { + "name": "hasParentInjector" + }, + { + "name": "hasTagAndTypeMatch" + }, + { + "name": "hasValidLength" + }, + { + "name": "hostReportError" + }, + { + "name": "identity" + }, + { + "name": "includeViewProviders" + }, + { + "name": "incrementInitPhaseFlags" + }, + { + "name": "indexOf" + }, + { + "name": "inheritContentQueries" + }, + { + "name": "inheritHostBindings" + }, + { + "name": "inheritViewQuery" + }, + { + "name": "initTNodeFlags" + }, + { + "name": "injectArgs" + }, + { + "name": "injectInjectorOnly" + }, + { + "name": "injectRootLimpMode" + }, + { + "name": "injectableDefOrInjectorDefFactory" + }, + { + "name": "insertBloom" + }, + { + "name": "instructionState" + }, + { + "name": "invertObject" + }, + { + "name": "invokeHostBindingsInCreationMode" + }, + { + "name": "isAnimationProp" + }, + { + "name": "isArray" + }, + { + "name": "isArrayLike" + }, + { + "name": "isComponentDef" + }, + { + "name": "isComponentHost" + }, + { + "name": "isContentQueryHost" + }, + { + "name": "isCssClassMatching" + }, + { + "name": "isDirectiveHost" + }, + { + "name": "isEmptyInputValue" + }, + { + "name": "isForwardRef" + }, + { + "name": "isFunction" + }, + { + "name": "isInlineTemplate" + }, + { + "name": "isJsObject" + }, + { + "name": "isLContainer" + }, + { + "name": "isLView" + }, + { + "name": "isListLikeIterable" + }, + { + "name": "isNodeMatchingSelector" + }, + { + "name": "isNodeMatchingSelectorList" + }, + { + "name": "isObject" + }, + { + "name": "isOptionsObj" + }, + { + "name": "isPositive" + }, + { + "name": "isPresent" + }, + { + "name": "isProceduralRenderer" + }, + { + "name": "isPromise" + }, + { + "name": "isPromise" + }, + { + "name": "isPropertyUpdated" + }, + { + "name": "isRootView" + }, + { + "name": "isScheduler" + }, + { + "name": "isStylingMatch" + }, + { + "name": "isStylingValuePresent" + }, + { + "name": "isTypeProvider" + }, + { + "name": "isValueProvider" + }, + { + "name": "iterator" + }, + { + "name": "keyValDiff" + }, + { + "name": "keyValueArrayGet" + }, + { + "name": "keyValueArrayIndexOf" + }, + { + "name": "keyValueArraySet" + }, + { + "name": "leaveDI" + }, + { + "name": "leaveView" + }, + { + "name": "leaveViewLight" + }, + { + "name": "localeEn" + }, + { + "name": "makeParamDecorator" + }, + { + "name": "makeRecord" + }, + { + "name": "map" + }, + { + "name": "markAsComponentHost" + }, + { + "name": "markDuplicates" + }, + { + "name": "markViewDirty" + }, + { + "name": "maybeUnwrapEmpty" + }, + { + "name": "maybeUnwrapFn" + }, + { + "name": "maybeWrapInNotSelector" + }, + { + "name": "mergeAll" + }, + { + "name": "mergeHostAttribute" + }, + { + "name": "mergeHostAttrs" + }, + { + "name": "modelGroupProvider" + }, + { + "name": "modules" + }, + { + "name": "multiFactoryAdd" + }, + { + "name": "multiProvidersFactoryResolver" + }, + { + "name": "multiResolve" + }, + { + "name": "multiViewProvidersFactoryResolver" + }, + { + "name": "nativeAppendChild" + }, + { + "name": "nativeAppendOrInsertBefore" + }, + { + "name": "nativeInsertBefore" + }, + { + "name": "nativeParentNode" + }, + { + "name": "nextBindingIndex" + }, + { + "name": "nextNgElementId" + }, + { + "name": "ngOnChangesSetInput" + }, + { + "name": "noSideEffects" + }, + { + "name": "noop" + }, + { + "name": "noop" + }, + { + "name": "normalizeAsyncValidator" + }, + { + "name": "normalizeValidator" + }, + { + "name": "observable" + }, + { + "name": "onEnter" + }, + { + "name": "onLeave" + }, + { + "name": "optionsReducer" + }, + { + "name": "pickAsyncValidators" + }, + { + "name": "pickValidators" + }, + { + "name": "pipeFromArray" + }, + { + "name": "platformBrowser" + }, + { + "name": "platformCore" + }, + { + "name": "promise" + }, + { + "name": "providerToFactory" + }, + { + "name": "readPatchedLView" + }, + { + "name": "refCount" + }, + { + "name": "refreshComponent" + }, + { + "name": "refreshContentQueries" + }, + { + "name": "refreshView" + }, + { + "name": "registerDestroyHooksIfSupported" + }, + { + "name": "registerPostOrderHooks" + }, + { + "name": "rememberChangeHistoryAndInvokeOnChangesHook" + }, + { + "name": "remove" + }, + { + "name": "removeDir" + }, + { + "name": "removeFromArray" + }, + { + "name": "renderComponent" + }, + { + "name": "renderComponentOrTemplate" + }, + { + "name": "renderStringify" + }, + { + "name": "renderView" + }, + { + "name": "resetPreOrderHookFlags" + }, + { + "name": "resolveDirectives" + }, + { + "name": "resolveForwardRef" + }, + { + "name": "resolveProvider" + }, + { + "name": "resolvedPromise" + }, + { + "name": "resolvedPromise" + }, + { + "name": "rxSubscriber" + }, + { + "name": "saveNameToExportMap" + }, + { + "name": "saveResolvedLocalsInData" + }, + { + "name": "scheduleArray" + }, + { + "name": "scheduleMicroTask" + }, + { + "name": "searchTokensOnInjector" + }, + { + "name": "selectIndexInternal" + }, + { + "name": "selectValueAccessor" + }, + { + "name": "setBindingRootForHostBindings" + }, + { + "name": "setCheckNoChangesMode" + }, + { + "name": "setCurrentDirectiveIndex" + }, + { + "name": "setCurrentInjector" + }, + { + "name": "setCurrentQueryIndex" + }, + { + "name": "setDirectiveInputsWhichShadowsStyling" + }, + { + "name": "setIncludeViewProviders" + }, + { + "name": "setInjectImplementation" + }, + { + "name": "setInputsForProperty" + }, + { + "name": "setInputsFromAttrs" + }, + { + "name": "setLocaleId" + }, + { + "name": "setPreviousOrParentTNode" + }, + { + "name": "setSelectedIndex" + }, + { + "name": "setTStylingRangeNext" + }, + { + "name": "setTStylingRangeNextDuplicate" + }, + { + "name": "setTStylingRangePrevDuplicate" + }, + { + "name": "setUpAttributes" + }, + { + "name": "setUpControl" + }, + { + "name": "setUpFormContainer" + }, + { + "name": "shareSubjectFactory" + }, + { + "name": "shouldSearchParent" + }, + { + "name": "stringify" + }, + { + "name": "stringifyCSSSelector" + }, + { + "name": "stringifyForError" + }, + { + "name": "subscribeTo" + }, + { + "name": "subscribeToArray" + }, + { + "name": "syncPendingControls" + }, + { + "name": "throwMixedMultiProviderError" + }, + { + "name": "throwMultipleComponentError" + }, + { + "name": "toObservable" + }, + { + "name": "toRefArray" + }, + { + "name": "toTStylingRange" + }, + { + "name": "trackByIdentity" + }, + { + "name": "u" + }, + { + "name": "unimplemented" + }, + { + "name": "unwrapRNode" + }, + { + "name": "updateControl" + }, + { + "name": "updateMicroTaskStatus" + }, + { + "name": "updateTransplantedViewCount" + }, + { + "name": "viewAttachedToChangeDetector" + }, + { + "name": "wrapListener" + }, + { + "name": "writeDirectClass" + }, + { + "name": "writeDirectStyle" + }, + { + "name": "ɵAbstractFormGroupDirective_BaseFactory" + }, + { + "name": "ɵInternalFormsSharedModule" + }, + { + "name": "ɵNgNoValidate" + }, + { + "name": "ɵɵInheritDefinitionFeature" + }, + { + "name": "ɵɵNgOnChangesFeature" + }, + { + "name": "ɵɵProvidersFeature" + }, + { + "name": "ɵɵadvance" + }, + { + "name": "ɵɵattribute" + }, + { + "name": "ɵɵclassProp" + }, + { + "name": "ɵɵdefineComponent" + }, + { + "name": "ɵɵdefineDirective" + }, + { + "name": "ɵɵdefineInjectable" + }, + { + "name": "ɵɵdefineInjector" + }, + { + "name": "ɵɵdefineNgModule" + }, + { + "name": "ɵɵdirectiveInject" + }, + { + "name": "ɵɵelement" + }, + { + "name": "ɵɵelementEnd" + }, + { + "name": "ɵɵelementStart" + }, + { + "name": "ɵɵgetFactoryOf" + }, + { + "name": "ɵɵgetInheritedFactory" + }, + { + "name": "ɵɵinject" + }, + { + "name": "ɵɵlistener" + }, + { + "name": "ɵɵnextContext" + }, + { + "name": "ɵɵproperty" + }, + { + "name": "ɵɵtemplate" + }, + { + "name": "ɵɵtext" + } +] \ No newline at end of file diff --git a/packages/core/test/bundling/forms/forms_e2e_spec.ts b/packages/core/test/bundling/forms/forms_e2e_spec.ts new file mode 100644 index 0000000000..eacb295420 --- /dev/null +++ b/packages/core/test/bundling/forms/forms_e2e_spec.ts @@ -0,0 +1,67 @@ +/** + * @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 + */ + +import '@angular/compiler'; +import {ɵwhenRendered as whenRendered} from '@angular/core'; +import {withBody} from '@angular/private/testing'; +import * as path from 'path'; + +const PACKAGE = 'angular/packages/core/test/bundling/forms'; +const BUNDLES = ['bundle.js', 'bundle.min_debug.js', 'bundle.min.js']; + +describe('functional test for forms', () => { + BUNDLES.forEach((bundle) => { + describe(`using ${bundle} bundle`, () => { + it('should render template form', withBody('', async () => { + require(path.join(PACKAGE, bundle)); + await (window as any).waitForApp; + + // Template forms + const templateFormsComponent = (window as any).templateFormsComponent; + await whenRendered(templateFormsComponent); + + const templateForm = document.querySelector('app-template-forms')!; + + // Check for inputs + const iputs = templateForm.querySelectorAll('input'); + expect(iputs.length).toBe(5); + + // Check for button + const templateButtons = templateForm.querySelectorAll('button'); + expect(templateButtons.length).toBe(1); + expect(templateButtons[0]).toBeDefined(); + + // Make sure button click works + const templateFormSpy = spyOn(templateFormsComponent, 'addCity'); + templateButtons[0].click(); + expect(templateFormSpy).toHaveBeenCalled(); + + // Reactive forms + const reactiveFormsComponent = (window as any).reactiveFormsComponent; + await whenRendered(reactiveFormsComponent); + + const reactiveForm = document.querySelector('app-reactive-forms')!; + + // Check for inputs + const inputs = reactiveForm.querySelectorAll('input'); + expect(inputs.length).toBe(5); + + // Check for button + const reactiveButtons = reactiveForm.querySelectorAll('button'); + expect(reactiveButtons.length).toBe(1); + expect(reactiveButtons[0]).toBeDefined(); + + // Make sure button click works + const reactiveFormSpy = spyOn(reactiveFormsComponent, 'addCity').and.callThrough(); + reactiveButtons[0].click(); + expect(reactiveFormSpy).toHaveBeenCalled(); + expect(reactiveFormsComponent.addresses.length).toBe(2); + })); + }); + }); +}); diff --git a/packages/core/test/bundling/forms/index.html b/packages/core/test/bundling/forms/index.html new file mode 100644 index 0000000000..0703f0dbb5 --- /dev/null +++ b/packages/core/test/bundling/forms/index.html @@ -0,0 +1,32 @@ + + + + + Angular Forms Example + + + + + + + + + + diff --git a/packages/core/test/bundling/forms/index.ts b/packages/core/test/bundling/forms/index.ts new file mode 100644 index 0000000000..4a2e8d1294 --- /dev/null +++ b/packages/core/test/bundling/forms/index.ts @@ -0,0 +1,138 @@ +/** + * @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 + */ +import {Component, NgModule, ɵNgModuleFactory as NgModuleFactory} from '@angular/core'; +import {FormArray, FormBuilder, FormControl, FormGroup, FormsModule, NgForm, ReactiveFormsModule, Validators} from '@angular/forms'; +import {BrowserModule, platformBrowser} from '@angular/platform-browser'; + +@Component({ + selector: 'app-template-forms', + template: ` +
+
+
+ First Name: + +
+
+ Last Name: + +
+
+ Subscribe: + +
+ +
Disabled:
+ +
+ City +
+ + +
+
`, +}) +class TemplateFormsComponent { + name = {first: 'Nancy', last: 'Drew', subscribed: true}; + addresses = [{city: 'Toronto'}]; + constructor() { + // We use this reference in our test + (window as any).templateFormsComponent = this; + } + + addCity() { + this.addresses.push(({city: ''})); + } +} + +@Component({ + selector: 'app-reactive-forms', + template: ` +
+
+ First Name: + +
+
+ Last Name: + +
+ +
+ Subscribe: + +
+ +
Disabled:
+
+
+
City:
+
+
+ +
`, +}) +class ReactiveFormsComponent { + profileForm!: FormGroup; + addresses!: FormArray; + + get itemControls() { + return (this.profileForm.get('addresses') as FormArray).controls; + } + + constructor(private formBuilder: FormBuilder) { + // We use this reference in our test + (window as any).reactiveFormsComponent = this; + } + + ngOnInit() { + this.profileForm = new FormGroup({ + firstName: new FormControl('', Validators.required), + lastName: new FormControl(''), + addresses: new FormArray([]), + subscribed: new FormControl(), + disabledInput: new FormControl({value: '', disabled: true}), + }); + + this.addCity(); + } + + createItem(): FormGroup { + return this.formBuilder.group({ + city: '', + }); + } + + addCity(): void { + this.addresses = this.profileForm.get('addresses') as FormArray; + this.addresses.push(this.createItem()); + } +} + +@Component({ + selector: 'app-root', + template: ` + + + ` +}) +class RootComponent { +} + +@NgModule({ + declarations: [RootComponent, TemplateFormsComponent, ReactiveFormsComponent], + imports: [BrowserModule, FormsModule, ReactiveFormsModule] +}) +class FormsExampleModule { + ngDoBootstrap(app: any) { + app.bootstrap(RootComponent); + } +} + +(window as any).waitForApp = platformBrowser().bootstrapModuleFactory( + new NgModuleFactory(FormsExampleModule), {ngZone: 'noop'}); diff --git a/packages/core/test/bundling/forms/treeshaking_spec.ts b/packages/core/test/bundling/forms/treeshaking_spec.ts new file mode 100644 index 0000000000..546a88ee0a --- /dev/null +++ b/packages/core/test/bundling/forms/treeshaking_spec.ts @@ -0,0 +1,35 @@ +/** + * @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 + */ + +import '@angular/compiler'; +import * as fs from 'fs'; +import * as path from 'path'; + +const UTF8 = { + encoding: 'utf-8' +}; +const PACKAGE = 'angular/packages/core/test/bundling/forms'; + +describe('treeshaking with uglify', () => { + let content: string; + // We use the debug version as otherwise symbols/identifiers would be mangled (and the test would + // always pass) + const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js')); + beforeAll(() => { + content = fs.readFileSync(contentPath, UTF8); + }); + + it('should drop unused TypeScript helpers', () => { + expect(content).not.toContain('__asyncGenerator'); + }); + + it('should not contain rxjs from commonjs distro', () => { + expect(content).not.toContain('commonjsGlobal'); + expect(content).not.toContain('createCommonjsModule'); + }); +});