|
19 | 19 | Jekyll::PostcssTrigger.css_touched = false |
20 | 20 | end |
21 | 21 |
|
22 | | - describe "module initialization" do |
23 | | - it "has last_check_time accessor" do |
24 | | - _(Jekyll::PostcssTrigger).must_respond_to :last_check_time |
25 | | - _(Jekyll::PostcssTrigger).must_respond_to :last_check_time= |
26 | | - end |
27 | | - |
28 | | - it "has css_touched accessor" do |
29 | | - _(Jekyll::PostcssTrigger).must_respond_to :css_touched |
30 | | - _(Jekyll::PostcssTrigger).must_respond_to :css_touched= |
31 | | - end |
32 | | - |
33 | | - it "initializes with nil last_check_time" do |
| 22 | + describe "state management" do |
| 23 | + it "initializes with nil last_check_time and false css_touched" do |
34 | 24 | _(Jekyll::PostcssTrigger.last_check_time).must_be_nil |
35 | | - end |
36 | | - |
37 | | - it "initializes with false css_touched" do |
38 | 25 | _(Jekyll::PostcssTrigger.css_touched).must_equal false |
39 | 26 | end |
40 | | - end |
41 | 27 |
|
42 | | - describe "state management" do |
43 | 28 | it "can set and get last_check_time" do |
44 | | - time = Time.now |
| 29 | + time = Time. now |
45 | 30 | Jekyll::PostcssTrigger.last_check_time = time |
46 | 31 | _(Jekyll::PostcssTrigger.last_check_time).must_equal time |
47 | 32 | end |
|
50 | 35 | Jekyll::PostcssTrigger.css_touched = true |
51 | 36 | _(Jekyll::PostcssTrigger.css_touched).must_equal true |
52 | 37 | end |
53 | | - |
54 | | - it "can reset state" do |
55 | | - Jekyll::PostcssTrigger.last_check_time = Time.now |
56 | | - Jekyll::PostcssTrigger.css_touched = true |
57 | | - |
58 | | - Jekyll::PostcssTrigger.last_check_time = nil |
59 | | - Jekyll::PostcssTrigger.css_touched = false |
60 | | - |
61 | | - _(Jekyll::PostcssTrigger.last_check_time).must_be_nil |
62 | | - _(Jekyll::PostcssTrigger.css_touched).must_equal false |
63 | | - end |
64 | 38 | end |
65 | 39 |
|
66 | | - describe "file modification detection logic" do |
| 40 | + describe "integration: HTML change triggers CSS rebuild" do |
67 | 41 | before do |
68 | 42 | chdir_tempdir |
| 43 | + create_file("stylesheets/main.css", "/* css */") |
| 44 | + |
| 45 | + # Create a minimal Jekyll site |
| 46 | + @site = Jekyll::Site.new( |
| 47 | + Jekyll.configuration( |
| 48 | + source: ".", |
| 49 | + incremental: true, |
| 50 | + quiet: true |
| 51 | + ) |
| 52 | + ) |
69 | 53 | end |
70 | 54 |
|
71 | 55 | after do |
72 | 56 | teardown_tempdir |
73 | 57 | end |
74 | 58 |
|
75 | | - it "detects files modified after a timestamp" do |
76 | | - # Create a file |
77 | | - create_file("test.html", "<html>content</html>") |
| 59 | + it "records initial check time on first post_read" do |
| 60 | + _(Jekyll::PostcssTrigger.last_check_time).must_be_nil |
| 61 | + |
| 62 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 63 | + |
| 64 | + _(Jekyll::PostcssTrigger. last_check_time).wont_be_nil |
| 65 | + _(Jekyll::PostcssTrigger.css_touched).must_equal false |
| 66 | + end |
| 67 | + |
| 68 | + it "touches CSS when HTML file changes after first build" do |
| 69 | + # Create HTML file BEFORE first build |
| 70 | + create_file("index.html", "<html>original</html>") |
| 71 | + |
| 72 | + # First build - establish baseline |
| 73 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 74 | + first_check_time = Jekyll::PostcssTrigger. last_check_time |
78 | 75 |
|
79 | | - # Record current time |
80 | | - check_time = Time.now |
| 76 | + sleep 0.2 |
| 77 | + |
| 78 | + # NOW modify HTML file (after first build) |
| 79 | + create_file("index.html", "<html>modified</html>") |
| 80 | + css_original_mtime = File. mtime("stylesheets/main.css") |
81 | 81 |
|
82 | | - # Wait to ensure time difference |
83 | 82 | sleep 0.1 |
84 | 83 |
|
85 | | - # Modify the file |
86 | | - create_file("test.html", "<html>modified</html>") |
| 84 | + # Second build - should detect change |
| 85 | + Jekyll::Hooks.trigger :site, :post_read, @site |
87 | 86 |
|
88 | | - # Check mtime |
89 | | - _(File.mtime("test.html") > check_time).must_equal true |
| 87 | + _(Jekyll::PostcssTrigger.css_touched).must_equal true |
| 88 | + _(File.mtime("stylesheets/main.css") > css_original_mtime).must_equal true |
90 | 89 | end |
91 | 90 |
|
92 | | - it "does not detect unmodified files" do |
93 | | - # Create a file |
94 | | - create_file("test.html", "<html>content</html>") |
| 91 | + it "touches CSS when markdown file changes" do |
| 92 | + # Create markdown file first |
| 93 | + create_file("about. md", "# About Page") |
95 | 94 |
|
96 | | - # Record time after creation |
97 | | - sleep 0.1 |
98 | | - check_time = Time.now |
| 95 | + # First build |
| 96 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 97 | + |
| 98 | + sleep 0.2 |
| 99 | + |
| 100 | + # Modify markdown file |
| 101 | + create_file("about.md", "# About Page Modified") |
| 102 | + css_original_mtime = File.mtime("stylesheets/main.css") |
99 | 103 |
|
100 | | - # Wait |
101 | 104 | sleep 0.1 |
102 | 105 |
|
103 | | - # Don't modify the file |
| 106 | + # Second build |
| 107 | + Jekyll::Hooks.trigger :site, :post_read, @site |
104 | 108 |
|
105 | | - # Check mtime |
106 | | - _(File.mtime("test.html") > check_time).must_equal false |
| 109 | + _(Jekyll::PostcssTrigger.css_touched).must_equal true |
| 110 | + _(File.mtime("stylesheets/main.css") > css_original_mtime).must_equal true |
107 | 111 | end |
108 | 112 |
|
109 | | - it "can touch a file to update mtime" do |
110 | | - create_file("test.css", "/* css */") |
111 | | - original_mtime = File.mtime("test.css") |
| 113 | + it "touches CSS when layout file changes" do |
| 114 | + # Create layout file first |
| 115 | + create_file("_layouts/default.html", "<html>{{ content }}</html>") |
| 116 | + |
| 117 | + # First build |
| 118 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 119 | + |
| 120 | + sleep 0.2 |
| 121 | + |
| 122 | + # Modify layout file |
| 123 | + create_file("_layouts/default.html", "<html><body>{{ content }}</body></html>") |
| 124 | + css_original_mtime = File.mtime("stylesheets/main.css") |
112 | 125 |
|
113 | 126 | sleep 0.1 |
114 | 127 |
|
115 | | - FileUtils.touch("test.css") |
116 | | - new_mtime = File.mtime("test.css") |
| 128 | + # Second build |
| 129 | + Jekyll::Hooks.trigger :site, :post_read, @site |
117 | 130 |
|
118 | | - _(new_mtime > original_mtime).must_equal true |
| 131 | + _(Jekyll::PostcssTrigger. css_touched).must_equal true |
| 132 | + _(File.mtime("stylesheets/main.css") > css_original_mtime).must_equal true |
119 | 133 | end |
120 | 134 |
|
121 | | - it "matches HTML files with glob pattern" do |
122 | | - create_file("index.html", "<html></html>") |
123 | | - create_file("about.html", "<html></html>") |
124 | | - create_file("style.css", "/* css */") |
| 135 | + it "touches CSS when include file changes" do |
| 136 | + # Create include file first |
| 137 | + create_file("_includes/header.html", "<header>Header</header>") |
125 | 138 |
|
126 | | - html_files = Dir.glob("*.html") |
| 139 | + # First build |
| 140 | + Jekyll::Hooks.trigger :site, :post_read, @site |
127 | 141 |
|
128 | | - _(html_files.length).must_equal 2 |
129 | | - _(html_files).must_include "index.html" |
130 | | - _(html_files).must_include "about.html" |
131 | | - _(html_files).wont_include "style.css" |
132 | | - end |
| 142 | + sleep 0.2 |
133 | 143 |
|
134 | | - it "matches nested HTML files with glob pattern" do |
135 | | - create_file("_includes/header.html", "<header></header>") |
136 | | - create_file("_layouts/default.html", "<html></html>") |
| 144 | + # Modify include file |
| 145 | + create_file("_includes/header.html", "<header>New Header</header>") |
| 146 | + css_original_mtime = File.mtime("stylesheets/main.css") |
137 | 147 |
|
138 | | - includes_files = Dir.glob("_includes/**/*.html") |
139 | | - layouts_files = Dir.glob("_layouts/**/*.html") |
| 148 | + sleep 0.1 |
| 149 | + |
| 150 | + # Second build |
| 151 | + Jekyll::Hooks.trigger :site, :post_read, @site |
140 | 152 |
|
141 | | - _(includes_files.length).must_equal 1 |
142 | | - _(layouts_files.length).must_equal 1 |
| 153 | + _(Jekyll::PostcssTrigger.css_touched).must_equal true |
| 154 | + _(File.mtime("stylesheets/main.css") > css_original_mtime).must_equal true |
143 | 155 | end |
144 | 156 |
|
145 | | - it "matches markdown files with glob pattern" do |
146 | | - create_file("about.md", "# About") |
147 | | - create_file("contact.md", "# Contact") |
| 157 | + it "does not touch CSS when no HTML/MD files changed" do |
| 158 | + # First build |
| 159 | + Jekyll::Hooks.trigger :site, :post_read, @site |
148 | 160 |
|
149 | | - md_files = Dir.glob("*.md") |
| 161 | + sleep 0.2 |
150 | 162 |
|
151 | | - _(md_files.length).must_equal 2 |
152 | | - end |
153 | | - end |
| 163 | + # Don't modify any files |
| 164 | + css_original_mtime = File.mtime("stylesheets/main.css") |
154 | 165 |
|
155 | | - describe "integration with incremental config" do |
156 | | - before do |
157 | | - chdir_tempdir |
158 | | - end |
| 166 | + sleep 0.1 |
159 | 167 |
|
160 | | - after do |
161 | | - teardown_tempdir |
| 168 | + # Second build |
| 169 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 170 | + |
| 171 | + _(Jekyll::PostcssTrigger.css_touched).must_equal false |
| 172 | + _(File.mtime("stylesheets/main.css")).must_equal css_original_mtime |
162 | 173 | end |
163 | 174 |
|
164 | | - it "recognizes incremental mode in config" do |
165 | | - config = Jekyll.configuration( |
166 | | - source: ".", |
167 | | - incremental: true, |
168 | | - quiet: true |
169 | | - ) |
| 175 | + it "does not touch CSS multiple times in same build" do |
| 176 | + # First build |
| 177 | + Jekyll::Hooks.trigger :site, :post_read, @site |
170 | 178 |
|
171 | | - _(config['incremental']).must_equal true |
172 | | - end |
| 179 | + sleep 0.2 |
173 | 180 |
|
174 | | - it "recognizes non-incremental mode in config" do |
175 | | - config = Jekyll.configuration( |
176 | | - source: ".", |
177 | | - incremental: false, |
178 | | - quiet: true |
179 | | - ) |
| 181 | + # Modify multiple HTML files |
| 182 | + create_file("index.html", "<html>modified</html>") |
| 183 | + create_file("about.html", "<html>also modified</html>") |
| 184 | + css_original_mtime = File.mtime("stylesheets/main.css") |
180 | 185 |
|
181 | | - _(config['incremental']).must_equal false |
182 | | - end |
183 | | - end |
| 186 | + sleep 0.1 |
184 | 187 |
|
185 | | - describe "CSS file operations" do |
186 | | - before do |
187 | | - chdir_tempdir |
| 188 | + # Second build |
| 189 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 190 | + first_touch_mtime = File.mtime("stylesheets/main.css") |
| 191 | + |
| 192 | + # Try to trigger again in same "build" |
| 193 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 194 | + second_touch_mtime = File.mtime("stylesheets/main.css") |
| 195 | + |
| 196 | + _(first_touch_mtime).must_equal second_touch_mtime |
188 | 197 | end |
189 | 198 |
|
190 | | - after do |
191 | | - teardown_tempdir |
| 199 | + it "resets css_touched flag after post_write" do |
| 200 | + # First build |
| 201 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 202 | + |
| 203 | + sleep 0.2 |
| 204 | + create_file("index.html", "<html>modified</html>") |
| 205 | + sleep 0.1 |
| 206 | + |
| 207 | + # Second build - CSS should be touched |
| 208 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 209 | + _(Jekyll::PostcssTrigger.css_touched).must_equal true |
| 210 | + |
| 211 | + # Trigger post_write |
| 212 | + Jekyll::Hooks.trigger :site, :post_write, @site |
| 213 | + |
| 214 | + # Flag should be reset |
| 215 | + _(Jekyll::PostcssTrigger.css_touched).must_equal false |
192 | 216 | end |
193 | 217 |
|
194 | | - it "can check if CSS file exists" do |
195 | | - create_file("stylesheets/main.css", "/* css */") |
| 218 | + it "does nothing when not in incremental mode" do |
| 219 | + # Create non-incremental site |
| 220 | + non_incremental_site = Jekyll::Site.new( |
| 221 | + Jekyll.configuration( |
| 222 | + source: ".", |
| 223 | + incremental: false, |
| 224 | + quiet: true |
| 225 | + ) |
| 226 | + ) |
| 227 | + |
| 228 | + Jekyll::PostcssTrigger.last_check_time = nil |
196 | 229 |
|
197 | | - _(File.exist?("stylesheets/main.css")).must_equal true |
| 230 | + # Trigger hook |
| 231 | + Jekyll::Hooks.trigger :site, :post_read, non_incremental_site |
| 232 | + |
| 233 | + # Should not set check time |
| 234 | + _(Jekyll::PostcssTrigger.last_check_time).must_be_nil |
198 | 235 | end |
199 | 236 |
|
200 | | - it "can touch CSS file" do |
201 | | - create_file("stylesheets/main.css", "/* css */") |
202 | | - original_mtime = File.mtime("stylesheets/main.css") |
| 237 | + it "handles missing CSS file gracefully" do |
| 238 | + # Remove CSS file |
| 239 | + FileUtils.rm_f("stylesheets/main.css") |
203 | 240 |
|
204 | | - sleep 0.1 |
| 241 | + # First build |
| 242 | + Jekyll::Hooks.trigger :site, :post_read, @site |
205 | 243 |
|
206 | | - FileUtils.touch("stylesheets/main.css") |
207 | | - new_mtime = File.mtime("stylesheets/main.css") |
| 244 | + sleep 0.2 |
| 245 | + create_file("index.html", "<html>modified</html>") |
| 246 | + sleep 0.1 |
208 | 247 |
|
209 | | - _(new_mtime > original_mtime).must_equal true |
| 248 | + # Should not crash when CSS file doesn't exist |
| 249 | + _{ Jekyll::Hooks.trigger :site, :post_read, @site }.must_be_silent |
210 | 250 | end |
211 | 251 |
|
212 | | - it "preserves CSS file content when touched" do |
213 | | - content = "/* original css */" |
214 | | - create_file("stylesheets/main.css", content) |
| 252 | + it "excludes _site directory from change detection" do |
| 253 | + # First build |
| 254 | + Jekyll::Hooks.trigger :site, :post_read, @site |
215 | 255 |
|
216 | | - FileUtils.touch("stylesheets/main.css") |
| 256 | + sleep 0.2 |
217 | 257 |
|
218 | | - _(File.read("stylesheets/main.css")).must_equal content |
| 258 | + # Modify file in _site (generated output) |
| 259 | + create_file("_site/index.html", "<html>generated</html>") |
| 260 | + css_original_mtime = File.mtime("stylesheets/main.css") |
| 261 | + |
| 262 | + sleep 0.1 |
| 263 | + |
| 264 | + # Second build |
| 265 | + Jekyll::Hooks.trigger :site, :post_read, @site |
| 266 | + |
| 267 | + # CSS should NOT be touched (changes in _site are ignored) |
| 268 | + _(Jekyll::PostcssTrigger.css_touched).must_equal false |
| 269 | + _(File.mtime("stylesheets/main.css")).must_equal css_original_mtime |
219 | 270 | end |
220 | 271 | end |
221 | 272 | end |
0 commit comments