@isi-ui7/bos7-shared 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,136 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { render, screen, waitFor } from "@testing-library/react";
3
+
4
+ // Dimock supaya mode `edit`/`view` tidak menggantung di InlineLoading: tanpa
5
+ // `loadApiPath` yang selesai, `loading` tidak pernah kembali false dan yang
6
+ // terender hanya spinner — uji akan "lulus" karena stepper-nya memang belum
7
+ // sempat dirender, bukan karena perbaikannya bekerja. Itu lulus palsu.
8
+ vi.mock("./workflow/crud-client", () => ({
9
+ fetchDetailData: vi.fn(async () => ({ f1: "satu", f2: "dua", f3: "tiga" })),
10
+ submitWorkflowForm: vi.fn(async () => "wf-1"),
11
+ }));
12
+
13
+ import { CrudSchemaPage } from "./crud-components";
14
+ import type { CrudForm } from "./form-types";
15
+
16
+ type D = { f1: string; f2: string; f3: string };
17
+
18
+ const schema: CrudForm<D> = {
19
+ title: { create: "Baru", edit: "Ubah", view: "Lihat" },
20
+ emptyData: { f1: "", f2: "", f3: "" },
21
+ createApiPath: "/api/x/create",
22
+ updateApiPath: () => "/api/x/1",
23
+ loadApiPath: () => "/api/x/1",
24
+ layout: {
25
+ type: "wizard",
26
+ pages: [
27
+ { label: "Langkah Satu", sublabel: "Sub Satu", sections: [{ title: "S1", fields: [{ key: "f1", label: "Field Satu", type: "text", span: 4 }] }] },
28
+ { label: "Langkah Dua", sublabel: "Sub Dua", sections: [{ title: "S2", fields: [{ key: "f2", label: "Field Dua", type: "text", span: 4 }] }] },
29
+ { label: "Langkah Tiga", sublabel: "Sub Tiga", sections: [{ title: "S3", fields: [{ key: "f3", label: "Field Tiga", type: "text", span: 4 }] }] },
30
+ ],
31
+ },
32
+ };
33
+
34
+ // Stepper dirender sebagai <nav aria-label=…> — satu-satunya landmark navigasi
35
+ // di halaman ini, jadi role "navigation" cukup untuk membedakannya.
36
+ const stepper = () => screen.queryByRole("navigation");
37
+
38
+ // Pada `view` field dirender sebagai nilai baca-saja, BUKAN input berlabel —
39
+ // jadi getByLabelText hanya bekerja di create/edit. Query teks label bekerja di
40
+ // ketiga mode, sehingga uji ini membandingkan hal yang sama di semua mode.
41
+ const fieldTampil = (nama: string) => screen.queryByText(nama) !== null;
42
+
43
+ beforeEach(() => {
44
+ vi.clearAllMocks();
45
+ });
46
+
47
+ describe("navigasi wizard hanya pada mode create", () => {
48
+ it("create — stepper TAMPIL dan hanya halaman aktif yang dirender", async () => {
49
+ render(<CrudSchemaPage schema={schema} mode="create" />);
50
+
51
+ expect(stepper(), "stepper harus ada saat membuat data baru").not.toBeNull();
52
+ expect(screen.getByText("Langkah Tiga")).toBeTruthy(); // ada di stepper…
53
+ expect(fieldTampil("Field Satu")).toBe(true);
54
+ // …tapi field-nya belum, karena halaman 3 belum dibuka.
55
+ expect(fieldTampil("Field Tiga")).toBe(false);
56
+ });
57
+
58
+ it("view — stepper TIDAK ada, dan SELURUH halaman terbaca sekaligus", async () => {
59
+ render(<CrudSchemaPage schema={schema} mode="view" />);
60
+ await waitFor(() => expect(fieldTampil("Field Satu")).toBe(true));
61
+
62
+ expect(stepper(), "view tidak boleh punya navigasi langkah").toBeNull();
63
+ // Inti perbaikannya: nol navigasi TIDAK boleh berarti isi yang hilang.
64
+ // Sebelum ini, `view` merender satu halaman saja sementara footernya nol
65
+ // tombol Lanjut — jadi langkah 2-5 tidak bisa dibaca sama sekali.
66
+ for (const label of ["Field Satu", "Field Dua", "Field Tiga"]) {
67
+ expect(fieldTampil(label), `${label} harus terbaca di view`).toBe(true);
68
+ }
69
+ });
70
+
71
+ // Ditambahkan setelah verifikasi adversarial membantah klaim "nol isi yang
72
+ // hilang": versi pertama perbaikan ini me-`flatMap` seluruh section dan
73
+ // membuang `pg.label`/`pg.sublabel` — 10 string konkret lenyap dari layar
74
+ // perorangan, dan uji versi pertama nol memeriksanya karena ia hanya
75
+ // menanyakan field dan stepper.
76
+ it.each(["view", "edit"] as const)(
77
+ "%s — label & sublabel halaman TETAP terbaca sebagai judul kelompok",
78
+ async (mode) => {
79
+ render(<CrudSchemaPage schema={schema} mode={mode} />);
80
+ await waitFor(() => expect(fieldTampil("Field Satu")).toBe(true));
81
+
82
+ expect(stepper(), "judul kelompok bukan navigasi").toBeNull();
83
+ for (const l of ["Langkah Satu", "Langkah Dua", "Langkah Tiga"]) {
84
+ expect(fieldTampil(l), `${l} hilang dari ${mode}`).toBe(true);
85
+ }
86
+ for (const s of ["Sub Satu", "Sub Dua", "Sub Tiga"]) {
87
+ expect(fieldTampil(s), `sublabel ${s} hilang dari ${mode}`).toBe(true);
88
+ }
89
+ },
90
+ );
91
+
92
+ it("edit — stepper TIDAK ada, seluruh halaman terbaca, nol tombol Lanjut", async () => {
93
+ render(<CrudSchemaPage schema={schema} mode="edit" />);
94
+ await waitFor(() => expect(fieldTampil("Field Satu")).toBe(true));
95
+
96
+ expect(stepper(), "edit tidak boleh punya navigasi langkah").toBeNull();
97
+ expect(fieldTampil("Field Tiga")).toBe(true);
98
+
99
+ const tombol = screen.getAllByRole("button").map((b) => b.textContent ?? "");
100
+ expect(tombol.some((t) => /lanjut|next/i.test(t)), `masih ada tombol Lanjut: ${tombol.join("|")}`).toBe(false);
101
+ expect(tombol.some((t) => /kembali|prev/i.test(t)), `masih ada tombol Kembali: ${tombol.join("|")}`).toBe(false);
102
+ });
103
+
104
+ // Kontrol kedua, dan ini yang penting: `tabs` juga punya `pages`, jadi ia
105
+ // kandidat paling mungkin ikut terseret kalau urutan cabang render bergeser.
106
+ // Tanpa kontrol ini, memindahkan cabang datar ke atas cabang `tabs` akan
107
+ // meratakan 4 layar bos7-enterprise/bos7-financing tanpa satu pun galat.
108
+ it("kontrol negatif — layout tabs tetap bertab, tidak ikut diratakan", async () => {
109
+ const tabs: CrudForm<D> = {
110
+ ...schema,
111
+ layout: {
112
+ type: "tabs",
113
+ pages: [
114
+ { label: "Tab Satu", sections: [{ title: "T1", fields: [{ key: "f1", label: "Field Satu", type: "text", span: 4 }] }] },
115
+ { label: "Tab Dua", sections: [{ title: "T2", fields: [{ key: "f2", label: "Field Dua", type: "text", span: 4 }] }] },
116
+ ],
117
+ },
118
+ };
119
+ render(<CrudSchemaPage schema={tabs} mode="view" />);
120
+ await waitFor(() => expect(fieldTampil("Field Satu")).toBe(true));
121
+
122
+ // Tab masih tab: tombol role=tab ada, dan hanya tab aktif yang terlihat.
123
+ expect(screen.getAllByRole("tab").length, "tab hilang — cabang datar menelan layout tabs").toBe(2);
124
+ expect(stepper()).toBeNull();
125
+ });
126
+
127
+ it("kontrol negatif — layout single-page tidak ikut berubah", async () => {
128
+ const single: CrudForm<D> = {
129
+ ...schema,
130
+ layout: { type: "single-page", sections: [{ title: "S", fields: [{ key: "f1", label: "Field Satu", type: "text", span: 4 }] }] },
131
+ };
132
+ render(<CrudSchemaPage schema={single} mode="view" />);
133
+ await waitFor(() => expect(fieldTampil("Field Satu")).toBe(true));
134
+ expect(stepper()).toBeNull();
135
+ });
136
+ });