scriptorium 0.0.3 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.lt3 +324 -0
- data/README.md +3155 -1
- data/assets/.DS_Store +0 -0
- data/assets/README.md +44 -0
- data/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/icons/ui/.DS_Store +0 -0
- data/assets/icons/ui/back.png +0 -0
- data/assets/icons/ui/copy.png +0 -0
- data/assets/icons/ui/down.png +0 -0
- data/assets/icons/ui/end.png +0 -0
- data/assets/icons/ui/exit.png +0 -0
- data/assets/icons/ui/foo +10 -0
- data/assets/icons/ui/home.png +0 -0
- data/assets/icons/ui/left.png +0 -0
- data/assets/icons/ui/next.png +0 -0
- data/assets/icons/ui/right.png +0 -0
- data/assets/icons/ui/start.png +0 -0
- data/assets/icons/ui/up.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/assets/samples/placeholder.svg +9 -0
- data/assets/themes/standard/favicon.svg +6 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/README.txt +6 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
- data/doc/anti-amnesia/20250807-213025.md +116 -0
- data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
- data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
- data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
- data/doc/banner_svg_config.md +114 -0
- data/doc/contrib.lt3 +8 -0
- data/doc/dependencies.md +281 -0
- data/doc/hacker.lt3 +5 -0
- data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
- data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
- data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
- data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
- data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
- data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
- data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
- data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
- data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
- data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
- data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
- data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
- data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
- data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
- data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
- data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
- data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
- data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
- data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
- data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
- data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
- data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
- data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
- data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
- data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
- data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
- data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
- data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
- data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
- data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
- data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
- data/doc/imported/0018-ruby-puns/post.html +46 -0
- data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
- data/doc/imported/0020-fffff/metadata.txt +7 -0
- data/doc/imported/0020-fffff/post.html +24 -0
- data/doc/imported/0020-fffff/source.lt3 +12 -0
- data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
- data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
- data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
- data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
- data/doc/imported/0023-doctor-sleep/post.html +63 -0
- data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
- data/doc/imported/0024-just-a-test/metadata.txt +7 -0
- data/doc/imported/0024-just-a-test/post.html +24 -0
- data/doc/imported/0024-just-a-test/source.lt3 +12 -0
- data/doc/imported/import_summary.txt +98 -0
- data/doc/livetext-informal-spec.txt +65 -0
- data/doc/myuserdoc/ch-0.lt3 +31 -0
- data/doc/myuserdoc/ch-1.lt3 +37 -0
- data/doc/myuserdoc/ch-10.lt3 +22 -0
- data/doc/myuserdoc/ch-2.lt3 +37 -0
- data/doc/myuserdoc/ch-3.lt3 +19 -0
- data/doc/myuserdoc/ch-4.lt3 +43 -0
- data/doc/myuserdoc/ch-5.lt3 +22 -0
- data/doc/myuserdoc/ch-6.lt3 +19 -0
- data/doc/myuserdoc/ch-7.lt3 +16 -0
- data/doc/myuserdoc/ch-8.lt3 +13 -0
- data/doc/myuserdoc/ch-9.lt3 +19 -0
- data/doc/myuserdoc/tweak.rb +18 -0
- data/doc/myuserdoc/userdoc-toc.txt +88 -0
- data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
- data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
- data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
- data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
- data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
- data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
- data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
- data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
- data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
- data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
- data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
- data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
- data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
- data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
- data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
- data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
- data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
- data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
- data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
- data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
- data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
- data/doc/old-posts/0024-just-a-test.lt3 +12 -0
- data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
- data/doc/old-repo +1 -0
- data/doc/reddit_credentials_template.json +8 -0
- data/doc/reddit_integration.md +207 -0
- data/doc/user.lt3 +35 -0
- data/doc/user_guide_section_1.md +137 -0
- data/doc/user_guide_section_10.md +515 -0
- data/doc/user_guide_section_11.md +708 -0
- data/doc/user_guide_section_2.md +233 -0
- data/doc/user_guide_section_3.md +5 -0
- data/doc/user_guide_section_4.md +221 -0
- data/doc/user_guide_section_5.md +243 -0
- data/doc/user_guide_section_6.md +147 -0
- data/doc/user_guide_section_7.md +311 -0
- data/doc/user_guide_section_8.md +224 -0
- data/doc/user_guide_section_9.md +375 -0
- data/lib/rouge/lexers/livetext.rb +74 -0
- data/lib/scriptorium/api.rb +2373 -0
- data/lib/scriptorium/banner_svg.rb +729 -0
- data/lib/scriptorium/contract.rb +34 -0
- data/lib/scriptorium/exceptions.rb +201 -1
- data/lib/scriptorium/helpers.rb +675 -0
- data/lib/scriptorium/post.rb +259 -0
- data/lib/scriptorium/reddit.rb +83 -0
- data/lib/scriptorium/repo.rb +938 -0
- data/lib/scriptorium/standard_files.rb +149 -0
- data/lib/scriptorium/support/bootstrap/css.txt +5 -0
- data/lib/scriptorium/support/bootstrap/js.txt +4 -0
- data/lib/scriptorium/support/common_js/clipboard.js +35 -0
- data/lib/scriptorium/support/common_js/content-loader.js +187 -0
- data/lib/scriptorium/support/common_js/navigation.js +52 -0
- data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
- data/lib/scriptorium/support/config/reddit.txt +10 -0
- data/lib/scriptorium/support/config/reddit_template.txt +17 -0
- data/lib/scriptorium/support/config/social.txt +8 -0
- data/lib/scriptorium/support/highlight/css.txt +2 -0
- data/lib/scriptorium/support/highlight/custom.css +119 -0
- data/lib/scriptorium/support/highlight/js.txt +1 -0
- data/lib/scriptorium/support/post_index/config.txt +15 -0
- data/lib/scriptorium/support/post_index/style.css +55 -0
- data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
- data/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
- data/lib/scriptorium/support/templates/layout.txt +5 -0
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/lib/scriptorium/support/theme/footer.lt3 +2 -0
- data/lib/scriptorium/support/theme/header.lt3 +4 -0
- data/lib/scriptorium/support/theme/left.lt3 +3 -0
- data/lib/scriptorium/support/theme/main.lt3 +5 -0
- data/lib/scriptorium/support/theme/right.lt3 +3 -0
- data/lib/scriptorium/theme.rb +192 -0
- data/lib/scriptorium/version.rb +1 -1
- data/lib/scriptorium/view.rb +1021 -0
- data/lib/scriptorium/widgets/featured_posts.rb +149 -0
- data/lib/scriptorium/widgets/links.rb +112 -0
- data/lib/scriptorium/widgets/pages.rb +133 -0
- data/lib/scriptorium/widgets/widget.rb +133 -0
- data/lib/scriptorium.rb +38 -34
- data/lib/skeleton.rb +10 -1
- data/scriptorium.gemspec +17 -5
- data/test/README.md +69 -0
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +83 -0
- data/test/api_demo.rb +99 -0
- data/test/assets/imagenotfound.jpg +0 -0
- data/test/assets/images/.DS_Store +0 -0
- data/test/assets/images/README.md +27 -0
- data/test/assets/images/odd_aspect.png +0 -0
- data/test/assets/images/perfect.png +0 -0
- data/test/assets/images/small.png +0 -0
- data/test/assets/images/tall.png +0 -0
- data/test/assets/images/very_tall.png +0 -0
- data/test/assets/images/very_wide.png +0 -0
- data/test/assets/images/wide.png +0 -0
- data/test/assets/testbanner.jpg +0 -0
- data/test/banner_svg/simple_helpers.rb +13 -0
- data/test/banner_svg/unit.rb +1000 -0
- data/test/config/deployment.txt +5 -0
- data/test/ed_test.rb +204 -0
- data/test/integration/cursor_banner_combinations.rb +193 -0
- data/test/integration/cursor_banner_features.rb +374 -0
- data/test/integration/integration_test.rb +326 -0
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +500 -0
- data/test/manual/asset_mgmt.rb +67 -0
- data/test/manual/banner-tests/index.html +45 -0
- data/test/manual/banner-tests/svg.txt +3 -0
- data/test/manual/banner-tests/test01.html +122 -0
- data/test/manual/banner-tests/test02.html +122 -0
- data/test/manual/banner-tests/test03.html +122 -0
- data/test/manual/banner-tests/test04.html +129 -0
- data/test/manual/banner-tests/test05.html +129 -0
- data/test/manual/banner-tests/test06.html +129 -0
- data/test/manual/banner-tests/test07.html +129 -0
- data/test/manual/banner-tests/test08.html +123 -0
- data/test/manual/banner-tests/test09.html +123 -0
- data/test/manual/banner-tests/test10.html +123 -0
- data/test/manual/banner-tests/test11.html +123 -0
- data/test/manual/banner-tests/test12.html +123 -0
- data/test/manual/banner-tests/test13.html +123 -0
- data/test/manual/banner-tests/test14.html +123 -0
- data/test/manual/banner-tests/test15.html +122 -0
- data/test/manual/banner-tests/test16.html +122 -0
- data/test/manual/banner-tests/test17.html +122 -0
- data/test/manual/banner-tests/test18.html +132 -0
- data/test/manual/banner-tests/test19.html +132 -0
- data/test/manual/banner-tests/test20.html +132 -0
- data/test/manual/banner-tests/test21.html +132 -0
- data/test/manual/banner-tests/test22.html +132 -0
- data/test/manual/banner-tests/test23.html +132 -0
- data/test/manual/banner-tests/test24.html +132 -0
- data/test/manual/banner-tests/test25.html +131 -0
- data/test/manual/banner_environment.rb +205 -0
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/environment.rb +67 -0
- data/test/manual/make_banner.rb +153 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/sample_banner_config.txt +12 -0
- data/test/manual/test_advanced_widgets.rb +73 -0
- data/test/manual/test_banner_combinations.rb +120 -0
- data/test/manual/test_banner_features.rb +306 -0
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_basic_posts.rb +47 -0
- data/test/manual/test_layout_widgets.rb +40 -0
- data/test/manual/test_pagination.rb +24 -0
- data/test/manual/test_random_posts.rb +38 -0
- data/test/manual/test_syntax_highlighting.rb +167 -0
- data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
- data/test/rubytext/rubytext_demo_test.rb +42 -0
- data/test/rubytext/rubytext_testing_guide.md +277 -0
- data/test/run_automated_tests.rb +45 -0
- data/test/staging/.DS_Store +0 -0
- data/test/support/preview_utils.rb +88 -0
- data/test/syntax_highlighting_test.lt3 +124 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +240 -0
- data/test/tui_editor_integration_test.rb +296 -0
- data/test/tui_integration_test.rb +883 -0
- data/test/unit/api.rb +1776 -0
- data/test/unit/asset_management.rb +219 -0
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/clipboard_test.rb +60 -0
- data/test/unit/contract_test.rb +69 -0
- data/test/unit/core.rb +1211 -0
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +478 -0
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +183 -0
- data/test/unit/livetext_basic.rb +57 -0
- data/test/unit/livetext_compatibility.rb +82 -0
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/permalink_copy_test.rb +211 -0
- data/test/unit/post.rb +309 -0
- data/test/unit/post_index_config_test.rb +258 -0
- data/test/unit/post_state_helpers_test.rb +137 -0
- data/test/unit/read_commented_file_test.rb +278 -0
- data/test/unit/reddit_test.rb +235 -0
- data/test/unit/repo.rb +569 -0
- data/test/unit/social_test.rb +366 -0
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +498 -0
- data/test/unit/widgets.rb +669 -0
- data/test/web_integration_test.rb +231 -0
- data/test/web_test_helper.rb +218 -0
- data/test/web_workflow_test.rb +527 -0
- data/test/wizard_test.rb +123 -0
- data/ui/README.md +67 -0
- data/ui/common/lib/ui_common.rb +8 -0
- data/ui/rubytext/README.md +191 -0
- data/ui/rubytext/bin/scriptorium-rubytext +402 -0
- data/ui/rubytext/lib/rubytext_ui.rb +300 -0
- data/ui/tui/bin/scriptorium +1890 -0
- data/ui/tui/test/tui_test.rb +23 -0
- data/ui/web/app/app.rb +2600 -0
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +150 -0
- data/ui/web/app/views/advanced_config.erb +196 -0
- data/ui/web/app/views/asset_management.erb +645 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/banner_config.erb +200 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/configure_view.erb +401 -0
- data/ui/web/app/views/dashboard.erb +154 -0
- data/ui/web/app/views/deploy_config.erb +149 -0
- data/ui/web/app/views/edit_pages.erb +363 -0
- data/ui/web/app/views/edit_post.erb +175 -0
- data/ui/web/app/views/edit_theme.erb +73 -0
- data/ui/web/app/views/edit_theme_file.erb +74 -0
- data/ui/web/app/views/error_page.erb +29 -0
- data/ui/web/app/views/header_config.erb +155 -0
- data/ui/web/app/views/layout_config.erb +147 -0
- data/ui/web/app/views/navbar_config.erb +411 -0
- data/ui/web/app/views/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +779 -0
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +164 -0
- data/ui/web/test/web_basic_test.rb +38 -0
- data/ui/web/test_navbar.txt +7 -0
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -0
- metadata +434 -8
- data/lib/scriptorium/engine.rb +0 -22
- data/test/engine/unit.rb +0 -44
@@ -0,0 +1,240 @@
|
|
1
|
+
module TestHelpers
|
2
|
+
|
3
|
+
include Scriptorium::Helpers
|
4
|
+
|
5
|
+
# Disable Design by Contract in tests by default
|
6
|
+
ENV['DBC_DISABLED'] = 'true'
|
7
|
+
|
8
|
+
def assert_dir_exist?(dir)
|
9
|
+
assert Dir.exist?(dir), "Directory '#{dir}' was not found"
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_file_exist?(file)
|
13
|
+
assert File.exist?(file), "File '#{file}' was not found"
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_test_repo
|
17
|
+
Scriptorium::Repo.create("test/scriptorium-TEST", testmode: true) # testing
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_file_contains?(file, str)
|
21
|
+
text = File.read(file)
|
22
|
+
text.include?(str)
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert_file_lines(file, num)
|
26
|
+
lines = File.readlines(file)
|
27
|
+
assert lines.size == num, "Expected #{num} lines in #{file}; found #{lines.size}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Assert that a string includes text, with concise error message
|
31
|
+
def assert_includes_concise_string(content, text, description)
|
32
|
+
unless content.include?(text)
|
33
|
+
# Show content size and a snippet for debugging
|
34
|
+
size = content.size
|
35
|
+
snippet = content[0, 300].gsub(/\s+/, ' ').strip
|
36
|
+
flunk "#{description} - Expected to find '#{text}' in content (#{size} bytes). Content snippet: #{snippet}..."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def assert_file_newer?(f1, f2)
|
41
|
+
assert File.mtime(f1) > File.mtime(f2), "File #{f1} is not newer than #{f2}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def assert_file_older?(f1, f2)
|
45
|
+
assert File.mtime(f1) < File.mtime(f2), "File #{f1} is not older than #{f2}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def assert_class(obj, klass)
|
49
|
+
assert obj.is_a?(klass), "Expected a #{klass}, got #{obj.class}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def see_file(file)
|
53
|
+
puts "----- File: #{file}"
|
54
|
+
system("cat #{file}")
|
55
|
+
puts "-----"
|
56
|
+
end
|
57
|
+
|
58
|
+
def see(label, var)
|
59
|
+
puts "#{label} = <<<\n#{var}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert_wildcard_exist?(pattern)
|
63
|
+
glob = Dir.glob(pattern)
|
64
|
+
assert glob.size == 1, "Wildcard '#{pattern}' - expected 1 entry"
|
65
|
+
end
|
66
|
+
|
67
|
+
def assert_generated_post_found?(repo, num, views)
|
68
|
+
id4 = d4(num)
|
69
|
+
views = [views] if views.is_a?(String)
|
70
|
+
assert_file_exist?(repo.root/:posts/id4/"body.html")
|
71
|
+
assert_file_exist?(repo.root/:posts/id4/"meta.txt")
|
72
|
+
views.each do |view|
|
73
|
+
assert_wildcard_exist?(repo.root/:views/view/:output/:posts/"#{id4}-*.html")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def random_post(repo, views: nil)
|
78
|
+
views ||= []
|
79
|
+
views = [views] if views.is_a?(String)
|
80
|
+
rnum = rand(10000).to_i
|
81
|
+
name = repo.create_draft(title: "Random Post #{rnum}",
|
82
|
+
body: "Just a (#{rand(10000).to_i}) random post",
|
83
|
+
views: views)
|
84
|
+
num = repo.finish_draft(name)
|
85
|
+
num
|
86
|
+
end
|
87
|
+
|
88
|
+
def try_post_with_views(repo, views)
|
89
|
+
num = random_post(repo, views: views)
|
90
|
+
repo.generate_post(num)
|
91
|
+
assert_generated_post_found?(repo, num, views)
|
92
|
+
end
|
93
|
+
|
94
|
+
def post_with_views(repo, views) # No assert - for manual tests
|
95
|
+
num = random_post(repo, views: views)
|
96
|
+
repo.generate_post(num)
|
97
|
+
end
|
98
|
+
|
99
|
+
def num_posts_per_view(repo, view, exp)
|
100
|
+
posts = repo.all_posts(view)
|
101
|
+
assert posts.size == exp, "Expected #{exp} #{view} posts, found #{posts.size}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_post(repo, title: "Test Post", views: ["sample"], body: "Hello")
|
105
|
+
draft = repo.create_draft(title: title, views: views, body: body)
|
106
|
+
num = repo.finish_draft(draft)
|
107
|
+
repo.generate_post(num)
|
108
|
+
Scriptorium::Post.new(repo, num)
|
109
|
+
end
|
110
|
+
|
111
|
+
def assert_ordered(str, *targets)
|
112
|
+
located = []
|
113
|
+
targets.each do |t|
|
114
|
+
located << str.index(t)
|
115
|
+
end
|
116
|
+
assert located == located.sort, "Targets out of order (#{located})"
|
117
|
+
end
|
118
|
+
|
119
|
+
def assert_present(str, *targets)
|
120
|
+
result = true
|
121
|
+
missing = []
|
122
|
+
targets.each do |t|
|
123
|
+
if ! str.include?(t)
|
124
|
+
result = false
|
125
|
+
missing << t
|
126
|
+
end
|
127
|
+
end
|
128
|
+
assert result, "Targets missing: #{missing.join(", ").inspect}"
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_3_views # For test_posts_generated_and_indexed_across_multiple_views
|
132
|
+
@repo.create_view("blog1", "Blog 1", "nothing (1)")
|
133
|
+
@repo.create_view("blog2", "Blog 2", "nothing (2)")
|
134
|
+
@repo.create_view("blog3", "Blog 3", "nothing (3)")
|
135
|
+
end
|
136
|
+
|
137
|
+
def create_13_posts_manual
|
138
|
+
post_with_views(@repo, "blog1")
|
139
|
+
post_with_views(@repo, "blog2")
|
140
|
+
post_with_views(@repo, "blog3")
|
141
|
+
post_with_views(@repo, %w[blog1 blog2])
|
142
|
+
post_with_views(@repo, %w[blog2 blog3])
|
143
|
+
post_with_views(@repo, %w[blog1 blog3])
|
144
|
+
post_with_views(@repo, %w[blog1 blog2 blog3])
|
145
|
+
post_with_views(@repo, "blog1")
|
146
|
+
post_with_views(@repo, "blog1")
|
147
|
+
post_with_views(@repo, "blog1")
|
148
|
+
post_with_views(@repo, "blog2")
|
149
|
+
post_with_views(@repo, "blog2")
|
150
|
+
post_with_views(@repo, "blog3")
|
151
|
+
end
|
152
|
+
|
153
|
+
def create_13_posts # For test_posts_generated_and_indexed_across_multiple_views
|
154
|
+
try_post_with_views(@repo, "blog1")
|
155
|
+
try_post_with_views(@repo, "blog2")
|
156
|
+
try_post_with_views(@repo, "blog3")
|
157
|
+
try_post_with_views(@repo, %w[blog1 blog2])
|
158
|
+
try_post_with_views(@repo, %w[blog2 blog3])
|
159
|
+
try_post_with_views(@repo, %w[blog1 blog3])
|
160
|
+
try_post_with_views(@repo, %w[blog1 blog2 blog3])
|
161
|
+
try_post_with_views(@repo, "blog1")
|
162
|
+
try_post_with_views(@repo, "blog1")
|
163
|
+
try_post_with_views(@repo, "blog1")
|
164
|
+
try_post_with_views(@repo, "blog2")
|
165
|
+
try_post_with_views(@repo, "blog2")
|
166
|
+
try_post_with_views(@repo, "blog3")
|
167
|
+
# blog1 1 4 6 7 8 9 10
|
168
|
+
# blog2 2 4 5 11 12
|
169
|
+
# blog3 3 5 6 7 13
|
170
|
+
end
|
171
|
+
|
172
|
+
def alter_pubdates # For test_posts_generated_and_indexed_across_multiple_views
|
173
|
+
@repo.post(1).set_pubdate("2025-07-01")
|
174
|
+
@repo.post(2).set_pubdate("2025-07-02")
|
175
|
+
@repo.post(3).set_pubdate("2025-07-03")
|
176
|
+
@repo.post(4).set_pubdate("2025-07-04")
|
177
|
+
@repo.post(5).set_pubdate("2025-07-05")
|
178
|
+
@repo.post(6).set_pubdate("2025-07-06")
|
179
|
+
@repo.post(7).set_pubdate("2025-07-07")
|
180
|
+
@repo.post(8).set_pubdate("2025-07-08")
|
181
|
+
@repo.post(9).set_pubdate("2025-07-09")
|
182
|
+
@repo.post(10).set_pubdate("2025-07-10")
|
183
|
+
@repo.post(11).set_pubdate("2025-07-11")
|
184
|
+
@repo.post(12).set_pubdate("2025-07-12")
|
185
|
+
@repo.post(13).set_pubdate("2025-07-13")
|
186
|
+
end
|
187
|
+
|
188
|
+
def try_blog1_index # For test_posts_generated_and_indexed_across_multiple_views
|
189
|
+
@repo.generate_post_index("blog1")
|
190
|
+
%w[header main right footer].each do |section|
|
191
|
+
file = @repo.root/:views/"blog1"/:output/:panes/"#{section}.html"
|
192
|
+
assert File.exist?(file), "Expected section file #{file} to exist"
|
193
|
+
end
|
194
|
+
@repo.tree("/tmp/blog1.txt")
|
195
|
+
post_index = @repo.root/:views/"blog1"/:output/"post_index.html"
|
196
|
+
assert File.exist?(post_index), "Expected blog1 post_index.html to be generated"
|
197
|
+
content = File.read(post_index)
|
198
|
+
|
199
|
+
assert content.include?("July 1</div>"), "Expected July 1 in post_index"
|
200
|
+
assert content.include?("July 4</div>"), "Expected July 4 in post_index"
|
201
|
+
assert content.include?("July 6</div>"), "Expected July 6 in post_index"
|
202
|
+
assert content.include?("July 7</div>"), "Expected July 7 in post_index"
|
203
|
+
assert content.include?("July 8</div>"), "Expected July 8 in post_index"
|
204
|
+
assert content.include?("July 9</div>"), "Expected July 9 in post_index"
|
205
|
+
assert content.include?("July 10</div>"), "Expected July 10 in post_index"
|
206
|
+
refute content.include?("July 2</div>"), "Expected July 2 not in post_index"
|
207
|
+
refute content.include?("July 3</div>"), "Expected July 3 not in post_index"
|
208
|
+
refute content.include?("July 5"), "Expected July 5 not in post_index"
|
209
|
+
refute content.include?("July 11"), "Expected July 11 not in post_index"
|
210
|
+
refute content.include?("July 12"), "Expected July 12 not in post_index"
|
211
|
+
refute content.include?("July 13"), "Expected July 13 not in post_index"
|
212
|
+
end
|
213
|
+
|
214
|
+
def pseudoword
|
215
|
+
syllables = %w[tel mas re ko tem sil cro nim tes ran vel san tos le tor
|
216
|
+
de del mac dor mor ma ril odo tre kon lan sa te ti do mu]
|
217
|
+
n = syllables.size
|
218
|
+
num = rand(1..3)
|
219
|
+
str = ""
|
220
|
+
num.times { str << syllables[rand(n)] }
|
221
|
+
str
|
222
|
+
end
|
223
|
+
|
224
|
+
def pseudowords(n, prefix = "")
|
225
|
+
arr = [prefix]
|
226
|
+
n.times { arr << pseudoword }
|
227
|
+
arr.join(" ")
|
228
|
+
end
|
229
|
+
|
230
|
+
def pseudoline
|
231
|
+
pseudowords(10) + "\n"
|
232
|
+
end
|
233
|
+
|
234
|
+
def pseudolines(n)
|
235
|
+
str = ""
|
236
|
+
n.times { str << pseudoline }
|
237
|
+
str
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
@@ -0,0 +1,296 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pty'
|
4
|
+
require 'expect'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require_relative '../lib/scriptorium'
|
8
|
+
|
9
|
+
class TUIEditorIntegrationTest < Minitest::Test
|
10
|
+
# Test repository path
|
11
|
+
TEST_REPO_PATH = "scriptorium-TEST"
|
12
|
+
|
13
|
+
def setup
|
14
|
+
cleanup_test_repo
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
cleanup_test_repo
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_001_links_widget_editing_workflow
|
22
|
+
# Test the complete links widget editing workflow using PTY
|
23
|
+
# Start with no repo, let TUI create it, trigger wizard, configure links widget, edit content
|
24
|
+
|
25
|
+
# Ensure clean start
|
26
|
+
cleanup_test_repo
|
27
|
+
|
28
|
+
ENV['NOREADLINE'] = '1'
|
29
|
+
|
30
|
+
PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
|
31
|
+
begin
|
32
|
+
run_links_widget_workflow(read, write)
|
33
|
+
ensure
|
34
|
+
# Clean up the process
|
35
|
+
Process.kill('TERM', pid) rescue nil
|
36
|
+
Process.wait(pid) rescue nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
ensure
|
40
|
+
ENV.delete('NOREADLINE')
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_002_basic_tui_flow
|
44
|
+
# Test basic TUI flow without complex wizard
|
45
|
+
ENV['NOREADLINE'] = '1'
|
46
|
+
|
47
|
+
PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
|
48
|
+
begin
|
49
|
+
run_basic_tui_workflow(read, write)
|
50
|
+
|
51
|
+
ensure
|
52
|
+
# Clean up the process
|
53
|
+
Process.kill('TERM', pid) rescue nil
|
54
|
+
Process.wait(pid) rescue nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
ENV.delete('NOREADLINE')
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_003_create_post_workflow
|
62
|
+
# Test creating a post through the TUI
|
63
|
+
ENV['NOREADLINE'] = '1'
|
64
|
+
|
65
|
+
PTY.spawn({'NOREADLINE' => '1'}, 'ruby bin/scriptorium --test') do |read, write, pid|
|
66
|
+
begin
|
67
|
+
run_create_post_workflow(read, write)
|
68
|
+
ensure
|
69
|
+
# Clean up the process
|
70
|
+
Process.kill('TERM', pid) rescue nil
|
71
|
+
Process.wait(pid) rescue nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
ENV.delete('NOREADLINE')
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def get_string(read, pattern, message, timeout = 5)
|
81
|
+
# Convenience method to get a string matching a pattern with timeout
|
82
|
+
# Set VERBOSE=1 to see detailed output, defaults to silent
|
83
|
+
output = read.expect(pattern, timeout)
|
84
|
+
if output
|
85
|
+
puts "Found: #{output[0].strip}" if ENV['VERBOSE']
|
86
|
+
else
|
87
|
+
# Pattern not found
|
88
|
+
# Read what we actually got
|
89
|
+
available = read.read_nonblock(1000) rescue ""
|
90
|
+
# Available output logged above
|
91
|
+
end
|
92
|
+
assert output, message
|
93
|
+
output[0] # Return the matched string
|
94
|
+
end
|
95
|
+
|
96
|
+
def cleanup_test_repo
|
97
|
+
# More aggressive cleanup - remove any test repositories
|
98
|
+
FileUtils.rm_rf(TEST_REPO_PATH) if Dir.exist?(TEST_REPO_PATH)
|
99
|
+
FileUtils.rm_rf("scriptorium-TEST") if Dir.exist?("scriptorium-TEST")
|
100
|
+
# Also clean up any other potential test repos
|
101
|
+
Dir.glob("scriptorium-*TEST*").each do |dir|
|
102
|
+
FileUtils.rm_rf(dir) if Dir.exist?(dir)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def send_and_expect(read, write, input, expected_pattern, description)
|
107
|
+
write.puts input
|
108
|
+
sleep 0.1 # Small delay to ensure input is processed
|
109
|
+
result = get_string(read, expected_pattern, description)
|
110
|
+
# Add explicit assertion for the expected pattern
|
111
|
+
assert result.match?(expected_pattern), "#{description}: Expected pattern '#{expected_pattern}' not found in output"
|
112
|
+
result
|
113
|
+
rescue Errno::EIO => e
|
114
|
+
# Handle case where TUI terminates immediately after output
|
115
|
+
if expected_pattern.to_s.include?("Goodbye!")
|
116
|
+
# If we're expecting Goodbye! and get an I/O error, that's probably OK
|
117
|
+
# The TUI terminated after outputting Goodbye!
|
118
|
+
return
|
119
|
+
else
|
120
|
+
raise e
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def run_links_widget_workflow(read, write)
|
125
|
+
# Wait for initial output
|
126
|
+
get_string(read, /No repository found\./, "Should show 'No repository found'")
|
127
|
+
|
128
|
+
# Send 'y' to create new repository
|
129
|
+
send_and_expect(read, write, "y", "Created test repository successfully.",
|
130
|
+
"Should show repository created")
|
131
|
+
|
132
|
+
# Wait for editor setup
|
133
|
+
get_string(read, "No editor configured", "Should show editor setup")
|
134
|
+
|
135
|
+
# Wait for editor list
|
136
|
+
get_string(read, "Available editors", "Should show available editors")
|
137
|
+
|
138
|
+
# Wait for editor choice prompt
|
139
|
+
get_string(read, "Choose editor", "Should prompt for editor selection")
|
140
|
+
send_and_expect(read, write, "4", "Selected editor: ed",
|
141
|
+
"Should show editor selection")
|
142
|
+
|
143
|
+
# Wait for setup completion
|
144
|
+
get_string(read, "Setup complete", "Should show setup completion")
|
145
|
+
|
146
|
+
# Wait for assistance question
|
147
|
+
get_string(read, /Do you want assistance/, "Should ask about assistance")
|
148
|
+
|
149
|
+
# Send 'y' for assistance
|
150
|
+
send_and_expect(read, write, "y", /Enter view name/,
|
151
|
+
"Should prompt for view name")
|
152
|
+
|
153
|
+
# Send view name
|
154
|
+
send_and_expect(read, write, "testview", /Enter view title/,
|
155
|
+
"Should prompt for view title")
|
156
|
+
|
157
|
+
# Send view title
|
158
|
+
send_and_expect(read, write, "Test View", /Enter subtitle/,
|
159
|
+
"Should prompt for subtitle")
|
160
|
+
|
161
|
+
# Send subtitle
|
162
|
+
send_and_expect(read, write, "Test Subtitle", "Would you like to edit the layout",
|
163
|
+
"Should ask about editing layout")
|
164
|
+
|
165
|
+
# Send 'n' to skip layout editing (avoid ed interaction issues)
|
166
|
+
send_and_expect(read, write, "n", "Would you like to configure header",
|
167
|
+
"Should ask about header configuration")
|
168
|
+
|
169
|
+
# Wait for container configuration questions (in wizard order: header, main, left, right, footer)
|
170
|
+
send_and_expect(read, write, "n", "Would you like to configure main",
|
171
|
+
"Should ask about main configuration")
|
172
|
+
send_and_expect(read, write, "n", "Would you like to configure left",
|
173
|
+
"Should ask about left configuration")
|
174
|
+
|
175
|
+
# Say yes to configure left sidebar
|
176
|
+
send_and_expect(read, write, "y", "Add widgets to left",
|
177
|
+
"Should ask about adding widgets to left")
|
178
|
+
|
179
|
+
# Say yes to add widgets
|
180
|
+
send_and_expect(read, write, "y", "Available widgets: links, pages, featuredposts",
|
181
|
+
"Should show available widgets")
|
182
|
+
|
183
|
+
send_and_expect(read, write, "y", /Add links widget\?/, "Should ask about adding links widget")
|
184
|
+
|
185
|
+
send_and_expect(read, write, "n", /Add pages widget\?/, "Should ask about adding pages widget")
|
186
|
+
|
187
|
+
send_and_expect(read, write, "n", /Add featuredposts widget\?/, "Should ask about adding featuredposts widget")
|
188
|
+
|
189
|
+
send_and_expect(read, write, "n", /Configure links widget\?/, "Should ask about configuring links widget")
|
190
|
+
|
191
|
+
# Say no to configure links widget - now should proceed to next container
|
192
|
+
send_and_expect(read, write, "n", "Would you like to configure right",
|
193
|
+
"Should ask about right configuration")
|
194
|
+
|
195
|
+
|
196
|
+
send_and_expect(read, write, "n", "Would you like to configure footer",
|
197
|
+
"Should ask about footer configuration")
|
198
|
+
send_and_expect(read, write, "n", "View setup complete",
|
199
|
+
"Should show setup completion")
|
200
|
+
|
201
|
+
# Wait for main prompt
|
202
|
+
get_string(read, "[testview]", "Should show main prompt")
|
203
|
+
|
204
|
+
# Send 'quit' to exit
|
205
|
+
send_and_expect(read, write, "quit", "Goodbye!",
|
206
|
+
"Should show goodbye message")
|
207
|
+
end
|
208
|
+
|
209
|
+
def run_basic_tui_workflow(read, write)
|
210
|
+
# Wait for initial output
|
211
|
+
get_string(read, "No repository found.", "Should show 'No repository found'")
|
212
|
+
|
213
|
+
# Send 'y' to create new repository
|
214
|
+
send_and_expect(read, write, "y", "Created test repository successfully.",
|
215
|
+
"Should show repository created")
|
216
|
+
|
217
|
+
# Wait for editor setup
|
218
|
+
get_string(read, "No editor configured", "Should show editor setup")
|
219
|
+
|
220
|
+
# Wait for editor list
|
221
|
+
get_string(read, "Available editors", "Should show available editors")
|
222
|
+
|
223
|
+
# Wait for editor choice prompt
|
224
|
+
get_string(read, "Choose editor", "Should prompt for editor selection")
|
225
|
+
send_and_expect(read, write, "4", "Selected editor: ed",
|
226
|
+
"Should show editor selection")
|
227
|
+
|
228
|
+
# Wait for setup completion
|
229
|
+
get_string(read, "Setup complete", "Should show setup completion")
|
230
|
+
|
231
|
+
# Wait for assistance question
|
232
|
+
get_string(read, /Do you want assistance/, "Should ask about assistance")
|
233
|
+
|
234
|
+
# Send 'n' to skip assistance
|
235
|
+
send_and_expect(read, write, "n", "[sample]", "Should show main prompt")
|
236
|
+
|
237
|
+
# Send 'quit' to exit
|
238
|
+
send_and_expect(read, write, "quit", "Goodbye!",
|
239
|
+
"Should show goodbye message")
|
240
|
+
end
|
241
|
+
|
242
|
+
def run_create_post_workflow(read, write)
|
243
|
+
# Wait for initial output
|
244
|
+
get_string(read, "No repository found.", "Should show 'No repository found'")
|
245
|
+
|
246
|
+
# Send 'y' to create new repository
|
247
|
+
send_and_expect(read, write, "y", "Created test repository successfully.",
|
248
|
+
"Should show repository created")
|
249
|
+
|
250
|
+
# Wait for editor setup
|
251
|
+
get_string(read, "No editor configured", "Should show editor setup")
|
252
|
+
|
253
|
+
# Wait for editor list
|
254
|
+
get_string(read, "Available editors", "Should show available editors")
|
255
|
+
|
256
|
+
# Wait for editor choice prompt
|
257
|
+
get_string(read, "Choose editor", "Should prompt for editor selection")
|
258
|
+
send_and_expect(read, write, "4", "Selected editor: ed",
|
259
|
+
"Should show editor selection")
|
260
|
+
|
261
|
+
# Wait for setup completion
|
262
|
+
get_string(read, "Setup complete", "Should show setup completion")
|
263
|
+
|
264
|
+
# Wait for assistance question
|
265
|
+
get_string(read, /Do you want assistance/, "Should ask about assistance")
|
266
|
+
|
267
|
+
# Send 'n' to skip assistance
|
268
|
+
send_and_expect(read, write, "n", "[sample]", "Should show main prompt")
|
269
|
+
|
270
|
+
# Create a post
|
271
|
+
send_and_expect(read, write, "new post Test Post", /Created draft:/,
|
272
|
+
"Should show draft created")
|
273
|
+
|
274
|
+
# Wait for editor opening
|
275
|
+
get_string(read, "Opening in ed", "Should show editor opening")
|
276
|
+
|
277
|
+
# Simulate ed interaction
|
278
|
+
sleep 1
|
279
|
+
write.puts "a"
|
280
|
+
write.puts "Test content"
|
281
|
+
write.puts "."
|
282
|
+
write.puts "w"
|
283
|
+
write.puts "q"
|
284
|
+
sleep 1
|
285
|
+
|
286
|
+
# Wait for post creation
|
287
|
+
get_string(read, "Post created", "Should show post created")
|
288
|
+
|
289
|
+
# Wait for main prompt
|
290
|
+
get_string(read, "[sample]", "Should show main prompt")
|
291
|
+
|
292
|
+
# Send 'quit' to exit
|
293
|
+
send_and_expect(read, write, "quit", "Goodbye!",
|
294
|
+
"Should show goodbye message")
|
295
|
+
end
|
296
|
+
end
|