mengw15 commented on code in PR #7365:
URL: https://github.com/apache/texera/pull/7365#discussion_r3735346534
##########
frontend/src/app/workspace/component/result-exportation/result-exportation.component.spec.ts:
##########
@@ -367,6 +368,104 @@ describe("ResultExportationComponent", () => {
expect(component.userAccessibleDatasets).toBe(before);
expect(component.inputDatasetName).toBe(nameBefore);
});
+
+ // Renders the template in each of the states it switches on so the *ngIf /
*ngFor /
+ // (click) / [(ngModel)] constructs actually execute. detectChanges() is the
coverage switch.
+ describe("template rendering", () => {
+ function setAllOperators(ids: string[]): void {
+ const graph = TestBed.inject(WorkflowActionService) as unknown as {
+ getTexeraGraph: ReturnType<typeof vi.fn>;
+ };
+ graph.getTexeraGraph.mockReturnValue({
+ getAllOperators: () => ids.map(id => ({ operatorID: id })),
+ });
+ }
+
+ function restrict(entries: Record<string, string[]>): void {
+ const map = new Map<string, Set<string>>();
+ Object.entries(entries).forEach(([op, labels]) => map.set(op, new
Set(labels)));
+ component.downloadability = new WorkflowResultDownloadability(map);
+ }
+
+ it("renders the restricted-export error alert when every operator is
blocked", () => {
+ setAllOperators(["op-a"]);
+ restrict({ "op-a": ["Sales ([email protected])"] });
+ fixture.detectChanges();
+
+ expect(component.isExportRestricted).toBe(true);
+ const alert = fixture.debugElement.query(By.css("nz-alert"));
+ expect(alert).toBeTruthy();
+ expect(alert.nativeElement.textContent).toContain("Export unavailable");
+ });
+
+ it("renders the partial-skip warning alert when only some operators are
blocked", () => {
+ setAllOperators(["op-a", "op-b"]);
+ restrict({ "op-a": ["Sales ([email protected])"] });
+ fixture.detectChanges();
+
+ expect(component.hasPartialNonDownloadable).toBe(true);
+ expect(fixture.nativeElement.textContent).toContain("Some operators will
be skipped");
+ });
+
+ it("renders the export-type select and its output-gated options when
export is allowed", () => {
+ setAllOperators(["op-a"]);
+ restrict({}); // nothing blocked -> not restricted
+ component.exportType = "csv"; // != "data"
+ component.isTableOutput = true;
+ component.isVisualizationOutput = true;
+ component.containsBinaryData = false;
+ fixture.detectChanges();
+
+ expect(component.isExportRestricted).toBe(false);
+
expect(fixture.debugElement.query(By.css("#exportTypeInput"))).toBeTruthy();
+ });
+
+ it("renders the filename input when the export type is 'data'", () => {
+ setAllOperators(["op-a"]);
+ restrict({});
+ component.exportType = "data";
+ fixture.detectChanges();
+
+
expect(fixture.debugElement.query(By.css("#filenameInput"))).toBeTruthy();
+ });
+
+ it("renders the local Export button and exports on click", () => {
+ setAllOperators(["op-a"]);
+ restrict({});
+ component.destination = "local";
+ fixture.detectChanges();
+
+ const exportBtn = fixture.debugElement
+ .queryAll(By.css("button"))
+ .find(btn => btn.nativeElement.textContent.trim() === "Export");
+ expect(exportBtn).toBeTruthy();
+
+ exportBtn!.triggerEventHandler("click", null);
+ expect(exportWorkflowExecutionResult).toHaveBeenCalledTimes(1);
+ expect(exportWorkflowExecutionResult.mock.calls[0][7]).toBe("local");
Review Comment:
Done — the call args are bound to a `const` before indexing, matching the
rest of the spec.
##########
frontend/src/app/workspace/component/result-exportation/result-exportation.component.spec.ts:
##########
@@ -367,6 +368,104 @@ describe("ResultExportationComponent", () => {
expect(component.userAccessibleDatasets).toBe(before);
expect(component.inputDatasetName).toBe(nameBefore);
});
+
+ // Renders the template in each of the states it switches on so the *ngIf /
*ngFor /
+ // (click) / [(ngModel)] constructs actually execute. detectChanges() is the
coverage switch.
+ describe("template rendering", () => {
+ function setAllOperators(ids: string[]): void {
+ const graph = TestBed.inject(WorkflowActionService) as unknown as {
+ getTexeraGraph: ReturnType<typeof vi.fn>;
+ };
+ graph.getTexeraGraph.mockReturnValue({
+ getAllOperators: () => ids.map(id => ({ operatorID: id })),
+ });
+ }
+
+ function restrict(entries: Record<string, string[]>): void {
+ const map = new Map<string, Set<string>>();
+ Object.entries(entries).forEach(([op, labels]) => map.set(op, new
Set(labels)));
+ component.downloadability = new WorkflowResultDownloadability(map);
+ }
+
+ it("renders the restricted-export error alert when every operator is
blocked", () => {
+ setAllOperators(["op-a"]);
+ restrict({ "op-a": ["Sales ([email protected])"] });
+ fixture.detectChanges();
+
+ expect(component.isExportRestricted).toBe(true);
+ const alert = fixture.debugElement.query(By.css("nz-alert"));
+ expect(alert).toBeTruthy();
+ expect(alert.nativeElement.textContent).toContain("Export unavailable");
+ });
+
+ it("renders the partial-skip warning alert when only some operators are
blocked", () => {
+ setAllOperators(["op-a", "op-b"]);
+ restrict({ "op-a": ["Sales ([email protected])"] });
+ fixture.detectChanges();
+
+ expect(component.hasPartialNonDownloadable).toBe(true);
+ expect(fixture.nativeElement.textContent).toContain("Some operators will
be skipped");
+ });
+
+ it("renders the export-type select and its output-gated options when
export is allowed", () => {
+ setAllOperators(["op-a"]);
+ restrict({}); // nothing blocked -> not restricted
+ component.exportType = "csv"; // != "data"
+ component.isTableOutput = true;
+ component.isVisualizationOutput = true;
+ component.containsBinaryData = false;
+ fixture.detectChanges();
+
+ expect(component.isExportRestricted).toBe(false);
+
expect(fixture.debugElement.query(By.css("#exportTypeInput"))).toBeTruthy();
+ });
+
+ it("renders the filename input when the export type is 'data'", () => {
+ setAllOperators(["op-a"]);
+ restrict({});
+ component.exportType = "data";
+ fixture.detectChanges();
+
+
expect(fixture.debugElement.query(By.css("#filenameInput"))).toBeTruthy();
+ });
+
+ it("renders the local Export button and exports on click", () => {
+ setAllOperators(["op-a"]);
+ restrict({});
+ component.destination = "local";
+ fixture.detectChanges();
+
+ const exportBtn = fixture.debugElement
+ .queryAll(By.css("button"))
+ .find(btn => btn.nativeElement.textContent.trim() === "Export");
+ expect(exportBtn).toBeTruthy();
+
+ exportBtn!.triggerEventHandler("click", null);
+ expect(exportWorkflowExecutionResult).toHaveBeenCalledTimes(1);
+ expect(exportWorkflowExecutionResult.mock.calls[0][7]).toBe("local");
+ });
+
+ it("renders the dataset destination with its list and create button", ()
=> {
+ setAllOperators(["op-a"]);
+ restrict({});
+ component.destination = "dataset";
+ fixture.detectChanges();
+
+ // the dataset search input drives the (input) handler
+ const search =
fixture.debugElement.query(By.css("input[name='datasetName']"));
+ expect(search).toBeTruthy();
+ search.triggerEventHandler("input", { target: { value: "" } });
Review Comment:
Good point. I tried asserting the rendered option text, but `nz-auto-option`
content only enters the DOM once the autocomplete panel expands, and jsdom
doesn't drive that reliably (focus events and
`NzAutocompleteTriggerDirective.openPanel()` both leave the panel closed) —
asserting on it would have been flaky. Instead the test now asserts the list
the `*ngFor` is bound to: `filteredUserAccessibleDatasets` holds exactly the
WRITE dataset, with the READ one filtered out. A comment in the spec records
why the option content itself isn't asserted.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]