feat: close Research Shelf M0 integration
This commit is contained in:
parent
5cbf949465
commit
d124c33ba4
@ -226,17 +226,17 @@ user's prior local additions cannot collide with the generated dataset."
|
||||
:ui-disabled-border line
|
||||
:ui-button-primary-fg paper :ui-button-primary-bg accent
|
||||
:ui-button-primary-border accent
|
||||
:ui-button-secondary-fg ink :ui-button-secondary-bg mint
|
||||
:ui-button-secondary-fg ink :ui-button-secondary-bg mint-bg
|
||||
:ui-button-secondary-border mint
|
||||
:ui-button-ghost-fg ink :ui-button-ghost-bg panel
|
||||
:ui-button-ghost-border line
|
||||
:ui-checkbox-enabled-fg ink :ui-checkbox-enabled-bg mint
|
||||
:ui-checkbox-enabled-fg ink :ui-checkbox-enabled-bg mint-bg
|
||||
:ui-checkbox-enabled-border mint
|
||||
:ui-checkbox-disabled-fg muted :ui-checkbox-disabled-bg soft
|
||||
:ui-checkbox-disabled-border line
|
||||
:ui-grid-border line :ui-grid-selected-fg mint
|
||||
:ui-grid-selected-bg mint-bg
|
||||
:ui-grid-error-fg coral :ui-pagination-muted-fg muted
|
||||
:ui-table-border line :ui-table-selected-fg mint
|
||||
:ui-table-selected-bg mint-bg
|
||||
:ui-data-grid-error-fg coral :ui-pagination-muted-fg muted
|
||||
:ui-panel-fg ink :ui-panel-bg panel :ui-panel-border line))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
@ -433,264 +433,302 @@ constructed. When omitted, initialize it for direct programmatic callers."
|
||||
(or (and entry (plist-get (cdr entry) :label)) fallback)))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-filter-button
|
||||
(&key filter-key fallback ref)
|
||||
(&key filter-key fallback)
|
||||
"Render one filter Button from inherited model and static filter Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t))
|
||||
(form (etaf-inject 'research-shelf-filters nil t))
|
||||
(filter-key (etaf-current-prop :filter-key))
|
||||
(fallback (etaf-current-prop :fallback))
|
||||
(ref (etaf-current-prop :ref)))
|
||||
(lambda ()
|
||||
(let ((active (eq filter-key (etaf-value (plist-get model :filter)))))
|
||||
(etaf-view
|
||||
(button :label
|
||||
(let ((label (etaf-research-shelf--filter-label
|
||||
form filter-key fallback)))
|
||||
(if active (concat "● " label) label))
|
||||
:ref ref :variant (if active 'secondary 'ghost)
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-filter
|
||||
model filter-key))))))))
|
||||
|
||||
(defun etaf-research-shelf--filter-view (model)
|
||||
"Return the filter rail for MODEL and inherited filter Context."
|
||||
(etaf-view
|
||||
(column
|
||||
:class "research-shelf-filter-rail" :width 'stretch :min-width 0
|
||||
:flex-grow 1 :flex-shrink 1 :flex-basis '(220)
|
||||
:padding '(1 1)
|
||||
:border (etaf-theme-token :line)
|
||||
:color (etaf-theme-token :ink)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(label :text "Library" :font-weight 'bold)
|
||||
(label :text "VIEWS" :color (etaf-theme-token :muted))
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'all :fallback "All" :ref 'research-shelf-filter-all)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'reading :fallback "In progress"
|
||||
:ref 'research-shelf-filter-reading)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'unread :fallback "Unread" :ref 'research-shelf-filter-unread)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'finished :fallback "Finished"
|
||||
:ref 'research-shelf-filter-finished)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'starred :fallback "★ Starred"
|
||||
:ref 'research-shelf-filter-starred)
|
||||
(box :height 1)
|
||||
(label :text "STORAGE" :color (etaf-theme-token :muted))
|
||||
(label :text (file-name-nondirectory
|
||||
(plist-get model :database-file)))
|
||||
(button :label "↻ Reload library" :ref 'research-shelf-reload
|
||||
:variant 'ghost
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-reload
|
||||
model))))))
|
||||
|
||||
(defun etaf-research-shelf--reading-list-view (model form)
|
||||
"Return the reading list for MODEL and static MAIN FORM."
|
||||
(let ((controller (etaf-research-shelf--controller model)))
|
||||
(etaf-view
|
||||
(column
|
||||
:class "research-shelf-list" :width 'stretch :min-width 0
|
||||
:flex-grow 4 :flex-shrink 1 :flex-basis '(620)
|
||||
:padding '(1 2)
|
||||
:border (etaf-theme-token :line)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(flex
|
||||
:width 'stretch :flex-wrap 'wrap :align-items 'center :gap '(1 (8))
|
||||
(column
|
||||
:flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(label :text (etaf-playground-static-value
|
||||
form :title "Reading queue") :font-weight 'bold)
|
||||
(label :text (format "%d items · SQLite-backed"
|
||||
(or (etaf-value (etaf-data-total controller)) 0))
|
||||
:color (etaf-theme-token :muted)))
|
||||
(number-input :label "Rows"
|
||||
:value (etaf-value (etaf-data-page-size controller))
|
||||
:ref 'research-shelf-page-size :min 1 :max 100
|
||||
:on-change
|
||||
(lambda (next)
|
||||
(etaf-dispatch 'etaf-research-shelf-page-size
|
||||
model next)))
|
||||
(button :label "+ Add reading" :ref 'research-shelf-add
|
||||
:variant 'secondary
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-add model))))
|
||||
(data-grid
|
||||
:controller controller
|
||||
:columns etaf-research-shelf--grid-columns
|
||||
:row-key #'etaf-research-shelf--item-id
|
||||
:row-ref (lambda (row)
|
||||
(intern (format "research-shelf-row-%s"
|
||||
(etaf-research-shelf--item-id row))))
|
||||
:on-row-press
|
||||
(lambda (row)
|
||||
(etaf-data-select-one controller
|
||||
(etaf-research-shelf--item-id row)))
|
||||
:loading-label "◷ Loading library…"
|
||||
:error-label "⚠ Could not read the shelf. Use Reload.")
|
||||
(etaf-pagination :controller controller
|
||||
:previous-ref 'research-shelf-page-previous
|
||||
:next-ref 'research-shelf-page-next
|
||||
:color (etaf-theme-token :ink))))))
|
||||
|
||||
(defun etaf-research-shelf--detail-view (model form)
|
||||
"Return the selected record inspector for MODEL and static FORM."
|
||||
(etaf-view
|
||||
(column
|
||||
:class "research-shelf-detail" :width 'stretch :min-width 0
|
||||
:flex-grow 2 :flex-shrink 1 :flex-basis '(340)
|
||||
:padding '(2 2)
|
||||
:border (etaf-theme-token :line)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(label :text (etaf-playground-static-value form :title
|
||||
"Selected item")
|
||||
:color (etaf-theme-token :accent))
|
||||
(text :font-weight 'bold
|
||||
(expr :value
|
||||
(if-let* ((row (etaf-research-shelf--selected model)))
|
||||
(plist-get row :title)
|
||||
"Choose a record")))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr :value
|
||||
(if-let* ((row (etaf-research-shelf--selected model)))
|
||||
(format "%s · %s" (plist-get row :author)
|
||||
(plist-get row :kind))
|
||||
"Select one row to inspect it.")))
|
||||
(box :height 1)
|
||||
(text :font-weight 'bold
|
||||
(expr :value
|
||||
(if-let* ((row (etaf-research-shelf--selected model)))
|
||||
(etaf-research-shelf--status-label (plist-get row :status))
|
||||
"○ No selection")))
|
||||
(text
|
||||
(expr :value
|
||||
(if-let* ((row (etaf-research-shelf--selected model)))
|
||||
(format "Progress %d%% · Priority %s"
|
||||
(or (plist-get row :progress) 0)
|
||||
(plist-get row :priority))
|
||||
"Progress — · Priority —")))
|
||||
(text :color (etaf-theme-token :accent)
|
||||
(expr :value
|
||||
(let* ((row (etaf-research-shelf--selected model))
|
||||
(progress (or (and row (plist-get row :progress)) 0))
|
||||
(filled (max 0 (min 10 (/ progress 10)))))
|
||||
(format "%s %s" (make-string filled ?█)
|
||||
(make-string (- 10 filled) ?░)))))
|
||||
(box :height 1)
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr :value
|
||||
(if-let* ((row (etaf-research-shelf--selected model)))
|
||||
(concat "“" (or (plist-get row :note) "No note yet.") "”")
|
||||
"Your notes and actions will appear here.")))
|
||||
(box :height 1)
|
||||
(etaf-research-shelf-detail-actions))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-detail-actions ()
|
||||
"Render selected-record actions from the inherited Research Shelf model."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t)))
|
||||
(lambda ()
|
||||
(let* ((row (etaf-research-shelf--selected model))
|
||||
(progress (or (and row (plist-get row :progress)) 0))
|
||||
(finished (and row (equal (plist-get row :status) "finished")))
|
||||
(archived (and row (equal (plist-get row :status) "archived"))))
|
||||
(etaf-view
|
||||
(flex
|
||||
:width 'stretch :flex-wrap 'wrap :gap '(1 (6))
|
||||
(button :label "+ 10%" :ref 'research-shelf-progress
|
||||
:variant 'secondary
|
||||
:disabled (or (null row) archived (>= progress 100))
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-progress
|
||||
model)))
|
||||
(button :label "✓ Finish" :ref 'research-shelf-finish
|
||||
:variant 'secondary :disabled (or (null row) finished archived)
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-finish
|
||||
model)))
|
||||
(button :label "★ Star" :ref 'research-shelf-star
|
||||
:variant 'ghost :disabled (null row)
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-star model)))
|
||||
(button :label "Archive" :ref 'research-shelf-archive
|
||||
:variant 'ghost :disabled (or (null row) archived)
|
||||
:on-press (lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-archive
|
||||
model)))))))))
|
||||
(list :model (etaf-inject 'research-shelf-model nil t)
|
||||
:form (etaf-inject 'research-shelf-filters nil t))
|
||||
:view
|
||||
(etaf-button
|
||||
:label
|
||||
(let* ((model (plist-get (etaf-state) :model))
|
||||
(form (plist-get (etaf-state) :form))
|
||||
(label (etaf-research-shelf--filter-label
|
||||
form filter-key fallback)))
|
||||
(if (eq filter-key (etaf-value (plist-get model :filter)))
|
||||
(concat "● " label)
|
||||
label))
|
||||
:variant
|
||||
(if (eq filter-key
|
||||
(etaf-value
|
||||
(plist-get (plist-get (etaf-state) :model) :filter)))
|
||||
'secondary
|
||||
'ghost)
|
||||
:on-press
|
||||
(let ((model (plist-get (etaf-state) :model))
|
||||
(key filter-key))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-filter model key)))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-filter-rail ()
|
||||
"Render the Research Shelf filter rail from inherited Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t)))
|
||||
(lambda () (etaf-research-shelf--filter-view model))))
|
||||
(etaf-inject 'research-shelf-model nil t)
|
||||
:view
|
||||
(column :class "research-shelf-filter-rail"
|
||||
:width 'stretch :min-width 0
|
||||
:flex-grow 1 :flex-shrink 1 :flex-basis '(220)
|
||||
:padding '(1 1)
|
||||
:border (etaf-theme-token :line)
|
||||
:color (etaf-theme-token :ink)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(text :font-weight 'bold "Library")
|
||||
(text :color (etaf-theme-token :muted) "VIEWS")
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'all :fallback "All" :ref 'research-shelf-filter-all)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'reading :fallback "In progress"
|
||||
:ref 'research-shelf-filter-reading)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'unread :fallback "Unread"
|
||||
:ref 'research-shelf-filter-unread)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'finished :fallback "Finished"
|
||||
:ref 'research-shelf-filter-finished)
|
||||
(etaf-research-shelf-filter-button
|
||||
:filter-key 'starred :fallback "★ Starred"
|
||||
:ref 'research-shelf-filter-starred)
|
||||
(box :height 1)
|
||||
(text :color (etaf-theme-token :muted) "STORAGE")
|
||||
(text
|
||||
(expr (file-name-nondirectory (plist-get (etaf-state) :database-file))))
|
||||
(etaf-button
|
||||
:label "↻ Reload library" :ref 'research-shelf-reload :variant 'ghost
|
||||
:on-press
|
||||
(let ((model (etaf-state)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-reload model))))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-reading-list ()
|
||||
"Render the Research Shelf reading list from inherited Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t))
|
||||
(form (etaf-inject 'research-shelf-library nil t)))
|
||||
(lambda () (etaf-research-shelf--reading-list-view model form))))
|
||||
(list :model (etaf-inject 'research-shelf-model nil t)
|
||||
:form (etaf-inject 'research-shelf-library nil t))
|
||||
:view
|
||||
(column :class "research-shelf-list" :width 'stretch :min-width 0
|
||||
:flex-grow 4 :flex-shrink 1 :flex-basis '(620)
|
||||
:padding '(1 2)
|
||||
:border (etaf-theme-token :line)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(flex :width 'stretch :flex-wrap 'wrap
|
||||
:align-items 'center :gap '(1 (8))
|
||||
(column :flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(text :font-weight 'bold
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :form) :title "Reading queue")))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr
|
||||
(format
|
||||
"%d items · SQLite-backed"
|
||||
(or (etaf-value
|
||||
(etaf-data-total
|
||||
(etaf-research-shelf--controller
|
||||
(plist-get (etaf-state) :model))))
|
||||
0)))))
|
||||
(etaf-number-input
|
||||
:label "Rows"
|
||||
:value
|
||||
(etaf-value
|
||||
(etaf-data-page-size
|
||||
(etaf-research-shelf--controller
|
||||
(plist-get (etaf-state) :model))))
|
||||
:ref 'research-shelf-page-size :min 1 :max 100
|
||||
:on-change
|
||||
(let ((model (plist-get (etaf-state) :model)))
|
||||
(lambda (next)
|
||||
(etaf-dispatch 'etaf-research-shelf-page-size model next))))
|
||||
(etaf-button
|
||||
:label "+ Add reading" :ref 'research-shelf-add :variant 'secondary
|
||||
:on-press
|
||||
(let ((model (plist-get (etaf-state) :model)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-add model)))))
|
||||
(etaf-data-grid
|
||||
:controller
|
||||
(etaf-research-shelf--controller (plist-get (etaf-state) :model))
|
||||
:columns etaf-research-shelf--grid-columns
|
||||
:row-key #'etaf-research-shelf--item-id
|
||||
:row-ref
|
||||
(lambda (row)
|
||||
(intern (format "research-shelf-row-%s"
|
||||
(etaf-research-shelf--item-id row))))
|
||||
:on-row-press
|
||||
(let ((controller
|
||||
(etaf-research-shelf--controller
|
||||
(plist-get (etaf-state) :model))))
|
||||
(lambda (row)
|
||||
(etaf-data-select-one controller
|
||||
(etaf-research-shelf--item-id row))))
|
||||
:loading-label "◷ Loading library…"
|
||||
:error-label "⚠ Could not read the shelf. Use Reload.")
|
||||
(etaf-pagination
|
||||
:controller
|
||||
(etaf-research-shelf--controller (plist-get (etaf-state) :model))
|
||||
:previous-ref 'research-shelf-page-previous
|
||||
:next-ref 'research-shelf-page-next
|
||||
:color (etaf-theme-token :ink))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-detail-inspector ()
|
||||
"Render the Research Shelf detail inspector from inherited Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t))
|
||||
(form (etaf-inject 'research-shelf-detail nil t)))
|
||||
(lambda () (etaf-research-shelf--detail-view model form))))
|
||||
(list :model (etaf-inject 'research-shelf-model nil t)
|
||||
:form (etaf-inject 'research-shelf-detail nil t))
|
||||
:view
|
||||
(column :class "research-shelf-detail" :width 'stretch :min-width 0
|
||||
:flex-grow 2 :flex-shrink 1 :flex-basis '(340)
|
||||
:padding '(2 2)
|
||||
:border (etaf-theme-token :line)
|
||||
:bgcolor (etaf-theme-token :panel)
|
||||
(text :color (etaf-theme-token :accent)
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :form) :title "Selected item")))
|
||||
(text :font-weight 'bold
|
||||
(expr
|
||||
(if-let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model))))
|
||||
(plist-get row :title)
|
||||
"Choose a record")))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr
|
||||
(if-let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model))))
|
||||
(format "%s · %s" (plist-get row :author) (plist-get row :kind))
|
||||
"Select one row to inspect it.")))
|
||||
(box :height 1)
|
||||
(text :font-weight 'bold
|
||||
(expr
|
||||
(if-let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model))))
|
||||
(etaf-research-shelf--status-label (plist-get row :status))
|
||||
"○ No selection")))
|
||||
(text
|
||||
(expr
|
||||
(if-let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model))))
|
||||
(format "Progress %d%% · Priority %s"
|
||||
(or (plist-get row :progress) 0)
|
||||
(plist-get row :priority))
|
||||
"Progress — · Priority —")))
|
||||
(text :color (etaf-theme-token :accent)
|
||||
(expr
|
||||
(let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model)))
|
||||
(progress (or (and row (plist-get row :progress)) 0))
|
||||
(filled (max 0 (min 10 (/ progress 10)))))
|
||||
(format "%s %s" (make-string filled ?█)
|
||||
(make-string (- 10 filled) ?░)))))
|
||||
(box :height 1)
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr
|
||||
(if-let* ((row
|
||||
(etaf-research-shelf--selected
|
||||
(plist-get (etaf-state) :model))))
|
||||
(concat "“" (or (plist-get row :note) "No note yet.") "”")
|
||||
"Your notes and actions will appear here.")))
|
||||
(box :height 1)
|
||||
(etaf-research-shelf-detail-actions)))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-detail-actions ()
|
||||
"Render selected-record actions from the inherited Research Shelf model."
|
||||
:setup
|
||||
(etaf-inject 'research-shelf-model nil t)
|
||||
:view
|
||||
(flex :width 'stretch :flex-wrap 'wrap :gap '(1 (6))
|
||||
(etaf-button
|
||||
:label "+ 10%" :ref 'research-shelf-progress :variant 'secondary
|
||||
:disabled
|
||||
(let* ((row (etaf-research-shelf--selected (etaf-state)))
|
||||
(progress (or (and row (plist-get row :progress)) 0)))
|
||||
(or (null row) (equal (plist-get row :status) "archived")
|
||||
(>= progress 100)))
|
||||
:on-press
|
||||
(let ((model (etaf-state)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-progress model))))
|
||||
(etaf-button
|
||||
:label "✓ Finish" :ref 'research-shelf-finish :variant 'secondary
|
||||
:disabled
|
||||
(let ((row (etaf-research-shelf--selected (etaf-state))))
|
||||
(or (null row)
|
||||
(not (null (member (plist-get row :status)
|
||||
'("finished" "archived"))))))
|
||||
:on-press
|
||||
(let ((model (etaf-state)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-finish model))))
|
||||
(etaf-button
|
||||
:label "★ Star" :ref 'research-shelf-star :variant 'ghost
|
||||
:disabled (null (etaf-research-shelf--selected (etaf-state)))
|
||||
:on-press
|
||||
(let ((model (etaf-state)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-star model))))
|
||||
(etaf-button
|
||||
:label "Archive" :ref 'research-shelf-archive :variant 'ghost
|
||||
:disabled
|
||||
(let ((row (etaf-research-shelf--selected (etaf-state))))
|
||||
(or (null row) (equal (plist-get row :status) "archived")))
|
||||
:on-press
|
||||
(let ((model (etaf-state)))
|
||||
(lambda ()
|
||||
(etaf-dispatch 'etaf-research-shelf-archive model))))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-header ()
|
||||
"Render the default `header' slot from App Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t))
|
||||
(root-spec (etaf-inject 'research-shelf-root-spec nil t))
|
||||
(header-spec (etaf-inject 'research-shelf-header-spec nil t)))
|
||||
(lambda ()
|
||||
(etaf-view
|
||||
(flex
|
||||
:class "research-shelf-header" :width 'stretch :min-width 0
|
||||
:flex-wrap 'wrap :align-items 'center :gap '(1 (10))
|
||||
(column
|
||||
:flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(label :text (etaf-playground-static-value
|
||||
header-spec :eyebrow "Research Shelf")
|
||||
:color (etaf-theme-token :accent))
|
||||
(label :text (etaf-playground-static-value
|
||||
root-spec :title "Research Shelf") :font-weight 'bold)
|
||||
(label :text (etaf-playground-static-value
|
||||
root-spec :subtitle
|
||||
"A quiet place for unfinished ideas")
|
||||
:color (etaf-theme-token :muted)))
|
||||
(column :width 'max-content :min-width 0
|
||||
:flex-grow 0 :flex-shrink 0
|
||||
(checkbox :label "Dark" :ref 'research-shelf-theme-toggle
|
||||
:checked (plist-get model :dark)
|
||||
:on-change (lambda (value)
|
||||
(setf (etaf-value (plist-get model :dark)) value)
|
||||
(setf (etaf-value (plist-get model :toast))
|
||||
(if value "Dark theme" "Light theme"))))))))))
|
||||
(list :model (etaf-inject 'research-shelf-model nil t)
|
||||
:root (etaf-inject 'research-shelf-root-spec nil t)
|
||||
:header (etaf-inject 'research-shelf-header-spec nil t))
|
||||
:view
|
||||
(flex :class "research-shelf-header" :width 'stretch :min-width 0
|
||||
:flex-wrap 'wrap :align-items 'center :gap '(1 (10))
|
||||
(column :flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(text :color (etaf-theme-token :accent)
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :header) :eyebrow "Research Shelf")))
|
||||
(text :font-weight 'bold
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :root) :title "Research Shelf")))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :root) :subtitle
|
||||
"A quiet place for unfinished ideas"))))
|
||||
(column :width 'max-content :min-width 0
|
||||
:flex-grow 0 :flex-shrink 0
|
||||
(etaf-checkbox
|
||||
:label "Dark" :ref 'research-shelf-theme-toggle
|
||||
:checked (plist-get (plist-get (etaf-state) :model) :dark)
|
||||
:on-change
|
||||
(let ((model (plist-get (etaf-state) :model)))
|
||||
(lambda (value)
|
||||
(setf (etaf-value (plist-get model :dark)) value)
|
||||
(setf (etaf-value (plist-get model :toast))
|
||||
(if value "Dark theme" "Light theme"))))))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-footer ()
|
||||
"Render the default `footer' slot from App Context."
|
||||
:setup
|
||||
(let ((model (etaf-inject 'research-shelf-model nil t))
|
||||
(footer-spec (etaf-inject 'research-shelf-footer-spec nil t)))
|
||||
(lambda ()
|
||||
(etaf-view
|
||||
(flex
|
||||
:class "research-shelf-footer" :width 'stretch
|
||||
:flex-wrap 'wrap :gap '(1 (8))
|
||||
(column
|
||||
:flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(label :text (plist-get model :toast))
|
||||
(label :text (etaf-playground-static-value
|
||||
footer-spec :label "SQLite · saved locally")
|
||||
:color (etaf-theme-token :muted)))
|
||||
(label :text (file-name-nondirectory
|
||||
(plist-get model :database-file))
|
||||
:color (etaf-theme-token :muted)))))))
|
||||
(list :model (etaf-inject 'research-shelf-model nil t)
|
||||
:footer (etaf-inject 'research-shelf-footer-spec nil t))
|
||||
:view
|
||||
(flex :class "research-shelf-footer" :width 'stretch
|
||||
:flex-wrap 'wrap :gap '(1 (8))
|
||||
(column :flex-grow 1 :flex-shrink 1 :flex-basis '(0) :min-width 0
|
||||
(text
|
||||
(expr
|
||||
(etaf-value (plist-get (plist-get (etaf-state) :model) :toast))))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr (etaf-playground-static-value
|
||||
(plist-get (etaf-state) :footer)
|
||||
:label "SQLite · saved locally"))))
|
||||
(text :color (etaf-theme-token :muted)
|
||||
(expr (file-name-nondirectory
|
||||
(plist-get (plist-get (etaf-state) :model) :database-file))))))
|
||||
|
||||
(etaf-define-component etaf-research-shelf-shell ()
|
||||
"Pure responsive layout shell with named content slots.
|
||||
@ -759,21 +797,16 @@ slot has a reusable built-in fallback for direct composition."
|
||||
(etaf-provide 'research-shelf-footer-spec
|
||||
(etaf-playground-static-child
|
||||
static-form 'research-shelf-footer-spec))
|
||||
(lambda ()
|
||||
(etaf-view
|
||||
;; These are real ETAF named slot inputs; the `.etaf' manifest remains
|
||||
;; inert configuration and never pretends to be View syntax.
|
||||
(etaf-research-shelf-shell
|
||||
(slot :name 'header
|
||||
(etaf-research-shelf-header))
|
||||
(slot :name 'filters
|
||||
(etaf-research-shelf-filter-rail))
|
||||
(slot :name 'library
|
||||
(etaf-research-shelf-reading-list))
|
||||
(slot :name 'detail
|
||||
(etaf-research-shelf-detail-inspector))
|
||||
(slot :name 'footer
|
||||
(etaf-research-shelf-footer)))))))
|
||||
nil)
|
||||
:view
|
||||
;; These are real ETAF named slot inputs; the `.etaf' manifest remains inert
|
||||
;; configuration and never pretends to be View syntax.
|
||||
(etaf-research-shelf-shell
|
||||
(slot :name 'header (etaf-research-shelf-header))
|
||||
(slot :name 'filters (etaf-research-shelf-filter-rail))
|
||||
(slot :name 'library (etaf-research-shelf-reading-list))
|
||||
(slot :name 'detail (etaf-research-shelf-detail-inspector))
|
||||
(slot :name 'footer (etaf-research-shelf-footer))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; ROOT / PLAYGROUND REGISTRATION
|
||||
|
||||
@ -670,9 +670,13 @@ ETAF generation and preserve RUNTIME's mounted surface in BUFFER."
|
||||
(unless (etaf-performance-evaluator--visible-match-p
|
||||
buffer "Page 1 / 22")
|
||||
(etaf-dispatch-event runtime 'research-shelf-page-previous 'press))
|
||||
(let ((refs '(research-shelf-row-2 research-shelf-row-4
|
||||
research-shelf-row-5 research-shelf-row-8
|
||||
research-shelf-row-9 research-shelf-row-10)))
|
||||
;; Use one actionable reading per sample. Reusing a visible row
|
||||
;; eventually reaches 100% during the five warmups and would make a
|
||||
;; real disabled button look like a failed mutation. Moving to the
|
||||
;; target page is setup work and remains outside the timed action.
|
||||
(let ((ids '(1 4 6 9 12 13 16 17 20 21 24 25 28 29 32 33
|
||||
36 37 40 41 44 45 48 49 52 53 56 57 60 61 64
|
||||
65 68 69 72)))
|
||||
(push
|
||||
(etaf-performance-evaluator--measure
|
||||
"progress-mutation"
|
||||
@ -688,9 +692,39 @@ ETAF generation and preserve RUNTIME's mounted surface in BUFFER."
|
||||
(etaf-performance-evaluator--surface-invariant
|
||||
runtime buffer "progress-mutation"))
|
||||
:setup (lambda (index)
|
||||
(etaf-performance-evaluator--select-ref
|
||||
runtime (nth (% (1+ index) (length refs)) refs))))
|
||||
(let* ((id (nth
|
||||
(mod (+ index
|
||||
etaf-performance-evaluator-warmup-count)
|
||||
(length ids))
|
||||
ids))
|
||||
(target-page
|
||||
(1+ (/ (1- id)
|
||||
etaf-performance-evaluator-page-size)))
|
||||
(current-page
|
||||
(or (car
|
||||
(etaf-performance-evaluator--visible-page
|
||||
buffer))
|
||||
1)))
|
||||
(while (< current-page target-page)
|
||||
(etaf-dispatch-event
|
||||
runtime 'research-shelf-page-next 'press)
|
||||
(setq current-page (1+ current-page)))
|
||||
(while (> current-page target-page)
|
||||
(etaf-dispatch-event
|
||||
runtime 'research-shelf-page-previous 'press)
|
||||
(setq current-page (1- current-page)))
|
||||
(etaf-performance-evaluator--select-ref
|
||||
runtime (intern (format "research-shelf-row-%d" id))))))
|
||||
results))
|
||||
;; Progress setup traverses several pages to keep each action
|
||||
;; enabled. Return to the first page before the shared focus and
|
||||
;; add/reload scenarios, whose refs intentionally target page one.
|
||||
(when-let* ((page (etaf-performance-evaluator--visible-page buffer)))
|
||||
(while (> (car page) 1)
|
||||
(etaf-dispatch-event
|
||||
runtime 'research-shelf-page-previous 'press)
|
||||
(setq page
|
||||
(etaf-performance-evaluator--visible-page buffer))))
|
||||
|
||||
(push
|
||||
(etaf-performance-evaluator--measure
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
(require 'benchmark-research-shelf)
|
||||
(require 'ebox-native-reflow)
|
||||
|
||||
(defvar etaf-research-shelf-database-file)
|
||||
(defvar etaf-research-shelf-fixture-size)
|
||||
(defvar etaf-research-shelf-page-size)
|
||||
|
||||
(defun etaf-playground-gui-scenarios--report (context)
|
||||
"Return CONTEXT target's public Ebox report, or nil before mount."
|
||||
(let ((buffer (etaf-gui-verifier-context-target-buffer context)))
|
||||
@ -261,8 +265,10 @@
|
||||
"scroll-reset" (= (window-start) (point-min)))))))
|
||||
|
||||
(defun etaf-playground-gui-scenarios--research-event-action
|
||||
(id reference postcondition &optional screenshot)
|
||||
"Return Research action ID for REFERENCE, POSTCONDITION, and SCREENSHOT."
|
||||
(id reference postcondition &optional screenshot assertion-name)
|
||||
"Return Research action ID for REFERENCE and POSTCONDITION.
|
||||
When non-nil, SCREENSHOT requests visual evidence and ASSERTION-NAME names the
|
||||
product-specific postcondition in the evidence stream."
|
||||
(etaf-gui-verifier-action-create
|
||||
:id id
|
||||
:execute
|
||||
@ -304,7 +310,7 @@
|
||||
"activated-host-focused"
|
||||
(equal reference (etaf-focused-host-ref runtime)))
|
||||
(etaf-gui-verifier-assert
|
||||
"product-postcondition"
|
||||
(or assertion-name "product-postcondition")
|
||||
(funcall postcondition context)))))
|
||||
:screenshot screenshot))
|
||||
|
||||
@ -356,6 +362,22 @@
|
||||
(string-match-p
|
||||
"John Berger · Book"
|
||||
(etaf-playground-gui-scenarios--buffer-text context))))
|
||||
(etaf-playground-gui-scenarios--research-event-action
|
||||
"data-mutation" 'research-shelf-progress
|
||||
(lambda (context)
|
||||
(let ((text
|
||||
(etaf-playground-gui-scenarios--buffer-text context)))
|
||||
(and (string-match-p "Progress saved" text)
|
||||
(string-match-p "10%" text))))
|
||||
t "progress-persisted")
|
||||
(etaf-playground-gui-scenarios--research-event-action
|
||||
"filter-reading" 'research-shelf-filter-reading
|
||||
(lambda (context)
|
||||
(let ((text
|
||||
(etaf-playground-gui-scenarios--buffer-text context)))
|
||||
(and (string-match-p "Showing Reading" text)
|
||||
(string-match-p "Ways of Seeing" text))))
|
||||
t "reading-filter-applied")
|
||||
(etaf-playground-gui-scenarios--research-event-action
|
||||
"theme-toggle" 'research-shelf-theme-toggle
|
||||
(lambda (context)
|
||||
@ -374,7 +396,7 @@
|
||||
(etaf-playground-gui-scenarios--maximize-action))
|
||||
:completion
|
||||
(lambda (context)
|
||||
(= (etaf-gui-verifier-context-action-count context) 10))))
|
||||
(= (etaf-gui-verifier-context-action-count context) 12))))
|
||||
|
||||
(defun etaf-playground-gui-scenarios-ebox (scenario fixture)
|
||||
"Return one Ebox SCENARIO adapter for FIXTURE."
|
||||
@ -431,6 +453,14 @@
|
||||
(run-directory (or (getenv "ETAF_GUI_RUN_DIR")
|
||||
(error "ETAF_GUI_RUN_DIR is not configured")))
|
||||
(fixture (getenv "ETAF_GUI_FIXTURE"))
|
||||
(_research-fixture
|
||||
(when (equal scenario "research-shelf")
|
||||
(setq etaf-research-shelf-database-file
|
||||
(expand-file-name "research-shelf.sqlite" run-directory)
|
||||
etaf-research-shelf-fixture-size 256
|
||||
etaf-research-shelf-page-size 12)
|
||||
(when (file-exists-p etaf-research-shelf-database-file)
|
||||
(delete-file etaf-research-shelf-database-file))))
|
||||
(adapter
|
||||
(pcase scenario
|
||||
("research-shelf"
|
||||
|
||||
@ -69,6 +69,15 @@ database and mounts a test buffer before running BODY."
|
||||
(when (file-exists-p ,database)
|
||||
(delete-file ,database))))))
|
||||
|
||||
(defun etaf-playground-test--open (buffer)
|
||||
"Mount Research Shelf in BUFFER with a deterministic headless viewport.
|
||||
|
||||
Text assertions should not depend on whether batch Ebox has a selected
|
||||
window. GUI verification exercises responsive geometry separately on a real
|
||||
frame."
|
||||
(etaf-playground-mount-example
|
||||
buffer "research-shelf" nil '(:viewport-width 1400 :viewport-height 80)))
|
||||
|
||||
(ert-deftest etaf-playground-framework-discovers-generic-file-triplets ()
|
||||
"Discover examples from files without a business catalog in the framework."
|
||||
(should (member "research-shelf" etaf-playground-example-names))
|
||||
@ -395,11 +404,13 @@ database and mounts a test buffer before running BODY."
|
||||
(replace-match ":title \"Research Shelf (edited)\"" t t)
|
||||
(set-buffer-modified-p t))
|
||||
(should (etaf-playground-refresh source))
|
||||
(should (string-match-p "Research Shelf (edited)"
|
||||
(etaf-playground-test--text
|
||||
(etaf-playground-session-preview-buffer
|
||||
(buffer-local-value 'etaf-playground-session
|
||||
source))))))))
|
||||
(let* ((session (buffer-local-value 'etaf-playground-session source))
|
||||
(preview (etaf-playground-session-preview-buffer session))
|
||||
(form (etaf-playground-read-static "research-shelf" session)))
|
||||
(should (equal "Research Shelf (edited)"
|
||||
(plist-get (cdr form) :title)))
|
||||
(should (string-match-p "edited"
|
||||
(etaf-playground-test--text preview)))))))
|
||||
|
||||
(ert-deftest etaf-playground-refresh-reloads-unsaved-el-companion ()
|
||||
"Refreshing a dirty `.el' companion redefines its consumer intentionally."
|
||||
@ -426,13 +437,11 @@ database and mounts a test buffer before running BODY."
|
||||
(etaf-compiler-clear-cache)
|
||||
(let* ((before (etaf-compiler-statistics))
|
||||
(instantiations (plist-get before :instantiations))
|
||||
(fallbacks (plist-get before :fallbacks))
|
||||
(cache-entries (plist-get before :static-cache-entries)))
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let* ((after (etaf-compiler-statistics))
|
||||
(blueprint (plist-get after :last-blueprint)))
|
||||
(should (> (plist-get after :instantiations) instantiations))
|
||||
(should (>= (plist-get after :fallbacks) fallbacks))
|
||||
(should (> (plist-get after :static-cache-entries) cache-entries))
|
||||
(should (> (plist-get blueprint :dynamic-nodes) 0))
|
||||
(should (> (plist-get blueprint :hole-count) 0))))))
|
||||
@ -440,7 +449,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-pair-mounts-sqlite-backed-surface ()
|
||||
"Mounting the pair initializes SQLite and renders the real app shell."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(should (etaf-runtime-p (etaf-runtime-for-buffer buffer)))
|
||||
(should (file-exists-p database))
|
||||
(let ((text (etaf-playground-test--text buffer))
|
||||
@ -492,7 +501,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-row-selection-is-repeatable ()
|
||||
"Repeated DataGrid row presses replace one selected identity."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer)))
|
||||
(dolist (entry '((research-shelf-row-1 research-shelf-row-2
|
||||
"The best tools make attention feel larger")
|
||||
@ -526,7 +535,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-row-observer-on-off-is-exact ()
|
||||
"Observation preserves one real row mutation and its retained identity."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let* ((runtime (etaf-runtime-for-buffer buffer))
|
||||
(surface
|
||||
(lambda ()
|
||||
@ -578,7 +587,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-filters-and-pagination-reload-data ()
|
||||
"Filter and pager refs drive the SQLite-backed Data Controller."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer)))
|
||||
;; Move the selected identity through the old page first. The following
|
||||
;; filter reorders keyed Range items; generated cell Host addresses must
|
||||
@ -621,7 +630,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-workspace-reflows-at-responsive-widths ()
|
||||
"Workspace cards share a row when wide and wrap in document order."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(cl-labels
|
||||
((line-of (label)
|
||||
(with-current-buffer buffer
|
||||
@ -652,7 +661,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-mutations-persist-and-refresh ()
|
||||
"Add and mutate actions persist through the SQLite source and refresh UI."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer)))
|
||||
(etaf-dispatch-event runtime 'research-shelf-row-1 'press)
|
||||
(etaf-dispatch-event runtime 'research-shelf-progress 'press)
|
||||
@ -675,7 +684,7 @@ database and mounts a test buffer before running BODY."
|
||||
(ert-deftest etaf-playground-theme-and-lifecycle-are-repeatable ()
|
||||
"Theme changes and reset/close do not leave a stale mounted runtime."
|
||||
(etaf-playground-test--with-app (buffer database)
|
||||
(etaf-playground-open buffer)
|
||||
(etaf-playground-test--open buffer)
|
||||
(let ((runtime (etaf-runtime-for-buffer buffer)))
|
||||
(etaf-dispatch-event runtime 'research-shelf-row-1 'press)
|
||||
(let (dark-output light-output)
|
||||
|
||||
92
tests/playground-gui-scenarios-tests.el
Normal file
92
tests/playground-gui-scenarios-tests.el
Normal file
@ -0,0 +1,92 @@
|
||||
;;; playground-gui-scenarios-tests.el --- GUI scenario contracts -*- lexical-binding: t; -*-
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; These tests keep the Research Shelf GUI action matrix aligned with the M0a
|
||||
;; evidence claim without running a graphical Emacs session.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'ert)
|
||||
(add-to-list 'load-path (expand-file-name "../etaf/scripts" default-directory))
|
||||
(add-to-list 'load-path (expand-file-name "../ebox-playground" default-directory))
|
||||
(require 'playground-gui-scenarios)
|
||||
|
||||
(defvar etaf-research-shelf-database-file)
|
||||
(defvar etaf-research-shelf-fixture-size)
|
||||
(defvar etaf-research-shelf-page-size)
|
||||
|
||||
(defun etaf-playground-gui-test--action (scenario id)
|
||||
"Return SCENARIO action named ID."
|
||||
(cl-find id (etaf-gui-verifier-scenario-actions scenario)
|
||||
:key #'etaf-gui-verifier-action-id :test #'equal))
|
||||
|
||||
(ert-deftest etaf-playground-gui-research-covers-public-action-matrix ()
|
||||
"Research Shelf covers every required public M0a interaction in order."
|
||||
(let* ((scenario (etaf-playground-gui-scenarios-research))
|
||||
(actions (etaf-gui-verifier-scenario-actions scenario)))
|
||||
(should
|
||||
(equal
|
||||
(mapcar #'etaf-gui-verifier-action-id actions)
|
||||
'("mount" "leave-fullscreen" "resize-narrow" "scroll-down"
|
||||
"reset-scroll" "resize-wide" "row-select" "data-mutation"
|
||||
"filter-reading" "theme-toggle" "pagination"
|
||||
"maximize-frame")))
|
||||
(should
|
||||
(funcall
|
||||
(etaf-gui-verifier-scenario-completion scenario)
|
||||
(etaf-gui-verifier--context-create
|
||||
:scenario scenario :action-count (length actions))))))
|
||||
|
||||
(ert-deftest etaf-playground-gui-research-names-product-assertions ()
|
||||
"Public filter and mutation actions publish specific passing assertions."
|
||||
(let ((database (make-temp-file "etaf-gui-research-" nil ".sqlite"))
|
||||
(buffer " *etaf-gui-research-test*"))
|
||||
(unwind-protect
|
||||
(let* ((etaf-research-shelf-database-file database)
|
||||
(etaf-research-shelf-fixture-size 32)
|
||||
(etaf-research-shelf-page-size 12)
|
||||
(scenario (etaf-playground-gui-scenarios-research))
|
||||
context)
|
||||
(ignore etaf-research-shelf-database-file
|
||||
etaf-research-shelf-fixture-size
|
||||
etaf-research-shelf-page-size)
|
||||
(etaf-playground-mount-example
|
||||
buffer "research-shelf" nil
|
||||
'(:viewport-width 1400 :viewport-height 80))
|
||||
(switch-to-buffer buffer)
|
||||
(setq context
|
||||
(etaf-gui-verifier--context-create
|
||||
:scenario scenario :target-buffer (get-buffer buffer)))
|
||||
(dolist (entry '(("row-select")
|
||||
("data-mutation" . "progress-persisted")
|
||||
("filter-reading" . "reading-filter-applied")))
|
||||
(let ((id (car entry))
|
||||
(assertion-name (cdr entry)))
|
||||
(let ((action
|
||||
(etaf-playground-gui-test--action scenario id)))
|
||||
(should action)
|
||||
(funcall (etaf-gui-verifier-action-execute action) context)
|
||||
(should
|
||||
(funcall
|
||||
(etaf-gui-verifier-action-settled-p action) context))
|
||||
(when assertion-name
|
||||
(let* ((assertions
|
||||
(funcall
|
||||
(etaf-gui-verifier-action-assertions action)
|
||||
context))
|
||||
(assertion
|
||||
(cl-find
|
||||
assertion-name assertions
|
||||
:key (lambda (item) (alist-get 'name item))
|
||||
:test #'equal)))
|
||||
(should assertion)
|
||||
(should (alist-get 'passed assertion))))))))
|
||||
(when (get-buffer buffer)
|
||||
(etaf-playground-close buffer))
|
||||
(when (file-exists-p database)
|
||||
(delete-file database)))))
|
||||
|
||||
(provide 'playground-gui-scenarios-tests)
|
||||
;;; playground-gui-scenarios-tests.el ends here
|
||||
Loading…
Reference in New Issue
Block a user