Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ Se uma mudanca exigir novo seletor, adicione um novo `data-testid` mantendo o
antigo. Se uma automacao falhar porque um seletor foi removido, a correcao deve
restaurar o `data-testid` no frontend, nao trocar o teste para seletor fragil.

Nao preserve seletor em elemento que deixou de fazer parte da jornada real. Se
uma funcionalidade ainda nao esta pronta, e proibido manter `data-testid` em
placeholder invisivel (`aria-hidden`, `sr-only`, `opacity-0`, tamanho de 1px ou
equivalente) apenas para satisfazer testes. Documente a pendencia e reative o
contrato quando o elemento voltar visivel e utilizavel.

Estrutura base:

```text
Expand Down
12 changes: 12 additions & 0 deletions automations/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ Regras obrigatorias:
- mudanca de `data-testid` so pode acontecer com pedido explicito e migracao
coordenada dos testes afetados.

Contrato de visibilidade:

- automacoes nao devem validar elementos escondidos apenas para preservar
compatibilidade artificial;
- se o elemento nao esta visivel ou utilizavel pelo usuario, ele nao faz parte
do contrato ativo daquela jornada;
- nao aceite `data-testid` em placeholders com `aria-hidden`, `sr-only`,
`opacity-0`, tamanho de 1px ou padrao equivalente;
- quando uma funcionalidade ficar pendente, registre TODO ou issue apontando o
contrato futuro e remova a assercao ativa ate o elemento voltar de forma
visivel e testavel.

Prioridade obrigatoria de seletores:

1. `data-testid`
Expand Down
10 changes: 1 addition & 9 deletions automations/pages/dashboard-resumo.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ export class DashboardResumoPage {
page.getByTestId('metric-card-orders-today'),
page.getByTestId('metric-card-revenue'),
page.getByTestId('metric-card-ticket'),
page.getByTestId('metric-card-preparing'),
page.getByTestId('metric-card-new-clients'),
page.getByTestId('metric-card-repurchase'),
page.getByTestId('metric-card-kitchen-time'),
];
this.grafico = page.getByTestId('grafico-vendas');
this.pedidosRecentes = page.getByTestId('pedidos-recentes-list');
this.botaoVerTodos = page.getByTestId('ver-todos-pedidos-button');
}

async abrir() {
Expand All @@ -30,9 +27,4 @@ export class DashboardResumoPage {
async validarPedidosRecentes() {
await expect(this.pedidosRecentes).toBeVisible();
}

async navegarParaPedidos() {
await this.botaoVerTodos.click();
await this.page.waitForURL('**/dashboard/pedidos');
}
}
2 changes: 0 additions & 2 deletions automations/pages/dashboard.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export class DashboardPage {
constructor(page) {
this.page = page;
this.topbar = page.getByTestId('topbar');
this.nomeUsuario = page.getByTestId('user-menu-name');
this.saudacao = page.getByTestId('dashboard-greeting');
this.botaoSair = page.getByTestId('logout-button');
}
Expand All @@ -15,7 +14,6 @@ export class DashboardPage {

async validarUsuarioExibido(nome) {
await expect(this.topbar).toBeVisible();
await expect(this.nomeUsuario).toHaveText(nome);
await expect(this.saudacao).toContainText(nome);
}

Expand Down
10 changes: 5 additions & 5 deletions automations/tests/frontend/dashboard/resumo.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ test.describe('dashboard autenticado', () => {
await dashboardResumoPage.validarPedidosRecentes();
});

test('navega para a tela de pedidos pelo atalho do resumo', { tag: ['@frontend', '@regressao', '@contrato'] }, async ({
dashboardResumoPage,
}) => {
await dashboardResumoPage.navegarParaPedidos();
});
// TODO(#57): reativar cobertura para metric-card-preparing,
// metric-card-new-clients, metric-card-repurchase e
// ver-todos-pedidos-button quando esses elementos voltarem como parte
// visivel e utilizavel do dashboard. Eles nao devem existir escondidos
// apenas para satisfazer a automacao.
});
7 changes: 7 additions & 0 deletions web/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ Regras obrigatorias:
restaurar o `data-testid` no frontend, nao alterar o teste para um seletor
mais fragil

Excecao obrigatoria: nao mantenha `data-testid` em elemento que foi retirado da
jornada real do usuario. E proibido deixar seletor em placeholder invisivel
(`aria-hidden`, `sr-only`, `opacity-0`, tamanho de 1px ou equivalente) apenas
para fazer teste passar. Se a funcionalidade ainda nao esta pronta, remova o
elemento do contrato ativo, documente a pendencia em issue ou TODO do teste e
reative o `data-testid` somente quando o elemento voltar visivel e utilizavel.

Alterar `data-testid` sem pedido explicito do responsavel do fluxo e bloqueio
de PR.

Expand Down
59 changes: 31 additions & 28 deletions web/src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { ArrowRight, Eye, EyeOff, ShieldCheck, Sparkles, Utensils } from "lucide-react";
import { ArrowRight, Eye, EyeOff, ShieldCheck } from "lucide-react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { AuthCarousel } from "@/features/auth/components/AuthCarousel";
Expand Down Expand Up @@ -43,17 +43,19 @@ function AppleIcon() {

function AuthBrand() {
return (
<Link href="/" className="flex items-center gap-3" aria-label="MeVêUm">
<span className="grid h-[46px] w-[46px] place-items-center rounded-[18px] bg-[#FF5C0A] text-white shadow-[0_22px_55px_rgba(234,88,12,0.28)]">
<Utensils className="h-5 w-5" aria-hidden />
<Link href="/" className="flex items-center gap-2.5" aria-label="MeVêUm">
<span className="grid h-9 w-9 place-items-center rounded-xl bg-[#17100C] text-base font-semibold text-white shadow-sm">
M
</span>
<span className="text-xl font-semibold tracking-normal text-[#17100C]">
MeVê<span className="text-[#FF5C0A]">Um</span>
</span>
<span className="text-2xl font-bold tracking-normal text-black">MeVêUm</span>
</Link>
);
}

const inputClass =
"input-base h-[54px] rounded-lg border-[#E8E0D6] bg-[#FBF7F4] px-4 text-base text-[#1C1917] placeholder:text-[#8D8780] focus:border-[#FF5C0A] focus:ring-2 focus:ring-[#FF5C0A]/15";
"input-base h-12 rounded-lg border-[#E8E0D6] bg-[#FBF7F4] px-4 text-sm text-[#1C1917] placeholder:text-[#8D8780] focus:border-[#FF5C0A] focus:ring-2 focus:ring-[#FF5C0A]/15";

export default function LoginPage() {
const router = useRouter();
Expand Down Expand Up @@ -85,31 +87,32 @@ export default function LoginPage() {
}

return (
<main className="min-h-screen bg-[#FBF7F4]">
<div className="mx-auto grid min-h-screen w-full max-w-[1400px] grid-cols-1 lg:grid-cols-2">
<section className="flex min-h-screen flex-col px-6 py-8 sm:px-10 lg:px-16 lg:py-12">
<main className="relative min-h-screen overflow-x-hidden bg-[#FBF7F4] lg:h-screen lg:overflow-hidden">
<div className="bg-grain absolute inset-0 opacity-35" />
<div className="relative mx-auto grid min-h-screen w-full max-w-7xl grid-cols-1 gap-8 px-5 py-5 lg:h-screen lg:min-h-0 lg:grid-cols-[minmax(0,0.95fr)_minmax(420px,0.85fr)]">
<section className="flex min-h-screen flex-col lg:min-h-0">
<header className="flex items-center justify-between gap-4">
<AuthBrand />
<Link href="/" className="text-lg font-medium text-[#6F6861] transition-colors hover:text-[#1C1917]">
← Voltar ao site
<Link href="/" className="text-sm font-medium text-[#6F6861] transition-colors hover:text-[#1C1917]">
&larr; Voltar ao site
</Link>
</header>

<div className="flex flex-1 items-center py-12">
<div className="mx-auto w-full max-w-[560px]">
<div className="mb-7 inline-flex items-center gap-2 rounded-full border border-[#E8E0D6] bg-[#FBF7F4] px-4 py-1.5 shadow-[0_1px_2px_rgba(28,25,23,0.04)]">
<Sparkles className="h-4 w-4 text-[#FF5C0A]" aria-hidden />
<span className="text-base font-medium text-[#3B342E]">Bem-vindo de volta</span>
<div className="flex flex-1 items-center py-8 lg:py-4">
<div className="mx-auto w-full max-w-[470px]">
<div className="mb-5 inline-flex items-center gap-2 rounded-full border border-lborder bg-white px-3 py-1 text-xs font-medium text-lmuted">
<span className="h-1.5 w-1.5 rounded-full bg-ember" />
Bem-vindo de volta
</div>

<h1 className="max-w-[520px] text-[42px] font-bold leading-[1.16] tracking-normal text-black sm:text-[46px]">
<h1 className="max-w-[440px] text-[34px] font-semibold leading-[1.12] tracking-normal text-black sm:text-[38px]">
Entre na sua <span className="text-[#FF5C0A]">central de pedidos.</span>
</h1>
<p className="mt-6 text-xl leading-relaxed text-[#625A53]">
<p className="mt-4 text-base leading-relaxed text-[#625A53]">
Acesse seu cardápio, dashboard e pedidos em um só lugar.
</p>

<div className="mt-8 grid grid-cols-1 gap-3 sm:grid-cols-3">
<div className="mt-6 grid grid-cols-1 gap-3 sm:grid-cols-3">
{[
{ label: "Google", provedor: "google" as const, icon: <GoogleIcon /> },
{ label: "Microsoft", provedor: "microsoft" as const, icon: <MicrosoftIcon /> },
Expand All @@ -120,26 +123,26 @@ export default function LoginPage() {
type="button"
onClick={() => iniciarOAuth(provedor)}
data-testid={`social-login-${provedor}`}
className="flex h-[54px] items-center justify-center gap-3 rounded-lg border border-[#E8E0D6] bg-[#FBF7F4] text-lg font-medium text-[#2C2722] shadow-[0_2px_8px_rgba(28,25,23,0.08)] transition hover:bg-white"
className="flex h-12 items-center justify-center gap-2.5 rounded-lg border border-[#E8E0D6] bg-[#FBF7F4] text-sm font-medium text-[#2C2722] shadow-[0_2px_8px_rgba(28,25,23,0.08)] transition hover:bg-white"
>
{icon}
<span>{label}</span>
</button>
))}
</div>

<div className="relative my-8">
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-[#E2D9CF]" />
</div>
<div className="relative flex justify-center">
<span className="bg-[#FBF7F4] px-4 text-sm font-bold tracking-[0.32em] text-[#AAA29A]">
<span className="bg-[#FBF7F4] px-4 text-xs font-bold tracking-[0.28em] text-[#AAA29A]">
OU COM E-MAIL
</span>
</div>
</div>

<form onSubmit={handleSubmit(onSubmit)} noValidate data-testid="login-form" className="space-y-5">
<form onSubmit={handleSubmit(onSubmit)} noValidate data-testid="login-form" className="space-y-4">
<div>
<label htmlFor="email" className="mb-2 block text-sm font-bold text-[#1C1917]">
E-mail
Expand Down Expand Up @@ -173,7 +176,7 @@ export default function LoginPage() {
<input
id="senha"
type={showPassword ? "text" : "password"}
placeholder="••••••••"
placeholder="........"
autoComplete="current-password"
data-testid="password-input"
className={`${inputClass} pr-12${errors.senha ? " border-red-400 focus:border-red-400" : ""}`}
Expand All @@ -200,28 +203,28 @@ export default function LoginPage() {
type="submit"
disabled={isSubmitting}
data-testid="submit-login-button"
className="mt-7 flex h-[56px] w-full items-center justify-center gap-3 rounded-lg bg-[#FF5C0A] text-lg font-bold tracking-[0.04em] text-white shadow-[0_22px_40px_rgba(234,88,12,0.22)] transition hover:bg-[#EA580C] disabled:cursor-not-allowed disabled:opacity-60"
className="mt-6 flex h-12 w-full items-center justify-center gap-3 rounded-lg bg-[#FF5C0A] text-sm font-bold tracking-[0.04em] text-white shadow-[0_18px_34px_rgba(234,88,12,0.18)] transition hover:bg-[#EA580C] disabled:cursor-not-allowed disabled:opacity-60"
>
{isSubmitting ? "Entrando..." : "ENTRAR"}
{!isSubmitting && <ArrowRight className="h-5 w-5" aria-hidden />}
</button>
</form>

<p className="mt-8 text-center text-lg text-[#625A53]">
<p className="mt-6 text-center text-sm text-[#625A53]">
Ainda não tem conta?{" "}
<Link href="/register" className="font-bold text-[#FF5C0A] hover:underline">
Criar conta grátis
</Link>
</p>

<div className="mt-10 flex items-center justify-center gap-2 text-sm text-[#8D8780]">
<div className="mt-7 flex items-center justify-center gap-2 text-xs text-[#8D8780]">
<ShieldCheck className="h-4 w-4 text-[#FF5C0A]" aria-hidden />
<span>Conexão segura · seus dados são criptografados</span>
</div>
</div>
</div>

<footer className="pt-6 text-base text-[#8D8780]">
<footer className="hidden pb-1 text-xs text-[#8D8780] lg:block">
© 2026 MeVêUm · Sistema para restaurantes brasileiros
</footer>
</section>
Expand Down
Loading
Loading