Files
asepharyana 1cdb82a76f Sync config from arch
- hypr/apps.lua
- hypr/autostart.lua
- hypr/envs.lua
- hypr/hyprland.lua
- hypr/hyprsunset.conf
- hypr/input.lua
- hypr/looknfeel.lua
- hypr/omasettings.lua
- hypr/xdph.conf
- omarchy/branding/about.txt
- omarchy/branding/screensaver.txt
- omarchy/extensions/omarchy-menu.jsonc
- omarchy/hooks/battery-low.d/play-warning-sound.sample
- omarchy/hooks/font-set.d/show-font-notification.sample
- omarchy/hooks/post-boot.d/weather.sample
- omarchy/hooks/post-update.d/install-voxtype.hook
- omarchy/hooks/post-update.d/setup-agent.hook
- omarchy/hooks/post-update.d/setup-fingerprint.hook
- omarchy/hooks/post-update.d/show-update-notification.sample
- omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample
- omarchy/hooks/theme-set.d/show-theme-notification.sample
- omarchy/shell.json
- omarchy/shell.toml
- omarchy/theme.name
- omarchy/themes/azure-glow/README.md
- omarchy/themes/azure-glow/alacritty.toml
- omarchy/themes/azure-glow/btop.theme
- omarchy/themes/azure-glow/hyprland.conf
- omarchy/themes/azure-glow/hyprlock.conf
- omarchy/themes/azure-glow/icons.theme
- … 269 more
2026-09-23 15:19:12 +07:00

183 lines
8.2 KiB
JavaScript

#!/usr/bin/env node
// The detail screen draws every labelled, copyable field through DetailField.
// These assertions guard the properties that make a card safe to put on
// screen -- masking, empty-field suppression, and the promise that a copy
// still goes through the panel's one clipboard path.
//
// node tests/detail-field.test.js
const fs = require("fs")
const path = require("path")
const read = f => fs.existsSync(path.join(__dirname, "..", f))
? fs.readFileSync(path.join(__dirname, "..", f), "utf8") : ""
const fieldSrc = read("DetailField.qml")
const panelSrc = read("Panel.qml")
let pass = 0
const failures = []
const check = (label, ok, detail) => ok ? pass++ : failures.push(`${label}\n ${detail}`)
check("DetailField exists", fieldSrc !== "", "DetailField.qml is missing")
// --- the component itself ----------------------------------------------------
check("an empty field draws nothing at all",
/visible:\s*root\.value\s*!==\s*""/.test(fieldSrc),
"an identity fills in a handful of its fields; the rest must not leave labelled blanks")
check("a sensitive field is masked until it is revealed",
/masked:\s*root\.sensitive\s*&&\s*!root\.revealed/.test(fieldSrc)
&& /text:\s*root\.masked\s*\?\s*Model\.maskString\(root\.value\)\s*:\s*root\.value/.test(fieldSrc),
fieldSrc)
check("the reveal button appears only on sensitive fields",
/visible:\s*root\.sensitive/.test(fieldSrc), fieldSrc)
check("the component reports intent rather than reaching for the clipboard",
/signal copyRequested\(\)/.test(fieldSrc)
&& /signal revealToggled\(\)/.test(fieldSrc)
&& !/copyToClipboard/.test(fieldSrc),
"DetailField must not know how a copy is performed")
check("field text is pinned to plain text",
/textFormat:\s*Text\.PlainText/.test(fieldSrc), fieldSrc)
check("long values elide rather than pushing the row wider",
/elide:\s*Text\.ElideRight/.test(fieldSrc), fieldSrc)
// --- how the detail screen uses it -------------------------------------------
const uses = panelSrc.match(/DetailField \{[\s\S]*?\n \}/g) || []
check("the detail screen draws its fields through the component",
uses.length >= 14, `found ${uses.length} DetailField uses`)
check("every use routes its copy through the panel's one clipboard path",
uses.every(u => /onCopyRequested:\s*root\.copyToClipboard\(/.test(u)),
uses.filter(u => !/onCopyRequested:\s*root\.copyToClipboard\(/.test(u)).join("\n---\n"))
// A card number, a security code, an SSN, a passport and a licence. Nothing
// here can be rotated after it leaks, which is the argument for masking them
// that a password does not have.
for (const [label, value] of [
["Card Number", "number"],
["Security Code", "code"],
["Social Security Number", "ssn"],
["Passport Number", "passportNumber"],
["Licence Number", "licenseNumber"],
]) {
const use = uses.find(u => u.includes(`label: "${label}"`))
check(`${label} is masked on screen`,
Boolean(use) && /sensitive:\s*true/.test(use),
use || `no DetailField labelled ${label}`)
check(`${label} reads the value the model parsed`,
Boolean(use) && use.includes(value), use || "")
}
// Brand and cardholder are printed on the front of the card in plain sight;
// masking them would be theatre.
for (const label of ["Brand", "Cardholder Name", "Expires"]) {
const use = uses.find(u => u.includes(`label: "${label}"`))
check(`${label} is not needlessly masked`,
Boolean(use) && !/sensitive:\s*true/.test(use), use || `no DetailField labelled ${label}`)
}
// --- reveals are per field ---------------------------------------------------
//
// One shared flag served every masked field to begin with, which was invisible
// while a login had exactly one secret. A card has two and an identity three,
// so revealing a card number also uncovered its security code, and an identity
// showed its social security, passport and licence numbers together.
const revealKeys = uses
.filter(u => /sensitive:\s*true/.test(u))
.map(u => (u.match(/revealed: root\.isFieldRevealed\("([^"]+)"\)/) || [])[1])
check("every masked field has a reveal key", revealKeys.every(Boolean),
JSON.stringify(revealKeys))
check("no two masked fields share a reveal key",
new Set(revealKeys).size === revealKeys.length, JSON.stringify(revealKeys))
check("each toggles only its own key",
uses.filter(u => /sensitive:\s*true/.test(u)).every(u => {
const shown = (u.match(/revealed: root\.isFieldRevealed\("([^"]+)"\)/) || [])[1]
const toggled = (u.match(/onRevealToggled: root\.toggleFieldReveal\("([^"]+)"\)/) || [])[1]
return shown && shown === toggled
}), "a field must reveal and hide the same key")
check("no single shared reveal flag is left",
!/root\.passwordRevealed/.test(panelSrc),
"one flag for every masked field is what caused them to move together")
check("toggling one key leaves the others alone",
/if \(next\[key\]\) delete next\[key\]\s*\n\s*else next\[key\] = true/.test(panelSrc),
"expected a per-key toggle over a copy of the map")
// `v` cannot mean five things at once, so it reaches the one secret the item is
// mostly about and the tooltips only advertise it there.
check("v reaches the item's principal secret only",
/primaryRevealKey:\s*\n?\s*detailIsCard \? "cardNumber" : \(detailIsLoginLike \? "password" : ""\)/.test(panelSrc),
"expected a single primary key per item type")
check("the reveal hint is a property rather than a hardcoded (v)",
/property string revealHint: ""/.test(fieldSrc)
&& !/\+ " \(v\)"/.test(fieldSrc),
"every masked field claimed the v shortcut")
// --- the save does not hold the panel hostage --------------------------------
check("the form closes when the command is launched, not when it returns",
/createItemProc\.running = true[\s\S]{0,400}currentScreen = "main"/.test(panelSrc),
"the user should get the panel back immediately")
check("only one save is in flight at a time",
/if \(pendingSave\) \{[\s\S]{0,140}return\s*\n\s*\}/.test(panelSrc),
"there is one process per kind; a second command would lose the first")
check("a row still being saved cannot be edited",
/if \(item\.pending\) \{[\s\S]{0,120}Still saving/.test(panelSrc),
"editing it would race the save it is waiting on")
check("nor deleted",
/if \(detailItem\.pending \|\| Model\.isPendingItemId\(detailItem\.id\)\)/.test(panelSrc),
"a create has no vault id to delete yet")
check("a refused save puts the list back to what the vault holds",
/items = Model\.replaceItemById\(items, save\.id, save\.previous\)/.test(panelSrc),
"the panel must not keep showing something the vault rejected")
check("and keeps what the user typed so it can be reopened",
/failedSave = \{ name: save\.name, form: save\.form \}/.test(panelSrc)
&& /function reopenFailedSave\(\)/.test(panelSrc),
"a refused save must not cost the user their edit")
check("a save that lands but cannot be sanitised drops its provisional row",
/if \(save && save\.isCreate\) items = Model\.replaceItemById\(items, save\.id, null\)/.test(panelSrc),
"a provisional row must not survive the reload that replaces it")
check("the saving row is marked in the list",
/text: itemData\.pending \? "[^"]*" : Model\.itemTypeGlyph/.test(panelSrc),
"the user needs to see which row has not landed yet")
// --- gating ------------------------------------------------------------------
check("login fields are gated on the type, not on 'not an SSH key'",
/readonly property bool detailIsLoginLike: detailTypeCode === 1 \|\| detailTypeCode === 2/.test(panelSrc)
&& !/typeCode !== 5 && \(root\.detailPassword/.test(panelSrc),
"a card answers 'not an SSH key' too, and would draw an empty password row")
check("card fields are drawn only for cards, identity fields only for identities",
(panelSrc.match(/visible: root\.detailIsCard/g) || []).length >= 5
&& (panelSrc.match(/visible: root\.detailIsIdentity/g) || []).length >= 8,
"each block must gate on its own type")
check("an address is one copyable block, not seven rows",
/detailIdentityAddress/.test(panelSrc)
&& /tooltipText: "Copy address"/.test(panelSrc),
"an address is copied as an address")
console.log(`${pass} passed, ${failures.length} failed`)
if (failures.length) {
console.error("\nFAILURES:\n " + failures.join("\n "))
process.exit(1)
}