From 69a6db45fda78f103c9b829534cb1c5027a70e2b Mon Sep 17 00:00:00 2001 From: sand4rt Date: Tue, 7 May 2024 18:49:56 +0200 Subject: [PATCH] chore(ct): revert adapters imports and template --- packages/playwright-ct-angular/index.d.ts | 13 +- .../playwright-ct-angular/registerSource.mjs | 175 +++++++----------- .../ct-angular/tests/injection.spec.ts | 9 +- .../ct-angular/tests/template.spec.ts | 44 ----- 4 files changed, 73 insertions(+), 168 deletions(-) delete mode 100644 tests/components/ct-angular/tests/template.spec.ts diff --git a/packages/playwright-ct-angular/index.d.ts b/packages/playwright-ct-angular/index.d.ts index c67b1a867e..583574f12b 100644 --- a/packages/playwright-ct-angular/index.d.ts +++ b/packages/playwright-ct-angular/index.d.ts @@ -17,24 +17,18 @@ import type { Locator } from 'playwright/test'; import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; -import type { Provider, Type } from '@angular/core'; +import type { Type } from '@angular/core'; export type ComponentEvents = Record; export interface MountOptions { props?: Partial | Record, // TODO: filter props and handle signals - providers?: Provider[], on?: ComponentEvents; hooksConfig?: HooksConfig; } -export interface MountTemplateOptions extends MountOptions { - imports?: Type[]; -} - export interface MountResult extends Locator { unmount(): Promise; - update(options: { props?: Partial, on?: Partial, @@ -42,11 +36,6 @@ export interface MountResult extends Locator { } export interface ComponentFixtures { - mount( - template: string, - options?: MountTemplateOptions - ): Promise>; - mount( component: Type, options?: MountOptions diff --git a/packages/playwright-ct-angular/registerSource.mjs b/packages/playwright-ct-angular/registerSource.mjs index b18aab7e48..4d54eeea15 100644 --- a/packages/playwright-ct-angular/registerSource.mjs +++ b/packages/playwright-ct-angular/registerSource.mjs @@ -17,10 +17,7 @@ // @ts-check // This file is injected into the registry as text, no dependencies are allowed. -/** - * @typedef {{type: string} & import('./index').MountTemplateOptions} TemplateInfo - * @typedef {{type: import('@angular/core').Type} & import('./index').MountOptions | TemplateInfo} ComponentInfo - */ +/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */ import 'zone.js'; import { @@ -33,13 +30,75 @@ import { platformBrowserDynamicTesting, } from '@angular/platform-browser-dynamic/testing'; +/** @type {WeakMap>} */ +const __pwOutputSubscriptionRegistry = new WeakMap(); + +/** @type {Map} */ +const __pwFixtureRegistry = new Map(); + getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting(), ); +/** + * @param {ObjectComponent} component + */ +async function __pwRenderComponent(component) { + const componentMetadata = reflectComponentType(component.type); + if (!componentMetadata?.isStandalone) + throw new Error('Only standalone components are supported'); + + TestBed.configureTestingModule({ + imports: [component.type], + }); + + await TestBed.compileComponents(); + + const fixture = TestBed.createComponent(component.type); + fixture.nativeElement.id = 'root'; + + __pwUpdateProps(fixture, component.props); + __pwUpdateEvents(fixture, component.on); + + fixture.autoDetectChanges(); + + return fixture; +} + +/** + * @param {import('@angular/core/testing').ComponentFixture} fixture + */ +function __pwUpdateProps(fixture, props = {}) { + for (const [name, value] of Object.entries(props)) + fixture.componentRef.setInput(name, value); +} + +/** + * @param {import('@angular/core/testing').ComponentFixture} fixture + */ +function __pwUpdateEvents(fixture, events = {}) { + const outputSubscriptionRecord = + __pwOutputSubscriptionRegistry.get(fixture) ?? {}; + for (const [name, listener] of Object.entries(events)) { + /* Unsubscribe previous listener. */ + outputSubscriptionRecord[name]?.unsubscribe(); + + const subscription = fixture.componentInstance[ + name + ].subscribe((/** @type {unknown} */ event) => listener(event)); + + /* Store new subscription. */ + outputSubscriptionRecord[name] = subscription; + } + + /* Update output subscription registry. */ + __pwOutputSubscriptionRegistry.set(fixture, outputSubscriptionRecord); +} + window.playwrightMount = async (component, rootElement, hooksConfig) => { - __pwAssertIsNotJsx(component); + if (component.__pw_type === 'jsx') + throw new Error('JSX mount notation is not supported'); for (const hook of window.__pw_hooks_before_mount || []) await hook({ hooksConfig, TestBed }); @@ -66,116 +125,16 @@ window.playwrightUnmount = async rootElement => { fixture.nativeElement.replaceChildren(); }; -/** - * @param {{type: import('@angular/core').Type} & import('./index').MountOptions | {type: string} & import('./index').MountTemplateOptions} component - */ window.playwrightUpdate = async (rootElement, component) => { - __pwAssertIsNotJsx(component); + if (component.__pw_type === 'jsx') + throw new Error('JSX mount notation is not supported'); const fixture = __pwFixtureRegistry.get(rootElement.id); if (!fixture) throw new Error('Component was not mounted'); - __pwUpdateProps(fixture, component); + __pwUpdateProps(fixture, component.props); __pwUpdateEvents(fixture, component.on); fixture.detectChanges(); }; - -/** @type {WeakMap>} */ -const __pwOutputSubscriptionRegistry = new WeakMap(); - -/** @type {Map} */ -const __pwFixtureRegistry = new Map(); - -/** - * @param {ComponentInfo} component - */ -async function __pwRenderComponent(component) { - /** @type {import('@angular/core').Type} */ - let componentClass; - - if (__pwIsTemplate(component)) { - const templateInfo = /** @type {TemplateInfo} */(component); - componentClass = defineComponent({ - standalone: true, - selector: 'pw-template-component', - imports: templateInfo.imports, - template: templateInfo.type, - })(class {}); - } else { - componentClass = /** @type {import('@angular/core').Type} */(component.type); - } - - const componentMetadata = reflectComponentType(componentClass); - if (!componentMetadata?.isStandalone) - throw new Error('Only standalone components are supported'); - - TestBed.configureTestingModule({ - imports: [componentClass], - providers: component.providers, - }); - - await TestBed.compileComponents(); - - const fixture = TestBed.createComponent(componentClass); - fixture.nativeElement.id = 'root'; - - __pwUpdateProps(fixture, component); - __pwUpdateEvents(fixture, component.on); - - fixture.autoDetectChanges(); - - return fixture; -} - -/** - * @param {import('@angular/core/testing').ComponentFixture} fixture - * @param {ComponentInfo} componentInfo - */ -function __pwUpdateProps(fixture, componentInfo) { - if (!componentInfo.props) - return; - - if (__pwIsTemplate(componentInfo)) { - Object.assign(fixture.componentInstance, componentInfo.props); - } else { - for (const [name, value] of Object.entries(componentInfo.props)) - fixture.componentRef.setInput(name, value); - } - -} - -/** - * @param {import('@angular/core/testing').ComponentFixture} fixture - */ -function __pwUpdateEvents(fixture, events = {}) { - const outputSubscriptionRecord = - __pwOutputSubscriptionRegistry.get(fixture) ?? {}; - for (const [name, listener] of Object.entries(events)) { - /* Unsubscribe previous listener. */ - outputSubscriptionRecord[name]?.unsubscribe(); - - const subscription = fixture.componentInstance[ - name - ].subscribe((/** @type {unknown} */ event) => listener(event)); - - /* Store new subscription. */ - outputSubscriptionRecord[name] = subscription; - } - - /* Update output subscription registry. */ - __pwOutputSubscriptionRegistry.set(fixture, outputSubscriptionRecord); -} - -function __pwAssertIsNotJsx(component) { - if (component.__pw_type === 'jsx') - throw new Error('JSX mount notation is not supported'); -} - -/** - * @param {ComponentInfo} component - */ -function __pwIsTemplate(component) { - return typeof component.type === 'string'; -} diff --git a/tests/components/ct-angular/tests/injection.spec.ts b/tests/components/ct-angular/tests/injection.spec.ts index cc5f01087a..c284ca1b1a 100644 --- a/tests/components/ct-angular/tests/injection.spec.ts +++ b/tests/components/ct-angular/tests/injection.spec.ts @@ -1,9 +1,10 @@ -import { InjectComponent, TOKEN } from "@/components/inject.component"; -import { expect, test } from "@playwright/experimental-ct-angular"; +import { InjectComponent, TOKEN } from '@/components/inject.component'; +import { expect, test } from '@playwright/experimental-ct-angular'; +import type { HooksConfig } from 'playwright'; test('inject a token', async ({ mount }) => { - const component = await mount(InjectComponent, { - providers: [{ provide: TOKEN, useValue: { text: 'has been overwritten' }}] + const component = await mount(InjectComponent, { + hooksConfig: { injectToken: true }, }); await expect(component).toHaveText('has been overwritten'); }); diff --git a/tests/components/ct-angular/tests/template.spec.ts b/tests/components/ct-angular/tests/template.spec.ts deleted file mode 100644 index 52e0263e36..0000000000 --- a/tests/components/ct-angular/tests/template.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ButtonComponent } from "@/components/button.component"; -import { expect, test } from "@playwright/experimental-ct-angular" - -test('render a template', async ({ mount }) => { - const component = await mount('

{{ 1 + 1 }}

'); - - await expect(component).toHaveText('2'); -}) - -test('render a template with child components', async ({ mount }) => { - const component = await mount('', { - imports: [ButtonComponent] - }); - - await expect(component.getByRole('button')).toContainText('Click'); -}) - -test('render a template with inputs', async ({ mount }) => { - const component = await mount('', { - imports: [ButtonComponent], - props: { - title: 'Click', - } - }); - - await expect(component.getByRole('button')).toContainText('Click'); -}) - -test('render a template with outputs', async ({ mount }) => { - let _message: string; - const component = await mount('', { - imports: [ButtonComponent], - props: { - title: 'Click', - onSubmit(message: string) { - _message = message; - } - } - }); - - await component.getByRole('button').click(); - - await expect(async () => {expect(_message).toBe('hello')}).toPass(); -})