Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { render } from "@testing-library/react";
import {
StockTicker,
getDirection,
formatPrice,
formatChange,
} from "content-src/components/Widgets/Stocks/StockTicker";
describe("getDirection", () => {
it("returns up/down/flat from the change sign", () => {
expect(getDirection("+2.1")).toBe("up");
expect(getDirection("-0.11")).toBe("down");
expect(getDirection("0.00")).toBe("flat");
expect(getDirection(undefined)).toBe("flat");
});
});
describe("formatPrice", () => {
it("formats the parsed price as US currency for an en-US locale", () => {
expect(formatPrice("$559.44 USD", "en-US")).toBe("$559.44");
});
it("keeps thousands separators", () => {
expect(formatPrice("$1,234.56 USD", "en-US")).toBe("$1,234.56");
});
it("uses the locale's decimal separator and symbol placement", () => {
// French uses a comma decimal separator and places the symbol after the amount.
const fr = formatPrice("$559.44 USD", "fr-FR");
expect(fr).toContain("559,44");
expect(fr).not.toContain("559.44");
});
it("returns the raw string when there is no number to parse", () => {
expect(formatPrice("", "en-US")).toBe("");
expect(formatPrice(undefined, "en-US")).toBe("");
});
});
describe("formatChange", () => {
it("formats the change as a signed percent for an en-US locale", () => {
expect(formatChange("+0.2", "en-US")).toBe("+0.2%");
expect(formatChange("-0.21", "en-US")).toBe("-0.21%");
});
it("shows no sign for a flat change and keeps the source precision", () => {
expect(formatChange("0.00", "en-US")).toBe("0.00%");
});
it("formats an integer change with no decimal places", () => {
expect(formatChange("+1", "en-US")).toBe("+1%");
});
it("uses the locale's decimal separator", () => {
const fr = formatChange("+0.2", "fr-FR");
expect(fr).toContain("0,2");
expect(fr).not.toContain("0.2");
});
it("returns the raw string when there is no number to parse", () => {
expect(formatChange("", "en-US")).toBe("");
});
});
describe("StockTicker", () => {
function renderCard(props = {}) {
const { container } = render(
<StockTicker
name="SPDR S&P 500 ETF Trust"
ticker="SPY"
price="$559.44 USD"
changePercent="+2.1"
{...props}
/>
);
return container;
}
it("renders ticker, formatted price and formatted change as visual (aria-hidden) text", () => {
const container = renderCard();
expect(container.querySelector(".stock-ticker-symbol").textContent).toBe(
"SPY"
);
expect(container.querySelector(".stock-ticker-price").textContent).toBe(
"$559.44"
);
expect(container.querySelector(".stock-ticker-change").textContent).toBe(
"+2.1%"
);
});
it("applies the direction modifier to the indicator and change", () => {
const up = renderCard();
expect(up.querySelector(".stock-indicator--up")).toBeTruthy();
expect(up.querySelector(".stock-ticker-change--up")).toBeTruthy();
const down = render(
<StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="-0.21" />
).container;
expect(down.querySelector(".stock-indicator--down")).toBeTruthy();
expect(down.querySelector(".stock-ticker-change--down")).toBeTruthy();
});
it("falls through to the base color when the change is flat", () => {
const flat = render(
<StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="0.00" />
).container;
expect(flat.querySelector(".stock-indicator--flat")).toBeTruthy();
expect(flat.querySelector(".stock-ticker-change--up")).toBeNull();
expect(flat.querySelector(".stock-ticker-change--down")).toBeNull();
});
it("sets the flat arrow inline and mirrors it for right-to-left locales", () => {
const ltr = render(
<StockTicker name="n" ticker="DIA" price="$1 USD" changePercent="0.00" />
).container;
expect(
ltr.querySelector(".stock-indicator--flat").style.backgroundImage
).toContain("shaft-arrow-right.svg");
document.dir = "rtl";
try {
const rtl = render(
<StockTicker
name="n"
ticker="DIA"
price="$1 USD"
changePercent="0.00"
/>
).container;
expect(
rtl.querySelector(".stock-indicator--flat").style.backgroundImage
).toContain("shaft-arrow-left.svg");
} finally {
document.dir = "";
}
});
it("marks the visual rows aria-hidden", () => {
const container = renderCard();
expect(
container.querySelector(".stock-indicator").getAttribute("aria-hidden")
).toBe("true");
expect(
container.querySelector(".stock-ticker-label").getAttribute("aria-hidden")
).toBe("true");
});
it("exposes a localized screen-reader label with the formatted change and price", () => {
const container = renderCard();
const sr = container.querySelector(".stock-ticker-sr");
expect(sr.getAttribute("data-l10n-id")).toBe(
"newtab-stocks-ticker-status-up"
);
const args = JSON.parse(sr.getAttribute("data-l10n-args"));
expect(args).toEqual({
name: "SPDR S&P 500 ETF Trust",
change: "+2.1%",
price: "$559.44",
});
});
it("uses the direction-specific screen-reader message id", () => {
const down = render(
<StockTicker name="n" ticker="IWM" price="$1 USD" changePercent="-0.21" />
).container;
expect(
down.querySelector(".stock-ticker-sr").getAttribute("data-l10n-id")
).toBe("newtab-stocks-ticker-status-down");
const flat = render(
<StockTicker name="n" ticker="DIA" price="$1 USD" changePercent="0.00" />
).container;
expect(
flat.querySelector(".stock-ticker-sr").getAttribute("data-l10n-id")
).toBe("newtab-stocks-ticker-status-flat");
});
it("renders as an aria-hidden placeholder with no screen-reader label while loading", () => {
const { container } = render(<StockTicker loading={true} />);
expect(container.querySelector(".stock-ticker-sr")).toBeNull();
expect(
container.querySelector("li.stock-ticker").getAttribute("aria-hidden")
).toBe("true");
});
it("falls back to the ticker symbol as the screen-reader subject when name is missing, and is not aria-hidden", () => {
const { container } = render(
<StockTicker
name=""
ticker="SPY"
price="$559.44 USD"
changePercent="+2.1"
/>
);
const sr = container.querySelector(".stock-ticker-sr");
expect(sr.getAttribute("data-l10n-id")).toBe(
"newtab-stocks-ticker-status-up"
);
const args = JSON.parse(sr.getAttribute("data-l10n-args"));
expect(args.name).toBe("SPY");
expect(
container.querySelector("li.stock-ticker").getAttribute("aria-hidden")
).toBeNull();
});
it("uses the medium layout with no name by default", () => {
const container = renderCard();
expect(container.querySelector(".stock-ticker--medium")).toBeTruthy();
expect(container.querySelector(".stock-ticker-name")).toBeNull();
});
it("renders the large layout: full name plus ticker, then change and price", () => {
const { container } = render(
<StockTicker
size="large"
name="SPDR S&P 500 ETF Trust"
ticker="SPY"
price="$559.44 USD"
changePercent="+2.1"
/>
);
expect(container.querySelector(".stock-ticker--large")).toBeTruthy();
expect(container.querySelector(".stock-ticker-name").textContent).toBe(
"SPDR S&P 500 ETF Trust"
);
expect(container.querySelector(".stock-ticker-symbol").textContent).toBe(
"SPY"
);
expect(container.querySelector(".stock-ticker-price").textContent).toBe(
"$559.44"
);
const args = JSON.parse(
container.querySelector(".stock-ticker-sr").getAttribute("data-l10n-args")
);
expect(args).toEqual({
name: "SPDR S&P 500 ETF Trust",
change: "+2.1%",
price: "$559.44",
});
});
});