Expand graphical acceptance coverage
This commit is contained in:
+23
-2
@@ -22,6 +22,16 @@ export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=$XDG_RUNT
|
|||||||
export OMARCHY_PATH="${OMARCHY_PATH:-$ROOT}"
|
export OMARCHY_PATH="${OMARCHY_PATH:-$ROOT}"
|
||||||
export PATH="$OMARCHY_PATH/bin:$PATH"
|
export PATH="$OMARCHY_PATH/bin:$PATH"
|
||||||
|
|
||||||
|
if [[ -z ${DISPLAY:-} ]]; then
|
||||||
|
display=$(systemctl --user show-environment | sed -n 's/^DISPLAY=//p' | head -1)
|
||||||
|
export DISPLAY="${display:-:0}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${LANG:-} ]]; then
|
||||||
|
locale_name=$(systemctl --user show-environment | sed -n 's/^LANG=//p' | head -1)
|
||||||
|
export LANG="${locale_name:-C.UTF-8}"
|
||||||
|
fi
|
||||||
|
|
||||||
# First boot may still be settling; wait for Hyprland to come up.
|
# First boot may still be settling; wait for Hyprland to come up.
|
||||||
boot_deadline=$((SECONDS + ${OMARCHY_ACCEPTANCE_BOOT_TIMEOUT:-300}))
|
boot_deadline=$((SECONDS + ${OMARCHY_ACCEPTANCE_BOOT_TIMEOUT:-300}))
|
||||||
|
|
||||||
@@ -66,9 +76,20 @@ if (( ${#tests[@]} == 0 )); then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
status=0
|
||||||
|
suite_started=$SECONDS
|
||||||
for test in "${tests[@]}"; do
|
for test in "${tests[@]}"; do
|
||||||
|
test_started=$SECONDS
|
||||||
printf '==> %s\n' "${test#$ROOT/}"
|
printf '==> %s\n' "${test#$ROOT/}"
|
||||||
bash "$test"
|
if ! timeout "${OMARCHY_ACCEPTANCE_TEST_TIMEOUT:-420}" bash "$test"; then
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
printf ' completed in %ss\n' "$((SECONDS - test_started))"
|
||||||
done
|
done
|
||||||
|
|
||||||
printf 'ok - acceptance suite passed (artifacts in %s)\n' "$OMARCHY_ACCEPTANCE_DIR"
|
if ((status != 0)); then
|
||||||
|
printf 'not ok - acceptance suite failed in %ss (artifacts in %s)\n' "$((SECONDS - suite_started))" "$OMARCHY_ACCEPTANCE_DIR" >&2
|
||||||
|
exit $status
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'ok - acceptance suite passed in %ss (artifacts in %s)\n' "$((SECONDS - suite_started))" "$OMARCHY_ACCEPTANCE_DIR"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ set -euo pipefail
|
|||||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
launch_and_verify() {
|
launch_and_verify() {
|
||||||
local name="$1" command="$2" class="$3"
|
local name="$1" command="$2" class="$3" timeout="${4:-45}"
|
||||||
|
|
||||||
# A pre-existing window makes the test ambiguous (and closing it would be
|
# A pre-existing window makes the test ambiguous (and closing it would be
|
||||||
# hostile on a dev machine) — acceptance runs expect a fresh session.
|
# hostile on a dev machine) — acceptance runs expect a fresh session.
|
||||||
@@ -14,9 +14,9 @@ launch_and_verify() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
launch_app "$command"
|
launch_app "$command"
|
||||||
wait_until "$name opens a window" 90 window_present "$class"
|
wait_until "$name opens a window" "$timeout" window_present "$class"
|
||||||
sleep 1
|
sleep 1
|
||||||
screenshot "app-$name"
|
screenshot "success-app-$name"
|
||||||
|
|
||||||
local deadline=$((SECONDS + 30))
|
local deadline=$((SECONDS + 30))
|
||||||
while window_present "$class" >/dev/null 2>&1; do
|
while window_present "$class" >/dev/null 2>&1; do
|
||||||
@@ -31,15 +31,19 @@ launch_and_verify() {
|
|||||||
pass "$name window closes"
|
pass "$name window closes"
|
||||||
}
|
}
|
||||||
|
|
||||||
# name|command|window class regex
|
# Keep launch coverage to the primary daily-use paths. The system acceptance
|
||||||
|
# test separately verifies the complete core package manifest.
|
||||||
|
# name|command|window class regex|launch timeout
|
||||||
apps='terminal|foot|^foot$
|
apps='terminal|foot|^foot$
|
||||||
browser|chromium --new-window|(?i)chromium
|
browser|chromium --new-window|(?i)chromium
|
||||||
files|nautilus --new-window|org.gnome.Nautilus
|
neovim|xdg-terminal-exec --app-id=org.omarchy.nvim nvim|org.omarchy.nvim
|
||||||
calculator|gnome-calculator|org.gnome.Calculator
|
writer|omawrite|(?i)omawrite'
|
||||||
notes|obsidian|(?i)obsidian
|
|
||||||
office|libreoffice|(?i)(soffice|libreoffice)
|
|
||||||
pdf-viewer|evince|(?i)evince'
|
|
||||||
|
|
||||||
while IFS='|' read -r name command class; do
|
status=0
|
||||||
launch_and_verify "$name" "$command" "$class"
|
while IFS='|' read -r name command class timeout; do
|
||||||
|
if ! (launch_and_verify "$name" "$command" "$class" "$timeout"); then
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
done <<<"$apps"
|
done <<<"$apps"
|
||||||
|
|
||||||
|
exit $status
|
||||||
|
|||||||
@@ -17,15 +17,33 @@ pass() {
|
|||||||
fail() {
|
fail() {
|
||||||
local description="$1"
|
local description="$1"
|
||||||
local detail="${2:-}"
|
local detail="${2:-}"
|
||||||
|
local step=${description,,}
|
||||||
|
|
||||||
|
step=${step// /-}
|
||||||
|
step=${step//[^a-z0-9-]/}
|
||||||
|
|
||||||
[[ -n $detail ]] && printf '%s\n' "$detail" >&2
|
[[ -n $detail ]] && printf '%s\n' "$detail" >&2
|
||||||
screenshot "failure-$(date +%s)"
|
screenshot "failure-$step"
|
||||||
printf 'not ok - %s\n' "$description" >&2
|
printf 'not ok - %s\n' "$description" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
screenshot() {
|
screenshot() {
|
||||||
grim "$ARTIFACTS/$1.png" 2>/dev/null || true
|
timeout 10 grim "$ARTIFACTS/$1.png" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
screen_contains() {
|
||||||
|
local text="$1"
|
||||||
|
local snapshot="/tmp/omarchy-acceptance-ocr-$$.png"
|
||||||
|
|
||||||
|
if ! timeout 10 grim "$snapshot" 2>/dev/null; then
|
||||||
|
rm -f "$snapshot"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
tesseract "$snapshot" stdout --psm 11 2>/dev/null | grep -Fqi -- "$text"
|
||||||
|
local status=$?
|
||||||
|
rm -f "$snapshot"
|
||||||
|
return $status
|
||||||
}
|
}
|
||||||
|
|
||||||
# Poll a command until it succeeds; screenshot and fail on timeout.
|
# Poll a command until it succeeds; screenshot and fail on timeout.
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
CONFIG_FILE="$HOME/.config/omarchy/shell.json"
|
||||||
|
DEFAULTS_FILE="$OMARCHY_PATH/config/omarchy/shell.json"
|
||||||
|
config_backup=$(mktemp)
|
||||||
|
config_existed=0
|
||||||
|
|
||||||
|
if [[ -f $CONFIG_FILE ]]; then
|
||||||
|
cp "$CONFIG_FILE" "$config_backup"
|
||||||
|
config_existed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
restore_bar_config() {
|
||||||
|
omarchy-shell shell hide omarchy.menu >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
if ((config_existed)); then
|
||||||
|
mkdir -p "$(dirname "$CONFIG_FILE")"
|
||||||
|
cp "$config_backup" "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
rm -f "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
omarchy-shell shell reloadConfig >/dev/null 2>&1 || true
|
||||||
|
rm -f "$config_backup"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap restore_bar_config EXIT
|
||||||
|
|
||||||
|
bar_is_vertical() {
|
||||||
|
local width height
|
||||||
|
|
||||||
|
read -r width height < <(hyprctl -j layers | jq -r '
|
||||||
|
[.. | objects | select(.namespace? == "omarchy-bar")][0]
|
||||||
|
| [.w, .h] | @tsv
|
||||||
|
')
|
||||||
|
|
||||||
|
[[ $width =~ ^[0-9]+$ && $height =~ ^[0-9]+$ ]] && ((width < height))
|
||||||
|
}
|
||||||
|
|
||||||
|
bar_is_horizontal() {
|
||||||
|
local width height
|
||||||
|
|
||||||
|
read -r width height < <(hyprctl -j layers | jq -r '
|
||||||
|
[.. | objects | select(.namespace? == "omarchy-bar")][0]
|
||||||
|
| [.w, .h] | @tsv
|
||||||
|
')
|
||||||
|
|
||||||
|
[[ $width =~ ^[0-9]+$ && $height =~ ^[0-9]+$ ]] && ((width > height))
|
||||||
|
}
|
||||||
|
|
||||||
|
bar_position_is() {
|
||||||
|
local expected="$1"
|
||||||
|
|
||||||
|
[[ $(jq -r '.bar.position // "top"' "$CONFIG_FILE") == $expected ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
source_file=$DEFAULTS_FILE
|
||||||
|
((config_existed)) && source_file=$CONFIG_FILE
|
||||||
|
original_position=$(jq -r '.bar.position // "top"' "$source_file")
|
||||||
|
|
||||||
|
omarchy-shell shell summon omarchy.menu '{"menu":"root"}' >/dev/null
|
||||||
|
wait_until "root menu opens" 15 layer_present "omarchy-menu"
|
||||||
|
wait_until "root menu content is visible" 15 screen_contains "Apps"
|
||||||
|
screenshot "success-menu-01-root"
|
||||||
|
|
||||||
|
wtype -k Down -k Down -k Down
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-menu-02-style-selected"
|
||||||
|
wtype -k Return
|
||||||
|
|
||||||
|
wait_until "style submenu is visible" 15 screen_contains "Theme"
|
||||||
|
screenshot "success-menu-03-style-submenu"
|
||||||
|
|
||||||
|
wtype -k Down -k Down -k Down -k Return
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-menu-04-menu-bar-submenu"
|
||||||
|
|
||||||
|
wtype -k Return
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-menu-05-position-submenu"
|
||||||
|
|
||||||
|
wtype -k Down -k Down -k Return
|
||||||
|
wait_until "menu bar position changes to left" 20 bar_position_is "left"
|
||||||
|
wait_until "menu bar becomes vertical" 20 bar_is_vertical
|
||||||
|
wait_until "menu closes after selecting a position" 15 layer_absent "omarchy-menu"
|
||||||
|
screenshot "success-menu-06-bar-left"
|
||||||
|
|
||||||
|
if ((config_existed)); then
|
||||||
|
cp "$config_backup" "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
rm -f "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
omarchy-shell shell reloadConfig >/dev/null
|
||||||
|
|
||||||
|
if [[ $original_position == "left" || $original_position == "right" ]]; then
|
||||||
|
wait_until "menu bar restores its original vertical position" 20 bar_is_vertical
|
||||||
|
else
|
||||||
|
wait_until "menu bar restores its original horizontal position" 20 bar_is_horizontal
|
||||||
|
fi
|
||||||
|
screenshot "success-menu-07-bar-restored"
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
restore_bar_config
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
WEATHER_FILE="$HOME/.local/state/omarchy/settings/weather.json"
|
||||||
|
weather_backup=$(mktemp)
|
||||||
|
weather_existed=0
|
||||||
|
|
||||||
|
if [[ -f $WEATHER_FILE ]]; then
|
||||||
|
cp "$WEATHER_FILE" "$weather_backup"
|
||||||
|
weather_existed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hide_panels() {
|
||||||
|
local plugin
|
||||||
|
|
||||||
|
for plugin in omarchy.weather omarchy.bluetooth omarchy.network omarchy.audio omarchy.monitor omarchy.power; do
|
||||||
|
omarchy-shell shell hide "$plugin" >/dev/null 2>&1 || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_weather() {
|
||||||
|
hide_panels
|
||||||
|
|
||||||
|
if ((weather_existed)); then
|
||||||
|
mkdir -p "$(dirname "$WEATHER_FILE")"
|
||||||
|
cp "$weather_backup" "$WEATHER_FILE"
|
||||||
|
else
|
||||||
|
rm -f "$WEATHER_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$weather_backup"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap restore_weather EXIT
|
||||||
|
|
||||||
|
open_and_capture_panel() {
|
||||||
|
local name="$1" plugin="$2"
|
||||||
|
|
||||||
|
omarchy-shell shell summon "$plugin" >/dev/null
|
||||||
|
wait_until "$name panel opens" 15 layer_present "omarchy-keyboard-panel"
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-panel-$name"
|
||||||
|
|
||||||
|
omarchy-shell shell hide "$plugin" >/dev/null
|
||||||
|
wait_until "$name panel closes" 15 layer_absent "omarchy-keyboard-panel"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Give weather deterministic coordinates so this test exercises the real
|
||||||
|
# Open-Meteo forecast instead of IP geolocation through wttr.in.
|
||||||
|
omarchy-weather-location --set "San Francisco" "37.7749,-122.4194"
|
||||||
|
omarchy-shell shell summon omarchy.weather >/dev/null
|
||||||
|
wait_until "weather panel opens" 15 layer_present "omarchy-keyboard-panel"
|
||||||
|
wait_until "weather location is visible" 30 screen_contains "SAN FRANCISCO"
|
||||||
|
wait_until "weather details are visible" 30 screen_contains "WIND"
|
||||||
|
screenshot "success-panel-weather"
|
||||||
|
omarchy-shell shell hide omarchy.weather >/dev/null
|
||||||
|
wait_until "weather panel closes" 15 layer_absent "omarchy-keyboard-panel"
|
||||||
|
|
||||||
|
status=0
|
||||||
|
panels='bluetooth|omarchy.bluetooth
|
||||||
|
network|omarchy.network
|
||||||
|
audio|omarchy.audio
|
||||||
|
monitor|omarchy.monitor'
|
||||||
|
|
||||||
|
while IFS='|' read -r name plugin; do
|
||||||
|
if ! (trap - EXIT; open_and_capture_panel "$name" "$plugin"); then
|
||||||
|
status=1
|
||||||
|
hide_panels
|
||||||
|
wait_until "$name failed panel is dismissed" 15 layer_absent "omarchy-keyboard-panel"
|
||||||
|
fi
|
||||||
|
done <<<"$panels"
|
||||||
|
|
||||||
|
# The power widget intentionally disappears on desktops and VMs without a
|
||||||
|
# battery. Exercise it on laptops, and verify that hardware-less sessions take
|
||||||
|
# the supported no-panel path instead of treating that as a shell failure.
|
||||||
|
if upower -e | grep -q '/battery_'; then
|
||||||
|
if ! (trap - EXIT; open_and_capture_panel "power" "omarchy.power"); then
|
||||||
|
status=1
|
||||||
|
hide_panels
|
||||||
|
wait_until "power failed panel is dismissed" 15 layer_absent "omarchy-keyboard-panel"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pass "power panel is hidden without battery hardware"
|
||||||
|
screenshot "success-panel-power-unavailable"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The common panel keyboard contract uses Tab to move to the next bar panel.
|
||||||
|
omarchy-shell shell summon omarchy.bluetooth >/dev/null
|
||||||
|
wait_until "panel keyboard navigation starts on bluetooth" 15 screen_contains "Bluetooth"
|
||||||
|
screenshot "success-panel-navigation-01-bluetooth"
|
||||||
|
wtype -k Tab
|
||||||
|
sleep 2
|
||||||
|
wait_until "Tab keeps a shell panel open" 15 layer_present "omarchy-keyboard-panel"
|
||||||
|
screenshot "success-panel-navigation-02-next"
|
||||||
|
hide_panels
|
||||||
|
wait_until "keyboard-navigated panel closes" 15 layer_absent "omarchy-keyboard-panel"
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
restore_weather
|
||||||
|
exit $status
|
||||||
@@ -14,7 +14,11 @@ wait_until "omarchy-shell responds to ping" 60 omarchy-shell shell ping
|
|||||||
|
|
||||||
# Core shell plugins are loaded
|
# Core shell plugins are loaded
|
||||||
plugins=$(omarchy-shell shell listPlugins)
|
plugins=$(omarchy-shell shell listPlugins)
|
||||||
for plugin in omarchy.bar omarchy.launcher omarchy.emojis omarchy.menu omarchy.notifications; do
|
for plugin in \
|
||||||
|
omarchy.audio omarchy.background omarchy.bar omarchy.bluetooth \
|
||||||
|
omarchy.clipboard omarchy.emojis omarchy.launcher omarchy.menu \
|
||||||
|
omarchy.monitor omarchy.network omarchy.notifications omarchy.power \
|
||||||
|
omarchy.reminders omarchy.weather; do
|
||||||
[[ $plugins == *"$plugin"* ]] || fail "shell plugin is loaded: $plugin" "loaded plugins: $plugins"
|
[[ $plugins == *"$plugin"* ]] || fail "shell plugin is loaded: $plugin" "loaded plugins: $plugins"
|
||||||
pass "shell plugin is loaded: $plugin"
|
pass "shell plugin is loaded: $plugin"
|
||||||
done
|
done
|
||||||
@@ -53,4 +57,4 @@ if [[ -n $failed_user ]]; then
|
|||||||
fi
|
fi
|
||||||
pass "no failed user units"
|
pass "no failed user units"
|
||||||
|
|
||||||
screenshot "desktop"
|
screenshot "success-desktop"
|
||||||
|
|||||||
@@ -15,34 +15,102 @@ open_and_close() {
|
|||||||
|
|
||||||
wait_until "$name opens" 15 layer_present "$namespace"
|
wait_until "$name opens" 15 layer_present "$namespace"
|
||||||
sleep 1
|
sleep 1
|
||||||
screenshot "$name-open"
|
screenshot "success-$name-open"
|
||||||
|
|
||||||
omarchy-shell shell hide "$plugin" >/dev/null
|
omarchy-shell shell hide "$plugin" >/dev/null
|
||||||
wait_until "$name closes" 15 layer_absent "$namespace"
|
wait_until "$name closes" 15 layer_absent "$namespace"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Overlays open and close on IPC command
|
# Search and select an emoji. The host harness separately proves the shortcut
|
||||||
open_and_close "emoji-picker" omarchy.emojis omarchy-emojis
|
# with a QMP hardware key chord, while this test focuses on UI behavior.
|
||||||
open_and_close "menu" omarchy.menu omarchy-menu '{"menu":"root"}'
|
omarchy-shell shell summon omarchy.emojis >/dev/null
|
||||||
open_and_close "clipboard" omarchy.clipboard omarchy-clipboard
|
wait_until "emoji picker opens" 15 layer_present "omarchy-emojis"
|
||||||
|
wtype "rocket"
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-emoji-picker-search"
|
||||||
|
wtype -k Return
|
||||||
|
wait_until "emoji picker selection closes" 15 layer_absent "omarchy-emojis"
|
||||||
|
|
||||||
# The launcher does the full loop: open, search by typing, launch the top hit
|
# Seed two clipboard entries, search for the older one, and copy it back out.
|
||||||
if window_present "org.gnome.Calculator" >/dev/null 2>&1; then
|
clipboard_token="Omarchy acceptance clipboard $(date +%s)"
|
||||||
fail "launcher test starts with no calculator window" "a calculator window is already open"
|
printf '%s' "$clipboard_token" | wl-copy
|
||||||
|
wait_until "clipboard history captures test text" 15 grep -Fq "$clipboard_token" "$HOME/.local/state/omarchy/clipboard-history.json"
|
||||||
|
printf '%s' "clipboard decoy" | wl-copy
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
omarchy-shell shell summon omarchy.clipboard >/dev/null
|
||||||
|
wait_until "clipboard opens" 15 layer_present "omarchy-clipboard"
|
||||||
|
wtype "$clipboard_token"
|
||||||
|
wait_until "clipboard search finds test text" 15 screen_contains "Omarchy acceptance clipboard"
|
||||||
|
screenshot "success-clipboard-search"
|
||||||
|
wtype -M shift -k Return -m shift
|
||||||
|
wait_until "clipboard selection closes" 15 layer_absent "omarchy-clipboard"
|
||||||
|
wait_until "clipboard selection restores test text" 15 bash -c '[[ $(wl-paste --no-newline) == "$1" ]]' _ "$clipboard_token"
|
||||||
|
|
||||||
|
# Exercise the system branch without invoking any destructive action.
|
||||||
|
omarchy-shell shell summon omarchy.menu '{"menu":"system"}' >/dev/null
|
||||||
|
wait_until "system menu opens" 15 layer_present "omarchy-menu"
|
||||||
|
wait_until "system menu content is visible" 15 screen_contains "Shutdown"
|
||||||
|
screenshot "success-system-menu"
|
||||||
|
wtype -k Escape
|
||||||
|
wait_until "system menu closes" 15 layer_absent "omarchy-menu"
|
||||||
|
|
||||||
|
# Preview both visual selectors and cancel without changing user state. These
|
||||||
|
# cover thumbnail generation, the image-grid overlay, and current selection.
|
||||||
|
launch_app "omarchy-theme-bg-switcher"
|
||||||
|
wait_until "background selector opens" 30 layer_present "omarchy-image-selector"
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-background-selector"
|
||||||
|
wtype -k Escape
|
||||||
|
wait_until "background selector closes" 15 layer_absent "omarchy-image-selector"
|
||||||
|
|
||||||
|
launch_app "omarchy-theme-switcher"
|
||||||
|
wait_until "theme selector opens" 30 layer_present "omarchy-image-selector"
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-theme-selector"
|
||||||
|
wtype -k Escape
|
||||||
|
wait_until "theme selector closes" 15 layer_absent "omarchy-image-selector"
|
||||||
|
|
||||||
|
# Walk the reminder flow through each input screen, but dismiss before it
|
||||||
|
# schedules a real timer in the test user's session.
|
||||||
|
omarchy-shell shell summon omarchy.reminders >/dev/null
|
||||||
|
wait_until "reminder flow opens" 15 layer_present "omarchy-reminders"
|
||||||
|
screenshot "success-reminder-01-minutes-prompt"
|
||||||
|
wtype "5"
|
||||||
|
sleep 1
|
||||||
|
screenshot "success-reminder-02-minutes-entered"
|
||||||
|
wtype -k Return
|
||||||
|
wait_until "reminder message prompt opens" 15 screen_contains "Reminder message"
|
||||||
|
screenshot "success-reminder-03-message-prompt"
|
||||||
|
wtype -k Escape
|
||||||
|
wait_until "reminder flow closes" 15 layer_absent "omarchy-reminders"
|
||||||
|
|
||||||
|
# Render a real shell notification and clear it through the notification IPC.
|
||||||
|
omarchy-shell notifications dismissAll >/dev/null
|
||||||
|
omarchy-notification-send "Acceptance notification" "Shell notification rendering" --expire-time=15000
|
||||||
|
wait_until "notification popup opens" 15 layer_present "omarchy-notifications"
|
||||||
|
wait_until "notification content is visible" 15 screen_contains "Acceptance notification"
|
||||||
|
screenshot "success-notification-popup"
|
||||||
|
omarchy-shell notifications dismissAll >/dev/null
|
||||||
|
wait_until "notification popup closes" 15 layer_absent "omarchy-notifications"
|
||||||
|
|
||||||
|
# The launcher does the full loop: open, search by typing, launch the top hit.
|
||||||
|
if window_present "(?i)omawrite" >/dev/null 2>&1; then
|
||||||
|
fail "launcher test starts with no Omawrite window" "an Omawrite window is already open"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
omarchy-shell shell summon omarchy.launcher >/dev/null
|
omarchy-shell shell summon omarchy.launcher >/dev/null
|
||||||
wait_until "launcher opens" 15 layer_present "omarchy-launcher"
|
wait_until "launcher opens" 15 layer_present "omarchy-launcher"
|
||||||
sleep 1
|
sleep 1
|
||||||
screenshot "launcher-open"
|
screenshot "success-launcher-open"
|
||||||
|
|
||||||
wtype "calculator"
|
wtype "omawrite"
|
||||||
sleep 1
|
sleep 1
|
||||||
screenshot "launcher-search"
|
screenshot "success-launcher-search"
|
||||||
wtype -k Return
|
wtype -k Return
|
||||||
|
|
||||||
wait_until "launcher launches the top search hit" 60 window_present "org.gnome.Calculator"
|
wait_until "launcher launches the top search hit" 60 window_present "(?i)omawrite"
|
||||||
wait_until "launcher closes after launching" 15 layer_absent "omarchy-launcher"
|
wait_until "launcher closes after launching" 15 layer_absent "omarchy-launcher"
|
||||||
|
|
||||||
close_windows "org.gnome.Calculator"
|
close_windows "(?i)omawrite"
|
||||||
wait_until "calculator window closes" 30 window_absent "org.gnome.Calculator"
|
wait_until "Omawrite window closes" 30 window_absent "(?i)omawrite"
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||||
|
|
||||||
|
status=0
|
||||||
|
|
||||||
|
verify_core_packages() {
|
||||||
|
local package
|
||||||
|
local -a missing=()
|
||||||
|
|
||||||
|
while IFS= read -r package; do
|
||||||
|
[[ -z $package || $package == \#* ]] && continue
|
||||||
|
pacman -Q "$package" >/dev/null 2>&1 || missing+=("$package")
|
||||||
|
done <"$OMARCHY_PATH/install/omarchy-base.packages"
|
||||||
|
|
||||||
|
(( ${#missing[@]} == 0 )) || fail "all Omarchy core packages are installed" "missing packages: ${missing[*]}"
|
||||||
|
pass "all Omarchy core packages are installed (${#missing[@]} missing)"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_defaults() {
|
||||||
|
[[ $(omarchy-default-browser) == "chromium" ]] || fail "Chromium is the default browser"
|
||||||
|
pass "Chromium is the default browser"
|
||||||
|
|
||||||
|
[[ $(omarchy-default-terminal) == "foot" ]] || fail "Foot is the default terminal"
|
||||||
|
pass "Foot is the default terminal"
|
||||||
|
|
||||||
|
[[ $(omarchy-default-editor) == "nvim" ]] || fail "Neovim is the default editor"
|
||||||
|
pass "Neovim is the default editor"
|
||||||
|
|
||||||
|
[[ $(omarchy-theme-current) != "Unknown" ]] || fail "a current theme is configured"
|
||||||
|
pass "a current theme is configured"
|
||||||
|
|
||||||
|
[[ $(omarchy-theme-bg-current) != "Unknown" ]] || fail "a current background is configured"
|
||||||
|
pass "a current background is configured"
|
||||||
|
|
||||||
|
[[ -n $(omarchy-font-current) ]] || fail "a monospace font is configured"
|
||||||
|
pass "a monospace font is configured"
|
||||||
|
|
||||||
|
[[ $(xdg-mime query default x-scheme-handler/http) == "chromium.desktop" ]] || fail "HTTP MIME handling uses Chromium"
|
||||||
|
[[ $(xdg-mime query default inode/directory) == "org.gnome.Nautilus.desktop" ]] || fail "directory MIME handling uses Nautilus"
|
||||||
|
pass "desktop MIME handlers are configured"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_services() {
|
||||||
|
local unit
|
||||||
|
|
||||||
|
for unit in \
|
||||||
|
avahi-daemon.service cups.service cups-browsed.service docker.socket \
|
||||||
|
NetworkManager.service power-profiles-daemon.service sddm.service \
|
||||||
|
systemd-resolved.service ufw.service; do
|
||||||
|
systemctl is-enabled --quiet "$unit" || fail "core system services are enabled" "$unit is not enabled"
|
||||||
|
done
|
||||||
|
pass "core system services are enabled"
|
||||||
|
|
||||||
|
for unit in NetworkManager.service systemd-resolved.service ufw.service; do
|
||||||
|
systemctl is-active --quiet "$unit" || fail "critical system services are running" "$unit is not active"
|
||||||
|
done
|
||||||
|
pass "critical system services are running"
|
||||||
|
|
||||||
|
systemctl --user is-active --quiet pipewire.service pipewire-pulse.service wireplumber.service ||
|
||||||
|
fail "user audio services are running"
|
||||||
|
pass "user audio services are running"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_runtime_tools() {
|
||||||
|
timeout 20 docker info >/dev/null 2>&1 || fail "Docker is usable by the desktop user"
|
||||||
|
pass "Docker is usable by the desktop user"
|
||||||
|
|
||||||
|
nvim --headless '+qa' >/dev/null 2>&1 || fail "Neovim starts headlessly"
|
||||||
|
pass "Neovim starts headlessly"
|
||||||
|
|
||||||
|
timeout 10 fastfetch --pipe false >/dev/null 2>&1 || fail "Fastfetch can read system information"
|
||||||
|
pass "Fastfetch can read system information"
|
||||||
|
|
||||||
|
git --version >/dev/null || fail "Git is installed and runnable"
|
||||||
|
tmux -V >/dev/null || fail "Tmux is installed and runnable"
|
||||||
|
mise --version >/dev/null || fail "Mise is installed and runnable"
|
||||||
|
pass "core terminal tools are runnable"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_user_setup() {
|
||||||
|
local directory
|
||||||
|
|
||||||
|
for directory in DESKTOP DOCUMENTS DOWNLOAD PICTURES; do
|
||||||
|
[[ -d $(xdg-user-dir "$directory") ]] || fail "XDG user directories exist" "$directory is missing"
|
||||||
|
done
|
||||||
|
pass "XDG user directories exist"
|
||||||
|
|
||||||
|
[[ -e $HOME/.local/state/omarchy/current/theme ]] || fail "current theme state exists"
|
||||||
|
[[ -e $HOME/.local/state/omarchy/current/background ]] || fail "current background state exists"
|
||||||
|
[[ -s $HOME/.config/omarchy/shell.json ]] || fail "shell configuration exists"
|
||||||
|
jq empty "$HOME/.config/omarchy/shell.json" || fail "shell configuration is valid JSON"
|
||||||
|
pass "Omarchy user state and shell configuration exist"
|
||||||
|
}
|
||||||
|
|
||||||
|
for check in verify_core_packages verify_defaults verify_services verify_runtime_tools verify_user_setup; do
|
||||||
|
if ! ("$check"); then
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $status
|
||||||
Reference in New Issue
Block a user