Skip to content
Merged
93 changes: 93 additions & 0 deletions scripts/screenshot/specs/app-setup-script-settings.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import * as React from "react";
import { expect, it } from "vitest";
import userEvent from "@testing-library/user-event";
import { createTestRepo, openRepo } from "../../../test/utils";
import { render, screen, waitFor, within } from "../../../test/test-utils";
import { Dashboard } from "../../../src/components/Dashboard";
import { saveAppSetupScript } from "../../../src/lib/api";
import { captureDocument } from "../capture";

const SCRIPT = [
"echo installing tools",
"echo 'warning: jj already installed'",
"echo 'error: brew not found' 1>&2",
"echo setup done",
].join("\n");

it("captures the application setup script settings", async () => {
const { repoPath } = createTestRepo(false);
openRepo(repoPath);
await saveAppSetupScript("", false);

const user = userEvent.setup();
render(<Dashboard />);
await user.click(await screen.findByLabelText("Settings"));
await user.click(await screen.findByRole("tab", { name: /application/i }));
const textarea = await screen.findByLabelText("Application Setup Script");
await screen.findByText("Never run");
const run = screen.getByRole("button", { name: /^run$/i });
expect(run).toBeDisabled();
await captureDocument(document, {
name: "app-setup-script-settings-01-empty",
viewport: { width: 1440, height: 1200 },
expectations: [
"An 'Application Setup Script' textarea with a monospace placeholder sits in the Application tab.",
"A 'Run on every app startup' switch is shown in the off state with its label beside it.",
"A disabled 'Run' button sits below the switch, with 'Never run' beside it.",
],
});

await user.type(textarea, SCRIPT);
await screen.findByText("Save settings to run the edited script.");
expect(run).toBeDisabled();
await captureDocument(document, {
name: "app-setup-script-settings-02-unsaved",
viewport: { width: 1440, height: 1200 },
expectations: [
"The textarea shows the four-line script in monospace.",
"The 'Run' button is still disabled (greyed out).",
"Beside it the hint reads 'Save settings to run the edited script.'",
],
});

await user.click(screen.getByRole("button", { name: /save settings/i }));
await waitFor(() => expect(run).toBeEnabled());
expect(screen.getByText("Never run")).toBeTruthy();
await captureDocument(document, {
name: "app-setup-script-settings-03-saved",
viewport: { width: 1440, height: 1200 },
expectations: [
"The 'Run' button is enabled after saving.",
"The status beside it still reads 'Never run': saving did not run the script.",
],
});

await user.click(run);
await screen.findByText(/Last run .* passed/);
await captureDocument(document, {
name: "app-setup-script-settings-04-ran",
viewport: { width: 1440, height: 1200 },
expectations: [
"Beside the enabled 'Run' button the status reads 'Last run <timestamp> · passed'.",
],
});

await user.click(screen.getByRole("button", { name: "Close" }));
await user.click(await screen.findByRole("tab", { name: /^Logs/ }));
await user.selectOptions(
await screen.findByLabelText("Log source"),
"app-setup",
);
const output = await screen.findByTestId("app-setup-logs-output");
await within(output).findByText("setup done");
await within(output).findByText("error: brew not found");
await captureDocument(document, {
name: "app-setup-script-settings-05-logs",
viewport: { width: 1440, height: 900 },
expectations: [
"The Logs tab 'Log source' select shows 'App setup', with a level filter and search box below it.",
"The feed lists the four script output lines, each prefixed with run '#1'.",
"The 'error: brew not found' line is styled as an error and the 'warning:' line as a warning.",
],
});
}, 60000);
40 changes: 40 additions & 0 deletions src-tauri/src/commands/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,43 @@ pub fn set_window_repo_path(
map.insert(window_map_label(window_label), repo_path);
Ok(())
}

#[tauri::command]
pub fn get_app_setup_script_status(
state: State<AppState>,
) -> Result<core::app_setup_script::AppSetupScriptStatus, String> {
let db = state.db.lock_or_recover();
core::app_setup_script::get_status(&db)
}

#[tauri::command]
pub fn save_app_setup_script(
state: State<AppState>,
script: String,
always_run: bool,
) -> Result<(), String> {
let db = state.db.lock_or_recover();
core::app_setup_script::save(&db, &script, always_run)
}

#[tauri::command]
pub fn run_app_setup_script() {
core::app_setup_script::spawn_run_if_needed(core::app_setup_script::Trigger::Manual);
}

#[tauri::command]
pub async fn get_app_setup_logs(
levels: Option<Vec<String>>,
search: Option<String>,
) -> Result<Vec<core::checks_logs::LogRecordView>, String> {
tauri::async_runtime::spawn_blocking(move || {
let query = core::checks_logs::LogQuery {
levels,
search,
..Default::default()
};
core::app_setup_script::query_logs(&core::app_setup_script::app_db_path()?, &query)
})
.await
.map_err(|e| e.to_string())?
}
Loading
Loading