Skip to content

Commit

Permalink
Fix incorrect target for hidden copy component (#2205)
Browse files Browse the repository at this point in the history
Fixes: #2146
  • Loading branch information
hudson-newey authored Jan 29, 2025
1 parent 56bcaf8 commit 784fbf4
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
import { BootstrapColorTypes } from "@helpers/bootstrapTypes";
import { NgbTooltipModule } from "@ng-bootstrap/ng-bootstrap";
import { createHostFactory, SpectatorHost } from "@ngneat/spectator";
import { createHostFactory, SpectatorHost, SpyObject } from "@ngneat/spectator";
import { IconsModule } from "@shared/icons/icons.module";
import { modelData } from "@test/helpers/faker";
import { ClipboardModule } from "ngx-clipboard";
import { ClipboardModule, ClipboardService } from "ngx-clipboard";
import { HiddenCopyComponent } from "./hidden-copy.component";

describe("HiddenCopyComponent", () => {
let spec: SpectatorHost<HiddenCopyComponent>;
let clipboardService: SpyObject<ClipboardService>;

const createHost = createHostFactory({
component: HiddenCopyComponent,
imports: [IconsModule, NgbTooltipModule, ClipboardModule],
});

function setup(props: Partial<HiddenCopyComponent>) {
function setup(props: Partial<HiddenCopyComponent> = {}) {
props.value ??= "value";
props.content ??= "content";
props.tooltip ??= "tooltip";

spec = createHost("<baw-hidden-copy></baw-hidden-copy>", {
props,
});

clipboardService = spec.inject(ClipboardService);
clipboardService.copyFromContent = jasmine.createSpy("copyFromContent") as any;
}

function getVisibilityButton() {
Expand All @@ -31,6 +36,14 @@ describe("HiddenCopyComponent", () => {
return spec.query<HTMLButtonElement>("#copy-btn");
}

function getCopyIcon() {
return spec.query("#copy-icon");
}

function getCopiedTooltip() {
return spec.query<HTMLSpanElement>("[ngbTooltip='Coped!']");
}

it("should create", () => {
setup({});
expect(spec.component).toBeTruthy();
Expand All @@ -45,7 +58,7 @@ describe("HiddenCopyComponent", () => {
it("should have tooltip", () => {
const tooltip = modelData.random.words();
setup({ tooltip });
// Container is body so that we dont have issues with the tooltip
// Container is body so that we don't have issues with the tooltip
// breaking css and clipping
expect(getVisibilityButton()).toHaveTooltip(tooltip, {
container: "body",
Expand Down Expand Up @@ -75,19 +88,39 @@ describe("HiddenCopyComponent", () => {
it("should have tooltip", () => {
const tooltip = modelData.random.words();
setup({ tooltip });
// Container is body so that we dont have issues with the tooltip
// Container is body so that we don't have issues with the tooltip
// breaking css and clipping

// if we hover over the "Copied!" tooltip element, it should not show
spec.focus(getCopyButton());

// Tooltip should only show on click
expect(getCopyButton()).toHaveTooltip("Copied!", {
triggers: "manual",
container: "body",
});
expect(getCopiedTooltip()).not.toBeVisible();

// after the button is clicked, we expect that the tooltip will be visible
spec.click(getCopyButton());
expect(getCopiedTooltip()).not.toBeVisible();
});

it("should not be disabled", () => {
setup({ disabled: undefined });
expect(getCopyButton()).not.toHaveAttribute("disabled");
});

// these tests were not always present which resulted in bugs such as the
// copy button not copying the text
// see: https://github.com/QutEcoacoustics/workbench-client/issues/2146
it("should copy if the copy icon is clicked", () => {
setup({ content: modelData.authToken() });
spec.click(getCopyIcon());
expect(clipboardService.copyFromContent).toHaveBeenCalledTimes(1);
});

it("should copy if the copy button is clicked", () => {
setup({ content: modelData.authToken() });
spec.click(getCopyButton());
expect(clipboardService.copyFromContent).toHaveBeenCalledTimes(1);
});
});

describe("content", () => {
Expand Down Expand Up @@ -135,6 +168,12 @@ describe("HiddenCopyComponent", () => {
setup({ disabled });
expect(getCopyButton()).toHaveAttribute("disabled");
});

it("should not copy if disabled and the copy button is clicked", () => {
setup({ content: modelData.authToken(), disabled: "true" });
spec.click(getCopyButton());
expect(clipboardService.copyFromContent).not.toHaveBeenCalled();
});
});

describe("color", () => {
Expand Down
53 changes: 36 additions & 17 deletions src/app/components/shared/hidden-copy/hidden-copy.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Component, Input } from "@angular/core";
import { BootstrapColorTypes } from "@helpers/bootstrapTypes";

/**
* Loading Animation
*/
@Component({
selector: "baw-hidden-copy",
template: `
Expand All @@ -22,29 +19,36 @@ import { BootstrapColorTypes } from "@helpers/bootstrapTypes";
<fa-icon [icon]="['fas', 'eye']"></fa-icon>
</button>
<pre
class="text-center form-control">{{ visible ? content : "..." }}<ng-content *ngIf="visible"></ng-content></pre>
<pre class="text-center form-control">{{ visible ? content : "..." }}<ng-content *ngIf="visible"></ng-content></pre>
<button
<!--
We use a manual trigger for the "Copied!" tooltip so that so that it is
only triggered by the cbOnSuccess event.
We also add the container="body" so that the tooltip can go above this
components top level container.
We can't add the ngbTooltip with the ngxClipboard directive otherwise
the content fails to copy.
-->
<span
#copyTooltip="ngbTooltip"
id="copy-btn"
type="button"
class="btn"
ngbTooltip="Copied!"
triggers="manual"
container="body"
ngbTooltip="Copied!"
[ngClass]="'btn-outline-' + color"
[disabled]="disabled"
>
<!-- ! Be careful changing how the clipboard works. It is not tested -->
<span
<button
id="copy-btn"
class="btn"
[ngClass]="'btn-outline-' + color"
[disabled]="disabled"
ngxClipboard
[cbContent]="value"
(cbOnSuccess)="copyTooltip.open()"
>
<fa-icon [icon]="['fas', 'copy']"></fa-icon>
</span>
</button>
<fa-icon id="copy-icon" [icon]="['fas', 'copy']"></fa-icon>
</button>
</span>
</div>
`,
styles: [
Expand All @@ -53,6 +57,21 @@ import { BootstrapColorTypes } from "@helpers/bootstrapTypes";
margin: 0;
white-space: pre-wrap;
}
/*
In bootstrap, any element that is inside the same form-control has
its edge border radius set to 0 so that all inner form-control
elements are flush.
However, because we have wrapped the copy-btn inside a tooltip <span>,
bootstrap attempts to flatten the span's border radius (which is not
visible) instead of the copy buttons.
to keep consistent with the bootstrap styling, I manually flatten the
left edges of the copy button.
*/
#copy-btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
`,
],
})
Expand Down

0 comments on commit 784fbf4

Please sign in to comment.