-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRakefile
More file actions
191 lines (170 loc) · 7.5 KB
/
Copy pathRakefile
File metadata and controls
191 lines (170 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# frozen_string_literal: true
require "rake/testtask"
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/**/*_test.rb"
end
namespace :test do
Rake::TestTask.new(:all) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/**/*_test.rb"
end
Rake::TestTask.new(:unit) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/unit/**/*_test.rb"
end
# Highest-risk pages only (~2 min): selection grounded in git churn
# (2026-07-19 analysis: blog + homepage + course + site-wide dominate
# 6-month history) + the lead-gen funnel (services, contact,
# free-consultation). Full system suite = test:system; everything = test:all.
# NextPilotContrastTest rides along (~1.3s, no baselines): it is the only
# thing in this suite that measures contrast as a NUMBER rather than as a
# pixel delta, and the only thing that sees the 71.7% of a register pilot
# that sits below the 1080px capture (20.11 §"What nothing guards").
CRITICAL_TESTS =
"/homepage|blog_index|blog_post$|visit_blog_post|course_|old_blog_url|" \
"test_services($|_menu)|contact_us|free_consultation|not_found|" \
"hamburger|color_system|mermaid|codeblock_language|friday_report|" \
"NextPilotContrastTest/"
Rake::TestTask.new(:critical) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/system/**/*_test.rb"
t.options = "--name='#{CRITICAL_TESTS}'"
end
# Smoke tier (~60s serial, less on Docker): the leanest gate that still
# catches a broken build. Basics (homepage/blog-post/404/course render) +
# bummers (the funnel forms, nav hover + mobile hamburger, and the one
# mermaid render that historically breaks). Deliberately EXCLUDES the
# per-section `_sections` sweeps and `test_codeblock_language_styles` - that
# single test is ~196s (44% of the suite) and trips a snap_diff reporter bug
# on any diff. Smoke is NOT a milestone gate: test:critical stays the pre-PR
# bar. Mermaid is desktop-only here (one render proves the surface).
SMOKE_TESTS =
"/test_homepage$|test_blog_post$|test_not_found$|test_course_landing|" \
"test_contact_us$|test_free_consultation$|test_services_menu$|" \
"test_top_bar_hamburger_menu$|test_vibe_code_rescue$|" \
"BlogSpecialContentDesktopTest#test_mermaid_post/"
Rake::TestTask.new(:smoke) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/system/**/*_test.rb"
t.options = "--name='#{SMOKE_TESTS}'"
end
Rake::TestTask.new(:system) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/system/**/*_test.rb"
end
Rake::TestTask.new(:integration) do |t|
t.libs << "test"
t.libs << "lib"
t.pattern = "test/integration/**/*_test.rb"
end
# Fast repo-shape guards (~2s): bin-script portability + hook wiring.
# The pre-push hook's test entrypoint - one task, so the hook never falls
# into the `ruby file1.rb file2.rb` trap (only file1 executes).
Rake::TestTask.new(:guards) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList[
"test/unit/bin_scripts_test.rb"
]
end
namespace :screenshots do
desc "Restore baseline PNGs rewritten by a test run (candidates live in the working tree; git HEAD is the baseline)"
task :reset do
sh "git checkout -- test/fixtures/screenshots"
end
end
# Broken-link checks (2026-07-21: GA 404 spike audit). Every *.html the build
# emits is globbed from disk and passed as an explicit input, so no PAGE is
# skipped.
#
# That is not the same as no LINK being skipped, and from the day the gate shipped (2026-07-21) it wasn't:
# the production build renders internal links absolute
# (https://jetthoughts.com/...) and `--offline` excludes every http(s) URI by
# design, so 133,874 of 149,516 links were excluded and the job was green
# because it inspected almost nothing (measured 2026-08-22 by planting a
# broken link and watching it pass - docs/20-29-testing-qa/20.11). The
# --remap below rewrites those absolute URLs back onto the built tree so
# they are actually resolved; without it this task checks little more than
# each page's own #main-content skip-link anchor.
#
# These build with ENVIRONMENT=production (not the top-level :build task's
# dev default) rather than depending on :build - the dev config mounts
# linkedin-posts/ (drafts that must not be link-checked) and uses
# relativeURLs, either of which would skew the scan. (Historical: dev also
# used to disable taxonomy/term kinds; re-enabled 2026-08-20 for the blog
# filter pills, but the production build here stays right regardless.)
# Memoized per rake process so `rake test:links test:html_proofer` builds
# ONCE. Both tasks default to the same OUTPUT_DIR, and a second full
# production build in the same job is what blew link-check.yml's timeout
# on cold caches before (see the workflow's setup-hugo build: 'false').
def build_for_linkcheck(dir)
@linkcheck_built ||= {}
return if @linkcheck_built[dir]
sh({ "ENVIRONMENT" => "production", "OUTPUT_DIR" => dir }, "./bin/hugo-build")
@linkcheck_built[dir] = true
end
desc "Broken internal links (offline, blocking) via lychee"
task :links do
dir = ENV.fetch("OUTPUT_DIR", "_dest/public-linkcheck")
build_for_linkcheck(dir)
html_files = Dir.glob("#{dir}/**/*.html")
abort "No HTML files found in #{dir} - did the build fail?" if html_files.empty?
puts "lychee: scanning #{html_files.size} pages for broken internal links..."
root = File.expand_path(dir)
sh("lychee", "--offline", "--no-progress",
"--remap", "https://jetthoughts.com/(.*) file://#{root}/$1",
"--root-dir", root, "#{dir}/**/*.html")
end
# Same page set including external links. Non-blocking: third-party
# uptime/rate-limits (e.g. jtway.co) are outside our control.
desc "Broken links incl. external (non-blocking report) via lychee"
task :links_external do
dir = ENV.fetch("OUTPUT_DIR", "_dest/public-linkcheck")
build_for_linkcheck(dir)
html_files = Dir.glob("#{dir}/**/*.html")
puts "lychee: scanning #{html_files.size} pages for broken links (internal + external)..."
begin
sh("lychee", "--no-progress", "--root-dir", File.expand_path(dir), "#{dir}/**/*.html")
rescue RuntimeError => e
puts "\nlychee reported failures (non-blocking): #{e.message}"
end
end
# CI-only complement to :links - html-proofer catches a few things lychee
# doesn't (missing image src files, malformed hash fragments). Internal-only
# and non-blocking, matching :links_external's failure handling.
desc "HTML/link/image validation via html-proofer (CI option, non-blocking)"
task :html_proofer do
dir = ENV.fetch("OUTPUT_DIR", "_dest/public-linkcheck")
build_for_linkcheck(dir)
begin
sh("bundle", "exec", "htmlproofer", dir, "--disable-external", "--checks", "Links,Images")
rescue RuntimeError => e
puts "\nhtml-proofer reported failures (non-blocking): #{e.message}"
end
end
end
desc "Build the site (Hugo)"
task :build do
sh "./bin/hugo-build"
end
desc "Run server (Hugo)"
task :dev do
# bin/dev (not the retired bin/hugo-dev): it exports HUGO_ENVIRONMENT so
# PostCSS actually runs in dev mode - the old script left it unset and paid
# the full PurgeCSS+cssnano production chain on every CSS rebuild.
sh "./bin/dev"
end
desc "Crawl site and run Lighthouse on each page (bin/lighthouse)"
task :lighthouse, [:limit] do |_t, args|
cmd = "./bin/lighthouse"
cmd += " --limit #{args[:limit]}" if args[:limit]
sh cmd
end
task default: "test:all"