Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions .eslintrc.js

This file was deleted.

2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ LICENSE
.gitignore
.prettierignore
.npmrc
bun.lock
package-lock.json
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Any additonal support would be very appreciated! Please reach out if you want to

| Angular | shallow-render |
| ------- | -------------- |
| 21x | 21x |
| 20x | 20x |
| 19x | 19x |
| 18x | 18x |
Expand Down
26 changes: 26 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const tseslint = require('typescript-eslint');
const angular = require('angular-eslint');

module.exports = tseslint.config(
{
ignores: ['dist/**', 'coverage/**'],
},
{
files: ['**/*.ts'],
extends: [...tseslint.configs.recommended, ...angular.configs.tsRecommended],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-console': 'error',
'@angular-eslint/prefer-standalone': 'off',
'@angular-eslint/prefer-inject': 'off',
},
},
{
files: ['**/*.spec.ts'],
rules: {
'@angular-eslint/no-input-rename': 'off',
'@angular-eslint/no-output-rename': 'off',
},
},
);
3 changes: 2 additions & 1 deletion lib/models/recursive-partial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import { InputSignal, InputSignalWithTransform } from '@angular/core';

export type RecursivePartial<T> = Partial<{
[key in keyof T]: T[key] extends InputSignal<infer U> | InputSignalWithTransform<any, infer U> // Handle signals like input() and input.required()
[key in keyof T]: T[key] extends
InputSignal<infer U> | InputSignalWithTransform<any, infer U> // Handle signals like input() and input.required()
? RecursivePartial<U> // Extract the type and recursively apply RecursivePartial
: T[key] extends (...a: Array<infer U>) => any // Function-based properties (like methods or other signals)
? (...a: Array<U>) => RecursivePartial<ReturnType<T[key]>> | ReturnType<T[key]>
Expand Down
1 change: 0 additions & 1 deletion lib/models/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export class Renderer<TComponent extends object> {
mockStatics(this._setup);
injectRootProviders(this._setup);

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const resolvedTestComponent = reflect.resolveDirective(this._setup.testComponentOrService)!;
if (!template) {
// If no template is used, the bindings should be verified to match the
Expand Down
4 changes: 2 additions & 2 deletions lib/models/rendering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ describe('Rendering', () => {
it('can be destructured', () => {
const { find } = new Rendering(fixture, element, instance, {}, testSetup);

expect(() => find('some-css-selector')).not.toThrowError();
expect(() => find('some-css-selector')).not.toThrow();
});

it('throws an error when used to find the test component by CSS', () => {
Expand Down Expand Up @@ -363,7 +363,7 @@ describe('Rendering', () => {
const found = findStructuralDirective(OtherDirective);

// tslint:disable-next-line no-void-expression
expect(() => renderStructuralDirective(found)).toThrowError(/You may only manually.*OtherDirective/);
expect(() => renderStructuralDirective(found)).toThrow(/You may only manually.*OtherDirective/);
});
});

Expand Down
4 changes: 2 additions & 2 deletions lib/models/rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class Rendering<TComponent extends object, TBindings> {
.map(result => {
try {
return result.injector.get<TDirective>(directiveOrMock);
} catch (e) {
} catch {
return undefined;
}
})
Expand Down Expand Up @@ -235,7 +235,7 @@ export class Rendering<TComponent extends object, TBindings> {
if (instance) {
return options && options.query ? options.query(instance) : true;
}
} catch (e) {}
} catch {}
return false;
})
.map(node => node.injector.get<TDirective>(directiveClass)),
Expand Down
4 changes: 2 additions & 2 deletions lib/models/test-setup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ describe('TestSetup', () => {
class MyStandaloneComponent {}

it('throws an error when no module is specified with a non-standalone component', () => {
expect(() => new TestSetup(MyTestComponent)).toThrowError(/A module must be specified/);
expect(() => new TestSetup(MyTestComponent)).toThrow(/A module must be specified/);
});

it('throws an error when a module is specified with a standalone component', () => {
expect(() => new TestSetup(MyStandaloneComponent, class {})).toThrowError(
expect(() => new TestSetup(MyStandaloneComponent, class {})).toThrow(
/Do not specify a module when testing .*\bstandalone\b/,
);
});
Expand Down
2 changes: 1 addition & 1 deletion lib/models/test-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class TestSetup<TTestTarget> {
readonly mocks = new Map();
readonly staticMocks = new Map();
readonly moduleReplacements = new Map<AngularModule, AngularModule>();
// eslint-disable-next-line @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
readonly mockPipes = new Map<PipeTransform | Type<PipeTransform>, Function>();
readonly mockCache = new MockCache();
readonly providers: Provider[] = [];
Expand Down
6 changes: 3 additions & 3 deletions lib/shallow.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { InjectionToken, PipeTransform, Provider, Type } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
import { BrowserModule } from '@angular/platform-browser';
import { RecursivePartial } from './models/recursive-partial';
import { Renderer } from './models/renderer';
import { Rendering, RenderOptions } from './models/rendering';
Expand Down Expand Up @@ -97,7 +97,7 @@ export class Shallow<TTestTarget extends object> {
this._alwaysMockPipes.set(pipe, transform);
return this;
}
// eslint-disable-next-line @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
private static readonly _alwaysMockPipes = new Map<PipeTransform | Type<PipeTransform>, Function>();

/**
Expand Down Expand Up @@ -443,7 +443,7 @@ export class Shallow<TTestTarget extends object> {
}
}

Shallow.neverMock(CommonModule, BrowserModule, FormsModule, ReactiveFormsModule, HAMMER_GESTURE_CONFIG);
Shallow.neverMock(CommonModule, BrowserModule, FormsModule, ReactiveFormsModule);

if (typeof jest === 'undefined') {
// Karma runs in one browser instance which can result in a buildup
Expand Down
2 changes: 1 addition & 1 deletion lib/test-frameworks/shallow-matchers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-namespace */
/* eslint-disable @typescript-eslint/no-empty-interface */
/* eslint-disable @typescript-eslint/no-empty-object-type */
import { QueryMatch } from '../models/query-match';
export interface ShallowMatchers {
toHaveFoundOne(): void;
Expand Down
36 changes: 25 additions & 11 deletions lib/tools/clear-angular-cache.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import { ɵdepsTracker } from '@angular/core';

// Expose private cache variables
const depsTracker: { [K in keyof typeof ɵdepsTracker]: (typeof ɵdepsTracker)[K] } & {
ownerNgModule: Map<unknown, unknown>;
ngModulesWithSomeUnresolvedDecls: Set<unknown>;
ngModulesScopeCache: Map<unknown, unknown>;
standaloneComponentsScopeCache: Map<unknown, unknown>;
} = ɵdepsTracker as any;
const depsTracker = ɵdepsTracker as unknown as Record<string, unknown>;

type Clearable = { clear(): void };

const resetCache = (key: string): void => {
const value = depsTracker[key];
if (value == null) {
return;
}
if (value instanceof Map || value instanceof Set) {
(value as Clearable).clear();
return;
}
if (value instanceof WeakMap) {
depsTracker[key] = new WeakMap();
return;
}
if (value instanceof WeakSet) {
depsTracker[key] = new WeakSet();
}
};

/**
* Clears Angular DepsTracker cache
*/
export const clearAngularCache = () => {
depsTracker.ownerNgModule.clear();
depsTracker.ngModulesWithSomeUnresolvedDecls.clear();
depsTracker.ngModulesScopeCache.clear();
depsTracker.standaloneComponentsScopeCache.clear();
resetCache('ownerNgModule');
resetCache('ngModulesWithSomeUnresolvedDecls');
resetCache('ngModulesScopeCache');
resetCache('standaloneComponentsScopeCache');
};
1 change: 0 additions & 1 deletion lib/tools/create-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export function createContainer(
imports?: any[],
standalone?: boolean,
): Type<ShallowRenderContainer> {
// eslint-disable-next-line @angular-eslint/prefer-standalone
@Component({ template, imports, standalone })
class ProxyShallowContainerComponent extends ShallowRenderContainer {
private bindings: any;
Expand Down
1 change: 0 additions & 1 deletion lib/tools/mock-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export function mockDirective<TDirective extends Type<any>>(
directive: TDirective,
config?: { stubs?: object; renderContentsOnInit?: boolean },
): TDirective {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { selector, exportAs, standalone } = reflect.resolveDirective(directive);
@MockOf(directive)
@Directive({
Expand Down
2 changes: 1 addition & 1 deletion lib/tools/ng-mock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe('ng-mock', () => {
throw new Error('BOOM');
});

expect(() => ngMock(BadComponent, testSetup)).toThrowError(/Shallow.*BadComponent[\s\S]*BOOM/g);
expect(() => ngMock(BadComponent, testSetup)).toThrow(/Shallow.*BadComponent[\s\S]*BOOM/g);
});

it('mocks a component', () => {
Expand Down
2 changes: 1 addition & 1 deletion lib/tools/output-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class PropertyNotAnEventEmitterOrSignalOutputError extends CustomError {
}
}

// eslint-disable-next-line @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
export const outputProxy = <TComponent extends Object>(component: TComponent): PickByType<TComponent, OutputTypes> => {
const outputs = reflect.getInputsAndOutputs(component.constructor).outputs.map(o => o.propertyName);

Expand Down
Loading