@testing-library/angular
Version:
Test your Angular components with the dom-testing-library
1 lines • 13.9 kB
Source Map (JSON)
{"version":3,"file":"testing-library-angular-zoneless.mjs","sources":["../../../../projects/testing-library/zoneless/src/public_api.ts","../../../../projects/testing-library/zoneless/src/testing-library-angular-zoneless.ts"],"sourcesContent":["import {\n Component,\n isStandalone,\n type Binding,\n type EnvironmentProviders,\n type Provider,\n type Type,\n} from '@angular/core';\nimport { ComponentFixture, TestBed } from '@angular/core/testing';\nimport {\n getQueriesForElement,\n prettyDOM,\n type BoundFunctions,\n type PrettyDOMOptions,\n type queries,\n type Queries,\n} from '@testing-library/dom';\n\nexport type RenderResultQueries<Q extends Queries = typeof queries> = BoundFunctions<Q>;\n\nexport interface RenderResult<ComponentType, WrapperType = ComponentType> extends RenderResultQueries {\n /**\n * @description\n * The containing DOM node of your rendered Angular Component.\n * This is a regular DOM node, so you can call container.querySelector etc. to inspect the children.\n */\n container: HTMLElement;\n\n /**\n * @description\n * Prints out the component's DOM with syntax highlighting.\n * Accepts an optional parameter, to print out a specific DOM node.\n *\n * @param\n * element: The to be printed HTML element, if not provided it will log the whole component's DOM\n */\n debug: (\n element?: Element | Document | (Element | Document)[],\n maxLength?: number,\n options?: PrettyDOMOptions,\n ) => void;\n\n /**\n * @description\n * The Angular `ComponentFixture` of the component or the wrapper.\n * If a template is provided, it will be the fixture of the wrapper.\n *\n * For more info see https://angular.io/api/core/testing/ComponentFixture\n */\n fixture: ComponentFixture<WrapperType>;\n}\n\nexport interface RenderOptions<Q extends Queries = typeof queries> {\n /**\n * @description\n * Queries to bind. Overrides the default set from DOM Testing Library unless merged.\n *\n * @default\n * undefined\n *\n * @example\n * import * as customQueries from 'custom-queries'\n * import { queries } from '@testing-library/angular'\n *\n * await render(AppComponent, {\n * queries: { ...queries, ...customQueries }\n * })\n */\n queries?: Q;\n\n /**\n * @description\n * Callback to configure the testbed before the compilation.\n *\n * @default\n * () => {}\n *\n * @example\n * await render(AppComponent, {\n * configureTestBed: (testBed) => { }\n * })\n */\n configureTestBed?: (testbed: TestBed) => void;\n\n /**\n * @description\n * Determines whether `fixture.detectChanges()` is called after the component is rendered.\n *\n * @default\n * true\n *\n * @example\n * await render(AppComponent, {\n * skipDetectChanges: false\n * })\n */\n skipDetectChanges?: boolean;\n\n /**\n * @description\n * Determines whether `fixture.whenStable()` is called after the component is rendered.\n *\n * @default\n * true\n *\n * @example\n * await render(AppComponent, {\n * waitForStableOnRender: false\n * })\n */\n waitForStableOnRender?: boolean;\n\n /**\n * @description\n * An array of providers to be added to the testbed.\n */\n providers?: (Provider | EnvironmentProviders)[];\n}\n\nexport interface ImportOverride {\n /** The import to replace (matched by identity) */\n replace: Type<unknown>;\n /** The replacement import to use instead */\n with: Type<unknown> | unknown[];\n}\n\nexport interface RenderComponentOptions<Q extends Queries = typeof queries> extends RenderOptions<Q> {\n /**\n * @description\n * An array of bindings to apply to the component using Angular's native bindings API.\n * This provides a more direct way to bind inputs and outputs compared to the `inputs` and `on` options.\n *\n * @default\n * []\n *\n * @example\n * import { inputBinding, outputBinding, twoWayBinding } from '@angular/core';\n * import { signal } from '@angular/core';\n *\n * await render(AppComponent, {\n * bindings: [\n * inputBinding('value', () => 'test value'),\n * outputBinding('click', (event) => console.log(event)),\n * twoWayBinding('name', signal('initial value'))\n * ]\n * })\n */\n bindings?: Binding[];\n\n /**\n * @description\n * Replace specific imports on a standalone component. This is useful for mocking dependencies of the component under test.\n *\n * @default\n * undefined\n *\n * @example\n * await render(AppComponent, {\n * importOverrides: [\n * { replace: RealChildComponent, with: MockChildComponent }\n * ]\n * })\n */\n importOverrides?: ImportOverride[];\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface RenderTemplateOptions<WrapperType, Properties extends object = {}, Q extends Queries = typeof queries>\n extends RenderOptions<Q> {\n /**\n * @description\n * An Angular component to wrap the component in.\n * The template will be overridden with the `template` option.\n * NOTE: A standalone component cannot be used as a wrapper.\n *\n * @default\n * `WrapperComponent`, a basic empty component.\n *\n * @example\n * await render(`<div spoiler message='SPOILER'></div>`, {\n * declarations: [SpoilerDirective]\n * wrapper: CustomWrapperComponent\n * })\n */\n wrapper?: Type<WrapperType>;\n\n /**\n * @description\n * An object of properties to set on the wrapper component instance.\n * This allows you to set input properties on the wrapper component, which can be useful for testing content projection or other wrapper-related functionality.\n *\n * @default\n * undefined\n *\n * @example\n * await render(`<div>{{ message }}</div>`, {\n * wrapperProperties: { message: 'Hello World' }\n * })\n */\n wrapperProperties?: Partial<Properties>;\n\n /**\n * @description\n * An array of modules to be imported into the testbed.\n */\n imports?: any[];\n}\n\nexport async function render<ComponentType>(\n component: Type<ComponentType>,\n renderOptions?: RenderComponentOptions,\n): Promise<RenderResult<ComponentType, ComponentType>>;\nexport async function render<WrapperType = WrapperComponent>(\n template: string,\n renderOptions?: RenderTemplateOptions<WrapperType>,\n): Promise<RenderResult<WrapperType>>;\nexport async function render<ComponentType, WrapperType = ComponentType>(\n componentOrTemplate: Type<ComponentType> | string,\n renderOptions: RenderComponentOptions | RenderTemplateOptions<WrapperType> = {},\n): Promise<RenderResult<ComponentType, ComponentType | WrapperType>> {\n TestBed.configureTestingModule({\n declarations: [WrapperComponent],\n imports: 'imports' in renderOptions ? renderOptions.imports : [],\n providers: renderOptions.providers ?? [],\n });\n\n if ('importOverrides' in renderOptions && (renderOptions as RenderComponentOptions).importOverrides?.length) {\n const sut = componentOrTemplate as Type<unknown>;\n if (typeof sut === 'function' && isStandalone(sut)) {\n const overrides = (renderOptions as RenderComponentOptions).importOverrides!;\n TestBed.overrideComponent(sut, {\n remove: { imports: overrides.map((o) => o.replace) },\n add: { imports: overrides.map((o) => o.with) },\n });\n } else {\n throw new Error(\n `Error while rendering: Cannot specify importOverrides on a template or non-standalone component.`,\n );\n }\n }\n\n renderOptions.configureTestBed?.(TestBed);\n await TestBed.compileComponents();\n\n const fixture =\n typeof componentOrTemplate === 'string'\n ? await createWrapperFixture(componentOrTemplate, (renderOptions ?? {}) as RenderTemplateOptions<WrapperType>)\n : await createComponentFixture(componentOrTemplate, (renderOptions ?? {}) as RenderComponentOptions);\n\n if (renderOptions.skipDetectChanges !== true) {\n fixture.detectChanges();\n }\n\n if (renderOptions.waitForStableOnRender === true) {\n await fixture.whenStable();\n }\n\n return {\n fixture,\n container: fixture.nativeElement,\n debug: (element = fixture.nativeElement, maxLength?: number, options?: PrettyDOMOptions) => {\n if (Array.isArray(element)) {\n for (const e of element) {\n console.log(prettyDOM(e, maxLength, options));\n }\n } else {\n console.log(prettyDOM(element, maxLength, options));\n }\n },\n ...getQueriesForElement(fixture.nativeElement, renderOptions?.queries),\n };\n}\n\nasync function createComponentFixture<SutType>(\n sut: Type<SutType>,\n options: RenderComponentOptions,\n): Promise<ComponentFixture<SutType>> {\n return TestBed.createComponent(sut, { bindings: options.bindings || [] });\n}\n\nasync function createWrapperFixture<WrapperType>(\n sut: string,\n options: RenderTemplateOptions<WrapperType>,\n): Promise<ComponentFixture<WrapperType>> {\n const wrapper = options.wrapper ?? (WrapperComponent as Type<WrapperType>);\n TestBed.overrideTemplate(wrapper, sut);\n const fixture = TestBed.createComponent(wrapper);\n setWrapperProperties(fixture, options.wrapperProperties);\n return fixture;\n}\n\nfunction setWrapperProperties<SutType>(\n fixture: ComponentFixture<SutType>,\n wrapperProperties: RenderTemplateOptions<SutType, any>['wrapperProperties'] = {},\n) {\n for (const key of Object.keys(wrapperProperties)) {\n const descriptor = Object.getOwnPropertyDescriptor((fixture.componentInstance as any).constructor.prototype, key);\n let _value = wrapperProperties[key];\n const defaultGetter = () => _value;\n const extendedSetter = (value: any) => {\n _value = value;\n descriptor?.set?.call(fixture.componentInstance, _value);\n fixture.changeDetectorRef.detectChanges();\n };\n\n Object.defineProperty(fixture.componentInstance, key, {\n get: descriptor?.get || defaultGetter,\n set: extendedSetter,\n // Allow the property to be defined again later.\n // This happens when the component properties are updated after initial render.\n // For Jest this is `true` by default, for Karma and a real browser the default is `false`\n configurable: true,\n });\n\n descriptor?.set?.call(fixture.componentInstance, _value);\n }\n return fixture;\n}\n\n@Component({\n selector: 'atl-wrapper-component',\n template: '',\n standalone: false,\n})\nclass WrapperComponent {}\n\nexport * from '@testing-library/dom';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}