Skip to content

ci: smoke tests using wwebjs#222

Open
rvignesh89 wants to merge 4 commits into
mainfrom
rvignesh/smoke-tests
Open

ci: smoke tests using wwebjs#222
rvignesh89 wants to merge 4 commits into
mainfrom
rvignesh/smoke-tests

Conversation

@rvignesh89
Copy link
Copy Markdown
Contributor

@rvignesh89 rvignesh89 commented May 28, 2026

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive end-to-end smoke testing with multi-environment support and automated status monitoring.
    • Added cloud-based session management for improved testing infrastructure.
  • Chores

    • Updated testing framework and dependencies to latest versions.
    • Configured automated testing workflows for production and staging environments.
    • Integrated real-time status reporting for test results.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive WhatsApp smoke testing framework, adding new TypeScript modules for session persistence, status reporting, and test orchestration. It updates dependencies and CI/CD workflows to execute smoke tests on a schedule and via manual triggers, validating chat flows end-to-end.

Changes

WhatsApp Smoke Test Suite

Layer / File(s) Summary
Project Configuration & Dependencies
package.json, wwebjs/smoke/tsconfig.json, .cursorignore, .gitignore
New runtime dependencies (whatsapp-web.js, @google-cloud/storage, tsx, qrcode-terminal), Cypress bumped from 13.6.2 to 15.15.0, new wa:smoke script; ignore rules added for .envrc and cypress/videos.
Test Configuration & Infrastructure Services
wwebjs/smoke/flows.ts, wwebjs/smoke/gcs-store.ts, wwebjs/smoke/instatus.ts
Flow definitions with expected message rules and environment configurations for production/staging; GCS-backed session store managing RemoteAuth ZIP uploads/downloads; Instatus API client reporting test status.
Smoke Test Runner Implementation
wwebjs/smoke/runner.ts
WhatsApp client initialization using RemoteAuth with GCS persistence; helper functions to wait for client readiness, collect and validate incoming messages, and enforce timeouts; main orchestration handling login, message flow execution, validation, and cleanup.
Test Specifications & CI/CD Workflows
cypress/e2e/smoke.spec.ts, .github/workflows/e2e.yml, .github/workflows/smoke.yml
Cypress E2E spec validating web UI login and message presence; e2e.yml updated to exclude both filesearch and smoke specs; new smoke.yml workflow with scheduled (30-min intervals) and manual triggers, Node 22 setup, GCP credential injection, and Instatus reporting integration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The PR introduces a new, self-contained WhatsApp smoke test framework with infrastructure services, orchestration logic, and CI/CD integration. Complexity stems from multi-component interactions (WhatsApp client, GCS, Instatus API), async/await patterns, and dependency management. Changes are cohesive and follow consistent patterns, but require understanding of RemoteAuth flows, message collection logic, and environment variable wiring.

Possibly related PRs

  • glific/cypress-testing#219: Updates the e2e.yml workflow to exclude the filesearch spec; this PR further extends that exclusion to also exclude the smoke spec.

Suggested labels

ready for review

Suggested reviewers

  • akanshaaa19
  • mdshamoon

🐰 A WhatsApp test hops into view,
With sessions stored in clouds so blue,
Messages flow and statuses gleam,
Smoke and status paint the dream! 🌬️✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding smoke tests using the whatsapp-web.js (wwebjs) library integrated into CI workflows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rvignesh/smoke-tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rvignesh89 rvignesh89 marked this pull request as ready for review May 28, 2026 09:30
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (2)
.github/workflows/smoke.yml (1)

30-30: ⚖️ Poor tradeoff

Consider pinning actions to SHA hashes.

Using action tags (e.g., @v4) instead of commit SHAs can expose the workflow to supply chain attacks if the tag is moved or the action is compromised. Pinning to immutable SHA hashes provides stronger security guarantees.

🔐 Example with SHA pinning
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

-      - uses: actions/setup-node@v4
+      - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0

Note: You can find current SHA hashes for these actions in their respective GitHub repositories.

Also applies to: 32-32

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/smoke.yml at line 30, The workflow uses mutable action
tags (e.g., "actions/checkout@v4") which can be moved and pose supply-chain
risk; replace those tag references with the corresponding immutable commit SHAs
for actions/checkout and the other action referenced (line 32) by updating the
uses entries to the full "actions/checkout@<SHA>" form (and the equivalent SHA
for the other action) so the workflow pins to a specific commit instead of a
floating tag.
cypress/e2e/smoke.spec.ts (1)

54-55: ⚡ Quick win

Consider a more dynamic wait strategy.

The hardcoded 30-second wait may be unnecessary if messages arrive faster, or insufficient if they're delayed. Consider polling for a specific message count or using a custom wait condition that checks for message presence with a reasonable timeout.

💡 Example using should assertion with retry
-      // Wait for 30 seconds to ensure all messages are in
-      cy.wait(30000);
-
-      cy.get('[data-testid="messageContainer"] [data-testid="content"]', { timeout: 10000 }).then(
+      // Wait for at least 3 messages with auto-retry
+      cy.get('[data-testid="messageContainer"] [data-testid="content"]', { timeout: 30000 })
+        .should('have.length.at.least', 3)
+        .then(
         ($messages) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cypress/e2e/smoke.spec.ts` around lines 54 - 55, Replace the hardcoded
cy.wait(30000) with a dynamic polling/assertion that waits for the expected
messages instead of a fixed timeout: stop using the cy.wait(30000) statement and
instead use Cypress retryable assertions (e.g.,
cy.get('<message-list-selector>').should('have.length.at.least', EXPECTED_COUNT,
{ timeout: 30000 }) or cy.contains('<expected-message-text>').should('exist', {
timeout: 30000 })) so the test proceeds as soon as messages arrive but still
fails after a reasonable timeout; update the selector/text and EXPECTED_COUNT to
match the application’s message container used in this spec.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/smoke.yml:
- Around line 47-48: The "Write GCP credentials" step writes the service account
JSON to /tmp/gcp-key.json with no explicit permissions; update the step so the
file is created with restrictive permissions (owner read/write only) by e.g.
setting a restrictive umask before writing or immediately running chmod 600 on
/tmp/gcp-key.json after the echo, ensuring the credentials file is only readable
by the runner process.

In `@cypress/e2e/smoke.spec.ts`:
- Around line 63-68: The current assertion builds a strict expected string in
dateString and checks Cypress.$(lastThree[0]).text() for an exact match, which
is flaky around midnights/timezones; update the assertion in the test (where
dateString and lastThree are used) to be tolerant: either (a) generate a small
set of allowed date strings (today, yesterday, tomorrow) and assert the WhatsApp
message contains any of those, or (b) replace the exact match with a regex that
validates the DD/MM/YYYY format (e.g., \d{2}\/\d{2}\/\d{4}) and only assert
format, not exact value; apply this change where dateString is defined and where
expect(...).to.contain(...) is called.
- Around line 34-35: Remove the redundant second click on the password field: in
the test where cy.get('[data-testid="outlinedInput"] [name="password"]').click()
is called twice, keep a single cy.get(...).click() before typing into the field
(remove the duplicate call referencing the same selector).

In `@wwebjs/smoke/flows.ts`:
- Around line 44-45: The botPhoneNumber fallback currently hard-codes a real
number; remove the '+918657048982' default and make BOT_PHONE_NUMBER required by
replacing the inline fallback with a strict check (read
process.env.BOT_PHONE_NUMBER into botPhoneNumber and if falsy throw a clear
error during startup), or set botPhoneNumber to undefined and add startup
validation that throws; update any code that uses botPhoneNumber (e.g.,
references in flows.ts) to rely on this validation so the process fails fast
instead of sending to an unintended recipient.

In `@wwebjs/smoke/gcs-store.ts`:
- Around line 73-75: The catch block that handles deletion from GCS currently
checks (err as NodeJS.ErrnoException)?.code !== '404' using a string; change
this to treat the GCS ApiError code as a number (compare to 404) and
additionally tolerate the HTTP response shape by checking err.code !== 404 ||
err.response?.statusCode !== 404 (or explicitly accept either 404 as number or
response.statusCode === 404) so that missing-object errors are swallowed and
other errors are rethrown; update the catch around the bucket.file(...).delete()
call accordingly and avoid relying on a top-level string '404'.

In `@wwebjs/smoke/instatus.ts`:
- Around line 14-23: The function reportToInstatus currently logs success for
any HTTP response and only treats transport errors as failures; update
reportToInstatus to check the fetch Response (res) using res.ok after the PUT
and treat non-2xx responses as failures by logging an error and throwing or
returning a rejected result so callers can handle it; locate the fetch call and
the console.log("Instatus report...") that follows it, replace or augment that
logic to inspect res.ok (and optionally include res.status/res.statusText and
body) and handle non-ok responses as errors.

In `@wwebjs/smoke/runner.ts`:
- Around line 27-38: The waitForRemoteSessionSaved Promise attaches its
'remote_session_saved' listener too late and can miss events that fired earlier;
update waitForRemoteSessionSaved to first check an existing saved-state on the
client (e.g., a boolean property or getter like client.remoteSessionSaved or
client.isRemoteSessionSaved(), add that property if it doesn't exist), resolve
immediately if true, otherwise attach client.once('remote_session_saved', ...)
and start the timeout; also ensure any other usage sites that currently add the
listener in finally follow the same pattern (check saved-state first then
attach) so the event cannot be missed.
- Around line 145-148: The runner currently only validates env.gcsBucket and
exits on missing value; add the same fail-fast checks for env.botPhoneNumber and
env.sessionId so missing bot/session configuration is reported immediately.
Update the validation block (the check around env.gcsBucket in
wwebjs/smoke/runner.ts) to validate env.gcsBucket, env.botPhoneNumber and
env.sessionId, using console.error() with actionable messages for each missing
variable and process.exit(1) to stop startup when any are absent.

---

Nitpick comments:
In @.github/workflows/smoke.yml:
- Line 30: The workflow uses mutable action tags (e.g., "actions/checkout@v4")
which can be moved and pose supply-chain risk; replace those tag references with
the corresponding immutable commit SHAs for actions/checkout and the other
action referenced (line 32) by updating the uses entries to the full
"actions/checkout@<SHA>" form (and the equivalent SHA for the other action) so
the workflow pins to a specific commit instead of a floating tag.

In `@cypress/e2e/smoke.spec.ts`:
- Around line 54-55: Replace the hardcoded cy.wait(30000) with a dynamic
polling/assertion that waits for the expected messages instead of a fixed
timeout: stop using the cy.wait(30000) statement and instead use Cypress
retryable assertions (e.g.,
cy.get('<message-list-selector>').should('have.length.at.least', EXPECTED_COUNT,
{ timeout: 30000 }) or cy.contains('<expected-message-text>').should('exist', {
timeout: 30000 })) so the test proceeds as soon as messages arrive but still
fails after a reasonable timeout; update the selector/text and EXPECTED_COUNT to
match the application’s message container used in this spec.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dfe5201b-6fc6-418c-99cf-ce76a8089e0f

📥 Commits

Reviewing files that changed from the base of the PR and between 383e31d and 0a6cebc.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (11)
  • .cursorignore
  • .github/workflows/e2e.yml
  • .github/workflows/smoke.yml
  • .gitignore
  • cypress/e2e/smoke.spec.ts
  • package.json
  • wwebjs/smoke/flows.ts
  • wwebjs/smoke/gcs-store.ts
  • wwebjs/smoke/instatus.ts
  • wwebjs/smoke/runner.ts
  • wwebjs/smoke/tsconfig.json

Comment on lines +47 to +48
- name: Write GCP credentials
run: echo '${{ secrets.GCP_SA_KEY_JSON }}' > /tmp/gcp-key.json
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Set restrictive permissions on the credentials file.

Writing the GCP service account key to a file without explicit permissions could expose it to other processes. While GitHub Actions runners are isolated, it's best practice to restrict file permissions.

🔒 Proposed fix
       - name: Write GCP credentials
-        run: echo '${{ secrets.GCP_SA_KEY_JSON }}' > /tmp/gcp-key.json
+        run: |
+          echo '${{ secrets.GCP_SA_KEY_JSON }}' > /tmp/gcp-key.json
+          chmod 600 /tmp/gcp-key.json
📝 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.

Suggested change
- name: Write GCP credentials
run: echo '${{ secrets.GCP_SA_KEY_JSON }}' > /tmp/gcp-key.json
- name: Write GCP credentials
run: |
echo '${{ secrets.GCP_SA_KEY_JSON }}' > /tmp/gcp-key.json
chmod 600 /tmp/gcp-key.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/smoke.yml around lines 47 - 48, The "Write GCP
credentials" step writes the service account JSON to /tmp/gcp-key.json with no
explicit permissions; update the step so the file is created with restrictive
permissions (owner read/write only) by e.g. setting a restrictive umask before
writing or immediately running chmod 600 on /tmp/gcp-key.json after the echo,
ensuring the credentials file is only readable by the runner process.

Comment thread cypress/e2e/smoke.spec.ts
Comment on lines +34 to +35
cy.get('[data-testid="outlinedInput"] [name="password"]').click();
cy.get('[data-testid="outlinedInput"] [name="password"]').click();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove redundant click.

The password field is clicked twice before typing. Only one click is needed to focus the field.

🔧 Proposed fix
-      cy.get('[data-testid="outlinedInput"] [name="password"]').click();
       cy.get('[data-testid="outlinedInput"] [name="password"]').click();
       cy.get('[data-testid="outlinedInput"] [name="password"]').type(SMOKE_TEST_LOGIN_PASSWORD);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cypress/e2e/smoke.spec.ts` around lines 34 - 35, Remove the redundant second
click on the password field: in the test where
cy.get('[data-testid="outlinedInput"] [name="password"]').click() is called
twice, keep a single cy.get(...).click() before typing into the field (remove
the duplicate call referencing the same selector).

Comment thread cypress/e2e/smoke.spec.ts
Comment on lines +63 to +68
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const dateString = `World! ${day}/${month}/${year}`;
expect(Cypress.$(lastThree[0]).text()).to.contain(dateString);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Date assertion may cause flaky failures.

The test constructs the expected date string from new Date() at test execution time and assumes the WhatsApp message contains the same date. This creates timing issues:

  • Tests running near midnight may fail if the message timestamp crosses the day boundary
  • Timezone differences between the test runner and the WhatsApp bot could cause mismatches
  • Message delays could result in different dates

Consider either:

  1. Accepting a date within a reasonable range (today ± 1 day)
  2. Using a regex pattern to validate date format rather than exact date
  3. Making the flow send a known static value instead of a dynamic date
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cypress/e2e/smoke.spec.ts` around lines 63 - 68, The current assertion builds
a strict expected string in dateString and checks Cypress.$(lastThree[0]).text()
for an exact match, which is flaky around midnights/timezones; update the
assertion in the test (where dateString and lastThree are used) to be tolerant:
either (a) generate a small set of allowed date strings (today, yesterday,
tomorrow) and assert the WhatsApp message contains any of those, or (b) replace
the exact match with a regex that validates the DD/MM/YYYY format (e.g.,
\d{2}\/\d{2}\/\d{4}) and only assert format, not exact value; apply this change
where dateString is defined and where expect(...).to.contain(...) is called.

Comment thread wwebjs/smoke/flows.ts
Comment on lines +44 to +45
botPhoneNumber: process.env.BOT_PHONE_NUMBER ?? '+918657048982',
sessionId: process.env.WHATSAPP_SESSION_ID ?? 'production-sender',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove the hard-coded production phone fallback.

If BOT_PHONE_NUMBER is not set, the run still targets a real number by default. With the current production default selection, that can send smoke traffic to an unintended recipient instead of failing fast.

Suggested fix
-    botPhoneNumber: process.env.BOT_PHONE_NUMBER ?? '+918657048982',
+    botPhoneNumber: process.env.BOT_PHONE_NUMBER ?? '',
📝 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.

Suggested change
botPhoneNumber: process.env.BOT_PHONE_NUMBER ?? '+918657048982',
sessionId: process.env.WHATSAPP_SESSION_ID ?? 'production-sender',
botPhoneNumber: process.env.BOT_PHONE_NUMBER ?? '',
sessionId: process.env.WHATSAPP_SESSION_ID ?? 'production-sender',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wwebjs/smoke/flows.ts` around lines 44 - 45, The botPhoneNumber fallback
currently hard-codes a real number; remove the '+918657048982' default and make
BOT_PHONE_NUMBER required by replacing the inline fallback with a strict check
(read process.env.BOT_PHONE_NUMBER into botPhoneNumber and if falsy throw a
clear error during startup), or set botPhoneNumber to undefined and add startup
validation that throws; update any code that uses botPhoneNumber (e.g.,
references in flows.ts) to rely on this validation so the process fails fast
instead of sending to an unintended recipient.

Comment thread wwebjs/smoke/gcs-store.ts
Comment on lines +73 to +75
} catch (err: unknown) {
if ((err as NodeJS.ErrnoException)?.code !== '404') throw err;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In the Node.js @google-cloud/storageclient, what fields/types are used on errors thrown byfile.delete() when the object does not exist?

💡 Result:

When you call bucket.file(name).delete() and the object does not exist, the client throws an ApiError (from @google-cloud/common) whose error body includes these fields, which are then exposed as properties on the thrown error: 1) code (number | undefined) - ApiError has a code?: number property. [1] - The thrown error for a missing object includes code: 404 in its body. [2] 2) message (string) - ApiError is constructed with a message string (and thus the thrown error has e.message). [3] - The missing-object case shows a message like No such object: <bucket>/<object>. [4] 3) errors (GoogleInnerError[] | undefined) - ApiError has an errors?: GoogleInnerError[] property. [1] - In the missing-object case, the error body includes errors: [Array]. [2] 4) response (r.Response | undefined) - ApiError has a response?: r.Response property. [1] - This response is set from errorBody.response in @google-cloud/common’s util. [3] Additionally, for the specific “not found” HTTP status: - The HTTP status code is 404, as shown by the missing-object error body having code: 404. [2] These are the fields/types you can rely on on the thrown error instance for this scenario: code?: number, message: string, errors?: GoogleInnerError[], and response?: r.Response. [1][3][2][4]

Citations:


Handle GCS “not found” errors by checking numeric HTTP 404.

bucket.file(...).delete() throws an ApiError where the missing-object case sets code: 404 as a number; comparing to '404' can incorrectly rethrow. Update the catch to test err.code !== 404 (optionally fall back to err.response?.statusCode), and don’t rely on statusCode being a top-level field.

Suggested fix
-    } catch (err: unknown) {
-      if ((err as NodeJS.ErrnoException)?.code !== '404') throw err;
+    } catch (err: unknown) {
+      const e = err as { code?: number; response?: { statusCode?: number } };
+      if (e.code !== 404 && e.response?.statusCode !== 404) throw err;
     }
📝 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.

Suggested change
} catch (err: unknown) {
if ((err as NodeJS.ErrnoException)?.code !== '404') throw err;
}
} catch (err: unknown) {
const e = err as { code?: number; response?: { statusCode?: number } };
if (e.code !== 404 && e.response?.statusCode !== 404) throw err;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wwebjs/smoke/gcs-store.ts` around lines 73 - 75, The catch block that handles
deletion from GCS currently checks (err as NodeJS.ErrnoException)?.code !==
'404' using a string; change this to treat the GCS ApiError code as a number
(compare to 404) and additionally tolerate the HTTP response shape by checking
err.code !== 404 || err.response?.statusCode !== 404 (or explicitly accept
either 404 as number or response.statusCode === 404) so that missing-object
errors are swallowed and other errors are rethrown; update the catch around the
bucket.file(...).delete() call accordingly and avoid relying on a top-level
string '404'.

Comment thread wwebjs/smoke/instatus.ts
Comment on lines +14 to +23
const res = await fetch(url, {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status }),
});
console.log(`Instatus report: ${status} → HTTP ${res.status}`);
} catch (err) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For Instatus v2 component update endpoints, are non-2xx responses considered failed updates that clients should explicitly handle?

💡 Result:

Yes. For Instatus v2 component update endpoints (PUT /v2/:page_id/components/:component_id), you should treat any non-2xx HTTP response as a failed update that clients must handle explicitly. Instatus’s API documentation states that “Responses from the Instatus API, including errors, are encoded as JSON” and that error responses include a code and message in the payload (so clients should not assume that only the request transport succeeded) [1]. For component updates, the API reference documents the update endpoint and shows a normal 200-style success example response when the update succeeds [2][3]. Given that Instatus uses explicit error payloads with an “error” object (code/message) and that non-2xx status codes are categorized by HTTP as client/server errors rather than successful responses [4], a non-2xx response indicates the server did not complete the update. Practical client guidance: consider the update successful only when the HTTP status is in the 2xx range and you can parse the success response body; otherwise, read the JSON error payload (error.code / error.message) and handle/retry/alert as appropriate [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the referenced file around the stated lines
ls -la
sed -n '1,120p' wwebjs/smoke/instatus.ts

# Check for any other fetch/error handling patterns in the repo
rg -n "instatus.*fetch|fetch\\(url|res\\.ok|HTTP .*res\\.status|reported|Instatus report" wwebjs/smoke/instatus.ts wwebjs -S

Repository: glific/cypress-testing

Length of output: 2434


Treat non-2xx Instatus responses as failures.

reportToInstatus logs success for any HTTP status and only treats network/transport errors as failures (the catch won’t run for 401/404/5xx). Check res.ok and fail the report on non-2xx.

Suggested fix
     const res = await fetch(url, {
       method: 'PUT',
       headers: {
         Authorization: `Bearer ${apiKey}`,
         'Content-Type': 'application/json',
       },
       body: JSON.stringify({ status }),
     });
-    console.log(`Instatus report: ${status} → HTTP ${res.status}`);
+    if (!res.ok) {
+      throw new Error(`Instatus report failed with HTTP ${res.status}`);
+    }
+    console.log(`Instatus report: ${status} → HTTP ${res.status}`);
For Instatus v2 component update endpoints, are non-2xx responses considered failed updates that clients should explicitly handle?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wwebjs/smoke/instatus.ts` around lines 14 - 23, The function reportToInstatus
currently logs success for any HTTP response and only treats transport errors as
failures; update reportToInstatus to check the fetch Response (res) using res.ok
after the PUT and treat non-2xx responses as failures by logging an error and
throwing or returning a rejected result so callers can handle it; locate the
fetch call and the console.log("Instatus report...") that follows it, replace or
augment that logic to inspect res.ok (and optionally include
res.status/res.statusText and body) and handle non-ok responses as errors.

Comment thread wwebjs/smoke/runner.ts
Comment on lines +27 to +38
function waitForRemoteSessionSaved(client: Client, timeoutMs: number): Promise<void> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Session was not saved to GCS within ${timeoutMs / 1000}s`));
}, timeoutMs);

client.once('remote_session_saved', () => {
clearTimeout(timer);
console.log('Remote session saved to GCS');
resolve();
});
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid missing remote_session_saved due late listener registration.

The listener is attached only in finally; if the event already fired earlier, this path waits the full timeout and emits a false warning.

Suggested fix
+  let remoteSessionSaved = false;
+  client.on('remote_session_saved', () => {
+    remoteSessionSaved = true;
+    console.log('Remote session saved to GCS');
+  });

   ...
-    if (!sessionAlreadyInGcs) {
+    if (!sessionAlreadyInGcs && !remoteSessionSaved) {
       try {
         await waitForRemoteSessionSaved(client, 90_000);
       } catch (err) {
         console.warn('Session may not have been uploaded to GCS:', (err as Error).message);
       }
     }

Also applies to: 222-227

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wwebjs/smoke/runner.ts` around lines 27 - 38, The waitForRemoteSessionSaved
Promise attaches its 'remote_session_saved' listener too late and can miss
events that fired earlier; update waitForRemoteSessionSaved to first check an
existing saved-state on the client (e.g., a boolean property or getter like
client.remoteSessionSaved or client.isRemoteSessionSaved(), add that property if
it doesn't exist), resolve immediately if true, otherwise attach
client.once('remote_session_saved', ...) and start the timeout; also ensure any
other usage sites that currently add the listener in finally follow the same
pattern (check saved-state first then attach) so the event cannot be missed.

Comment thread wwebjs/smoke/runner.ts
Comment on lines +145 to +148
if (!env.gcsBucket) {
console.error('GCS_BUCKET env var is required');
process.exit(1);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast on missing bot/session configuration, not only bucket.

Line 145 validates only gcsBucket; missing botPhoneNumber or sessionId fails later with less actionable errors (for example invalid chat id).

Suggested fix
   if (!env.gcsBucket) {
     console.error('GCS_BUCKET env var is required');
     process.exit(1);
   }
+  if (!env.botPhoneNumber) {
+    console.error('BOT_PHONE_NUMBER env var is required');
+    process.exit(1);
+  }
+  if (!env.sessionId) {
+    console.error('WHATSAPP_SESSION_ID env var is required');
+    process.exit(1);
+  }
📝 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.

Suggested change
if (!env.gcsBucket) {
console.error('GCS_BUCKET env var is required');
process.exit(1);
}
if (!env.gcsBucket) {
console.error('GCS_BUCKET env var is required');
process.exit(1);
}
if (!env.botPhoneNumber) {
console.error('BOT_PHONE_NUMBER env var is required');
process.exit(1);
}
if (!env.sessionId) {
console.error('WHATSAPP_SESSION_ID env var is required');
process.exit(1);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wwebjs/smoke/runner.ts` around lines 145 - 148, The runner currently only
validates env.gcsBucket and exits on missing value; add the same fail-fast
checks for env.botPhoneNumber and env.sessionId so missing bot/session
configuration is reported immediately. Update the validation block (the check
around env.gcsBucket in wwebjs/smoke/runner.ts) to validate env.gcsBucket,
env.botPhoneNumber and env.sessionId, using console.error() with actionable
messages for each missing variable and process.exit(1) to stop startup when any
are absent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant