Skip to content

Commit 51bc7ca

Browse files
Pessoaclaude
andcommitted
test(notificacoes): a cópia à mão do snapshot do servidor ganha vigia
Acabamento do #695. `getServerSnapshot` precisa de um valor determinístico, e derivá-lo chamando `prefsPadrao()` no escopo do módulo leria o `localStorage` de verdade no navegador — justamente o que ele existe para não fazer. Então `PREFS_DO_SERVIDOR` é uma duplicata deliberada, e estava certa. O que faltava era o vigia. Quem acrescentar uma categoria a `NOTIFY_UI_CATEGORIES` muda `prefsPadrao()` e não muda o objeto congelado; aí `getServerSnapshot` devolve um objeto SEM aquela chave, o componente lê `prefs[cat][canal]` e estoura — ou, pior, o React vê valores diferentes dos dois lados e o defeito de hidratação da #690 volta calado, que é a forma exata em que ele viveu até agora. A comparação roda com `window` apagado de propósito: é a única condição em que `prefsPadrao()` é determinístico, e é a condição em que o servidor roda. Tem controle de vacuidade — sem ele, o caso das categorias passaria com a lista vazia. Trabalho original de @dajiaohuang no PR #695. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent a9e529b commit 51bc7ca

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

lib/notifications/prefs.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,20 @@ const PREFS_DO_SERVIDOR: NotifyPrefs = {
101101
mention: { in_app: true, push: true },
102102
};
103103

104-
/** Sem `window`, `prefsPadrao()` devolve exatamente este valor — congelado aqui. */
104+
/**
105+
* Sem `window`, `prefsPadrao()` devolve exatamente este valor — congelado aqui.
106+
*
107+
* É uma DUPLICATA deliberada, e ela não pode ser derivada: chamar
108+
* `prefsPadrao()` no escopo do módulo leria o `localStorage` de verdade no
109+
* navegador, que é justamente o que este valor existe para não fazer.
110+
*
111+
* Duplicata sem vigia diverge. Quem acrescentar uma categoria a
112+
* `NOTIFY_UI_CATEGORIES`, ou mudar um padrão, muda `prefsPadrao()` e não muda
113+
* este objeto — e o desfecho é a volta silenciosa do defeito que o PR #695
114+
* consertou, ou pior: `getServerSnapshot` devolvendo um objeto sem a chave que
115+
* o componente vai ler. O vigia é
116+
* `tests/unit/prefs-do-servidor-nao-diverge-do-padrao.test.ts`.
117+
*/
105118
export function getPrefsSnapshotDoServidor(): NotifyPrefs {
106119
return PREFS_DO_SERVIDOR;
107120
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* O SNAPSHOT DO SERVIDOR É UMA CÓPIA À MÃO — ESTE ARQUIVO É O QUE A IMPEDE DE DIVERGIR.
3+
*
4+
* `lib/notifications/prefs.ts` guarda `PREFS_DO_SERVIDOR` escrito à mão, e a
5+
* duplicata é deliberada: derivar o valor chamando `prefsPadrao()` no escopo do
6+
* módulo leria o `localStorage` de verdade no navegador, que é exatamente o que
7+
* `getServerSnapshot` existe para não fazer.
8+
*
9+
* Mas duplicata sem vigia diverge. Acrescentar uma categoria a
10+
* `NOTIFY_UI_CATEGORIES` muda `prefsPadrao()` e não muda o objeto congelado — e
11+
* aí `getServerSnapshot` devolve um objeto SEM aquela chave. O componente lê
12+
* `prefs[cat][canal]` e estoura, ou (pior) o React vê valores diferentes dos
13+
* dois lados e o defeito de hidratação do #690 volta calado.
14+
*
15+
* A comparação tem de ser feita SEM `window` — é a única condição em que
16+
* `prefsPadrao()` é determinístico, e é a condição em que o servidor roda.
17+
*/
18+
import { afterEach, describe, expect, it } from "vitest";
19+
20+
import { NOTIFY_UI_CATEGORIES, getPrefsSnapshotDoServidor, prefsPadrao } from "@/lib/notifications/prefs";
21+
22+
const janelaReal = globalThis.window;
23+
24+
afterEach(() => {
25+
globalThis.window = janelaReal;
26+
});
27+
28+
/** O que `prefsPadrao()` produz num Node sem DOM — o que o servidor de verdade vê. */
29+
function padraoSemJanela() {
30+
// @ts-expect-error — apagar de propósito, para `typeof window === "undefined"` ser verdade.
31+
delete globalThis.window;
32+
try {
33+
return prefsPadrao();
34+
} finally {
35+
globalThis.window = janelaReal;
36+
}
37+
}
38+
39+
describe("o snapshot do servidor é idêntico ao padrão que o servidor produz", () => {
40+
it("CONTROLE: sem este caso, os de baixo passariam com a lista vazia", () => {
41+
expect(NOTIFY_UI_CATEGORIES.length).toBeGreaterThanOrEqual(5);
42+
});
43+
44+
it("os dois objetos são iguais em profundidade", () => {
45+
expect(
46+
getPrefsSnapshotDoServidor(),
47+
"`PREFS_DO_SERVIDOR` divergiu de `prefsPadrao()`. Quem mudar um tem de " +
48+
"mudar o outro — senão o servidor e a primeira renderização do cliente " +
49+
"voltam a discordar, que é o defeito da issue #690.",
50+
).toEqual(padraoSemJanela());
51+
});
52+
53+
it("toda categoria declarada existe no snapshot do servidor, nos dois canais", () => {
54+
const doServidor = getPrefsSnapshotDoServidor();
55+
for (const categoria of NOTIFY_UI_CATEGORIES) {
56+
expect(doServidor[categoria], `categoria \`${categoria}\` ausente`).toBeDefined();
57+
expect(typeof doServidor[categoria].in_app).toBe("boolean");
58+
expect(typeof doServidor[categoria].push).toBe("boolean");
59+
}
60+
});
61+
});

0 commit comments

Comments
 (0)