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 f3f3fbe131 test(frontend): add unit tests for AdminGmailComponent 
(#6576)
f3f3fbe131 is described below

commit f3f3fbe131891226c9b55261d991df41ed35054d
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sun Jul 19 21:13:14 2026 -0700

    test(frontend): add unit tests for AdminGmailComponent (#6576)
    
    ### What changes were proposed in this PR?
    
    Adds a Vitest unit spec for `AdminGmailComponent`, which previously had
    no test coverage. The 10 tests cover:
    - reactive-form construction and every validator branch (empty,
    malformed email, missing subject, missing content -> invalid; all filled
    with a well-formed email -> valid).
    - `getSenderEmail` success (sets `email`) and error (resets to undefined
    + logs) paths.
    - `sendTestEmail` forwarding the form's subject/content/email to
    `GmailService.sendEmail` in order.
    
    `FormBuilder` stays real via `ReactiveFormsModule`; `GmailService` is
    mocked with a controllable subject for both branches.
    
    ### Any related issues, documentation, discussions?
    
    Closes #6573.
    
    ### How was this PR tested?
    
    `npx ng test --watch=false --include='**/admin-gmail.component.spec.ts'`
    -> 10/10 passing. `yarn format:ci` passes.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.8 [1M context])
---
 .../admin/gmail/admin-gmail.component.spec.ts      | 168 +++++++++++++++++++++
 1 file changed, 168 insertions(+)

diff --git 
a/frontend/src/app/dashboard/component/admin/gmail/admin-gmail.component.spec.ts
 
b/frontend/src/app/dashboard/component/admin/gmail/admin-gmail.component.spec.ts
new file mode 100644
index 0000000000..7c24b30f10
--- /dev/null
+++ 
b/frontend/src/app/dashboard/component/admin/gmail/admin-gmail.component.spec.ts
@@ -0,0 +1,168 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 { ComponentFixture, TestBed } from "@angular/core/testing";
+import { FormsModule, ReactiveFormsModule } from "@angular/forms";
+import { NoopAnimationsModule } from "@angular/platform-browser/animations";
+import { HttpClientTestingModule } from "@angular/common/http/testing";
+import { Subject } from "rxjs";
+import { AdminGmailComponent } from "./admin-gmail.component";
+import { GmailService } from "../../../../common/service/gmail/gmail.service";
+import { commonTestProviders } from "../../../../common/testing/test-utils";
+
+describe("AdminGmailComponent", () => {
+  let component: AdminGmailComponent;
+  let fixture: ComponentFixture<AdminGmailComponent>;
+  let senderEmailSubject: Subject<string>;
+  let getSenderEmailSpy: ReturnType<typeof vi.fn>;
+  let sendEmailSpy: ReturnType<typeof vi.fn>;
+
+  /** Create the component (runs ngOnInit) and render the template once. */
+  function createComponent(): void {
+    fixture = TestBed.createComponent(AdminGmailComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }
+
+  beforeEach(async () => {
+    // Controllable GmailService double: getSenderEmail returns a subject we 
drive
+    // per test (both next and error branches); sendEmail is fire-and-forget 
so a
+    // plain vi.fn() is enough.
+    senderEmailSubject = new Subject<string>();
+    getSenderEmailSpy = vi.fn(() => senderEmailSubject.asObservable());
+    sendEmailSpy = vi.fn();
+    const gmailServiceStub = { getSenderEmail: getSenderEmailSpy, sendEmail: 
sendEmailSpy };
+
+    await TestBed.configureTestingModule({
+      imports: [AdminGmailComponent, FormsModule, ReactiveFormsModule, 
NoopAnimationsModule, HttpClientTestingModule],
+      providers: [{ provide: GmailService, useValue: gmailServiceStub }, 
...commonTestProviders],
+    }).compileComponents();
+  });
+
+  afterEach(() => {
+    fixture?.destroy();
+    document.querySelectorAll(".cdk-overlay-container").forEach(c => 
(c.innerHTML = ""));
+    vi.restoreAllMocks();
+  });
+
+  it("should create and render the reactive form template", () => {
+    createComponent();
+
+    expect(component).toBeTruthy();
+    const el = fixture.nativeElement as HTMLElement;
+    // The template binds each control; confirm the inputs rendered for .html 
coverage.
+    expect(el.querySelector('input[formControlName="email"]')).toBeTruthy();
+    expect(el.querySelector('input[formControlName="subject"]')).toBeTruthy();
+    
expect(el.querySelector('textarea[formControlName="content"]')).toBeTruthy();
+  });
+
+  describe("validateForm validation", () => {
+    beforeEach(() => createComponent());
+
+    it("builds the form with email/subject/content controls", () => {
+      expect(component.validateForm.contains("email")).toBe(true);
+      expect(component.validateForm.contains("subject")).toBe(true);
+      expect(component.validateForm.contains("content")).toBe(true);
+    });
+
+    it("is invalid when empty", () => {
+      expect(component.validateForm.valid).toBe(false);
+    });
+
+    it("is invalid when the email is malformed (all fields otherwise filled)", 
() => {
+      component.validateForm.setValue({
+        email: "not-an-email",
+        subject: "Hello",
+        content: "Body",
+      });
+      expect(component.validateForm.valid).toBe(false);
+      
expect(component.validateForm.get("email")?.hasError("email")).toBe(true);
+    });
+
+    it("is invalid when subject is missing", () => {
+      component.validateForm.setValue({
+        email: "[email protected]",
+        subject: null,
+        content: "Body",
+      });
+      expect(component.validateForm.valid).toBe(false);
+      
expect(component.validateForm.get("subject")?.hasError("required")).toBe(true);
+    });
+
+    it("is invalid when content is missing", () => {
+      component.validateForm.setValue({
+        email: "[email protected]",
+        subject: "Hello",
+        content: null,
+      });
+      expect(component.validateForm.valid).toBe(false);
+      
expect(component.validateForm.get("content")?.hasError("required")).toBe(true);
+    });
+
+    it("is valid when all three fields are filled with a well-formed email", 
() => {
+      component.validateForm.setValue({
+        email: "[email protected]",
+        subject: "Hello",
+        content: "Body",
+      });
+      expect(component.validateForm.valid).toBe(true);
+    });
+  });
+
+  describe("getSenderEmail (called from ngOnInit)", () => {
+    it("subscribes on init and sets email to the emitted value", () => {
+      createComponent();
+      expect(getSenderEmailSpy).toHaveBeenCalledTimes(1);
+      expect(component.email).toBeUndefined();
+
+      senderEmailSubject.next("[email protected]");
+
+      expect(component.email).toBe("[email protected]");
+    });
+
+    it("resets email to undefined and logs when the sender lookup errors", () 
=> {
+      const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
+      createComponent();
+      // Sentinel so the reset-to-undefined is observable, not a no-op default.
+      component.email = "[email protected]";
+      const err = new Error("lookup failed");
+
+      senderEmailSubject.error(err);
+
+      expect(component.email).toBeUndefined();
+      expect(logSpy).toHaveBeenCalledWith(err);
+    });
+  });
+
+  describe("sendTestEmail", () => {
+    it("calls GmailService.sendEmail with the form's subject, content and 
email", () => {
+      createComponent();
+      component.validateForm.setValue({
+        email: "[email protected]",
+        subject: "Test Subject",
+        content: "Test Content",
+      });
+
+      component.sendTestEmail();
+
+      expect(sendEmailSpy).toHaveBeenCalledTimes(1);
+      expect(sendEmailSpy).toHaveBeenCalledWith("Test Subject", "Test 
Content", "[email protected]");
+    });
+  });
+});

Reply via email to