Open History to see the last commit
1import { render } from "../../../test/render";
2import { DEFAULT_UNIFIED_SETTINGS } from "@t3tools/contracts/settings";
3import { StrictMode, type ReactNode } from "react";
4import { describe, expect, it, vi } from "vite-plus/test";
5import { page, userEvent } from "vite-plus/test/browser";
6
7import "../../index.css";
8import type { ScopedSettingsPatch } from "./scopedSettings";
9
10type WritingStyle = typeof DEFAULT_UNIFIED_SETTINGS.sourceControlWritingStyle;
11const state = vi.hoisted(() => ({
12 styles: [] as WritingStyle[],
13 updateSettings: vi.fn<(patch: ScopedSettingsPatch) => void>(),
14}));
15
16vi.mock(import("@tanstack/react-router"), async (original) => ({
17 ...(await original()),
18 useNavigate: (() => vi.fn()) as never,
19}));
20vi.mock(import("./useScopedSettings"), async (original) => ({
21 ...(await original()),
22 useScopedSettings: (() => ({
23 ...DEFAULT_UNIFIED_SETTINGS,
24 sourceControlWritingStyle: state.styles[0],
25 })) as never,
26 useScopedSettingsMixed: (keys) =>
27 !keys.includes("reviewGuidesEnabled") &&
28 JSON.stringify(state.styles[0]) !== JSON.stringify(state.styles[1]),
29 useUpdateScopedSettings: () => state.updateSettings,
30}));
31vi.mock(import("./SettingsScopeContext"), async (original) => ({
32 ...(await original()),
33 useSettingsScope: (() => ({
34 scope: { kind: "all", environmentIds: [] },
35 environment: null,
36 connectedEnvironments: [],
37 targets: state.styles.map((style) => ({
38 settings: { ...DEFAULT_UNIFIED_SETTINGS, sourceControlWritingStyle: style },
39 })),
40 target: null,
41 })) as never,
42}));
43vi.mock(import("../../state/environments"), async (original) => ({
44 ...(await original()),
45 useEnvironmentProviders: () => new Map(),
46}));
47vi.mock(import("./SettingsModelPicker"), async (original) => ({
48 ...(await original()),
49 SettingsModelPicker: (() => null) as never,
50}));
51vi.mock(import("./settingsLayout"), async (original) => ({
52 ...(await original()),
53 SettingsRow: ({ title, control, resetAction, children }) => (
54 <div>
55 <h3>{title}</h3>
56 {control}
57 {resetAction}
58 {children}
59 </div>
60 ),
61 SettingsSection: (({ children }: { children: ReactNode }) => children) as never,
62}));
63
64import { SourceControlWritingSettingsSection } from "./SourceControlWritingSettings";
65
66const resetButton = (label: string) =>
67 page.getByRole("button", { name: `Reset ${label} to default` });
68
69const content = () => (
70 <StrictMode>
71 <SourceControlWritingSettingsSection />
72 </StrictMode>
73);
74
75async function setup() {
76 state.styles = [
77 {
78 ...DEFAULT_UNIFIED_SETTINGS.sourceControlWritingStyle,
79 mode: "custom",
80 customInstructions: "First environment instructions",
81 followChangeRequestTemplates: true,
82 },
83 {
84 ...DEFAULT_UNIFIED_SETTINGS.sourceControlWritingStyle,
85 mode: "custom",
86 customInstructions: "Second environment instructions",
87 followChangeRequestTemplates: false,
88 },
89 ];
90 const screen = await render(content());
91 state.updateSettings.mockReset().mockImplementation((patch) => {
92 state.styles = state.styles.map((style) => ({ ...style, ...patch.sourceControlWritingStyle }));
93 void screen.rerender(content());
94 });
95 return screen;
96}
97
98describe("mixed source control instructions", () => {
99 it("resets mixed template preferences without replacing each environment's instructions", async () => {
100 await using _screen = await setup();
101 const initialInstructions = state.styles.map(({ mode, customInstructions }) => ({
102 mode,
103 customInstructions,
104 }));
105
106 await userEvent.click(page.getByRole("button", { name: "Advanced" }));
107 // Mid-open, Playwright scrolls the clipped panel to reach the button, then the growing panel
108 // shifts it between press and release and the click misses. Wait until the panel shows it.
109 await expect.element(resetButton("pull request templates")).toBeInViewport({ ratio: 1 });
110 await userEvent.click(resetButton("pull request templates"));
111
112 expect(state.updateSettings).toHaveBeenCalledTimes(1);
113 expect(state.styles.map((style) => style.followChangeRequestTemplates)).toEqual([
114 DEFAULT_UNIFIED_SETTINGS.sourceControlWritingStyle.followChangeRequestTemplates,
115 DEFAULT_UNIFIED_SETTINGS.sourceControlWritingStyle.followChangeRequestTemplates,
116 ]);
117 expect(
118 state.styles.map(({ mode, customInstructions }) => ({ mode, customInstructions })),
119 ).toEqual(initialInstructions);
120 });
121});