Três ofertas (site que traz pedidos pelo WhatsApp, sistema para tirar a operação da planilha, revisão de sistema existente) com miniatura e formulário com o tipo escolhido; botão principal do hero abre o WhatsApp; moldura da SEV no hero do celular; menu fecha ao navegar, Esc, foco preso incluindo a barra de cookies e espaço para ela; CinematicHome como componente de servidor com ilha cliente; /ia com H1 de oferta e cartão do que você recebe; botão flutuante em aside com transform; AVIF antes de WebP; copy sem repetir contato direto.
113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
import { render, screen, within } from "@testing-library/react";
|
|
import HomeFaq, { FAQ_ITEMS } from "./HomeFaq";
|
|
|
|
describe("HomeFaq", () => {
|
|
it("shows the five questions the site already backs up, closed by default", () => {
|
|
const { container } = render(<HomeFaq />);
|
|
|
|
expect(
|
|
screen.getByRole("heading", { name: "Perguntas frequentes" }),
|
|
).toBeInTheDocument();
|
|
const summaries = Array.from(container.querySelectorAll("summary")).map(
|
|
(summary) => summary.textContent?.replace("+", "").trim(),
|
|
);
|
|
expect(summaries).toEqual([
|
|
"Como começa um projeto?",
|
|
"Quanto custa?",
|
|
"Você atende fora de Santa Catarina?",
|
|
"Dá para continuar um sistema que já existe ou que foi feito com IA?",
|
|
"O que preciso ter para começar?",
|
|
]);
|
|
for (const details of container.querySelectorAll("details")) {
|
|
expect(details.open).toBe(false);
|
|
}
|
|
});
|
|
|
|
it("answers from what the site already says: first conversation, remote in all of Brazil, and the AI review", () => {
|
|
render(<HomeFaq />);
|
|
|
|
expect(
|
|
screen.getByText(/Com uma conversa para entender o problema/),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText(
|
|
/o atendimento é remoto, para empresas de todo o Brasil/,
|
|
),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("link", { name: "Ver a revisão de app feito com IA" }),
|
|
).toHaveAttribute("href", "/ia");
|
|
});
|
|
|
|
it("does not render the questions the owner has not answered yet", () => {
|
|
const { container } = render(<HomeFaq />);
|
|
|
|
for (const unanswered of [
|
|
"O código e os acessos ficam comigo?",
|
|
"Em nome de quem ficam domínio e hospedagem?",
|
|
"Como funciona o pagamento?",
|
|
]) {
|
|
// preparadas na lista, com resposta vazia...
|
|
expect(FAQ_ITEMS.find((item) => item.question === unanswered)).toEqual({
|
|
question: unanswered,
|
|
answer: "",
|
|
});
|
|
// ...e fora da página
|
|
expect(screen.queryByText(unanswered)).toBeNull();
|
|
}
|
|
expect(container.querySelectorAll("details")).toHaveLength(5);
|
|
});
|
|
|
|
it("answers 'Quanto custa?' with the owner's sentence only: no value, no deadline, and no promise that the first talk is free", () => {
|
|
render(<HomeFaq />);
|
|
|
|
const details = screen
|
|
.getByText("Quanto custa?")
|
|
.closest("details") as HTMLElement;
|
|
expect(
|
|
within(details).getByText(
|
|
"Depois da primeira conversa você recebe escopo, valor e prazo por escrito, antes de qualquer compromisso.",
|
|
),
|
|
).toBeInTheDocument();
|
|
expect(details.textContent).not.toMatch(
|
|
/R\$|\d|grátis|gratuit|sem custo|sem compromisso/i,
|
|
);
|
|
});
|
|
|
|
it("starts showing a prepared question as soon as it gets an answer", () => {
|
|
render(
|
|
<HomeFaq
|
|
items={[
|
|
{
|
|
question: "Como funciona o pagamento?",
|
|
answer: "Resposta do dono.",
|
|
},
|
|
{ question: "Ainda sem resposta?", answer: " " },
|
|
]}
|
|
/>,
|
|
);
|
|
|
|
const details = screen
|
|
.getByText("Como funciona o pagamento?")
|
|
.closest("details") as HTMLElement;
|
|
expect(within(details).getByText("Resposta do dono.")).toBeInTheDocument();
|
|
expect(screen.queryByText("Ainda sem resposta?")).toBeNull();
|
|
});
|
|
|
|
it("renders nothing, not even the heading, when no question has an answer", () => {
|
|
const { container } = render(
|
|
<HomeFaq items={[{ question: "Pergunta?", answer: "" }]} />,
|
|
);
|
|
|
|
expect(container).toBeEmptyDOMElement();
|
|
});
|
|
|
|
it("states no price, deadline, guarantee or payment policy", () => {
|
|
const { container } = render(<HomeFaq />);
|
|
|
|
expect(container.textContent).not.toMatch(
|
|
/R\$|garantia|\d+ dias|em até \d+|parcel|entrada de/i,
|
|
);
|
|
});
|
|
});
|