fix(home): oferta leva ao formulário, ofertas logo depois da vitrine
O botão das ofertas rola até o contato com o tipo marcado e não quebra mais as âncoras; ofertas com o que você recebe e primeiro passo, logo depois da vitrine; bloco de IA fora da home; cartão largo da SEV no hero do celular; separador da faixa de clientes só entre itens; favicon de 13 para 1,8 KB; pré-carregamento só no hover e nunca de /#... fora da home; X do menu e cabeçalho opaco; WhatsApp com "o case"; /ia com 3 passos e modelo de relatório ilustrativo; Sobre alinhado ao currículo; CSP Report-Only com os domínios do Ads.
This commit is contained in:
1 parent
fc44a69fb3
commit
9e2d65a926
51 files changed
+1730
-420
No files matched your search
@@ -109,20 +109,29 @@ describe("WorkModalities: as três ofertas", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("path: the site offer cites the Lavação 047 (catalog or price table, ready message, panel to edit alone)", () => {
|
||||
it("path: the site offer cites the Lavação 047 and delivers a catalog or price table, a ready WhatsApp message, a panel to edit prices and photos and the publication", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
const [site] = Array.from(container.querySelectorAll("article"));
|
||||
expect(site.textContent).toMatch(/Catálogo ou tabela de preços/);
|
||||
expect(site.textContent).toMatch(/mensagem pronta/);
|
||||
expect(site.textContent).toMatch(/painel para você editar/);
|
||||
expect(site.textContent).toMatch(/Lavação 047/);
|
||||
expect(
|
||||
within(site)
|
||||
.getAllByRole("listitem")
|
||||
.map((item) => item.textContent),
|
||||
).toEqual([
|
||||
"Catálogo ou tabela de preços",
|
||||
"Mensagem pronta no WhatsApp",
|
||||
"Painel para editar preços e fotos",
|
||||
"Publicação do site",
|
||||
]);
|
||||
});
|
||||
|
||||
it("path: the first two offers show the poster of their case, sized for a third of the row", () => {
|
||||
it("path: only the site offer shows a photo (the Lavação 047 poster, sized for a third of the row)", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
const [site, system] = Array.from(container.querySelectorAll("article"));
|
||||
const [site, system, review] = Array.from(
|
||||
container.querySelectorAll("article"),
|
||||
);
|
||||
const siteImage = within(site).getByRole("img");
|
||||
expect(original(siteImage)).toBe("/videos/lavacao-047/desktop.webp");
|
||||
expect(siteImage).toHaveAccessibleName(
|
||||
@@ -133,27 +142,72 @@ describe("WorkModalities: as três ofertas", () => {
|
||||
"(min-width: 1024px) 33vw, 100vw",
|
||||
);
|
||||
expect(siteImage).toHaveAttribute("loading", "lazy");
|
||||
expect(original(within(system).getByRole("img"))).toBe(
|
||||
"/videos/sev-modaintima/desktop.webp",
|
||||
);
|
||||
// a vitrine da SEV é uma loja, não um painel: contradiria o texto do sistema
|
||||
expect(within(system).queryByRole("img")).toBeNull();
|
||||
expect(system.querySelector("img")).toBeNull();
|
||||
expect(container.innerHTML).not.toContain("sev-modaintima/desktop.webp");
|
||||
expect(within(review).queryByRole("img")).toBeNull();
|
||||
});
|
||||
|
||||
it("path: the review offer has a checklist card instead of a poster, with what the review delivers", () => {
|
||||
it("path: the system and the review offers have a card with no photo, only an icon (decorative), and the deliverables below", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
const review = Array.from(container.querySelectorAll("article"))[2];
|
||||
expect(within(review).queryByRole("img")).toBeNull();
|
||||
expect(within(review).getByText("O que você recebe")).toBeInTheDocument();
|
||||
for (const item of [
|
||||
const [, system, review] = Array.from(
|
||||
container.querySelectorAll("article"),
|
||||
);
|
||||
for (const card of [system, review]) {
|
||||
const icon = within(card).getByTestId("offer-icon");
|
||||
expect(icon.querySelector("svg")).toHaveAttribute("aria-hidden", "true");
|
||||
expect(icon.textContent).toBe("");
|
||||
}
|
||||
expect(
|
||||
within(system)
|
||||
.getAllByRole("listitem")
|
||||
.map((item) => item.textContent),
|
||||
).toEqual([
|
||||
"Cadastro de clientes e produtos",
|
||||
"Pedidos e acompanhamento",
|
||||
"Relatórios",
|
||||
"Acesso por perfil",
|
||||
]);
|
||||
expect(
|
||||
within(review)
|
||||
.getAllByRole("listitem")
|
||||
.map((item) => item.textContent),
|
||||
).toEqual([
|
||||
"As falhas de acesso a dados",
|
||||
"O que dá para aproveitar",
|
||||
"O que é melhor refazer",
|
||||
"Um orçamento para pôr em produção",
|
||||
]) {
|
||||
expect(within(review).getByText(item)).toBeInTheDocument();
|
||||
]);
|
||||
});
|
||||
|
||||
it("path: every card says what you receive, with three or four items, once", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
for (const card of container.querySelectorAll("article")) {
|
||||
expect(
|
||||
within(card as HTMLElement).getAllByText("O que você recebe"),
|
||||
).toHaveLength(1);
|
||||
const items = within(card as HTMLElement).getAllByRole("listitem");
|
||||
expect(items.length).toBeGreaterThanOrEqual(3);
|
||||
expect(items.length).toBeLessThanOrEqual(4);
|
||||
}
|
||||
});
|
||||
|
||||
it("path: every card has its first step: a first conversation and, after it, the scope and the proposal in writing", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
const cards = Array.from(container.querySelectorAll("article"));
|
||||
for (const card of cards) {
|
||||
expect(within(card).getAllByText("Primeiro passo")).toHaveLength(1);
|
||||
expect(card.textContent).toMatch(
|
||||
/Primeira conversa para entender .+\. Depois, escopo e proposta por escrito\./,
|
||||
);
|
||||
}
|
||||
expect(screen.getAllByText("Primeiro passo")).toHaveLength(3);
|
||||
});
|
||||
|
||||
it("path: each button opens the contact form with the project type already chosen, all three with the same filled style", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
@@ -175,11 +229,11 @@ describe("WorkModalities: as três ofertas", () => {
|
||||
|
||||
const articles = Array.from(container.querySelectorAll("article"));
|
||||
expect(
|
||||
within(articles[0]).getByRole("link", { name: "Ver o case Lavação 047" }),
|
||||
within(articles[0]).getByRole("link", { name: "Ver case Lavação 047" }),
|
||||
).toHaveAttribute("href", "/cases/lavacao-047");
|
||||
expect(
|
||||
within(articles[1]).getByRole("link", {
|
||||
name: "Ver o case SEV Moda Íntima",
|
||||
name: "Ver case SEV Moda Íntima",
|
||||
}),
|
||||
).toHaveAttribute("href", "/cases/sev-modaintima");
|
||||
expect(
|
||||
@@ -189,18 +243,23 @@ describe("WorkModalities: as três ofertas", () => {
|
||||
).toHaveAttribute("href", "/ia");
|
||||
});
|
||||
|
||||
it("path: no duplicate service grid and no 'Reconhece algum destes cenários?' panel", () => {
|
||||
it("path: no duplicate service grid and no 'Reconhece algum destes cenários?' panel, only one link to /servicos after the cards", () => {
|
||||
const { container } = render(<WorkModalities />);
|
||||
|
||||
expect(screen.queryByText(/Reconhece algum destes cenários/)).toBeNull();
|
||||
expect(screen.queryByText(/Planilhas demais/)).toBeNull();
|
||||
expect(
|
||||
screen.queryByRole("link", { name: "Ver todos os serviços" }),
|
||||
).toBeNull();
|
||||
for (const link of screen.getAllByRole("link")) {
|
||||
expect(link.getAttribute("href")).not.toMatch(/^\/servicos/);
|
||||
}
|
||||
const services = screen.getByRole("link", {
|
||||
name: "Ver todos os serviços",
|
||||
});
|
||||
expect(services).toHaveAttribute("href", "/servicos");
|
||||
expect(container.querySelectorAll("article")).toHaveLength(3);
|
||||
// o link fica fora dos cartões, depois da grade
|
||||
expect(services.closest("article")).toBeNull();
|
||||
expect(
|
||||
screen
|
||||
.getAllByRole("link")
|
||||
.filter((link) => /^\/servicos/.test(link.getAttribute("href") ?? "")),
|
||||
).toEqual([services]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -278,6 +337,5 @@ describe("WorkModalities: sem prometer o que o dono não disse", () => {
|
||||
expect(container.textContent).not.toMatch(
|
||||
/R\$|em contrato|prazo de \d|\d+ dias|grátis|gratuit/i,
|
||||
);
|
||||
expect(screen.queryByText("Primeiro passo")).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user