Vmeda.Online/src/testing/utils.ts

139 lines
4.2 KiB
TypeScript
Raw Normal View History

// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, CUSTOM_ELEMENTS_SCHEMA, Type, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreSingletonClass } from '@singletons';
abstract class WrapperComponent<U> {
child!: U;
2020-10-07 09:13:54 +00:00
};
export interface RenderConfig {
declarations: unknown[];
providers: unknown[];
2020-10-07 09:13:54 +00:00
}
export type WrapperComponentFixture<T> = ComponentFixture<WrapperComponent<T>>;
export function mock<T>(instance?: Record<string, unknown>): T;
export function mock<T>(methods: string[], instance?: Record<string, unknown>): T;
export function mock<T>(
methodsOrInstance: string[] | Record<string, unknown> = [],
instance: Record<string, unknown> = {},
): T {
instance = Array.isArray(methodsOrInstance) ? instance : methodsOrInstance;
const methods = Array.isArray(methodsOrInstance) ? methodsOrInstance : [];
2020-10-07 09:13:54 +00:00
for (const method of methods) {
instance[method] = jest.fn();
2020-10-07 09:13:54 +00:00
}
return instance as T;
2020-10-07 09:13:54 +00:00
}
export function mockSingleton(singletonClass: CoreSingletonClass<unknown>, instance?: Record<string, unknown>): void;
2020-10-07 09:13:54 +00:00
export function mockSingleton(
singletonClass: CoreSingletonClass<unknown>,
methods: string[],
instance?: Record<string, unknown>,
): void;
export function mockSingleton(
singletonClass: CoreSingletonClass<unknown>,
methodsOrInstance: string[] | Record<string, unknown> = [],
instance: Record<string, unknown> = {},
2020-10-07 09:13:54 +00:00
): void {
instance = Array.isArray(methodsOrInstance) ? instance : methodsOrInstance;
const methods = Array.isArray(methodsOrInstance) ? methodsOrInstance : [];
singletonClass.setInstance(mock(methods, instance));
}
export async function renderComponent<T>(component: Type<T>, config: Partial<RenderConfig> = {}): Promise<ComponentFixture<T>> {
return renderAngularComponent(component, {
declarations: [],
providers: [],
...config,
});
}
export async function renderTemplate<T>(
component: Type<T>,
template: string,
config: Partial<RenderConfig> = {},
): Promise<WrapperComponentFixture<T>> {
config.declarations = config.declarations ?? [];
config.declarations.push(component);
return renderAngularComponent(
createWrapperComponent(template, component),
{
declarations: [],
providers: [],
...config,
},
);
2020-10-07 09:13:54 +00:00
}
export async function renderWrapperComponent<T>(
component: Type<T>,
tag: string,
inputs: Record<string, { toString() }> = {},
config: Partial<RenderConfig> = {},
): Promise<WrapperComponentFixture<T>> {
const inputAttributes = Object
.entries(inputs)
.map(([name, value]) => `${name}="${value.toString().replace(/"/g, '&quot;')}"`)
.join(' ');
return renderTemplate(component, `<${tag} ${inputAttributes}></${tag}>`, config);
}
async function renderAngularComponent<T>(component: Type<T>, config: RenderConfig): Promise<ComponentFixture<T>> {
config.declarations.push(component);
TestBed.configureTestingModule({
declarations: config.declarations,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: config.providers,
});
await TestBed.compileComponents();
2020-10-07 09:13:54 +00:00
const fixture = TestBed.createComponent(component);
2020-10-07 09:13:54 +00:00
fixture.autoDetectChanges(true);
2020-10-07 09:13:54 +00:00
await fixture.whenRenderingDone();
await fixture.whenStable();
2020-10-07 09:13:54 +00:00
return fixture;
}
function createWrapperComponent<U>(template: string, componentClass: Type<U>): Type<WrapperComponent<U>> {
@Component({ template })
class HostComponent extends WrapperComponent<U> {
@ViewChild(componentClass) child!: U;
}
return HostComponent;
}