Improve overview rendering with custom colors and graphical details
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, expect, test } from "bun:test";
|
||||
import { Window } from "happy-dom";
|
||||
import { act } from "react";
|
||||
import { act, useState } from "react";
|
||||
import type { Root } from "react-dom/client";
|
||||
import { ProgressOverview } from "./ProgressOverview";
|
||||
import { fixture } from "../habits/test-fixture";
|
||||
@@ -51,11 +51,15 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
function button(text: string) {
|
||||
return [...container.querySelectorAll<HTMLButtonElement>("button")].find((element) => element.textContent?.trim() === text)!;
|
||||
return [...container.querySelectorAll<HTMLButtonElement>("button")].find((element) => element.textContent?.trim() === text || element.getAttribute("aria-label") === text || element.getAttribute("aria-label")?.startsWith(`${text} `))!;
|
||||
}
|
||||
|
||||
function Dashboard() {
|
||||
const [creating, setCreating] = useState(false);
|
||||
return <><button id="create-overview" onClick={() => setCreating(true)}>Create overview</button><div className="ds-habit-list"><ProgressOverview creating={creating} onCloseCreate={() => setCreating(false)} date="2026-09-04" revision={0} onExpired={() => {}} onHistorySaved={() => {}} /></div></>;
|
||||
}
|
||||
async function render() {
|
||||
await act(async () => root.render(<ProgressOverview date="2026-09-04" revision={0} onExpired={() => {}} onHistorySaved={() => {}} />));
|
||||
await act(async () => root.render(<Dashboard />));
|
||||
}
|
||||
function checkbox(label: string) {
|
||||
return [...container.querySelectorAll('label')].find(element => element.textContent === label)!.querySelector<HTMLInputElement>('input')!;
|
||||
@@ -151,3 +155,42 @@ test("range changes retain the selected window and future or unscheduled days ha
|
||||
expect(container.querySelector('#overview-day')!.textContent).toContain('Upcoming');
|
||||
expect([...container.querySelectorAll('#overview-day button')].some(b => b.textContent?.startsWith('Edit '))).toBe(false);
|
||||
});
|
||||
|
||||
test("all overviews render in the habit list and custom colors persist without resetting other settings", async () => {
|
||||
const habit = await f.json('/habits', 'POST', { name: 'Read', method: 'manual' }, 201);
|
||||
const first = await f.json('/charts', 'POST', { name: 'Health', habitIds: [habit.id], settings: { mainColor: '#112233', shadeCount: 7 } }, 201);
|
||||
await f.json('/charts', 'POST', { name: 'Learning', habitIds: [habit.id] }, 201);
|
||||
await render();
|
||||
expect(container.querySelectorAll('.ds-habit-list > .ds-overview')).toHaveLength(2);
|
||||
expect(container.querySelector('select')).toBeNull();
|
||||
expect([...container.querySelectorAll('.ds-goal-meta')].map(el => el.textContent)).toEqual(['Combined chart · 1 habit', 'Combined chart · 1 habit']);
|
||||
await click('Edit overview Health');
|
||||
await click('Custom');
|
||||
const hex = container.querySelector<HTMLInputElement>('input[placeholder="#426582"]')!;
|
||||
await act(async () => {
|
||||
Object.getOwnPropertyDescriptor(dom.HTMLInputElement.prototype, 'value')!.set!.call(hex, '#a35488');
|
||||
hex.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
});
|
||||
await click('Save overview');
|
||||
expect((await f.json(`/charts/${first.id}`)).settings).toMatchObject({ mainColor: '#a35488', shadeCount: 7 });
|
||||
expect(container.querySelectorAll('.ds-overview')).toHaveLength(2);
|
||||
await click('Edit overview Health');
|
||||
expect(container.querySelector<HTMLInputElement>('input[placeholder="#426582"]')!.value).toBe('#a35488');
|
||||
});
|
||||
|
||||
test("day graphics show partial task and count progress without crediting incomplete habits", async () => {
|
||||
const count = await f.json('/habits', 'POST', { name: 'Water', method: 'count', target: 8, unit: 'glasses' }, 201);
|
||||
const routine = await f.json('/habits', 'POST', { name: 'Routine', method: 'tasks', tasks: [{ name: 'Stretch' }, { name: 'Walk' }] }, 201);
|
||||
const manual = await f.json('/habits', 'POST', { name: 'Read', method: 'manual' }, 201);
|
||||
await f.json(`/habits/${count.id}/days/2026-09-04/progress`, 'PUT', { count: 7 });
|
||||
await f.json(`/habits/${manual.id}/days/2026-09-04/progress`, 'PUT', { done: true });
|
||||
await f.json(`/habits/${routine.id}/days/2026-09-04/tasks/${routine.tasks[0].id}`, 'PUT', { done: true });
|
||||
await f.json('/charts', 'POST', { name: 'Together', habitIds: [count.id, routine.id, manual.id] }, 201);
|
||||
await render();
|
||||
await click('View day details');
|
||||
expect(container.querySelector('.ds-overview-ring')?.textContent).toBe('33%');
|
||||
expect(container.querySelector('progress[aria-label="Water progress"]')?.getAttribute('value')).toBe('7');
|
||||
expect(container.querySelector('progress[aria-label="Routine progress"]')?.getAttribute('value')).toBe('1');
|
||||
expect(container.querySelectorAll('.ds-overview-tasks li')).toHaveLength(2);
|
||||
expect(container.querySelector('.ds-overview-check')?.textContent).toBe('Checked in');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user