✨ Add renderer option on create-demo-profile command (#11894)

* ✨ Add renderer option on create-demo-profile command

Allow create-demo-profile to take an optional renderer (svg or
wasm) and store it on profile props. When omitted, no renderer is
written so the Penpot default still applies.

Closes #11893

AI-assisted-by: Muse Spark 1.3 Free

* 📚 Fix renderer doc version on create-demo-profile

Correct the ::doc/changes version for the new renderer param from
2.20 to 2.18.1.

AI-assisted-by: Muse Spark 1.3 Free
This commit is contained in:
Andrey Antukh 2026-09-28 18:21:07 +02:00 committed by GitHub
parent f311c7ab05
commit 72dad5d67d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 8 deletions

View File

@ -27,7 +27,8 @@
schema:create-demo-profile
[:map
[:skip-onboarding {:optional true} ::sm/boolean]
[:expires-in {:optional true} ::ct/duration]])
[:expires-in {:optional true} ::ct/duration]
[:renderer {:optional true} [::sm/one-of #{:svg :wasm}]]])
(def ^:private min-expires-in
(ct/duration "5m"))
@ -64,9 +65,10 @@
::doc/added "1.15"
::doc/changes [["1.15" "This method is migrated from mutations to commands."]
["2.18" "Add optional `skip-onboarding` param. When true, the profile is created with `onboarding-viewed` and `release-notes-viewed` (current version) set, skipping the onboarding flow."]
["2.18" "Add optional `expires-in` param. When set, the demo purge is scheduled that long after creation instead of the global deletion delay. Only values between 5 minutes and the global delay are accepted."]]
["2.18" "Add optional `expires-in` param. When set, the demo purge is scheduled that long after creation instead of the global deletion delay. Only values between 5 minutes and the global delay are accepted."]
["2.18.1" "Add optional `renderer` param. When set to `wasm` or `svg`, the profile is created with that `renderer` in props. When omitted, no renderer is stored and the Penpot default applies."]]
::sm/params schema:create-demo-profile}
[cfg {:keys [skip-onboarding expires-in]}]
[cfg {:keys [skip-onboarding expires-in renderer]}]
(when-not (contains? cf/flags :demo-users)
(ex/raise :type :validation
@ -93,7 +95,8 @@
;; overwrites this with the current
;; version, kept so the skip does not
;; depend on that default.
:release-notes-viewed (:main cf/version)))}
:release-notes-viewed (:main cf/version))
renderer (assoc :renderer renderer))}
profile (db/tx-run! cfg (fn [cfg]
(->> (auth/create-profile cfg params)
(auth/create-profile-rels cfg))))]

View File

@ -121,3 +121,36 @@
:expires-in "yes"})]
(t/is (th/ex-of-type? error :validation))
(t/is (th/ex-of-code? error :params-validation)))))
(t/deftest create-demo-profile-stores-wasm-renderer-when-requested
(with-redefs [cf/flags (conj cf/flags :demo-users)]
(let [{:keys [error result]} (th/command! {::th/type :create-demo-profile
:renderer :wasm})]
(t/is (nil? error))
(let [saved (th/db-get :profile {:email (:email result)})
decoded (profile/decode-row saved)]
(t/is (= :wasm (get-in decoded [:props :renderer])))))))
(t/deftest create-demo-profile-stores-svg-renderer-when-requested
(with-redefs [cf/flags (conj cf/flags :demo-users)]
(let [{:keys [error result]} (th/command! {::th/type :create-demo-profile
:renderer :svg})]
(t/is (nil? error))
(let [saved (th/db-get :profile {:email (:email result)})
decoded (profile/decode-row saved)]
(t/is (= :svg (get-in decoded [:props :renderer])))))))
(t/deftest create-demo-profile-omits-renderer-by-default
(with-redefs [cf/flags (conj cf/flags :demo-users)]
(let [{:keys [error result]} (th/command! {::th/type :create-demo-profile})]
(t/is (nil? error))
(let [saved (th/db-get :profile {:email (:email result)})
decoded (profile/decode-row saved)]
(t/is (false? (contains? (:props decoded) :renderer)))))))
(t/deftest create-demo-profile-rejects-unknown-renderer
(with-redefs [cf/flags (conj cf/flags :demo-users)]
(let [{:keys [error]} (th/command! {::th/type :create-demo-profile
:renderer :canvas})]
(t/is (th/ex-of-type? error :validation))
(t/is (th/ex-of-code? error :params-validation)))))

View File

@ -1,7 +1,7 @@
import { rpcPost, extractCookie } from "./client.mjs";
export async function createDemoProfile() {
const res = await rpcPost("create-demo-profile", {});
export async function createDemoProfile(params = {}) {
const res = await rpcPost("create-demo-profile", params);
if (res.body.type === "validation" || res.body.type === "restriction") {
throw new Error(
`Failed to create demo profile: ${res.body.code} - ${res.body.hint || ""}`
@ -31,8 +31,8 @@ export async function createAccessToken(cookie, name = "e2e-test-token") {
return res.body;
}
export async function setupTestProfile() {
const { email, password } = await createDemoProfile();
export async function setupTestProfile(params = {}) {
const { email, password } = await createDemoProfile(params);
const { profile, cookie } = await login(email, password);
return { profile, cookie, email, password };
}