chore(ct): revert adapters imports and template
This commit is contained in:
parent
d83f9ee4a9
commit
69a6db45fd
13
packages/playwright-ct-angular/index.d.ts
vendored
13
packages/playwright-ct-angular/index.d.ts
vendored
|
|
@ -17,24 +17,18 @@
|
||||||
import type { Locator } from 'playwright/test';
|
import type { Locator } from 'playwright/test';
|
||||||
import type { JsonObject } from '@playwright/experimental-ct-core/types/component';
|
import type { JsonObject } from '@playwright/experimental-ct-core/types/component';
|
||||||
import type { TestType } from '@playwright/experimental-ct-core';
|
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<string, Function>;
|
export type ComponentEvents = Record<string, Function>;
|
||||||
|
|
||||||
export interface MountOptions<HooksConfig extends JsonObject, Component> {
|
export interface MountOptions<HooksConfig extends JsonObject, Component> {
|
||||||
props?: Partial<Component> | Record<string, unknown>, // TODO: filter props and handle signals
|
props?: Partial<Component> | Record<string, unknown>, // TODO: filter props and handle signals
|
||||||
providers?: Provider[],
|
|
||||||
on?: ComponentEvents;
|
on?: ComponentEvents;
|
||||||
hooksConfig?: HooksConfig;
|
hooksConfig?: HooksConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MountTemplateOptions<HooksConfig extends JsonObject, Component> extends MountOptions<HooksConfig, Component> {
|
|
||||||
imports?: Type<unknown>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MountResult<Component> extends Locator {
|
export interface MountResult<Component> extends Locator {
|
||||||
unmount(): Promise<void>;
|
unmount(): Promise<void>;
|
||||||
|
|
||||||
update(options: {
|
update(options: {
|
||||||
props?: Partial<Component>,
|
props?: Partial<Component>,
|
||||||
on?: Partial<ComponentEvents>,
|
on?: Partial<ComponentEvents>,
|
||||||
|
|
@ -42,11 +36,6 @@ export interface MountResult<Component> extends Locator {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentFixtures {
|
export interface ComponentFixtures {
|
||||||
mount<HooksConfig extends JsonObject, Component = unknown>(
|
|
||||||
template: string,
|
|
||||||
options?: MountTemplateOptions<HooksConfig, Component>
|
|
||||||
): Promise<MountResult<Component>>;
|
|
||||||
|
|
||||||
mount<HooksConfig extends JsonObject, Component = unknown>(
|
mount<HooksConfig extends JsonObject, Component = unknown>(
|
||||||
component: Type<Component>,
|
component: Type<Component>,
|
||||||
options?: MountOptions<HooksConfig, Component>
|
options?: MountOptions<HooksConfig, Component>
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
// This file is injected into the registry as text, no dependencies are allowed.
|
// This file is injected into the registry as text, no dependencies are allowed.
|
||||||
|
|
||||||
/**
|
/** @typedef {import('../playwright-ct-core/types/component').ObjectComponent} ObjectComponent */
|
||||||
* @typedef {{type: string} & import('./index').MountTemplateOptions} TemplateInfo
|
|
||||||
* @typedef {{type: import('@angular/core').Type<unknown>} & import('./index').MountOptions | TemplateInfo} ComponentInfo
|
|
||||||
*/
|
|
||||||
|
|
||||||
import 'zone.js';
|
import 'zone.js';
|
||||||
import {
|
import {
|
||||||
|
|
@ -33,13 +30,75 @@ import {
|
||||||
platformBrowserDynamicTesting,
|
platformBrowserDynamicTesting,
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
/** @type {WeakMap<import('@angular/core/testing').ComponentFixture, Record<string, import('rxjs').Subscription>>} */
|
||||||
|
const __pwOutputSubscriptionRegistry = new WeakMap();
|
||||||
|
|
||||||
|
/** @type {Map<string, import('@angular/core/testing').ComponentFixture>} */
|
||||||
|
const __pwFixtureRegistry = new Map();
|
||||||
|
|
||||||
getTestBed().initTestEnvironment(
|
getTestBed().initTestEnvironment(
|
||||||
BrowserDynamicTestingModule,
|
BrowserDynamicTestingModule,
|
||||||
platformBrowserDynamicTesting(),
|
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) => {
|
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 || [])
|
for (const hook of window.__pw_hooks_before_mount || [])
|
||||||
await hook({ hooksConfig, TestBed });
|
await hook({ hooksConfig, TestBed });
|
||||||
|
|
@ -66,116 +125,16 @@ window.playwrightUnmount = async rootElement => {
|
||||||
fixture.nativeElement.replaceChildren();
|
fixture.nativeElement.replaceChildren();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {{type: import('@angular/core').Type<unknown>} & import('./index').MountOptions | {type: string} & import('./index').MountTemplateOptions} component
|
|
||||||
*/
|
|
||||||
window.playwrightUpdate = async (rootElement, 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);
|
const fixture = __pwFixtureRegistry.get(rootElement.id);
|
||||||
if (!fixture)
|
if (!fixture)
|
||||||
throw new Error('Component was not mounted');
|
throw new Error('Component was not mounted');
|
||||||
|
|
||||||
__pwUpdateProps(fixture, component);
|
__pwUpdateProps(fixture, component.props);
|
||||||
__pwUpdateEvents(fixture, component.on);
|
__pwUpdateEvents(fixture, component.on);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @type {WeakMap<import('@angular/core/testing').ComponentFixture, Record<string, import('rxjs').Subscription>>} */
|
|
||||||
const __pwOutputSubscriptionRegistry = new WeakMap();
|
|
||||||
|
|
||||||
/** @type {Map<string, import('@angular/core/testing').ComponentFixture>} */
|
|
||||||
const __pwFixtureRegistry = new Map();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {ComponentInfo} component
|
|
||||||
*/
|
|
||||||
async function __pwRenderComponent(component) {
|
|
||||||
/** @type {import('@angular/core').Type<unknown>} */
|
|
||||||
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<unknown>} */(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';
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { InjectComponent, TOKEN } from "@/components/inject.component";
|
import { InjectComponent, TOKEN } from '@/components/inject.component';
|
||||||
import { expect, test } from "@playwright/experimental-ct-angular";
|
import { expect, test } from '@playwright/experimental-ct-angular';
|
||||||
|
import type { HooksConfig } from 'playwright';
|
||||||
|
|
||||||
test('inject a token', async ({ mount }) => {
|
test('inject a token', async ({ mount }) => {
|
||||||
const component = await mount(InjectComponent, {
|
const component = await mount<HooksConfig>(InjectComponent, {
|
||||||
providers: [{ provide: TOKEN, useValue: { text: 'has been overwritten' }}]
|
hooksConfig: { injectToken: true },
|
||||||
});
|
});
|
||||||
await expect(component).toHaveText('has been overwritten');
|
await expect(component).toHaveText('has been overwritten');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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('<h1>{{ 1 + 1 }}</h1>');
|
|
||||||
|
|
||||||
await expect(component).toHaveText('2');
|
|
||||||
})
|
|
||||||
|
|
||||||
test('render a template with child components', async ({ mount }) => {
|
|
||||||
const component = await mount('<app-button title="Click"/>', {
|
|
||||||
imports: [ButtonComponent]
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(component.getByRole('button')).toContainText('Click');
|
|
||||||
})
|
|
||||||
|
|
||||||
test('render a template with inputs', async ({ mount }) => {
|
|
||||||
const component = await mount('<app-button [title]="title"/>', {
|
|
||||||
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('<app-button (submit)="onSubmit($event)"/>', {
|
|
||||||
imports: [ButtonComponent],
|
|
||||||
props: {
|
|
||||||
title: 'Click',
|
|
||||||
onSubmit(message: string) {
|
|
||||||
_message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await component.getByRole('button').click();
|
|
||||||
|
|
||||||
await expect(async () => {expect(_message).toBe('hello')}).toPass();
|
|
||||||
})
|
|
||||||
Loading…
Reference in a new issue