This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new cbe90c74c4 chore(frontend): clean up template-override anti-pattern in
component specs (#5189)
cbe90c74c4 is described below
commit cbe90c74c479b8b29b1a02a71a29c1bb17e7d7bd
Author: Yicong Huang <[email protected]>
AuthorDate: Sun May 24 15:39:11 2026 -0700
chore(frontend): clean up template-override anti-pattern in component specs
(#5189)
### What changes were proposed in this PR?
Three coordinated passes against the "specs that replace the parent
template at test time" anti-pattern:
1. **`frontend/TESTING.md`**: anti-patterns 2 and 3 are rewritten to
describe what actually goes wrong (the real `.component.html` never
executes, so v8 coverage stays at 0%), and a new Recipe F + anti-pattern
8 cover the right way to handle a heavy child component when one truly
cannot be instantiated — additive `overrideComponent({ remove, add })`
with a minimal stub child.
2. **Spec cleanups**: every spec that carried `template: ""`, a
stub-markup template substitute, `NO_ERRORS_SCHEMA`, or the broader
`set: { imports: [], schemas: [...] }` override is migrated to render
the real template. Two specs (Formly-driven and the full
WorkspaceComponent) keep the old shape behind a scoped `eslint-disable`
with a TODO; both need a more thorough redesign that isn't in scope
here.
3. **ESLint guardrail**: an `*.spec.ts` override in `.eslintrc.json`
blocks the patterns going forward — `NO_ERRORS_SCHEMA` imports from
`@angular/core`, any `template` or `imports` key inside
`overrideComponent({ set: ... })`. Each rule's message points at the
right replacement.
### Any related issues, documentation, discussions?
Closes #5188. Builds on the testing guide introduced in #5170 and the
lint-guardrail pattern from #5185.
### How was this PR tested?
`yarn ng test --watch=false --include=…` over the touched specs runs 13
files / 108 tests, all green. `yarn lint` and `yarn format:ci` both
clean. The three template files that originally pinned at 0% —
`preset-wrapper.component.html`, `operator-menu.component.html`,
`menu.component.html` — now report 44 / 79 / 59% line coverage under the
new shape.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Opus 4.7
---
frontend/.eslintrc.json | 13 +++++
frontend/TESTING.md | 61 ++++++++++++++++++++--
.../preset-wrapper.component.spec.ts | 4 --
.../admin/user/admin-user.component.spec.ts | 2 -
.../user/filters/filters.component.spec.ts | 2 -
.../user/list-item/list-item.component.spec.ts | 2 -
.../user-computing-unit.component.spec.ts | 2 -
.../user/user-icon/user-icon.component.spec.ts | 2 -
.../user/user-quota/user-quota.component.spec.ts | 2 -
.../left-panel/left-panel.component.spec.ts | 8 ---
.../operator-menu/operator-menu.component.spec.ts | 8 ---
.../component/menu/menu.component.spec.ts | 11 ++--
.../operator-property-edit-frame.component.spec.ts | 10 +++-
.../property-editor.component.spec.ts | 8 ---
.../component/workspace.component.spec.ts | 10 ++++
15 files changed, 91 insertions(+), 54 deletions(-)
diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json
index 5f6979335e..261ea9f2c0 100644
--- a/frontend/.eslintrc.json
+++ b/frontend/.eslintrc.json
@@ -118,6 +118,11 @@
"name": "@angular/common/http",
"importNames": ["HttpClientModule"],
"message": "Use HttpClientTestingModule from
'@angular/common/http/testing' in specs. HttpClientTestingModule supplies
HttpClient and routes requests through HttpTestingController instead of hitting
a real backend."
+ },
+ {
+ "name": "@angular/core",
+ "importNames": ["NO_ERRORS_SCHEMA"],
+ "message": "NO_ERRORS_SCHEMA silences template errors at the
cost of hiding real bugs (Angular docs warn against it). For standalone
components, the parent's `imports:` array already pulls children transitively,
so the schema is usually unnecessary. If a child component's ngOnInit fails
because of a missing service method, expand the service stub instead. If a
child genuinely cannot be instantiated, stub it via `overrideComponent({
remove: { imports: [Real] }, add: { impo [...]
}
]
}
@@ -127,6 +132,14 @@
{
"selector": "Property[key.name='providers'] > ArrayExpression >
Identifier[name='HttpClient']",
"message": "Don't list HttpClient as a bare provider in a spec.
HttpClientTestingModule (imported in 'imports') provides it; adding it to
'providers' on top of that overrides the testing backend with the real
HttpClient."
+ },
+ {
+ "selector":
"CallExpression[callee.property.name='overrideComponent']
Property[key.name='set'] > ObjectExpression > Property[key.name='template']",
+ "message": "Don't replace the component's template via
`overrideComponent({ set: { template: ... } })` — any substitution (empty
string, stub markup, anything) pins the real .component.html to 0% coverage and
skips testing the template-to-class bindings. If a child component blocks
instantiation, stub it via `overrideComponent({ remove: { imports: [Real] },
add: { imports: [Stub] } })`. If a service method is missing for a child's
ngOnInit, expand the service stub."
+ },
+ {
+ "selector":
"CallExpression[callee.property.name='overrideComponent']
Property[key.name='set'] > ObjectExpression > Property[key.name='imports']",
+ "message": "Avoid `overrideComponent({ set: { imports: ... } })` —
the `set` form for imports has known bugs in Angular standalone components (see
angular/angular#48432). Use the additive form `overrideComponent({ remove: {
imports: [Real] }, add: { imports: [Stub] } })` instead."
}
]
}
diff --git a/frontend/TESTING.md b/frontend/TESTING.md
index 67048e783e..da28d41e1f 100644
--- a/frontend/TESTING.md
+++ b/frontend/TESTING.md
@@ -206,6 +206,40 @@ it("debounces the query before firing", fakeAsync(() => {
`fakeAsync` works because `test-zone-setup.ts` installs a ProxyZone around
`it`/`test`. It does **not** install one around `beforeEach`, so do not write
`beforeEach(fakeAsync(...))` — set component state and call `tick()` from
inside the `it` body instead.
+### F. Stub a child component (rare, only when the child can't be instantiated)
+
+Standalone parents pull their `imports:` graph in transitively, so most child
components instantiate cleanly. Reach for this recipe only when a child
genuinely can't run under jsdom — e.g. it requires WebGL, opens a real
WebSocket, or depends on a service whose stub you cannot reasonably complete.
+
+Declare a minimal `@Component` with the **same selector** as the real child,
mark it `standalone`, and swap it in via the additive override:
+
+```ts
+import { Component } from "@angular/core";
+import { HeavyChildComponent } from "./heavy-child.component";
+
+@Component({
+ selector: "texera-heavy-child",
+ standalone: true,
+ template: "",
+})
+class StubHeavyChildComponent {}
+
+beforeEach(async () => {
+ TestBed.overrideComponent(ParentComponent, {
+ remove: { imports: [HeavyChildComponent] },
+ add: { imports: [StubHeavyChildComponent] },
+ });
+
+ await TestBed.configureTestingModule({ imports: [ParentComponent]
}).compileComponents();
+});
+```
+
+The parent's template still renders — the `<texera-heavy-child>` tag now
resolves to the stub. Coverage of the parent's `.component.html` is unaffected.
+
+Two patterns to **avoid** even when a child is awkward:
+
+- `overrideComponent({ set: { imports: [], schemas: [CUSTOM_ELEMENTS_SCHEMA] }
})` — the `set` form for imports has known Angular bugs
([angular/angular#48432](https://github.com/angular/angular/issues/48432)), and
the schema escape hatch quietly hides real template errors. Use `remove + add`
instead.
+- `overrideComponent({ set: { template: ... } })` — substituting the parent's
template (empty or stub) pins the real `.component.html` to 0 % coverage
forever. See Anti-pattern 3.
+
## Standalone components
Newly-generated components are standalone. The component itself goes into
`imports:`, never `declarations:`:
@@ -279,17 +313,26 @@ The license header is the only live code; the file
reports "0 tests, 0 failures"
**Fix**: delete the commented code outright (git history keeps it). Either
replace it with the minimum-viable spec from Recipe A, or remove the spec file
entirely.
-### 2. `NO_ERRORS_SCHEMA` everywhere
+### 2. `NO_ERRORS_SCHEMA`
+
+`schemas: [NO_ERRORS_SCHEMA]` tells Angular to swallow every "unknown element
/ unknown attribute" error from the template. [Angular's own docs warn against
it](https://angular.dev/guide/testing/components-scenarios): "you could waste
hours chasing phantom bugs that the compiler would have caught in an instant."
Even when the spec only asserts on the component class, the schema masks
template typos and silently disabled bindings.
+
+For standalone components the schema is also almost always unnecessary. A
standalone parent declares its template's children in its own `imports:` array,
and TestBed loads that import graph transitively — so the children are "known"
without any schema. NO_ERRORS_SCHEMA in a spec is usually a leftover from the
pre-standalone NgModule era.
+
+**Fix**: remove `NO_ERRORS_SCHEMA` and let the test run. The typical failure
modes and how to handle them:
-A spec adds `schemas: [NO_ERRORS_SCHEMA]` to silence "unknown element" errors
from un-imported children, but then asserts something about the parent template
that depends on the child rendering. Branches inside `*ngIf="child.ready"` are
dead because `child.ready` never fires.
+- _A child component's `ngOnInit` throws because a service method is missing
on the mock._ Extend the service stub — that's where the real coupling lives,
not in the template. (Example: the menu spec needed `getAllComputingUnits: ()
=> of([])` added to its `ComputingUnitStatusService` stub once the child's
`ngOnInit` started running.)
+- _A child component genuinely cannot be instantiated in jsdom (WebGL, native
module, etc.)._ Stub it via the additive override — see Recipe F.
-**Fix**: import the real child, or use `overrideComponent({ set: { imports:
[], schemas: [CUSTOM_ELEMENTS_SCHEMA] } })` to drop the child's transitive
imports while letting the unknown element render as an inert tag.
`CUSTOM_ELEMENTS_SCHEMA` says "I know what I'm doing", `NO_ERRORS_SCHEMA` says
"swallow all template errors" — the second is almost never what you want.
+ESLint enforces this rule on `*.spec.ts` files; importing `NO_ERRORS_SCHEMA`
from `@angular/core` is a lint error.
### 3. `overrideComponent({ set: { template: "" } })`
-Used historically to bypass a child template that wouldn't compile. Side
effect: the parent's template is wiped, so HTML coverage is permanently 0 %.
+Erases the parent's template at test time. `fixture.detectChanges()` then
renders an empty `<div>`, the original `.component.html` is permanently pinned
at 0 %, and every `*ngIf` / `(click)` / `{{ binding }}` in the file is silently
uncovered.
-**Fix**: see Anti-pattern 2 — override `imports` and `schemas` instead, keep
the template intact.
+**Fix**: delete the `overrideComponent({ set: { template: ... } })` block. If
the spec then errors because of a child, address it the same way as
Anti-pattern 2 — extend the service stub, or stub the child via Recipe F. Do
not replace the template with an empty-imports override either (see
Anti-pattern 8).
+
+ESLint enforces this rule on `*.spec.ts` files; the literal `template: ""`
inside `overrideComponent` is a lint error.
### 4. `declarations: [StandaloneComponent]`
@@ -315,6 +358,14 @@ Drift: spec A invents a partial mock for
`OperatorMetadataService`, spec B inven
**Fix**: use `StubOperatorMetadataService`. When you find yourself wanting a
new method on the stub, add it to the stub class, not to the spec.
+### 8. `overrideComponent({ set: { imports: [], schemas: [...] } })`
+
+Strips the parent's transitive imports and combines that with a permissive
schema so the template renders against unknown tags. The pattern looks clean
but has two problems: the `set` form for `imports` has documented bugs in
Angular standalone components
([angular/angular#48432](https://github.com/angular/angular/issues/48432))
where the override silently fails when the same component has been compiled by
an earlier spec, and the schema escape hatch hides real template errors just
like [...]
+
+**Fix**: use the additive `remove + add` form to swap specific heavy children
for stubs — see Recipe F. If only one or two children are problematic, name
them explicitly rather than blanket-stripping the whole import list.
+
+ESLint enforces this rule on `*.spec.ts` files; any `template` or `imports`
key inside `overrideComponent({ set: ... })` is a lint error.
+
## Coverage troubleshooting
`yarn test:ci` produces `coverage/lcov.info`; the GitHub-side dashboard is at
[app.codecov.io/gh/apache/texera](https://app.codecov.io/gh/apache/texera). If
a `.component.html` shows 0 % even though the spec passes, walk this list
top-to-bottom:
diff --git
a/frontend/src/app/common/formly/preset-wrapper/preset-wrapper.component.spec.ts
b/frontend/src/app/common/formly/preset-wrapper/preset-wrapper.component.spec.ts
index 09f415f256..474c0ca9a0 100644
---
a/frontend/src/app/common/formly/preset-wrapper/preset-wrapper.component.spec.ts
+++
b/frontend/src/app/common/formly/preset-wrapper/preset-wrapper.component.spec.ts
@@ -92,10 +92,6 @@ describe("PresetWrapperComponent", () => {
warning: vi.fn(),
};
- // Override the template so the spec doesn't depend on the ng-zorro
- // dropdown machinery — we exercise the public component API directly.
- TestBed.overrideComponent(PresetWrapperComponent, { set: { template: "" }
});
-
await TestBed.configureTestingModule({
imports: [PresetWrapperComponent],
providers: [
diff --git
a/frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts
b/frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts
index cbdd262cb4..ff5ef8cf39 100644
---
a/frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts
+++
b/frontend/src/app/dashboard/component/admin/user/admin-user.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, inject, TestBed } from "@angular/core/testing";
import { AdminUserComponent } from "./admin-user.component";
import { UserService } from "../../../../common/service/user/user.service";
@@ -37,7 +36,6 @@ describe("AdminUserComponent", () => {
await TestBed.configureTestingModule({
providers: [{ provide: UserService, useClass: StubUserService },
AdminUserService, ...commonTestProviders],
imports: [AdminUserComponent, FormsModule, HttpClientTestingModule,
NzDropDownModule, NzModalModule],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git
a/frontend/src/app/dashboard/component/user/filters/filters.component.spec.ts
b/frontend/src/app/dashboard/component/user/filters/filters.component.spec.ts
index 50deeb4877..f5878fcac3 100644
---
a/frontend/src/app/dashboard/component/user/filters/filters.component.spec.ts
+++
b/frontend/src/app/dashboard/component/user/filters/filters.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { FiltersComponent } from "./filters.component";
@@ -49,7 +48,6 @@ describe("FiltersComponent", () => {
...commonTestProviders,
],
imports: [FiltersComponent, NzModalModule, NzDropDownModule,
FormsModule, HttpClientTestingModule],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
index c00d509868..c8840a135b 100644
---
a/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
+++
b/frontend/src/app/dashboard/component/user/list-item/list-item.component.spec.ts
@@ -23,7 +23,6 @@ import { WorkflowPersistService } from
"src/app/common/service/workflow-persist/
import { HttpClientTestingModule } from "@angular/common/http/testing";
import { NzModalService } from "ng-zorro-antd/modal";
import { of, throwError } from "rxjs";
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { RouterTestingModule } from "@angular/router/testing";
import { StubUserService } from
"../../../../common/service/user/stub-user.service";
@@ -47,7 +46,6 @@ describe("ListItemComponent", () => {
NzModalService,
...commonTestProviders,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
fixture = TestBed.createComponent(ListItemComponent);
diff --git
a/frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.spec.ts
b/frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.spec.ts
index 683aa1154d..0a10aae28f 100644
---
a/frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.spec.ts
+++
b/frontend/src/app/dashboard/component/user/user-computing-unit/user-computing-unit.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserComputingUnitComponent } from "./user-computing-unit.component";
import { NzCardModule } from "ng-zorro-antd/card";
@@ -64,7 +63,6 @@ describe("UserComputingUnitComponent", () => {
NzCardModule,
NzIconModule.forChild([FileAddOutline]),
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
fixture = TestBed.createComponent(UserComputingUnitComponent);
diff --git
a/frontend/src/app/dashboard/component/user/user-icon/user-icon.component.spec.ts
b/frontend/src/app/dashboard/component/user/user-icon/user-icon.component.spec.ts
index 11731e0cf6..1681e2d1c0 100644
---
a/frontend/src/app/dashboard/component/user/user-icon/user-icon.component.spec.ts
+++
b/frontend/src/app/dashboard/component/user/user-icon/user-icon.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserIconComponent } from "./user-icon.component";
import { UserService } from "../../../../common/service/user/user.service";
@@ -41,7 +40,6 @@ describe("UserIconComponent", () => {
HttpClientTestingModule,
NzDropDownModule,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git
a/frontend/src/app/dashboard/component/user/user-quota/user-quota.component.spec.ts
b/frontend/src/app/dashboard/component/user/user-quota/user-quota.component.spec.ts
index 9b1f1e5dca..1190a562e9 100644
---
a/frontend/src/app/dashboard/component/user/user-quota/user-quota.component.spec.ts
+++
b/frontend/src/app/dashboard/component/user/user-quota/user-quota.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserQuotaComponent } from "./user-quota.component";
import { UserQuotaService } from
"../../../service/user/quota/user-quota.service";
@@ -46,7 +45,6 @@ describe("UserQuotaComponent", () => {
TestBed.configureTestingModule({
providers: [{ provide: UserQuotaService, useValue: mockUserQuotaService
}, ...commonTestProviders],
imports: [UserQuotaComponent, HttpClientTestingModule],
- schemas: [NO_ERRORS_SCHEMA],
});
fixture = TestBed.createComponent(UserQuotaComponent);
diff --git
a/frontend/src/app/workspace/component/left-panel/left-panel.component.spec.ts
b/frontend/src/app/workspace/component/left-panel/left-panel.component.spec.ts
index 4de5d4ab01..cee8ab6c57 100644
---
a/frontend/src/app/workspace/component/left-panel/left-panel.component.spec.ts
+++
b/frontend/src/app/workspace/component/left-panel/left-panel.component.spec.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, fakeAsync, TestBed, tick } from
"@angular/core/testing";
import { LeftPanelComponent } from "./left-panel.component";
import { mockPoint, mockScanPredicate } from
"../../service/workflow-graph/model/mock-workflow-data";
@@ -36,12 +35,6 @@ describe("LeftPanelComponent", () => {
let fixture: ComponentFixture<LeftPanelComponent>;
beforeEach(async () => {
- TestBed.overrideComponent(LeftPanelComponent, {
- set: {
- template: '<div id="left-container"><div #content></div></div>',
- },
- });
-
await TestBed.configureTestingModule({
imports: [LeftPanelComponent, HttpClientTestingModule,
RouterTestingModule.withRoutes([])],
providers: [
@@ -51,7 +44,6 @@ describe("LeftPanelComponent", () => {
},
...commonTestProviders,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git
a/frontend/src/app/workspace/component/left-panel/operator-menu/operator-menu.component.spec.ts
b/frontend/src/app/workspace/component/left-panel/operator-menu/operator-menu.component.spec.ts
index da753b0b2b..4ef4b5ab2a 100644
---
a/frontend/src/app/workspace/component/left-panel/operator-menu/operator-menu.component.spec.ts
+++
b/frontend/src/app/workspace/component/left-panel/operator-menu/operator-menu.component.spec.ts
@@ -33,19 +33,12 @@ import { WorkflowUtilService } from
"../../../service/workflow-graph/util/workfl
import { NzDropDownModule } from "ng-zorro-antd/dropdown";
import { NzCollapseModule } from "ng-zorro-antd/collapse";
import { commonTestProviders } from "../../../../common/testing/test-utils";
-import { NO_ERRORS_SCHEMA } from "@angular/core";
describe("OperatorPanelComponent", () => {
let component: OperatorMenuComponent;
let fixture: ComponentFixture<OperatorMenuComponent>;
beforeEach(async () => {
- TestBed.overrideComponent(OperatorMenuComponent, {
- set: {
- template: "",
- },
- });
-
await TestBed.configureTestingModule({
providers: [
{
@@ -67,7 +60,6 @@ describe("OperatorPanelComponent", () => {
BrowserAnimationsModule,
RouterTestingModule.withRoutes([]),
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git a/frontend/src/app/workspace/component/menu/menu.component.spec.ts
b/frontend/src/app/workspace/component/menu/menu.component.spec.ts
index 4c4de6cc5c..76de1c1e1b 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.spec.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.spec.ts
@@ -18,7 +18,6 @@
*/
import { DatePipe, Location } from "@angular/common";
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { HttpClientTestingModule } from "@angular/common/http/testing";
import { RouterTestingModule } from "@angular/router/testing";
@@ -44,7 +43,7 @@ import { ComputingUnitState } from
"../../../common/type/computing-unit-connecti
import { mockPoint, mockScanPredicate } from
"../../service/workflow-graph/model/mock-workflow-data";
import { saveAs } from "file-saver";
import type { ModalOptions } from "ng-zorro-antd/modal";
-import { ComputingUnitSelectionComponent } from
"../power-button/computing-unit-selection.component";
+import type { ComputingUnitSelectionComponent } from
"../power-button/computing-unit-selection.component";
import { WorkflowContent } from "../../../common/type/workflow";
import type { Mocked } from "vitest";
@@ -65,10 +64,6 @@ describe("MenuComponent", () => {
let validationStream$: BehaviorSubject<ValidationOutput>;
beforeEach(async () => {
- TestBed.overrideComponent(MenuComponent, {
- set: { template: "" },
- });
-
await TestBed.configureTestingModule({
imports: [MenuComponent, HttpClientTestingModule,
RouterTestingModule.withRoutes([]), NzModalModule],
providers: [
@@ -79,12 +74,14 @@ describe("MenuComponent", () => {
useValue: {
getSelectedComputingUnit: () => of(null),
getStatus: () => of(ComputingUnitState.NoComputingUnit),
+ // Read by ComputingUnitSelectionComponent.ngOnInit when the menu
+ // template renders the <texera-computing-unit-selection> child.
+ getAllComputingUnits: () => of([]),
},
},
{ provide: UserService, useClass: StubUserService },
...commonTestProviders,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
workflowActionService = TestBed.inject(WorkflowActionService);
diff --git
a/frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.spec.ts
b/frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.spec.ts
index cbb0f19726..d394040a9f 100644
---
a/frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.spec.ts
+++
b/frontend/src/app/workspace/component/property-editor/operator-property-edit-frame/operator-property-edit-frame.component.spec.ts
@@ -41,7 +41,7 @@ import {
mockViewResultsSchema,
} from "../../../service/operator-metadata/mock-operator-metadata.data";
import { configure } from "rxjs-marbles";
-import { NO_ERRORS_SCHEMA, SimpleChange } from "@angular/core";
+import { SimpleChange } from "@angular/core";
import { cloneDeep } from "lodash-es";
import Ajv from "ajv";
@@ -58,12 +58,19 @@ describe("OperatorPropertyEditFrameComponent", () => {
let workflowActionService: WorkflowActionService;
beforeEach(async () => {
+ // TODO(coverage): tests in this spec exercise dynamic Formly form
rendering;
+ // the real OperatorPropertyEditFrame template throws under jsdom when the
+ // Formly tree tries to read child.component from an uninstantiated field.
+ // The stub template lets the class-level tests run while we figure out a
+ // Formly-aware setup. Drop this override once that's done.
+ /* eslint-disable no-restricted-syntax */
TestBed.overrideComponent(OperatorPropertyEditFrameComponent, {
set: {
template:
'<div class="texera-workspace-property-editor-title">{{ formTitle
}}</div><div class="texera-workspace-property-editor-form"></div>',
},
});
+ /* eslint-enable no-restricted-syntax */
await TestBed.configureTestingModule({
providers: [
@@ -85,7 +92,6 @@ describe("OperatorPropertyEditFrameComponent", () => {
ReactiveFormsModule,
HttpClientTestingModule,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
fixture = TestBed.createComponent(OperatorPropertyEditFrameComponent);
diff --git
a/frontend/src/app/workspace/component/property-editor/property-editor.component.spec.ts
b/frontend/src/app/workspace/component/property-editor/property-editor.component.spec.ts
index 385ff33cfb..c472e3ef48 100644
---
a/frontend/src/app/workspace/component/property-editor/property-editor.component.spec.ts
+++
b/frontend/src/app/workspace/component/property-editor/property-editor.component.spec.ts
@@ -18,7 +18,6 @@
*/
import { CommonModule } from "@angular/common";
-import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { PropertyEditorComponent } from "./property-editor.component";
import {
@@ -41,12 +40,6 @@ describe("PropertyEditorComponent", () => {
let workflowActionService: WorkflowActionService;
beforeEach(async () => {
- TestBed.overrideComponent(PropertyEditorComponent, {
- set: {
- template: '<div id="right-container"><div
#contentWrapper></div></div>',
- },
- });
-
await TestBed.configureTestingModule({
imports: [PropertyEditorComponent, CommonModule,
HttpClientTestingModule],
providers: [
@@ -57,7 +50,6 @@ describe("PropertyEditorComponent", () => {
{ provide: ComputingUnitStatusService, useClass:
MockComputingUnitStatusService },
...commonTestProviders,
],
- schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});
diff --git a/frontend/src/app/workspace/component/workspace.component.spec.ts
b/frontend/src/app/workspace/component/workspace.component.spec.ts
index 088ac06f3c..f151ec3e4f 100644
--- a/frontend/src/app/workspace/component/workspace.component.spec.ts
+++ b/frontend/src/app/workspace/component/workspace.component.spec.ts
@@ -18,6 +18,12 @@
*/
import { Location } from "@angular/common";
+// TODO(coverage): this spec was set up in #5037 to render the workspace with
+// stripped child imports + CUSTOM_ELEMENTS_SCHEMA so the @ViewChild on
+// #codeEditor resolves while the deep child tree stays out of the bundle.
+// Migrating it off NO_ERRORS_SCHEMA / set:{imports:[]} requires providing
+// each child's transitive deps; tracking separately.
+// eslint-disable-next-line no-restricted-imports
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { HttpClientTestingModule } from "@angular/common/http/testing";
@@ -134,9 +140,13 @@ describe("WorkspaceComponent", () => {
// CUSTOM_ELEMENTS_SCHEMA. The template still renders, so `<ng-template
#codeEditor>`
// is wired up and the @ViewChild query resolves to a real
ViewContainerRef, while
// the children's transitive dependencies stay out of the test build.
+ // TODO(coverage): rewrite using stub child components via remove/add so
the
+ // template participates in coverage. See TESTING.md anti-pattern #9.
+ /* eslint-disable no-restricted-syntax */
TestBed.overrideComponent(WorkspaceComponent, {
set: { imports: [], providers: [], schemas: [CUSTOM_ELEMENTS_SCHEMA] },
});
+ /* eslint-enable no-restricted-syntax */
await TestBed.configureTestingModule({
imports: [WorkspaceComponent, HttpClientTestingModule],