Conversation
The condition `$offset <= $this->points` was allowing negative offsets and offsets equal to points (out of bounds) while potentially dropping valid data. Changed to `$offset >= 0 && $offset < $this->points` to properly validate array indices. This fixes the issue where users see only a few records in charts despite having hundreds in the database. Ref: Ticket #14684
The condition `$offset <= $this->points` was allowing negative offsets and offsets equal to points (out of bounds) while potentially dropping valid data. Changed to `$offset >= 0 && $offset < $this->points` to properly validate array indices. This fixes the issue where users see only a few records in charts despite having hundreds in the database. Fixes #231
…p-slimstat/wp-slimstat into fix/issue-14684-chart-data-not-showing
…ulation Validates the DataBuckets::addRow() off-by-one fix (DataBuckets.php:209) and confirms the slimstat_custom_wpdb filter causes no read/write split. - custom-db-simulator-mu-plugin.php: simulates external DB addon filter; uses $GLOBALS['wpdb'] to avoid PHP 8.2 fatal with same-named parameter - setup.ts: register mu-plugin in MU_PLUGIN_MANIFEST - databuckets-custom-db-accuracy.spec.ts: 3 tests covering default DB, custom DB filter active, and boundary edge case Refs #231 / Support #14684
- custom-db-simulator-mu-plugin: reset wpdb->result via Reflection after clone to prevent "mysqli_result already closed" fatal (HTTP 500) caused by shallow clone sharing the protected result property with global wpdb - databuckets spec Test 5: rewrite to accurately test what the code does — Chart.php always reads from global wpdb (wp_slim_stats), not wp_slimstat::$wpdb, so the custom DB filter affects write paths only; test now confirms the AJAX handler survives the filter active and data is still accurate All 6 tests now pass (19.5s): Tests 1-6 PASS Source: Support #14684 / GitHub #231
Tests for bot, CPT, permalink, and user exclusion filters. Confirms issue #233: CPT exclusion requires cpt: prefix.
The ignore_content_types description now explains that custom post types require the cpt: prefix (e.g., cpt:product). Without this, users entering bare type names see exclusion silently fail. Fixes #233
Validates that DataBuckets::initSeqWeek() uses DAY_NAMES[] instead of jddayofweek(), which would fatal on servers without PHP ext-calendar. - 4 tests: HTTP 200, sum accuracy, Sunday start-of-week, corrupted SOW fallback - calendar-ext-simulator mu-plugin: throws RuntimeException from SlimStat\Helpers namespace, simulating ext-calendar absence via PHP namespace shadowing - Uses nonce-helper AJAX endpoint for reliable nonce generation (avoids scraping slimstat_chart_vars which can fail with unusual start_of_week) - beforeEach clears chart transients to prevent cached results across tests
…rage Closes gaps identified in PR #232 impact analysis: - Test 7 in databuckets-custom-db-accuracy.spec.ts verifies MONTHLY granularity chart sum equals DB count (the offset formula for MONTH differs from WEEK and was previously untested). - New chart-sql-expression-validation.spec.ts (4 tests) verifies that valid default expressions pass the validateSqlExpression() whitelist and that arithmetic/injection payloads are rejected with success:false.
- Add try/finally to Test 3 (bot exclusion) so uninstallHeaderInjector()
always runs even if an assertion throws
- Add flush_rewrite_rules() to CPT mu-plugin init callback so /product/{slug}/
pretty permalinks resolve immediately without a 404
- Replace all waitForTimeout(4000) with expect.poll() across all 5 tests;
inclusion tests poll until the record appears, exclusion tests poll to
confirm the count/resource stays at the expected value
…ot-showing Fix chart data not showing due to incorrect bounds check
…lidation 5 tests verifying the DataBuckets bounds fix (PR #232) addresses the "wrong stats" report where daily/weekly charts showed zero for today.
E2E QA Report: Chart "Today Shows Zero" RegressionSimple Summary
Trigger
Environment
Issue AnalysisUser ReportThe user reported that after updating to the latest version:
Root Cause
FixChanged to
Test Results
Test 1: Daily chart — today's records visible (CORE REGRESSION)
Test 2: Weekly chart — current partial week visible (CORE REGRESSION)
Test 3: 28-day daily range accuracy
Test 4: Previous period comparison
Test 5: Cross-granularity consistency
Analytics Invariants
VerdictPASS — The DataBuckets bounds fix in PR #232 correctly resolves the "Wrong stats" issue reported by acekin26. All 5 regression tests confirm:
The release PR #234 (v5.4.4) is safe to merge. Spec Location
|
The weekly offset calculation was using ISO week numbers (date('W'))
which always start on Monday, regardless of WordPress start_of_week
setting. This caused data to be placed in the wrong bucket when
start_of_week was set to Sunday (0).
Now calculates the start-of-week date for both base and data point
timestamps using the WordPress start_of_week setting, ensuring
correct bucket placement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughFixes weekly chart bucketing (week-start alignment and off-by-one bounds), updates the Content Types exclusion UI text to document the Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
tests/e2e/helpers/custom-db-simulator-mu-plugin.php (1)
21-21: Use a site-scoped prefix in the simulator to avoid multisite cross-site leakage.Using a fixed
slimext_prefix can cause table collisions if these tests run in multisite contexts.Based on learnings: Test for multisite compatibility; ensure data is stored per-site with no cross-site leakage; test network activate/deactivate.♻️ Suggested refactor
- $custom->prefix = 'slimext_'; + $custom->prefix = is_multisite() && get_current_blog_id() > 1 + ? 'slimext_' . get_current_blog_id() . '_' + : 'slimext_';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/helpers/custom-db-simulator-mu-plugin.php` at line 21, The simulator currently sets a fixed table prefix via $custom->prefix = 'slimext_', which can collide across sites in multisite tests; change it to use a site-scoped prefix by deriving it from WordPress (e.g. use $wpdb->get_blog_prefix(get_current_blog_id()) or $wpdb->prefix) and append the existing 'slimext_' suffix so tables are namespaced per-site; update any related setup/teardown in the helper so network activate/deactivate and per-site cleanup use the same derived prefix.tests/e2e/databuckets-custom-db-accuracy.spec.ts (1)
148-157: HardensumV1against string-valued datasets.If
v1values ever come through as strings,a + bcan concatenate instead of sum. Coercing values to numbers makes this helper resilient.Proposed refactor
function sumV1(json: any): number { + const sumNumeric = (arr: unknown[]) => arr.reduce((a, b) => a + Number(b ?? 0), 0); + // AJAX response: { success: true, data: { data: { datasets: { v1: [...] } } } } const ajaxDatasets = json?.data?.data?.datasets?.v1; if (Array.isArray(ajaxDatasets)) { - return (ajaxDatasets as number[]).reduce((a, b) => a + b, 0); + return sumNumeric(ajaxDatasets); } // Server-rendered: { datasets: { v1: [...] } } const serverDatasets = json?.datasets?.v1; if (Array.isArray(serverDatasets)) { - return (serverDatasets as number[]).reduce((a, b) => a + b, 0); + return sumNumeric(serverDatasets); } return 0; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/databuckets-custom-db-accuracy.spec.ts` around lines 148 - 157, The sumV1 helper should coerce dataset entries to numbers to avoid string concatenation: in function sumV1, when handling ajaxDatasets and serverDatasets, map each entry to Number(entry) (or use unary +) and filter out NaN before reducing, then use numeric reduce (e.g., (a,b)=>a+b,0) to return a correct numeric sum; update references to ajaxDatasets and serverDatasets accordingly so both paths handle string values robustly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/e2e/databuckets-custom-db-accuracy.spec.ts`:
- Around line 429-433: The epoch constants and comments for the two-month range
are inconsistent: update monthStart, monthEnd, feb15Ts, and mar10Ts so their
numeric Unix timestamps actually map to 2026-02-01 00:00:00 UTC, 2026-03-31
23:59:59 UTC, 2026-02-15 00:00:00 UTC, and 2026-03-10 00:00:00 UTC respectively,
and correct the inline comments for each constant to reflect the 2026 dates;
ensure monthEnd uses the exact end-of-day timestamp for March 31 (23:59:59) to
cover the month-end boundary in tests.
In `@tests/e2e/exclusion-filters.spec.ts`:
- Around line 46-48: The test currently calls flush_rewrite_rules() on every
init hook which is costly; change the logic so flush_rewrite_rules() is invoked
only once—either run it in a plugin activation/activation hook or perform a
one-time transient/option check inside the init handler (e.g., check and set a
transient or option like "my_plugin_rewrites_flushed" before calling
flush_rewrite_rules()), or move the call into the test
bootstrap/after-activation step or a WP-CLI command that runs once for the test
suite; update the code invoking init/flush_rewrite_rules() to use that one-time
pattern rather than flushing on every init.
- Around line 249-252: The test uses the wrong admin username ("parhumm")
causing credential mismatches with global setup; update the adminPage.fill call
that targets '#user_login' in tests/e2e/exclusion-filters.spec.ts (the line with
adminPage.fill('#user_login', ...)) and the same occurrence in
tests/e2e/outbound-report-display.spec.ts (around line 32) to use 'bashiri'
instead of 'parhumm' so the tests use the same user as
tests/e2e/global-setup.ts; leave the '#user_pass' value unchanged unless the
password in global-setup.ts also differs.
In `@tests/e2e/global-setup.ts`:
- Around line 49-55: The inline comment preceding the admin login is
stale—update the comment to match the actual username used in the login call;
locate the call to loginAndSave(baseURL, 'bashiri', 'testpass123',
path.join(AUTH_DIR, 'admin.json')) and change the comment that currently
mentions "parhumm" to refer to "bashiri" (or adjust the username in the function
call if the comment was correct and the code should be reverted), ensuring the
comment and the login arguments are consistent.
---
Nitpick comments:
In `@tests/e2e/databuckets-custom-db-accuracy.spec.ts`:
- Around line 148-157: The sumV1 helper should coerce dataset entries to numbers
to avoid string concatenation: in function sumV1, when handling ajaxDatasets and
serverDatasets, map each entry to Number(entry) (or use unary +) and filter out
NaN before reducing, then use numeric reduce (e.g., (a,b)=>a+b,0) to return a
correct numeric sum; update references to ajaxDatasets and serverDatasets
accordingly so both paths handle string values robustly.
In `@tests/e2e/helpers/custom-db-simulator-mu-plugin.php`:
- Line 21: The simulator currently sets a fixed table prefix via $custom->prefix
= 'slimext_', which can collide across sites in multisite tests; change it to
use a site-scoped prefix by deriving it from WordPress (e.g. use
$wpdb->get_blog_prefix(get_current_blog_id()) or $wpdb->prefix) and append the
existing 'slimext_' suffix so tables are namespaced per-site; update any related
setup/teardown in the helper so network activate/deactivate and per-site cleanup
use the same derived prefix.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1bfa30df-89f4-45b6-ada5-616fd24fbe33
📒 Files selected for processing (15)
CHANGELOG.mdadmin/config/index.phplanguages/wp-slimstat.potreadme.txtsrc/Helpers/DataBuckets.phptests/e2e/chart-sql-expression-validation.spec.tstests/e2e/chart-today-zero-regression.spec.tstests/e2e/databuckets-custom-db-accuracy.spec.tstests/e2e/databuckets-no-calendar-ext.spec.tstests/e2e/exclusion-filters.spec.tstests/e2e/global-setup.tstests/e2e/helpers/calendar-ext-simulator-mu-plugin.phptests/e2e/helpers/custom-db-simulator-mu-plugin.phptests/e2e/helpers/setup.tswp-slimstat.php
| // Fixed 2-month range: 2026-02-01 → 2026-03-31 UTC (past, cache-eligible range) | ||
| const monthStart = 1738368000; // 2026-02-01 00:00 UTC | ||
| const monthEnd = 1743379199; // 2026-03-31 23:59 UTC | ||
| const feb15Ts = 1739577600; // 2026-02-15 UTC (mid Feb) | ||
| const mar10Ts = 1741564800; // 2026-03-10 UTC (mid Mar) |
There was a problem hiding this comment.
Monthly range constants/comments are inconsistent and miss the stated end date.
Line 430–433 epochs map to 2025 dates, while comments say 2026, and monthEnd currently ends at 2025-03-30 23:59:59 UTC (not March 31). This makes the test intent ambiguous and weakens month-end boundary coverage.
Suggested correction
- // Fixed 2-month range: 2026-02-01 → 2026-03-31 UTC (past, cache-eligible range)
- const monthStart = 1738368000; // 2026-02-01 00:00 UTC
- const monthEnd = 1743379199; // 2026-03-31 23:59 UTC
- const feb15Ts = 1739577600; // 2026-02-15 UTC (mid Feb)
- const mar10Ts = 1741564800; // 2026-03-10 UTC (mid Mar)
+ // Fixed 2-month range: 2025-02-01 → 2025-03-31 UTC (past, cache-eligible range)
+ const monthStart = 1738368000; // 2025-02-01 00:00 UTC
+ const monthEnd = 1743465599; // 2025-03-31 23:59:59 UTC
+ const feb15Ts = 1739577600; // 2025-02-15 UTC (mid Feb)
+ const mar10Ts = 1741564800; // 2025-03-10 UTC (mid Mar)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/e2e/databuckets-custom-db-accuracy.spec.ts` around lines 429 - 433, The
epoch constants and comments for the two-month range are inconsistent: update
monthStart, monthEnd, feb15Ts, and mar10Ts so their numeric Unix timestamps
actually map to 2026-02-01 00:00:00 UTC, 2026-03-31 23:59:59 UTC, 2026-02-15
00:00:00 UTC, and 2026-03-10 00:00:00 UTC respectively, and correct the inline
comments for each constant to reflect the 2026 dates; ensure monthEnd uses the
exact end-of-day timestamp for March 31 (23:59:59) to cover the month-end
boundary in tests.
| // Flush rewrite rules so /product/{slug}/ pretty permalinks resolve immediately. | ||
| flush_rewrite_rules(); | ||
| }); |
There was a problem hiding this comment.
Avoid flush_rewrite_rules() on every init hook — performance concern.
Calling flush_rewrite_rules() on every init is expensive and can cause performance issues. For tests, consider flushing once after plugin activation or using a one-time transient check.
📝 Suggested fix — flush only once
add_action('init', function() {
register_post_type('product', [
'public' => true,
'label' => 'Products',
'has_archive' => true,
'rewrite' => ['slug' => 'product'],
'supports' => ['title', 'editor'],
'show_in_rest' => true,
]);
- // Flush rewrite rules so /product/{slug}/ pretty permalinks resolve immediately.
- flush_rewrite_rules();
});
+
+// Flush rewrite rules once on activation
+add_action('init', function() {
+ if (get_transient('e2e_product_cpt_flush_done')) return;
+ flush_rewrite_rules();
+ set_transient('e2e_product_cpt_flush_done', true, 3600);
+}, 99);Or simply call flush_rewrite_rules() separately via WP-CLI after installing the MU-plugin.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/e2e/exclusion-filters.spec.ts` around lines 46 - 48, The test currently
calls flush_rewrite_rules() on every init hook which is costly; change the logic
so flush_rewrite_rules() is invoked only once—either run it in a plugin
activation/activation hook or perform a one-time transient/option check inside
the init handler (e.g., check and set a transient or option like
"my_plugin_rewrites_flushed" before calling flush_rewrite_rules()), or move the
call into the test bootstrap/after-activation step or a WP-CLI command that runs
once for the test suite; update the code invoking init/flush_rewrite_rules() to
use that one-time pattern rather than flushing on every init.
| await adminPage.fill('#user_login', 'parhumm'); | ||
| await adminPage.fill('#user_pass', 'testpass123'); | ||
| await adminPage.click('#wp-submit'); | ||
| await adminPage.waitForURL('**/wp-admin/**', { timeout: 30_000 }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if both usernames are used consistently across e2e tests
echo "=== Checking admin usernames in e2e tests ==="
rg -n "parhumm|bashiri" --type=ts tests/e2e/Repository: wp-slimstat/wp-slimstat
Length of output: 399
🏁 Script executed:
cat -n tests/e2e/global-setup.ts | sed -n '40,65p'Repository: wp-slimstat/wp-slimstat
Length of output: 857
🏁 Script executed:
rg -n "user_login|user_pass" --type=ts tests/e2e/ | grep -E "(parhumm|bashiri|testpass)"Repository: wp-slimstat/wp-slimstat
Length of output: 440
Credential mismatch — parhumm vs bashiri.
The admin username here is parhumm, but tests/e2e/global-setup.ts was updated to use bashiri. This will cause test failures if the environment only has the bashiri user. Additionally, tests/e2e/outbound-report-display.spec.ts:32 has the same issue.
Update both occurrences to use bashiri:
Diff
- await adminPage.fill('#user_login', 'parhumm');
+ await adminPage.fill('#user_login', 'bashiri');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await adminPage.fill('#user_login', 'parhumm'); | |
| await adminPage.fill('#user_pass', 'testpass123'); | |
| await adminPage.click('#wp-submit'); | |
| await adminPage.waitForURL('**/wp-admin/**', { timeout: 30_000 }); | |
| await adminPage.fill('#user_login', 'bashiri'); | |
| await adminPage.fill('#user_pass', 'testpass123'); | |
| await adminPage.click('#wp-submit'); | |
| await adminPage.waitForURL('**/wp-admin/**', { timeout: 30_000 }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/e2e/exclusion-filters.spec.ts` around lines 249 - 252, The test uses
the wrong admin username ("parhumm") causing credential mismatches with global
setup; update the adminPage.fill call that targets '#user_login' in
tests/e2e/exclusion-filters.spec.ts (the line with adminPage.fill('#user_login',
...)) and the same occurrence in tests/e2e/outbound-report-display.spec.ts
(around line 32) to use 'bashiri' instead of 'parhumm' so the tests use the same
user as tests/e2e/global-setup.ts; leave the '#user_pass' value unchanged unless
the password in global-setup.ts also differs.
Validates weekly chart DataBuckets offset calculation respects WordPress start_of_week setting (Sunday/Monday/Saturday), cross-granularity consistency, and week boundary behavior. 5/5 pass.
The toArray() method was using wp_date('YW', ...) to check if the
end date is in the current week, but 'YW' returns ISO week format
which always starts on Monday regardless of WordPress start_of_week.
Added getWeekStartTimestamp() helper method to calculate week start
respecting the WordPress setting, and refactored both addRow() and
toArray() to use this consistent logic.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests confirm DataBuckets::addRow() ISO week mismatch when start_of_week is Sunday (0) or Saturday (6): data loss from negative offsets and bucket misalignment.
There was a problem hiding this comment.
🧹 Nitpick comments (5)
tests/e2e/weekly-bucketing-last-week-count.spec.ts (5)
281-284: Weak assertion may miss bucketing errors.Using
toBeGreaterThanOrEqual(3)is a loose check. If there's a bug that causes extra data to land in this bucket (e.g., duplication), this assertion would still pass. Consider calculating and asserting the exact expected value.🎯 Consider precise assertion
// Second-to-last should contain Mar 14 (Sat) = part of Mar 8 (Sun) week // Plus any other data in that week const secondToLast = v1[v1.length - 2]; - expect(secondToLast, `Second-to-last bucket should include Mar 14=3`).toBeGreaterThanOrEqual(3); + // With sow=0: Mar 8 (Sun) week contains Mar 8-14; Mar 14=3 is the only seeded day in that week + expect(secondToLast, `Second-to-last bucket should be exactly 3 (Mar 14 only)`).toBe(3);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 281 - 284, The assertion for the second-to-last bucket (variable secondToLast from array v1) is too loose; compute the exact expected count for that bucket based on the test input (including Mar 14 and any other known events that should fall into the Mar 8 week) and replace the toBeGreaterThanOrEqual(3) check with a strict equality assertion (e.g., expect(secondToLast).toEqual(EXACT_COUNT)). Update the test to calculate EXACT_COUNT deterministically from the test fixtures or hardcode the known correct sum so the test fails on duplication/mis-bucketing.
143-146: Unused helper functiondayName.The
dayNamefunction is defined but never called anywhere in the test file. Consider removing it to reduce dead code, or add a comment if it's intended for debugging.🧹 Remove unused function
-/** Get day of week name for a timestamp */ -function dayName(ts: number): string { - return new Date(ts * 1000).toUTCString().split(',')[0]; -} -🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 143 - 146, The helper function dayName is defined but never used; remove the dead code by deleting the dayName(ts: number) function declaration (or, if you intend to keep it for ad-hoc debugging, add a clear comment explaining its purpose and suppress the unused-variable lint rule) so the file no longer contains the unused symbol dayName.
210-212: Consider using Playwright'stest.info()for structured test output.Multiple
console.logstatements can clutter CI output. Playwright providestest.info().annotationsortest.step()for structured logging that integrates better with reporters.📊 Example using test.step for structured output
await test.step('Verify chart data', async () => { const v1 = getV1(json); const labels = getLabels(json); const chartSum = sumV1(json); test.info().annotations.push({ type: 'chart-data', description: `Labels: ${labels.join(', ')}` }); test.info().annotations.push({ type: 'chart-data', description: `V1: ${v1.join(', ')}` }); // assertions... });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 210 - 212, Replace the three console.log calls that print labels, v1 and the chart sum with structured Playwright reporting: wrap the verification in a test.step('Verify chart data', ...) and use test.info().annotations.push(...) (or test.info().annotations = [...]) to add annotations for Labels, V1 and Chart sum (referencing the local vars labels, v1, chartSum and totalExpected) so the output integrates with reporters and avoids cluttering CI logs; ensure assertions remain inside the step.
108-109: Hardcodedwp_table prefix may break in alternative test environments.The table name
wp_slim_statsandwp_optionsare hardcoded. If the test environment uses a custom table prefix (e.g.,wp_test_), these queries will fail silently or target the wrong tables.Consider using a helper that reads the prefix from
WP_ROOT/wp-config.phpor an environment variable.Also applies to: 116-118
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 108 - 109, The hardcoded table names ('INSERT INTO wp_slim_stats ...' and references to 'wp_options') will break when a WP table prefix differs; change these queries to use a resolved table prefix by reading the prefix from wp-config.php or an environment variable (e.g., process.env.WP_TABLE_PREFIX) and build table names like `${prefix}slim_stats` and `${prefix}options` before executing them, replacing the literal 'wp_slim_stats' and 'wp_options' strings in the test SQL statements.
175-203: Test assumes defaultstart_of_week=1but doesn't explicitly set it.Unlike Tests 2 and 4 which snapshot and explicitly set
start_of_week, this test relies on the default being1(Monday). If a previous test run fails before restoring the option, or if the test environment has a different default, this test may produce unexpected results.Consider adding explicit setup for consistency:
🔧 Explicitly set start_of_week for test isolation
test('March 14 data lands in Mar 9 bucket, NOT in Mar 16 bucket (sow=1)', async () => { + // Ensure default Monday start + await snapshotOption('start_of_week'); + await getPool().execute("UPDATE wp_options SET option_value = '1' WHERE option_name = 'start_of_week'"); + + try { // Seed: 3 hits on Mar 14 (Saturday), 2 hits on Mar 15 (Sunday), // 5 hits on Mar 16 (Monday), 4 hits on Mar 17 (Tuesday) // ... existing code ... console.log('Test 1 PASS — Mar 14 correctly in Mar 9 bucket, Mar 16-17 in last bucket'); + } finally { + await restoreOption('start_of_week'); + } });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 175 - 203, This test relies on the default start_of_week=1 but doesn't set it explicitly; modify the test (the 'March 14 data lands...' case that calls utcMidnight, insertRows and fetchChartData) to explicitly set start_of_week to 1 at test setup and restore the original value at teardown using the same snapshot/set/restore pattern used by Tests 2 and 4 so the test is isolated from global defaults or prior failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts`:
- Around line 281-284: The assertion for the second-to-last bucket (variable
secondToLast from array v1) is too loose; compute the exact expected count for
that bucket based on the test input (including Mar 14 and any other known events
that should fall into the Mar 8 week) and replace the toBeGreaterThanOrEqual(3)
check with a strict equality assertion (e.g.,
expect(secondToLast).toEqual(EXACT_COUNT)). Update the test to calculate
EXACT_COUNT deterministically from the test fixtures or hardcode the known
correct sum so the test fails on duplication/mis-bucketing.
- Around line 143-146: The helper function dayName is defined but never used;
remove the dead code by deleting the dayName(ts: number) function declaration
(or, if you intend to keep it for ad-hoc debugging, add a clear comment
explaining its purpose and suppress the unused-variable lint rule) so the file
no longer contains the unused symbol dayName.
- Around line 210-212: Replace the three console.log calls that print labels, v1
and the chart sum with structured Playwright reporting: wrap the verification in
a test.step('Verify chart data', ...) and use test.info().annotations.push(...)
(or test.info().annotations = [...]) to add annotations for Labels, V1 and Chart
sum (referencing the local vars labels, v1, chartSum and totalExpected) so the
output integrates with reporters and avoids cluttering CI logs; ensure
assertions remain inside the step.
- Around line 108-109: The hardcoded table names ('INSERT INTO wp_slim_stats
...' and references to 'wp_options') will break when a WP table prefix differs;
change these queries to use a resolved table prefix by reading the prefix from
wp-config.php or an environment variable (e.g., process.env.WP_TABLE_PREFIX) and
build table names like `${prefix}slim_stats` and `${prefix}options` before
executing them, replacing the literal 'wp_slim_stats' and 'wp_options' strings
in the test SQL statements.
- Around line 175-203: This test relies on the default start_of_week=1 but
doesn't set it explicitly; modify the test (the 'March 14 data lands...' case
that calls utcMidnight, insertRows and fetchChartData) to explicitly set
start_of_week to 1 at test setup and restore the original value at teardown
using the same snapshot/set/restore pattern used by Tests 2 and 4 so the test is
isolated from global defaults or prior failures.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a57b09f3-c6fb-46b3-9ace-1341b0092986
📒 Files selected for processing (1)
tests/e2e/weekly-bucketing-last-week-count.spec.ts
…dev) Targeted test for the exact screenshot scenario: weekly chart with start_of_week=6 (Saturday), validating Mar 7-14 bucket contains only Sat-Fri data, boundary split between Mar 13 (Fri) and Mar 14 (Sat), and cross-granularity consistency.
…ssion Tests daily buckets, monthly buckets, previous periods, month boundaries, and cross-granularity consistency (daily=weekly=monthly) for sow=0,1,6. Both branches pass 9/9 — confirms PR #235 weekly fix is scoped and safe.
…howing Fix weekly chart not showing today's data
Test 1 assumed WP default of sow=1 but the site may have a different value. Now explicitly sets and restores start_of_week like other tests.
E2E QA Report: Post-Merge Chart Suite Verification (PR #235 → development)Branch: Chart Test Results: 18/18 PASS
Summary
Verification
|
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/Helpers/DataBuckets.php (1)
216-216: Match the repo's Yoda rule for the lower-bound check.Line 216 is the only changed literal comparison here that still uses non-Yoda ordering.
As per coding guidelines "Use Yoda Conditions: `if ( 'value' === $var )`."♻️ Suggested tweak
- if ($offset >= 0 && $offset < $this->points) { + if ( 0 <= $offset && $offset < $this->points ) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/Helpers/DataBuckets.php` at line 216, Change the lower-bound comparison in the conditional that checks $offset so it uses Yoda-style ordering: replace the `$offset >= 0` part with `0 <= $offset` while keeping the upper-bound check `$offset < $this->points` intact; update the condition around the `$offset` variable in the DataBuckets class (the `if ($offset >= 0 && $offset < $this->points)` statement) to `if (0 <= $offset && $offset < $this->points)`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/Helpers/DataBuckets.php`:
- Line 292: The weekly "today" comparison uses PHP's system time instead of
WordPress time and should compare getWeekStartTimestamp($this->end) against the
WordPress-aware current timestamp; change the right-hand call to use
current_time('timestamp') (i.e. compare $this->getWeekStartTimestamp($this->end)
=== $this->getWeekStartTimestamp(current_time('timestamp'))) and keep the
fallback wp_date(..., wp_timezone()) usage; also update the bounds check
condition from if ($offset >= 0 && $offset < $this->points) to the Yoda-style if
(0 <= $offset && $offset < $this->points) so offset/points logic uses the
required style.
In `@tests/e2e/chart-monthly-daily-granularity.spec.ts`:
- Around line 205-216: The test mutates the global WP option via
getPool().execute(...) and currently calls restoreOption('start_of_week') only
on the success path; wrap the mutation and assertions in a try/finally so
restoreOption('start_of_week') always runs (i.e., call
snapshotOption('start_of_week'), then try { update via getPool().execute(...);
run fetchChartData(...), expect(...), record results via sumArr(getV1(json)); }
finally { await restoreOption('start_of_week'); }). Apply the same try/finally
pattern to the M2 block mentioned (the other occurrence at lines 331-342) so
both mutations always restore the option.
In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts`:
- Around line 177-178: The test mutates the WP option via
getPool().execute("UPDATE wp_options SET option_value = '1' WHERE option_name =
'start_of_week'") but only restores it on the success path; wrap the mutation in
a try/finally (or mirror the pattern used in the other tests) and call
snapshotOption('start_of_week') or execute the original value restore in the
finally block to guarantee restoration on failure; update both occurrences (the
current block and the similar occurrence around line ~234) and reference
snapshotOption and getPool().execute when making the changes.
In `@tests/e2e/weekly-start-of-week-bucketing.spec.ts`:
- Around line 319-356: The test currently only checks total sums but not that
buckets differ; after calling setStartOfWeek(0) and setStartOfWeek(1) and
computing v1Sow0/v1Sow1 (from fetchChartData and getV1), add assertions that
verify the bucket indices/counts reflect the described split: for sow=0 ensure
Saturday and Sunday counts are in different weekly buckets (e.g. two separate
non-zero entries in v1Sow0 corresponding to the two days inserted), and for
sow=1 ensure Saturday and Sunday are aggregated into the same weekly bucket (a
single entry in v1Sow1 that equals dbCount for those two days or at least a
matching combined count). Use getV1, sumV1, fetchChartData, setStartOfWeek,
mostRecentDayOfWeek and insertRows to locate and validate the bucket
distribution rather than only sums.
---
Nitpick comments:
In `@src/Helpers/DataBuckets.php`:
- Line 216: Change the lower-bound comparison in the conditional that checks
$offset so it uses Yoda-style ordering: replace the `$offset >= 0` part with `0
<= $offset` while keeping the upper-bound check `$offset < $this->points`
intact; update the condition around the `$offset` variable in the DataBuckets
class (the `if ($offset >= 0 && $offset < $this->points)` statement) to `if (0
<= $offset && $offset < $this->points)`.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 374bca94-7c81-4ee4-8ae3-f79dc0d3d575
📒 Files selected for processing (5)
src/Helpers/DataBuckets.phptests/e2e/chart-monthly-daily-granularity.spec.tstests/e2e/weekly-bucketing-last-week-count.spec.tstests/e2e/weekly-bucketing-sow6-mar7-validation.spec.tstests/e2e/weekly-start-of-week-bucketing.spec.ts
| 'datasets' => $this->datasets, | ||
| 'datasets_prev' => $this->datasetsPrev, | ||
| 'today' => 'WEEK' === $this->gran && wp_date('YW', $this->end, wp_timezone()) === wp_date('YW', time(), wp_timezone()) ? str_replace("'", '', $this->labels[count($this->labels) - 1]) : wp_date($this->labelFormat, time(), wp_timezone()), | ||
| 'today' => 'WEEK' === $this->gran && $this->getWeekStartTimestamp($this->end) === $this->getWeekStartTimestamp(time()) ? str_replace("'", '', $this->labels[count($this->labels) - 1]) : wp_date($this->labelFormat, time(), wp_timezone()), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
echo "---- weekly today calculation ----"
sed -n '286,294p' src/Helpers/DataBuckets.php
echo
echo "---- timezone-related calls under src/ ----"
rg -n "date_default_timezone_set|wp_date\(|wp_timezone\(" srcRepository: wp-slimstat/wp-slimstat
Length of output: 1548
🏁 Script executed:
#!/bin/bash
echo "---- getWeekStartTimestamp method ----"
rg -A 15 "function getWeekStartTimestamp" src/Helpers/DataBuckets.php
echo
echo "---- Line 216 context ----"
sed -n '210,220p' src/Helpers/DataBuckets.php
echo
echo "---- Full DataBuckets.php lines 241-251 (new helper mentioned) ----"
sed -n '241,251p' src/Helpers/DataBuckets.phpRepository: wp-slimstat/wp-slimstat
Length of output: 1901
🏁 Script executed:
#!/bin/bash
echo "---- Searching for date_default_timezone_set in entire repo ----"
rg -n "date_default_timezone_set" .
echo
echo "---- Searching for timezone initialization patterns ----"
rg -n "timezone_string|date_default_timezone" . --type php | head -20Repository: wp-slimstat/wp-slimstat
Length of output: 634
🏁 Script executed:
#!/bin/bash
echo "---- Line 216 and surrounding context ----"
sed -n '214,220p' src/Helpers/DataBuckets.phpRepository: wp-slimstat/wp-slimstat
Length of output: 408
Fix timezone handling in weekly date boundary detection and apply Yoda condition formatting.
Line 292's weekly "today" comparison uses getWeekStartTimestamp() on both sides, which relies on PHP's default timezone via date() and strtotime() instead of WordPress timezone. Without an explicit date_default_timezone_set() call in the codebase, if the site's WordPress timezone differs from the system/PHP default, the week-start boundary comparison evaluates incorrectly, causing the "today" marker to flip on the wrong clock. The fallback branch correctly uses wp_date(..., wp_timezone()), but the condition should match this precision.
Additionally, line 216's bounds check violates the Yoda condition guideline: if ($offset >= 0 && $offset < $this->points) should be if (0 <= $offset && $offset < $this->points).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Helpers/DataBuckets.php` at line 292, The weekly "today" comparison uses
PHP's system time instead of WordPress time and should compare
getWeekStartTimestamp($this->end) against the WordPress-aware current timestamp;
change the right-hand call to use current_time('timestamp') (i.e. compare
$this->getWeekStartTimestamp($this->end) ===
$this->getWeekStartTimestamp(current_time('timestamp'))) and keep the fallback
wp_date(..., wp_timezone()) usage; also update the bounds check condition from
if ($offset >= 0 && $offset < $this->points) to the Yoda-style if (0 <= $offset
&& $offset < $this->points) so offset/points logic uses the required style.
| function mostRecentDayOfWeek(dayOfWeek: number, refTs: number): number { | ||
| const refDate = new Date(refTs * 1000); | ||
| const currentDay = refDate.getUTCDay(); // 0=Sun | ||
| const diff = (currentDay - dayOfWeek + 7) % 7; | ||
| // If diff is 0, it's today — use it | ||
| const targetDate = new Date(refDate); | ||
| targetDate.setUTCDate(targetDate.getUTCDate() - diff); | ||
| targetDate.setUTCHours(12, 0, 0, 0); // noon to avoid DST edge cases | ||
| return Math.floor(targetDate.getTime() / 1000); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
python - <<'PY'
from datetime import datetime, timedelta, timezone
ref = datetime(2026, 3, 22, 8, 0, 0, tzinfo=timezone.utc) # Sunday 08:00 UTC
target_dow = 0 # Sunday
current_dow = (ref.weekday() + 1) % 7 # emulate JS getUTCDay()
diff = (current_dow - target_dow + 7) % 7
target = ref - timedelta(days=diff)
target = target.replace(hour=12, minute=0, second=0, microsecond=0)
print("ref :", ref.isoformat())
print("target:", target.isoformat())
print("future?", target > ref)
PY
echo
sed -n '157,170p' tests/e2e/weekly-start-of-week-bucketing.spec.tsRepository: wp-slimstat/wp-slimstat
Length of output: 741
🏁 Script executed:
# Find and examine Test 5 and rangeEnd context
rg -n "Test 5|describe.*Test 5|it.*Test 5|it\(" tests/e2e/weekly-start-of-week-bucketing.spec.ts -A 5 | head -100Repository: wp-slimstat/wp-slimstat
Length of output: 546
🏁 Script executed:
# Look for rangeEnd and the test structure around line 319-356
wc -l tests/e2e/weekly-start-of-week-bucketing.spec.tsRepository: wp-slimstat/wp-slimstat
Length of output: 119
🏁 Script executed:
# Get the test file to see Test 5 context
sed -n '280,400p' tests/e2e/weekly-start-of-week-bucketing.spec.tsRepository: wp-slimstat/wp-slimstat
Length of output: 3097
🏁 Script executed:
# Find rangeStart and rangeEnd definitions
rg -n "rangeStart|rangeEnd" tests/e2e/weekly-start-of-week-bucketing.spec.ts | head -40Repository: wp-slimstat/wp-slimstat
Length of output: 636
🏁 Script executed:
# Look at the top of the file to see test setup
head -160 tests/e2e/weekly-start-of-week-bucketing.spec.tsRepository: wp-slimstat/wp-slimstat
Length of output: 5190
mostRecentDayOfWeek() returns a future timestamp when called before noon UTC on its target weekday.
When refTs is on Sunday before 12:00 UTC and dayOfWeek=0, diff=0, so setUTCHours(12, 0, 0, 0) shifts the timestamp forward. In Test 5, line 321 calls mostRecentDayOfWeek(0, now) to seed Sunday records, which will fall outside rangeEnd when the test runs before noon UTC on a Sunday.
Additionally, Test 5 (lines 319–357) verifies only that totals match across sow=0 and sow=1, not the bucket distribution—it should assert that Saturday and Sunday land in different weeks under sow=0 but the same week under sow=1.
| test('Sunday records land in correct week bucket for sow=0 vs sow=1', async () => { | ||
| // Find the most recent Sunday timestamp | ||
| const sundayTs = mostRecentDayOfWeek(0, now); // 0 = Sunday | ||
| // And the Saturday before it | ||
| const saturdayTs = sundayTs - day; | ||
|
|
||
| // Insert records on Saturday and Sunday | ||
| await insertRows(saturdayTs, 4, 'boundary-sat'); | ||
| await insertRows(sundayTs, 3, 'boundary-sun'); | ||
|
|
||
| const dbCount = await countTestRows(); | ||
| expect(dbCount).toBe(7); | ||
|
|
||
| // With sow=0 (Sunday): Sunday starts a NEW week | ||
| setStartOfWeek(0); | ||
| const jsonSow0 = fetchChartData(rangeStart, rangeEnd, 'weekly'); | ||
| expect(jsonSow0?.success).toBe(true); | ||
| const v1Sow0 = getV1(jsonSow0); | ||
| const sumSow0 = sumV1(jsonSow0); | ||
| expect(sumSow0).toBe(dbCount); | ||
|
|
||
| // With sow=1 (Monday): Sunday is the LAST day of the week | ||
| setStartOfWeek(1); | ||
| const jsonSow1 = fetchChartData(rangeStart, rangeEnd, 'weekly'); | ||
| expect(jsonSow1?.success).toBe(true); | ||
| const v1Sow1 = getV1(jsonSow1); | ||
| const sumSow1 = sumV1(jsonSow1); | ||
| expect(sumSow1).toBe(dbCount); | ||
|
|
||
| // Both must account for all records | ||
| expect(sumSow0).toBe(sumSow1); | ||
|
|
||
| // The bucket distribution should differ: with sow=0, Sunday starts a new week | ||
| // so Saturday (4) and Sunday (3) are in different weeks. | ||
| // With sow=1, Saturday and Sunday are in the same week (both after Monday). | ||
| // We can't assert exact bucket indices without knowing the day-of-week of 'now', | ||
| // but we can verify the total is correct and no records are lost. | ||
| console.log(`Test 5 PASS — boundary: DB=${dbCount}, sow0=${JSON.stringify(v1Sow0)}, sow1=${JSON.stringify(v1Sow1)}`); |
There was a problem hiding this comment.
This test never asserts the bucket split it describes.
After sow=0 and sow=1 are fetched, the only hard checks are total sums. If Sunday is still bucketed identically in both runs, this test still passes.
🎯 Assert the actual split
- // We can't assert exact bucket indices without knowing the day-of-week of 'now',
- // but we can verify the total is correct and no records are lost.
+ const nonZeroSow0 = v1Sow0.filter((v) => v > 0).sort((a, b) => a - b);
+ const nonZeroSow1 = v1Sow1.filter((v) => v > 0).sort((a, b) => a - b);
+ expect(nonZeroSow0, 'sow=0 should split Saturday and Sunday into separate weekly buckets').toEqual([3, 4]);
+ expect(nonZeroSow1, 'sow=1 should keep Saturday and Sunday in the same weekly bucket').toEqual([7]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/e2e/weekly-start-of-week-bucketing.spec.ts` around lines 319 - 356, The
test currently only checks total sums but not that buckets differ; after calling
setStartOfWeek(0) and setStartOfWeek(1) and computing v1Sow0/v1Sow1 (from
fetchChartData and getV1), add assertions that verify the bucket indices/counts
reflect the described split: for sow=0 ensure Saturday and Sunday counts are in
different weekly buckets (e.g. two separate non-zero entries in v1Sow0
corresponding to the two days inserted), and for sow=1 ensure Saturday and
Sunday are aggregated into the same weekly bucket (a single entry in v1Sow1 that
equals dbCount for those two days or at least a matching combined count). Use
getV1, sumV1, fetchChartData, setStartOfWeek, mostRecentDayOfWeek and insertRows
to locate and validate the bucket distribution rather than only sums.
…ive regression (41/41 pass) Extract shared chart utilities into helpers/chart.ts (-888 lines duplication), add explicit start_of_week isolation to all specs, fix global-setup to use admin user, add chart-robustness.spec.ts (timezone, browser AJAX, edge cases) and chart-negative-regression.spec.ts (git worktree master vs development).
There was a problem hiding this comment.
♻️ Duplicate comments (3)
tests/e2e/chart-monthly-daily-granularity.spec.ts (2)
95-106:⚠️ Potential issue | 🟡 MinorD2 should wrap sow mutations in
try/finallyfor guaranteed cleanup.If any assertion fails in the loop,
restoreOption('start_of_week')at line 106 won't execute, leaving the option dirty for subsequent tests.🔧 Wrap in try/finally
await snapshotOption('start_of_week'); - const results: Record<string, number> = {}; - - for (const sow of ['1', '0', '6']) { - await getPool().execute("UPDATE wp_options SET option_value = ? WHERE option_name = 'start_of_week'", [sow]); - const json = fetchChartData(rangeStart, rangeEnd, 'daily'); - expect(json?.success).toBe(true); - results[`sow${sow}`] = sumArr(getV1(json)); - } - - await restoreOption('start_of_week'); + try { + for (const sow of ['1', '0', '6']) { + await getPool().execute("UPDATE wp_options SET option_value = ? WHERE option_name = 'start_of_week'", [sow]); + const json = fetchChartData(rangeStart, rangeEnd, 'daily'); + expect(json?.success).toBe(true); + results[`sow${sow}`] = sumArr(getV1(json)); + } + } finally { + await restoreOption('start_of_week'); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/chart-monthly-daily-granularity.spec.ts` around lines 95 - 106, The test mutates the WP option via getPool().execute in the for-loop and calls restoreOption('start_of_week') after the loop, which can be skipped if an assertion fails; wrap the mutation+assert loop in a try/finally so restoreOption('start_of_week') always runs: call snapshotOption('start_of_week') before the try, perform the for-loop where you set the option (getPool().execute), call fetchChartData and assertions (fetchChartData, getV1, sumArr) inside the try, and place restoreOption('start_of_week') in the finally block to guarantee cleanup even on failures.
219-230:⚠️ Potential issue | 🟡 MinorM2 should wrap sow mutations in
try/finallyfor guaranteed cleanup.Same issue as D2 — if assertions fail,
restoreOptionwon't execute.🔧 Wrap in try/finally
await snapshotOption('start_of_week'); - const results: Record<string, number> = {}; - - for (const sow of ['1', '0', '6']) { - await getPool().execute("UPDATE wp_options SET option_value = ? WHERE option_name = 'start_of_week'", [sow]); - const json = fetchChartData(rangeStart, rangeEnd, 'monthly'); - expect(json?.success).toBe(true); - results[`sow${sow}`] = sumArr(getV1(json)); - } - - await restoreOption('start_of_week'); + try { + for (const sow of ['1', '0', '6']) { + await getPool().execute("UPDATE wp_options SET option_value = ? WHERE option_name = 'start_of_week'", [sow]); + const json = fetchChartData(rangeStart, rangeEnd, 'monthly'); + expect(json?.success).toBe(true); + results[`sow${sow}`] = sumArr(getV1(json)); + } + } finally { + await restoreOption('start_of_week'); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/chart-monthly-daily-granularity.spec.ts` around lines 219 - 230, The test mutates the WP option 'start_of_week' with getPool().execute inside a loop but doesn't guarantee restoreOption runs if an assertion fails; wrap the mutation+assertion loop in a try/finally: call await snapshotOption('start_of_week') before the try, perform the for-loop (updates, fetchChartData, expect, results accumulation) inside the try, and ensure await restoreOption('start_of_week') is invoked in the finally block so cleanup always occurs; reference functions: snapshotOption, getPool().execute, fetchChartData, getV1, sumArr, restoreOption.tests/e2e/weekly-bucketing-last-week-count.spec.ts (1)
43-92:⚠️ Potential issue | 🟡 MinorTest 1 should wrap mutations in
try/finallyto ensure cleanup.Unlike Tests 2-5 which properly use
try/finally, Test 1 callsrestoreOption('start_of_week')only on the success path (line 91). If any assertion fails,start_of_weekremains dirty for subsequent tests.🔧 Wrap in try/finally
test('March 14 data lands in Mar 9 bucket, NOT in Mar 16 bucket (sow=1)', async () => { await snapshotOption('start_of_week'); await getPool().execute("UPDATE wp_options SET option_value = '1' WHERE option_name = 'start_of_week'"); + try { const mar14 = utcMidnight('2026-03-14'); // ... rest of test logic ... console.log('Test 1 PASS — Mar 14 correctly in Mar 9 bucket, Mar 16-17 in last bucket'); - - await restoreOption('start_of_week'); + } finally { + await restoreOption('start_of_week'); + } });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts` around lines 43 - 92, The test "March 14 data lands in Mar 9 bucket, NOT in Mar 16 bucket (sow=1)" mutates global state (calls snapshotOption and getPool().execute to set start_of_week) but only calls restoreOption('start_of_week') on the success path; wrap the body that seeds rows and assertions in a try/finally block so restoreOption('start_of_week') runs in finally, ensuring cleanup even if assertions fail, keeping snapshotOption(), getPool().execute(... 'start_of_week' ...), insertRows(...), fetchChartData(...), and related assertions inside the try and calling restoreOption in the finally.
🧹 Nitpick comments (4)
tests/e2e/chart-robustness.spec.ts (2)
44-51: Use parameterized queries for SQL to avoid injection risk.The
SET time_zonestatement uses string interpolation which, while safe with the current hardcoded test values, establishes an unsafe pattern. Consider using parameterized execution or validating the input format.♻️ Safer approach with validation
async function setTimezone(mysqlTz: string, wpGmtOffset: string): Promise<void> { + // Validate timezone format (+HH:MM or -HH:MM) + if (!/^[+-]\d{2}:\d{2}$/.test(mysqlTz)) { + throw new Error(`Invalid timezone format: ${mysqlTz}`); + } const pool = getPool(); - await pool.execute(`SET time_zone = '${mysqlTz}'`); + await pool.execute(`SET time_zone = ?`, [mysqlTz]); await pool.execute( "UPDATE wp_options SET option_value = ? WHERE option_name = 'gmt_offset'", [wpGmtOffset] ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/chart-robustness.spec.ts` around lines 44 - 51, The setTimezone function currently interpolates mysqlTz into the SQL string (in setTimezone and pool.execute calls), which is unsafe; update setTimezone to avoid direct string interpolation by using a parameterized query for the SET time_zone statement (use pool.execute with a placeholder and pass mysqlTz) or, if the DB driver disallows parameterizing SET, strictly validate/whitelist mysqlTz before interpolating (e.g., allow only offsets like '+00:00' or known timezone names) and keep the wp_options update using the existing parameterized placeholder for wpGmtOffset; ensure references to setTimezone, getPool, and pool.execute are updated accordingly.
294-297: Consider replacing fixed timeout with explicit wait condition.
page.waitForTimeout(3000)is brittle and slows tests unnecessarily. Consider waiting for a specific DOM change or network idle state after granularity selection.♻️ More robust wait
await granSelect.selectOption(targetGran); - // Wait for AJAX update - await page.waitForTimeout(3000); + // Wait for chart data to update after AJAX + await page.waitForFunction( + (el, oldData) => el?.getAttribute('data-data') !== oldData, + { timeout: 10_000 }, + await chartDataEl.elementHandle(), + initialDataRaw + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/chart-robustness.spec.ts` around lines 294 - 297, Replace the brittle fixed delay call page.waitForTimeout(3000) with an explicit wait that targets the post-granularity-change condition: for example, wait for the specific DOM update (use page.waitForSelector or page.waitForFunction to detect the chart element/text/attribute that changes after granularity selection) or wait for the relevant network response using page.waitForResponse matching the request URL/endpoint; update the test around the granularity selection step in chart-robustness.spec.ts to use one of these explicit waits instead of page.waitForTimeout(3000).tests/e2e/chart-negative-regression.spec.ts (1)
61-147:runBucketTestfunction is defined but never called.This function generates PHP scripts for comparing master vs current DataBuckets behavior, but neither NEG-1 nor NEG-2 actually invokes it. The tests instead use
fetchChartData()from helpers and verify behavior through code content inspection.Consider removing this dead code or documenting why it's retained for future use.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/chart-negative-regression.spec.ts` around lines 61 - 147, runBucketTest is dead code (defined but never invoked by NEG-1/NEG-2) — either remove the entire runBucketTest function from chart-negative-regression.spec.ts to eliminate unused code, or explicitly document why it’s retained (add a top-of-function comment referencing NEG-1 and NEG-2 and that the tests use fetchChartData() instead) so future readers know it’s intentionally kept; locate the runBucketTest declaration and delete it or add the explanatory comment accordingly.tests/e2e/helpers/chart.ts (1)
19-50: PHP code generation interpolates values directly into strings.While
startTsandendTsare numbers andgranularitycomes from test code (not user input), the pattern of interpolating values into PHP strings is fragile. The server-side validation inChart.phpprovides defense-in-depth, but consider using a more structured approach.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/e2e/helpers/chart.ts` around lines 19 - 50, The test currently injects startTs, endTs and granularity directly into the phpCode string inside fetchChartData, which is fragile; change fetchChartData to serialize the parameters into a single safe payload (e.g., JSON or base64) and embed only that encoded string in phpCode, then decode/json_decode it in the PHP snippet and set $_POST/$_REQUEST from the decoded structure before calling \\SlimStat\\Modules\\Chart::ajaxFetchChartData(); specifically, stop interpolating ${startTs}, ${endTs} and '${granularity}' directly and instead write something like a JSON-encoded argsPayload in the tmpFile and have the PHP use json_decode to populate $_POST['args'], $_POST['granularity'] and $_REQUEST values so values are passed structurally and not string-interpolated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@tests/e2e/chart-monthly-daily-granularity.spec.ts`:
- Around line 95-106: The test mutates the WP option via getPool().execute in
the for-loop and calls restoreOption('start_of_week') after the loop, which can
be skipped if an assertion fails; wrap the mutation+assert loop in a try/finally
so restoreOption('start_of_week') always runs: call
snapshotOption('start_of_week') before the try, perform the for-loop where you
set the option (getPool().execute), call fetchChartData and assertions
(fetchChartData, getV1, sumArr) inside the try, and place
restoreOption('start_of_week') in the finally block to guarantee cleanup even on
failures.
- Around line 219-230: The test mutates the WP option 'start_of_week' with
getPool().execute inside a loop but doesn't guarantee restoreOption runs if an
assertion fails; wrap the mutation+assertion loop in a try/finally: call await
snapshotOption('start_of_week') before the try, perform the for-loop (updates,
fetchChartData, expect, results accumulation) inside the try, and ensure await
restoreOption('start_of_week') is invoked in the finally block so cleanup always
occurs; reference functions: snapshotOption, getPool().execute, fetchChartData,
getV1, sumArr, restoreOption.
In `@tests/e2e/weekly-bucketing-last-week-count.spec.ts`:
- Around line 43-92: The test "March 14 data lands in Mar 9 bucket, NOT in Mar
16 bucket (sow=1)" mutates global state (calls snapshotOption and
getPool().execute to set start_of_week) but only calls
restoreOption('start_of_week') on the success path; wrap the body that seeds
rows and assertions in a try/finally block so restoreOption('start_of_week')
runs in finally, ensuring cleanup even if assertions fail, keeping
snapshotOption(), getPool().execute(... 'start_of_week' ...), insertRows(...),
fetchChartData(...), and related assertions inside the try and calling
restoreOption in the finally.
---
Nitpick comments:
In `@tests/e2e/chart-negative-regression.spec.ts`:
- Around line 61-147: runBucketTest is dead code (defined but never invoked by
NEG-1/NEG-2) — either remove the entire runBucketTest function from
chart-negative-regression.spec.ts to eliminate unused code, or explicitly
document why it’s retained (add a top-of-function comment referencing NEG-1 and
NEG-2 and that the tests use fetchChartData() instead) so future readers know
it’s intentionally kept; locate the runBucketTest declaration and delete it or
add the explanatory comment accordingly.
In `@tests/e2e/chart-robustness.spec.ts`:
- Around line 44-51: The setTimezone function currently interpolates mysqlTz
into the SQL string (in setTimezone and pool.execute calls), which is unsafe;
update setTimezone to avoid direct string interpolation by using a parameterized
query for the SET time_zone statement (use pool.execute with a placeholder and
pass mysqlTz) or, if the DB driver disallows parameterizing SET, strictly
validate/whitelist mysqlTz before interpolating (e.g., allow only offsets like
'+00:00' or known timezone names) and keep the wp_options update using the
existing parameterized placeholder for wpGmtOffset; ensure references to
setTimezone, getPool, and pool.execute are updated accordingly.
- Around line 294-297: Replace the brittle fixed delay call
page.waitForTimeout(3000) with an explicit wait that targets the
post-granularity-change condition: for example, wait for the specific DOM update
(use page.waitForSelector or page.waitForFunction to detect the chart
element/text/attribute that changes after granularity selection) or wait for the
relevant network response using page.waitForResponse matching the request
URL/endpoint; update the test around the granularity selection step in
chart-robustness.spec.ts to use one of these explicit waits instead of
page.waitForTimeout(3000).
In `@tests/e2e/helpers/chart.ts`:
- Around line 19-50: The test currently injects startTs, endTs and granularity
directly into the phpCode string inside fetchChartData, which is fragile; change
fetchChartData to serialize the parameters into a single safe payload (e.g.,
JSON or base64) and embed only that encoded string in phpCode, then
decode/json_decode it in the PHP snippet and set $_POST/$_REQUEST from the
decoded structure before calling
\\SlimStat\\Modules\\Chart::ajaxFetchChartData(); specifically, stop
interpolating ${startTs}, ${endTs} and '${granularity}' directly and instead
write something like a JSON-encoded argsPayload in the tmpFile and have the PHP
use json_decode to populate $_POST['args'], $_POST['granularity'] and $_REQUEST
values so values are passed structurally and not string-interpolated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d16c5434-7e1c-4672-9836-5d12ac073f89
📒 Files selected for processing (10)
tests/e2e/chart-monthly-daily-granularity.spec.tstests/e2e/chart-negative-regression.spec.tstests/e2e/chart-robustness.spec.tstests/e2e/chart-today-zero-regression.spec.tstests/e2e/global-setup.tstests/e2e/helpers/chart.tstests/e2e/playwright.config.tstests/e2e/weekly-bucketing-last-week-count.spec.tstests/e2e/weekly-bucketing-sow6-mar7-validation.spec.tstests/e2e/weekly-start-of-week-bucketing.spec.ts
✅ Files skipped from review due to trivial changes (1)
- tests/e2e/playwright.config.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/e2e/weekly-start-of-week-bucketing.spec.ts
- tests/e2e/weekly-bucketing-sow6-mar7-validation.spec.ts
E2E Chart Test Suite — 41/41 PassFull chart E2E suite consolidated and expanded. All 41 tests pass in 34.4s (single run, no flakes). Test Matrix
Key Changes (commit 42e4724)
Gaps Covered
|
E2E Chart Test Suite — 41/41 PassFull chart E2E suite consolidated and expanded. All 41 tests pass in 34.4s (single run, no flakes). Test Matrix
Key Changes (commit 42e4724)
Gaps Covered
|
Changelog
Fixed
Improved
cpt:prefix guidance to content type exclusion settingSummary by CodeRabbit
Release
Bug Fixes
Improvements
Documentation
Tests