summaryrefslogtreecommitdiffstats
path: root/test/checkout.test.js
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:52:15 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:52:15 -0300
commit511a0ab33b5b12a4cd8a1d4dca6c5dce50cdb6c1 (patch)
tree462412b439743c2d04f1acf24f6557251d3a8265 /test/checkout.test.js
parent535dbda6b48171f8115b455e54790de94d97d42a (diff)
downloadwoocommerce-511a0ab33b5b12a4cd8a1d4dca6c5dce50cdb6c1.tar.gz
Name the municipality behind a CEP that does not existHEADv0.2.0main
A CEP that fails at the checkout is almost never a random number. It is a shopper who knows perfectly well which town they live in and got a digit wrong, most often by reaching for the -000 that 957 municipalities never received. The API now names the municipality such a number would have belonged to, in the body of its own 404, so the message can say "that would be in Areal/RJ, which has CEPs from 25845-001 to 25849-899" instead of leaving the shopper at a dead end with nothing to act on. It stays an error. Nothing from it is written into a checkout field, on either checkout and in either lookup mode: a CEP that does not exist has no address, and filling one in from the municipality behind it means a parcel delivered to the wrong town and a chargeback behind that. The one module that reads the 404 body hands its callers a finished sentence and never the data itself, so there is no shape in which it could leak into a field later. The two CEPs quoted are the lowest and the highest that really exist there, never a list and never a suggestion, because the range is sparse enough that a number out of the middle of it would most likely not exist either. The widget correctly throws its 404 away without reading it, so the body is fetched once more, on the miss path only and once per CEP. In proxy mode PHP passes the municipality through with the 404 and caches it with the miss, which is what keeps the two modes indistinguishable from the browser. Anything missing or misshapen falls back to the message the plugin has always shown.
Diffstat (limited to 'test/checkout.test.js')
-rw-r--r--test/checkout.test.js171
1 files changed, 169 insertions, 2 deletions
diff --git a/test/checkout.test.js b/test/checkout.test.js
index 074b13a..cce2575 100644
--- a/test/checkout.test.js
+++ b/test/checkout.test.js
@@ -168,7 +168,7 @@ describe("plugin", () => {
});
test("declares the version WooCommerce reports", () => {
- expect(wp(["plugin", "get", "cepis-woocommerce", "--field=version"])).toBe("0.1.0");
+ expect(wp(["plugin", "get", "cepis-woocommerce", "--field=version"])).toBe("0.2.0");
});
});
@@ -280,6 +280,47 @@ describe("block checkout", () => {
await close();
}, 90000);
+
+ test("a CEP that does not exist names its municipality and still fills nothing", async () => {
+ const { page, close } = await checkout("/checkout/");
+
+ await settled(page);
+ await typeCep(page, "#shipping-postcode", "01001000");
+ await page.waitForFunction(
+ () => document.querySelector("#shipping-address_1").value !== "",
+ undefined,
+ { timeout: 15000 },
+ );
+
+ await typeCep(page, "#shipping-postcode", "25845000");
+ await page.waitForFunction(
+ () =>
+ document.body.innerText.includes(
+ "would be in Areal/RJ, which has CEPs from 25845-001 to 25849-899",
+ ),
+ undefined,
+ { timeout: 15000 },
+ );
+
+ const after = await page.evaluate(() => ({
+ street: document.querySelector("#shipping-address_1").value,
+ city: document.querySelector("#shipping-city").value,
+ state: document.querySelector("#shipping-state").value,
+ store: JSON.stringify(window.wp.data.select("wc/store/cart").getCustomerData()),
+ }));
+
+ // The address the previous, real CEP produced is still there, untouched.
+ expect(after.street).toBe("Praça da Sé");
+ expect(after.city).toBe("São Paulo");
+ expect(after.state).toBe("SP");
+
+ // And nothing from the 404 reached the data store the order is built from.
+ // A municipality named in an error is a guess about a typo, not an address.
+ expect(after.store).not.toContain("Areal");
+ expect(after.store).not.toContain('"state":"RJ"');
+
+ await close();
+ }, 90000);
});
describe("classic checkout", () => {
@@ -443,6 +484,82 @@ describe("classic checkout", () => {
await close();
}, 90000);
+
+ test("a CEP that does not exist names its municipality and still fills nothing", async () => {
+ const { page, errors, close } = await checkout("/checkout-classico/");
+
+ await ready(page);
+ await typeCep(page, "#billing_postcode", "01001000");
+ await page.waitForFunction(
+ () => document.querySelector("#billing_address_1").value !== "",
+ undefined,
+ { timeout: 15000 },
+ );
+
+ await typeCep(page, "#billing_postcode", "25845000");
+ await page.waitForFunction(
+ () =>
+ (document.querySelector(".cepis-autofill-status") || {}).textContent ===
+ "CEP not found. This number would be in Areal/RJ, which has CEPs from 25845-001 to 25849-899. Check the number.",
+ undefined,
+ { timeout: 15000 },
+ );
+
+ const after = await page.evaluate(() => ({
+ street: document.querySelector("#billing_address_1").value,
+ city: document.querySelector("#billing_city").value,
+ state: document.querySelector("#billing_state").value,
+ invalid: document.querySelector("#billing_postcode").getAttribute("aria-invalid"),
+ leaked: Array.from(document.querySelectorAll("input, select, textarea"))
+ .map((field) => String(field.value == null ? "" : field.value))
+ .filter((value) => /areal|rio de janeiro|^RJ$/i.test(value)),
+ }));
+
+ // What the previous, real CEP filled in is still there.
+ expect(after.street).toBe("Praça da Sé");
+ expect(after.city).toBe("São Paulo");
+ expect(after.state).toBe("SP");
+ expect(after.invalid).toBe("true");
+
+ // The whole point: naming the municipality must not put it in a field.
+ // Shipping to a town the CEP does not belong to is a parcel gone astray.
+ expect(after.leaked).toEqual([]);
+ expect(errors).toEqual([]);
+
+ await close();
+ }, 90000);
+
+ test("a faixa it cannot use falls back to the plain message", async () => {
+ const { page, errors, close } = await checkout("/checkout-classico/");
+ const plain = "CEP not found. Check the number or fill the address in by hand.";
+
+ await ready(page);
+ await typeCep(page, "#billing_postcode", "25849000");
+
+ await page.waitForFunction(
+ (expected) =>
+ (document.querySelector(".cepis-autofill-status") || {}).textContent === expected,
+ plain,
+ { timeout: 15000 },
+ );
+
+ // Long enough for the follow-up request to have come back and, if it were
+ // going to, made a mess of the line.
+ await page.waitForTimeout(3000);
+
+ const after = await page.evaluate(() => ({
+ status: (document.querySelector(".cepis-autofill-status") || {}).textContent,
+ street: document.querySelector("#billing_address_1").value,
+ city: document.querySelector("#billing_city").value,
+ }));
+
+ expect(after.status).toBe(plain);
+ expect(after.street).toBe("");
+ expect(after.city).toBe("");
+ expect(errors).toEqual([]);
+
+ await close();
+ }, 90000);
});
describe("proxy mode", () => {
@@ -482,7 +599,7 @@ describe("proxy mode", () => {
const served = api.state.requests.filter((entry) => entry.cep === "01001000");
expect(served.length).toBe(1);
- expect(served[0].userAgent).toContain("cepis-woocommerce/0.1.0");
+ expect(served[0].userAgent).toContain("cepis-woocommerce/0.2.0");
expect(errors).toEqual([]);
await close();
@@ -516,6 +633,39 @@ describe("proxy mode", () => {
expect(api.state.requests.filter((entry) => entry.cep === "20040020").length).toBe(1);
}, 120000);
+ test("the municipality survives the proxy and its cache, and fills nothing", async () => {
+ api.reset();
+ const { page, close } = await checkout("/checkout-classico/");
+
+ await ready(page);
+ await typeCep(page, "#billing_postcode", "25845000");
+
+ await page.waitForFunction(
+ () =>
+ (document.querySelector(".cepis-autofill-status") || {}).textContent ===
+ "CEP not found. This number would be in Areal/RJ, which has CEPs from 25845-001 to 25849-899. Check the number.",
+ undefined,
+ { timeout: 20000 },
+ );
+
+ const after = await page.evaluate(() => ({
+ street: document.querySelector("#billing_address_1").value,
+ leaked: Array.from(document.querySelectorAll("input, select, textarea"))
+ .map((field) => String(field.value == null ? "" : field.value))
+ .filter((value) => /areal|rio de janeiro|^RJ$/i.test(value)),
+ }));
+
+ expect(after.street).toBe("");
+ expect(after.leaked).toEqual([]);
+
+ // One request reached the API. The lookup itself made it; the follow-up
+ // that reads the municipality out of the 404 body was served from the
+ // transient, which is only possible if the miss was cached with it.
+ expect(api.state.requests.filter((entry) => entry.cep === "25845000")).toHaveLength(1);
+
+ await close();
+ }, 90000);
+
test("the REST route refuses a request without a valid token", async () => {
const context = await browser.newContext();
const page = await context.newPage();
@@ -564,6 +714,23 @@ describe("translations", () => {
await close();
}, 90000);
+
+ test("so is the message that names the municipality", async () => {
+ const { page, close } = await checkout("/checkout-classico/");
+
+ await ready(page);
+ await typeCep(page, "#billing_postcode", "25845000");
+
+ await page.waitForFunction(
+ () =>
+ (document.querySelector(".cepis-autofill-status") || {}).textContent ===
+ "CEP não encontrado. Esse número seria de Areal/RJ, que tem CEPs de 25845-001 a 25849-899. Confira o número.",
+ undefined,
+ { timeout: 15000 },
+ );
+
+ await close();
+ }, 90000);
});
describe("housekeeping", () => {