Files
portifolio-evandrodevbr/lib/device.test.ts
T
Evandro Fonseca Junior 204ebd5fa5 fix(navegacao): foco em âncora de outra página, vitrine acessível e 3D mais leve
Foco cai no destino ao chegar de outra página; âncoras ignoram ?tipo=; movimento reduzido salta em todos os cliques; cronômetro da janela ampliada; degradê no topo de Projetos e legendas do mergulho com intervalos testados; vitrine acima da barra de cookies e com 2 paradas por projeto; reel-list.css no global; 3D montado em tarefas curtas, limitado a ~30 qps e estático com WebGL por software; pôsteres da vitrine de 330 para 158 KB; SC Plus regravado; scripts sem funções acima de complexidade 10.
2026-10-14 19:14:48 -03:00

125 lines
4.0 KiB
TypeScript

import {
isCoarsePointer,
isLowPowerDevice,
isMobileViewport,
isSaveData,
isSoftwareRenderer,
isSoftwareWebGL,
MOBILE_QUERY,
} from "./device";
const originalMatchMedia = window.matchMedia;
function mockMedia(active: string[]) {
window.matchMedia = jest.fn().mockImplementation((query: string) => ({
matches: active.includes(query),
media: query,
addEventListener() {},
removeEventListener() {},
}));
}
function mockNavigator(values: Record<string, unknown>) {
for (const [key, value] of Object.entries(values))
Object.defineProperty(navigator, key, { configurable: true, value });
}
beforeEach(() => {
mockMedia([]);
mockNavigator({
hardwareConcurrency: 8,
deviceMemory: undefined,
connection: undefined,
});
});
afterEach(() => {
window.matchMedia = originalMatchMedia;
});
describe("device hints", () => {
it("treats a capable desktop as full power", () => {
expect(isLowPowerDevice()).toBe(false);
expect(isCoarsePointer()).toBe(false);
expect(isSaveData()).toBe(false);
expect(isMobileViewport()).toBe(false);
});
it("reads the phone breakpoint from the shared query", () => {
mockMedia([MOBILE_QUERY]);
expect(isMobileViewport()).toBe(true);
expect(MOBILE_QUERY).toBe("(max-width: 767px)");
});
it.each([
["a touch pointer", () => mockMedia(["(pointer: coarse)"])],
["reduced motion", () => mockMedia(["(prefers-reduced-motion: reduce)"])],
["the data saver", () => mockNavigator({ connection: { saveData: true } })],
["four cores", () => mockNavigator({ hardwareConcurrency: 4 })],
["two cores", () => mockNavigator({ hardwareConcurrency: 2 })],
["4 GB of memory", () => mockNavigator({ deviceMemory: 4 })],
["2 GB of memory", () => mockNavigator({ deviceMemory: 2 })],
])("is low power with %s", (_label, arrange) => {
arrange();
expect(isLowPowerDevice()).toBe(true);
});
it("does not penalize a browser that hides the hardware hints", () => {
mockNavigator({ hardwareConcurrency: undefined, deviceMemory: undefined });
expect(isLowPowerDevice()).toBe(false);
});
it("keeps 8 GB and 6 cores on the full path", () => {
mockNavigator({ hardwareConcurrency: 6, deviceMemory: 8 });
expect(isLowPowerDevice()).toBe(false);
});
});
describe("software WebGL", () => {
it.each([
"ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)",
"llvmpipe (LLVM 15.0.7, 256 bits)",
"ANGLE (Microsoft, Microsoft Basic Render Driver (0x0000008C) Direct3D11 vs_5_0 ps_5_0, D3D11)",
"SWIFTSHADER",
])("recognizes the software renderer %s", (name) => {
expect(isSoftwareRenderer(name)).toBe(true);
});
it.each([
"ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11)",
"ANGLE (Apple, ANGLE Metal Renderer: Apple M2, Unspecified Version)",
"Mesa Intel(R) UHD Graphics 620 (KBL GT2)",
"",
])("does not mistake the GPU %s for software", (name) => {
expect(isSoftwareRenderer(name)).toBe(false);
});
/** Um contexto WebGL de mentira: a extensão de depuração e o nome do renderizador. */
function context(renderer: unknown, hasExtension = true) {
return {
getExtension: jest.fn((name: string) =>
hasExtension && name === "WEBGL_debug_renderer_info"
? { UNMASKED_RENDERER_WEBGL: 37446 }
: null,
),
getParameter: jest.fn((parameter: number) =>
parameter === 37446 ? renderer : null,
),
} as unknown as WebGL2RenderingContext;
}
it("reads the unmasked renderer through WEBGL_debug_renderer_info", () => {
expect(isSoftwareWebGL(context("llvmpipe (LLVM 15.0.7, 256 bits)"))).toBe(
true,
);
expect(isSoftwareWebGL(context("ANGLE (NVIDIA GeForce RTX 3060)"))).toBe(
false,
);
});
it("does not count against a browser that hides the extension or returns no name", () => {
expect(isSoftwareWebGL(context("llvmpipe", false))).toBe(false);
expect(isSoftwareWebGL(context(null))).toBe(false);
});
});